Skip to content

Commit db1dbab

Browse files
folkertdevlu-zero
authored andcommitted
add LibraryTypes
1 parent 08cdda3 commit db1dbab

File tree

3 files changed

+104
-67
lines changed

3 files changed

+104
-67
lines changed

src/build.rs

+98-57
Original file line numberDiff line numberDiff line change
@@ -103,28 +103,27 @@ fn build_pc_files(
103103

104104
fn patch_target(
105105
pkg: &mut Package,
106-
libkinds: &[&str],
106+
library_types: LibraryTypes,
107107
capi_config: &CApiConfig,
108108
) -> anyhow::Result<()> {
109109
use cargo::core::compiler::CrateType;
110110

111111
let manifest = pkg.manifest_mut();
112112
let targets = manifest.targets_mut();
113113

114-
let kinds: Vec<_> = libkinds
115-
.iter()
116-
.map(|&kind| match kind {
117-
"staticlib" => CrateType::Staticlib,
118-
"cdylib" => CrateType::Cdylib,
119-
_ => unreachable!(),
120-
})
121-
.collect();
114+
let mut kinds = Vec::with_capacity(2);
122115

123-
for target in targets.iter_mut() {
124-
if target.is_lib() {
125-
target.set_kind(TargetKind::Lib(kinds.clone()));
126-
target.set_name(&capi_config.library.name);
127-
}
116+
if library_types.staticlib {
117+
kinds.push(CrateType::Staticlib);
118+
}
119+
120+
if library_types.cdylib {
121+
kinds.push(CrateType::Cdylib);
122+
}
123+
124+
for target in targets.iter_mut().filter(|t| t.is_lib()) {
125+
target.set_kind(TargetKind::Lib(kinds.to_vec()));
126+
target.set_name(&capi_config.library.name);
128127
}
129128

130129
Ok(())
@@ -953,7 +952,7 @@ impl CPackage {
953952
fn from_package(
954953
pkg: &mut Package,
955954
args: &ArgMatches,
956-
libkinds: &[&str],
955+
library_types: LibraryTypes,
957956
rustc_target: &target::Target,
958957
root_output: &Path,
959958
) -> anyhow::Result<CPackage> {
@@ -962,7 +961,7 @@ impl CPackage {
962961
let root_path = pkg.root().to_path_buf();
963962
let capi_config = load_manifest_capi_config(pkg, rustc_target)?;
964963

965-
patch_target(pkg, libkinds, &capi_config)?;
964+
patch_target(pkg, library_types, &capi_config)?;
966965

967966
let name = &capi_config.library.name;
968967

@@ -971,7 +970,7 @@ impl CPackage {
971970
name,
972971
rustc_target,
973972
root_output,
974-
libkinds,
973+
library_types,
975974
&capi_config,
976975
args.get_flag("meson"),
977976
)?;
@@ -999,6 +998,63 @@ fn deprecation_warnings(ws: &Workspace, args: &ArgMatches) -> anyhow::Result<()>
999998
Ok(())
1000999
}
10011000

1001+
/// What library types to build
1002+
#[derive(Debug, Clone, Copy)]
1003+
pub struct LibraryTypes {
1004+
pub staticlib: bool,
1005+
pub cdylib: bool,
1006+
}
1007+
1008+
impl LibraryTypes {
1009+
fn from_target(target: &target::Target) -> Self {
1010+
// for os == "none", cdylib does not make sense. By default cdylib is also not built on
1011+
// musl, but that can be overriden by the user. That is useful when musl is being used as
1012+
// main libc, e.g. in Alpine, Gentoo and OpenWRT
1013+
//
1014+
// See also
1015+
//
1016+
// - https://github.com/lu-zero/cargo-c?tab=readme-ov-file#shared-libraries-are-not-built-on-musl-systems
1017+
// - https://github.com/lu-zero/cargo-c/issues/180
1018+
Self {
1019+
staticlib: true,
1020+
cdylib: target.os != "none" && target.env != "musl",
1021+
}
1022+
}
1023+
1024+
fn from_args(target: &target::Target, args: &ArgMatches) -> Self {
1025+
match args.get_many::<String>("library-type") {
1026+
Some(library_types) => Self::from_library_types(target, library_types),
1027+
None => Self::from_target(target),
1028+
}
1029+
}
1030+
1031+
pub(crate) fn from_library_types<S: AsRef<str>>(
1032+
target: &target::Target,
1033+
library_types: impl Iterator<Item = S>,
1034+
) -> Self {
1035+
let (mut staticlib, mut cdylib) = (false, false);
1036+
1037+
for library_type in library_types {
1038+
staticlib |= library_type.as_ref() == "staticlib";
1039+
cdylib |= library_type.as_ref() == "cdylib";
1040+
}
1041+
1042+
// when os is none, a cdylib cannot be produced
1043+
// forcing a cdylib for musl is allowed here (see [`LibraryTypes::from_target`])
1044+
cdylib &= target.os != "none";
1045+
1046+
Self { staticlib, cdylib }
1047+
}
1048+
1049+
const fn only_staticlib(self) -> bool {
1050+
self.staticlib && !self.cdylib
1051+
}
1052+
1053+
const fn only_cdylib(self) -> bool {
1054+
self.cdylib && !self.staticlib
1055+
}
1056+
}
1057+
10021058
fn static_libraries(link_line: &str, rustc_target: &target::Target) -> String {
10031059
link_line
10041060
.trim()
@@ -1029,28 +1085,15 @@ pub fn cbuild(
10291085
) -> anyhow::Result<(Vec<CPackage>, CompileOptions)> {
10301086
deprecation_warnings(ws, args)?;
10311087

1032-
let rustc = config.load_global_rustc(Some(ws))?;
1033-
let targets = args.targets()?;
1034-
let (target, is_target_overridden) = match targets.len() {
1035-
0 => (rustc.host.to_string(), false),
1036-
1 => (targets[0].to_string(), true),
1037-
_ => {
1038-
anyhow::bail!("Multiple targets not supported yet");
1039-
}
1088+
let (target, is_target_overridden) = match args.targets()?.as_slice() {
1089+
[] => (config.load_global_rustc(Some(ws))?.host.to_string(), false),
1090+
[target] => (target.to_string(), true),
1091+
[..] => anyhow::bail!("Multiple targets not supported yet"),
10401092
};
10411093

10421094
let rustc_target = target::Target::new(Some(&target), is_target_overridden)?;
10431095

1044-
let default_kind = || match (rustc_target.os.as_str(), rustc_target.env.as_str()) {
1045-
("none", _) | (_, "musl") => vec!["staticlib"],
1046-
_ => vec!["staticlib", "cdylib"],
1047-
};
1048-
1049-
let libkinds = args
1050-
.get_many::<String>("library-type")
1051-
.map_or_else(default_kind, |v| v.map(String::as_str).collect::<Vec<_>>());
1052-
let only_staticlib = !libkinds.contains(&"cdylib");
1053-
let only_cdylib = !libkinds.contains(&"staticlib");
1096+
let library_types = LibraryTypes::from_args(&rustc_target, args);
10541097

10551098
let profile = args.get_profile_name(default_profile, ProfileChecking::Custom)?;
10561099

@@ -1066,10 +1109,7 @@ pub fn cbuild(
10661109
.join(PathBuf::from(target))
10671110
.join(profiles.get_dir_name());
10681111

1069-
let capi_feature = InternedString::new("capi");
1070-
10711112
let mut members = Vec::new();
1072-
10731113
let mut pristine = false;
10741114

10751115
let requested: Vec<_> = compile_opts
@@ -1079,22 +1119,23 @@ pub fn cbuild(
10791119
.map(|p| p.package_id())
10801120
.collect();
10811121

1082-
for m in ws.members_mut().filter(|m| {
1083-
m.library().is_some()
1084-
&& m.summary().features().contains_key(&capi_feature)
1085-
&& requested.contains(&m.package_id())
1086-
}) {
1087-
let cpkg = CPackage::from_package(m, args, &libkinds, &rustc_target, &root_output)?;
1122+
let capi_feature = InternedString::new("capi");
1123+
let is_relevant_package = |package: &Package| {
1124+
package.library().is_some()
1125+
&& package.summary().features().contains_key(&capi_feature)
1126+
&& requested.contains(&package.package_id())
1127+
};
1128+
1129+
for m in ws.members_mut().filter(|p| is_relevant_package(p)) {
1130+
let cpkg = CPackage::from_package(m, args, library_types, &rustc_target, &root_output)?;
10881131

1089-
pristine = pristine || cpkg.finger_print.load_previous().is_err();
1132+
pristine |= cpkg.finger_print.load_previous().is_err();
10901133

10911134
members.push(cpkg);
10921135
}
10931136

1094-
if pristine {
1095-
// If the cache is somehow missing force a full rebuild;
1096-
compile_opts.build_config.force_rebuild = true;
1097-
}
1137+
// If the cache is somehow missing force a full rebuild;
1138+
compile_opts.build_config.force_rebuild |= pristine;
10981139

10991140
let exec = Arc::new(Exec::default());
11001141
let out_dirs = compile_with_exec(
@@ -1134,7 +1175,7 @@ pub fn cbuild(
11341175
// if the hash value does not match.
11351176
if new_build && !cpkg.finger_print.is_valid() {
11361177
let name = &cpkg.capi_config.library.name;
1137-
let (pkg_config_static_libs, static_libs) = if only_cdylib {
1178+
let (pkg_config_static_libs, static_libs) = if library_types.only_cdylib() {
11381179
(String::new(), String::new())
11391180
} else if let Some(libs) = exec.link_line.lock().unwrap().values().next() {
11401181
(static_libraries(libs, &rustc_target), libs.to_string())
@@ -1145,14 +1186,14 @@ pub fn cbuild(
11451186
let build_targets = &cpkg.build_targets;
11461187

11471188
let mut pc = PkgConfig::from_workspace(name, &cpkg.install_paths, args, capi_config);
1148-
if only_staticlib {
1189+
if library_types.only_staticlib() {
11491190
pc.add_lib(&pkg_config_static_libs);
11501191
}
11511192
pc.add_lib_private(&pkg_config_static_libs);
11521193

11531194
build_pc_files(ws, &capi_config.pkg_config.filename, &root_output, &pc)?;
11541195

1155-
if !only_staticlib && capi_config.library.import_library {
1196+
if !library_types.only_staticlib() && capi_config.library.import_library {
11561197
let lib_name = name;
11571198
build_def_file(ws, lib_name, &rustc_target, &root_output)?;
11581199
build_implib_file(ws, lib_name, &rustc_target, &root_output)?;
@@ -1178,7 +1219,7 @@ pub fn cbuild(
11781219
&name.replace('-', "_"),
11791220
&rustc_target,
11801221
&root_output,
1181-
&libkinds,
1222+
library_types,
11821223
capi_config,
11831224
args.get_flag("meson"),
11841225
)?;
@@ -1350,17 +1391,17 @@ mod tests {
13501391
let target_msvc = target::Target::new(Some("x86_64-pc-windows-msvc"), false).unwrap();
13511392
let target_mingw = target::Target::new(Some("x86_64-pc-windows-gnu"), false).unwrap();
13521393

1353-
assert_eq!(static_libraries(&libs_osx, &target_osx), "-lSystem -lc -lm");
1394+
assert_eq!(static_libraries(libs_osx, &target_osx), "-lSystem -lc -lm");
13541395
assert_eq!(
1355-
static_libraries(&libs_linux, &target_linux),
1396+
static_libraries(libs_linux, &target_linux),
13561397
"-lgcc_s -lutil -lrt -lpthread -lm -ldl -lc"
13571398
);
13581399
assert_eq!(
1359-
static_libraries(&libs_msvc, &target_msvc),
1400+
static_libraries(libs_msvc, &target_msvc),
13601401
"-lkernel32 -ladvapi32 -lntdll -luserenv -lws2_32 -lmsvcrt"
13611402
);
13621403
assert_eq!(
1363-
static_libraries(&libs_mingw, &target_mingw),
1404+
static_libraries(libs_mingw, &target_mingw),
13641405
"-lkernel32 -ladvapi32 -lntdll -luserenv -lws2_32"
13651406
);
13661407
}

src/build_targets.rs

+4-8
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::ffi::OsString;
22
use std::path::{Path, PathBuf};
33

4-
use crate::build::{CApiConfig, InstallTarget};
4+
use crate::build::{CApiConfig, InstallTarget, LibraryTypes};
55
use crate::install::LibType;
66
use crate::target::Target;
77

@@ -63,7 +63,7 @@ impl BuildTargets {
6363
name: &str,
6464
target: &Target,
6565
targetdir: &Path,
66-
libkinds: &[&str],
66+
library_types: LibraryTypes,
6767
capi_config: &CApiConfig,
6868
use_meson_naming_convention: bool,
6969
) -> anyhow::Result<BuildTargets> {
@@ -82,15 +82,11 @@ impl BuildTargets {
8282
));
8383
};
8484

85-
// Bare metal does not support shared objects
86-
let build_shared_lib = libkinds.contains(&"cdylib") && target.os.as_str() != "none";
87-
let build_static_lib = libkinds.contains(&"staticlib");
88-
8985
Ok(BuildTargets {
9086
pc,
9187
include,
92-
static_lib: build_static_lib.then_some(file_names.static_lib),
93-
shared_lib: build_shared_lib.then_some(file_names.shared_lib),
88+
static_lib: library_types.staticlib.then_some(file_names.static_lib),
89+
shared_lib: library_types.cdylib.then_some(file_names.shared_lib),
9490
impl_lib: file_names.impl_lib,
9591
debug_info: file_names.debug_info,
9692
def: file_names.def,

src/pkg_config_gen.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -325,8 +325,6 @@ mod test {
325325
}
326326

327327
mod test_canonicalize {
328-
use std::path::Path;
329-
330328
use super::canonicalize;
331329

332330
#[test]
@@ -408,6 +406,8 @@ mod test {
408406

409407
#[cfg(windows)]
410408
mod windows {
409+
use std::path::Path;
410+
411411
use super::*;
412412

413413
#[test]

0 commit comments

Comments
 (0)