Skip to content

Commit 21f2b00

Browse files
committed
feat: support build and link dynamic library
1 parent 59578ad commit 21f2b00

File tree

1 file changed

+47
-12
lines changed

1 file changed

+47
-12
lines changed

src/lib.rs

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ pub struct Build {
332332
shell_escaped_flags: Option<bool>,
333333
build_cache: Arc<BuildCache>,
334334
inherit_rustflags: bool,
335+
link_shared_flag: bool,
335336
}
336337

337338
/// Represents the types of errors that may occur while using cc-rs.
@@ -459,6 +460,7 @@ impl Build {
459460
shell_escaped_flags: None,
460461
build_cache: Arc::default(),
461462
inherit_rustflags: true,
463+
link_shared_flag: false,
462464
}
463465
}
464466

@@ -1227,6 +1229,14 @@ impl Build {
12271229
self
12281230
}
12291231

1232+
/// Configure whether cc should build dynamic library and link with `rustc-link-lib=dylib`
1233+
///
1234+
/// This option defaults to `false`.
1235+
pub fn link_shared_flag(&mut self, link_shared_flag: bool) -> &mut Build {
1236+
self.link_shared_flag = link_shared_flag;
1237+
self
1238+
}
1239+
12301240
#[doc(hidden)]
12311241
pub fn __set_env<A, B>(&mut self, a: A, b: B) -> &mut Build
12321242
where
@@ -1380,6 +1390,22 @@ impl Build {
13801390
Ok(is_supported)
13811391
}
13821392

1393+
fn get_canonical_library_names(name: &str) -> (&str, String, String) {
1394+
let lib_striped = name.strip_prefix("lib").unwrap_or(name);
1395+
let lib_name = if lib_striped.ends_with(".a") {
1396+
&lib_striped[..lib_striped.len() - 2]
1397+
} else if lib_striped.ends_with(".so") {
1398+
&lib_striped[..lib_striped.len() - 3]
1399+
} else {
1400+
lib_striped
1401+
};
1402+
(
1403+
lib_name,
1404+
format!("lib{lib_name}.a"),
1405+
format!("lib{lib_name}.so"),
1406+
)
1407+
}
1408+
13831409
/// Run the compiler, generating the file `output`
13841410
///
13851411
/// This will return a result instead of panicking; see [`Self::compile()`] for
@@ -1396,21 +1422,25 @@ impl Build {
13961422
}
13971423
}
13981424

1399-
let (lib_name, gnu_lib_name) = if output.starts_with("lib") && output.ends_with(".a") {
1400-
(&output[3..output.len() - 2], output.to_owned())
1401-
} else {
1402-
let mut gnu = String::with_capacity(5 + output.len());
1403-
gnu.push_str("lib");
1404-
gnu.push_str(output);
1405-
gnu.push_str(".a");
1406-
(output, gnu)
1407-
};
1425+
let (lib_name, static_name, dynlib_name) = Self::get_canonical_library_names(output);
14081426
let dst = self.get_out_dir()?;
14091427

14101428
let objects = objects_from_files(&self.files, &dst)?;
14111429

14121430
self.compile_objects(&objects)?;
1413-
self.assemble(lib_name, &dst.join(gnu_lib_name), &objects)?;
1431+
1432+
if self.link_shared_flag {
1433+
let objects = objects.iter().map(|o| o.dst.clone()).collect::<Vec<_>>();
1434+
1435+
let mut command = self.try_get_compiler()?.to_command();
1436+
let cmd = command
1437+
.args(["-shared", "-o"])
1438+
.arg(dst.join(dynlib_name))
1439+
.args(&objects);
1440+
run(cmd, &self.cargo_output)?;
1441+
}
1442+
1443+
self.assemble(lib_name, &dst.join(static_name), &objects)?;
14141444

14151445
let target = self.get_target()?;
14161446
if target.env == "msvc" {
@@ -1435,8 +1465,13 @@ impl Build {
14351465
}
14361466

14371467
if self.link_lib_modifiers.is_empty() {
1438-
self.cargo_output
1439-
.print_metadata(&format_args!("cargo:rustc-link-lib=static={}", lib_name));
1468+
if self.link_shared_flag {
1469+
self.cargo_output
1470+
.print_metadata(&format_args!("cargo:rustc-link-lib=dylib={}", lib_name));
1471+
} else {
1472+
self.cargo_output
1473+
.print_metadata(&format_args!("cargo:rustc-link-lib=static={}", lib_name));
1474+
}
14401475
} else {
14411476
self.cargo_output.print_metadata(&format_args!(
14421477
"cargo:rustc-link-lib=static:{}={}",

0 commit comments

Comments
 (0)