Add BSD feature

This should be used in lieu of manually targeting individual operating systems
when using features shared by all BSD families.

e.g. instead of

   #[cfg(any(target_os = "freebsd", target_os = "dragonflybsd", ...))]
   fn foo() { }

you would use

    #[cfg(feature = "bsd")]
    fn foo() { }

This feature is automatically detected at build-time (see build.rs changes) and
should *not* be enabled manually. Additionally, this feature may not be used to
conditionally require any other dependency, as that isn't supported for
auto-enabled features.
This commit is contained in:
Mahmoud Al-Qudsi 2023-03-19 17:50:32 -05:00
parent 57f4571a01
commit 34a4c7de7f
2 changed files with 44 additions and 2 deletions

View file

@ -4,7 +4,6 @@ version = "0.1.0"
edition = "2021" edition = "2021"
rust-version = "1.67" rust-version = "1.67"
[dependencies] [dependencies]
widestring-suffix = { path = "./widestring-suffix/" } widestring-suffix = { path = "./widestring-suffix/" }
@ -29,7 +28,7 @@ cxx-gen = { git = "https://github.com/fish-shell/cxx", branch = "fish" }
miette = { version = "5", features = ["fancy"] } miette = { version = "5", features = ["fancy"] }
[lib] [lib]
crate-type=["staticlib"] crate-type = ["staticlib"]
[features] [features]
# The fish-ffi-tests feature causes tests to be built which need to use the FFI. # The fish-ffi-tests feature causes tests to be built which need to use the FFI.
@ -37,6 +36,9 @@ crate-type=["staticlib"]
default = ["fish-ffi-tests"] default = ["fish-ffi-tests"]
fish-ffi-tests = ["inventory"] fish-ffi-tests = ["inventory"]
# The following features are auto-detected by the build-script and should not be enabled manually.
bsd = []
[patch.crates-io] [patch.crates-io]
cc = { git = "https://github.com/mqudsi/cc-rs", branch = "fish" } cc = { git = "https://github.com/mqudsi/cc-rs", branch = "fish" }
cxx = { git = "https://github.com/fish-shell/cxx", branch = "fish" } cxx = { git = "https://github.com/fish-shell/cxx", branch = "fish" }

View file

@ -1,3 +1,5 @@
use miette::miette;
fn main() -> miette::Result<()> { fn main() -> miette::Result<()> {
let rust_dir = std::env::var("CARGO_MANIFEST_DIR").expect("Env var CARGO_MANIFEST_DIR missing"); let rust_dir = std::env::var("CARGO_MANIFEST_DIR").expect("Env var CARGO_MANIFEST_DIR missing");
let target_dir = let target_dir =
@ -15,6 +17,8 @@ fn main() -> miette::Result<()> {
let autocxx_gen_dir = std::env::var("FISH_AUTOCXX_GEN_DIR") let autocxx_gen_dir = std::env::var("FISH_AUTOCXX_GEN_DIR")
.unwrap_or(format!("{}/{}", fish_build_dir, "fish-autocxx-gen/")); .unwrap_or(format!("{}/{}", fish_build_dir, "fish-autocxx-gen/"));
detect_features();
// Emit cxx junk. // Emit cxx junk.
// This allows "Rust to be used from C++" // This allows "Rust to be used from C++"
// This must come before autocxx so that cxx can emit its cxx.h header. // This must come before autocxx so that cxx can emit its cxx.h header.
@ -68,3 +72,39 @@ fn main() -> miette::Result<()> {
Ok(()) Ok(())
} }
/// Dynamically enables certain features at build-time, without their having to be explicitly
/// enabled in the `cargo build --features xxx` invocation.
///
/// This can be used to enable features that we check for and conditionally compile according to in
/// our own codebase, but [can't be used to pull in dependencies](0) even if they're gated (in
/// `Cargo.toml`) behind a feature we just enabled.
///
/// [0]: https://github.com/rust-lang/cargo/issues/5499
fn detect_features() {
for (feature, detector) in [
("bsd", detect_bsd),
]
{
match detector() {
Err(e) => eprintln!("{feature} detect: {e}"),
Ok(true) => println!("cargo:rustc-cfg=feature=\"{feature}\""),
Ok(false) => (),
}
}
}
/// Detect if we're being compiled on a BSD-derived OS. Does not yet play nicely with
/// cross-compilation.
///
/// Rust offers fine-grained conditional compilation per-os for the popular operating systems, but
/// doesn't necessarily include less-popular forks nor does it group them into families more
/// specific than "windows" vs "unix" so we can conditionally compile code for BSD systems.
fn detect_bsd() -> miette::Result<bool> {
let uname = std::process::Command::new("uname").output()
.map_err(|_| miette!("Error executing uname!"))?;
Ok(std::str::from_utf8(&uname.stdout)
.map(|s| s.to_ascii_lowercase())
.map(|s| s.contains("bsd"))
.unwrap_or(false))
}