Skip to content

Commit

Permalink
add LibraryTypes
Browse files Browse the repository at this point in the history
  • Loading branch information
folkertdev committed Sep 11, 2024
1 parent 56656f8 commit 126f802
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 61 deletions.
142 changes: 89 additions & 53 deletions src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,28 +102,27 @@ fn build_pc_files(

fn patch_target(
pkg: &mut Package,
libkinds: &[&str],
library_types: LibraryTypes,
capi_config: &CApiConfig,
) -> anyhow::Result<()> {
use cargo::core::compiler::CrateType;

let manifest = pkg.manifest_mut();
let targets = manifest.targets_mut();

let kinds: Vec<_> = libkinds
.iter()
.map(|&kind| match kind {
"staticlib" => CrateType::Staticlib,
"cdylib" => CrateType::Cdylib,
_ => unreachable!(),
})
.collect();
let mut kinds = Vec::with_capacity(2);

for target in targets.iter_mut() {
if target.is_lib() {
target.set_kind(TargetKind::Lib(kinds.clone()));
target.set_name(&capi_config.library.name);
}
if library_types.staticlib {
kinds.push(CrateType::Staticlib);
}

if library_types.cdylib {
kinds.push(CrateType::Cdylib);
}

for target in targets.iter_mut().filter(|t| t.is_lib()) {
target.set_kind(TargetKind::Lib(kinds.to_vec()));
target.set_name(&capi_config.library.name);
}

Ok(())
Expand Down Expand Up @@ -952,7 +951,7 @@ impl CPackage {
fn from_package(
pkg: &mut Package,
args: &ArgMatches,
libkinds: &[&str],
library_types: LibraryTypes,
rustc_target: &target::Target,
root_output: &Path,
) -> anyhow::Result<CPackage> {
Expand All @@ -961,7 +960,7 @@ impl CPackage {
let root_path = pkg.root().to_path_buf();
let capi_config = load_manifest_capi_config(pkg, rustc_target)?;

patch_target(pkg, libkinds, &capi_config)?;
patch_target(pkg, library_types, &capi_config)?;

let name = &capi_config.library.name;

Expand All @@ -970,7 +969,7 @@ impl CPackage {
name,
rustc_target,
root_output,
libkinds,
library_types,
&capi_config,
args.get_flag("meson"),
)?;
Expand Down Expand Up @@ -998,6 +997,58 @@ fn deprecation_warnings(ws: &Workspace, args: &ArgMatches) -> anyhow::Result<()>
Ok(())
}

/// What library types to build
#[derive(Debug, Clone, Copy)]
pub struct LibraryTypes {
pub staticlib: bool,
pub cdylib: bool,
}

impl LibraryTypes {
fn from_target(target: &target::Target) -> Self {
// for os == "none", cdylib does not make sense. By default cdylib is also not built on
// musl, but that can be overriden by the user. That is useful when musl is being used as
// main libc, e.g. in Alpine, Gentoo and OpenWRT
Self {
staticlib: true,
cdylib: target.os != "none" && target.env != "musl",
}
}

fn from_args(target: &target::Target, args: &ArgMatches) -> Self {
match args.get_many::<String>("library-type") {
Some(library_types) => Self::from_library_types(target, library_types),
None => Self::from_target(target),
}
}

pub(crate) fn from_library_types<S: AsRef<str>>(
target: &target::Target,
library_types: impl Iterator<Item = S>,
) -> Self {
let (mut staticlib, mut cdylib) = (false, false);

for library_type in library_types {
staticlib |= library_type.as_ref() == "staticlib";
cdylib |= library_type.as_ref() == "cdylib";
}

// when os is none, a cdylib cannot be produced
// forcing a cdylib for musl is allowed here (see [`LibraryTypes::from_target`])
cdylib &= target.os != "none";

Self { staticlib, cdylib }
}

const fn only_staticlib(self) -> bool {
self.staticlib && !self.cdylib
}

const fn only_cdylib(self) -> bool {
self.cdylib && !self.staticlib
}
}

pub fn cbuild(
ws: &mut Workspace,
config: &GlobalContext,
Expand All @@ -1006,28 +1057,15 @@ pub fn cbuild(
) -> anyhow::Result<(Vec<CPackage>, CompileOptions)> {
deprecation_warnings(ws, args)?;

let rustc = config.load_global_rustc(Some(ws))?;
let targets = args.targets()?;
let (target, is_target_overridden) = match targets.len() {
0 => (rustc.host.to_string(), false),
1 => (targets[0].to_string(), true),
_ => {
anyhow::bail!("Multiple targets not supported yet");
}
let (target, is_target_overridden) = match args.targets()?.as_slice() {
[] => (config.load_global_rustc(Some(ws))?.host.to_string(), false),
[target] => (target.to_string(), true),
[..] => anyhow::bail!("Multiple targets not supported yet"),
};

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

let default_kind = || match (rustc_target.os.as_str(), rustc_target.env.as_str()) {
("none", _) | (_, "musl") => vec!["staticlib"],
_ => vec!["staticlib", "cdylib"],
};

let libkinds = args
.get_many::<String>("library-type")
.map_or_else(default_kind, |v| v.map(String::as_str).collect::<Vec<_>>());
let only_staticlib = !libkinds.contains(&"cdylib");
let only_cdylib = !libkinds.contains(&"staticlib");
let library_types = LibraryTypes::from_args(&rustc_target, args);

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

Expand All @@ -1043,10 +1081,7 @@ pub fn cbuild(
.join(PathBuf::from(target))
.join(profiles.get_dir_name());

let capi_feature = InternedString::new("capi");

let mut members = Vec::new();

let mut pristine = false;

let requested: Vec<_> = compile_opts
Expand All @@ -1056,22 +1091,23 @@ pub fn cbuild(
.map(|p| p.package_id())
.collect();

for m in ws.members_mut().filter(|m| {
m.library().is_some()
&& m.summary().features().contains_key(&capi_feature)
&& requested.contains(&m.package_id())
}) {
let cpkg = CPackage::from_package(m, args, &libkinds, &rustc_target, &root_output)?;
let capi_feature = InternedString::new("capi");
let is_relevant_package = |package: &Package| {
package.library().is_some()
&& package.summary().features().contains_key(&capi_feature)
&& requested.contains(&package.package_id())
};

for m in ws.members_mut().filter(|p| is_relevant_package(p)) {
let cpkg = CPackage::from_package(m, args, library_types, &rustc_target, &root_output)?;

pristine = pristine || cpkg.finger_print.load_previous().is_err();
pristine |= cpkg.finger_print.load_previous().is_err();

members.push(cpkg);
}

if pristine {
// If the cache is somehow missing force a full rebuild;
compile_opts.build_config.force_rebuild = true;
}
// If the cache is somehow missing force a full rebuild;
compile_opts.build_config.force_rebuild |= pristine;

let exec = Arc::new(Exec::default());
let out_dirs = compile_with_exec(
Expand Down Expand Up @@ -1111,7 +1147,7 @@ pub fn cbuild(
// if the hash value does not match.
if new_build && !cpkg.finger_print.is_valid() {
let name = &cpkg.capi_config.library.name;
let static_libs = if only_cdylib {
let static_libs = if library_types.only_cdylib() {
"".to_string()
} else {
exec.link_line
Expand All @@ -1126,14 +1162,14 @@ pub fn cbuild(
let build_targets = &cpkg.build_targets;

let mut pc = PkgConfig::from_workspace(name, &cpkg.install_paths, args, capi_config);
if only_staticlib {
if library_types.only_staticlib() {
pc.add_lib(&static_libs);
}
pc.add_lib_private(&static_libs);

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

if !only_staticlib && capi_config.library.import_library {
if !library_types.only_staticlib() && capi_config.library.import_library {
let lib_name = name;
build_def_file(ws, lib_name, &rustc_target, &root_output)?;
build_implib_file(ws, lib_name, &rustc_target, &root_output)?;
Expand All @@ -1159,7 +1195,7 @@ pub fn cbuild(
&name.replace('-', "_"),
&rustc_target,
&root_output,
&libkinds,
library_types,
capi_config,
args.get_flag("meson"),
)?;
Expand Down
12 changes: 4 additions & 8 deletions src/build_targets.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::ffi::OsString;
use std::path::{Path, PathBuf};

use crate::build::{CApiConfig, InstallTarget};
use crate::build::{CApiConfig, InstallTarget, LibraryTypes};
use crate::install::LibType;
use crate::target::Target;

Expand Down Expand Up @@ -63,7 +63,7 @@ impl BuildTargets {
name: &str,
target: &Target,
targetdir: &Path,
libkinds: &[&str],
library_types: LibraryTypes,
capi_config: &CApiConfig,
use_meson_naming_convention: bool,
) -> anyhow::Result<BuildTargets> {
Expand All @@ -82,15 +82,11 @@ impl BuildTargets {
));
};

// Bare metal does not support shared objects
let build_shared_lib = libkinds.contains(&"cdylib") && target.os.as_str() != "none";
let build_static_lib = libkinds.contains(&"staticlib");

Ok(BuildTargets {
pc,
include,
static_lib: build_static_lib.then_some(file_names.static_lib),
shared_lib: build_shared_lib.then_some(file_names.shared_lib),
static_lib: library_types.staticlib.then_some(file_names.static_lib),
shared_lib: library_types.cdylib.then_some(file_names.shared_lib),
impl_lib: file_names.impl_lib,
debug_info: file_names.debug_info,
def: file_names.def,
Expand Down

0 comments on commit 126f802

Please sign in to comment.