diff --git a/Cargo.lock b/Cargo.lock index d9081f07edde..7b39947f369e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6186,6 +6186,8 @@ dependencies = [ "indicatif", "itertools 0.13.0", "parking_lot", + "re_build_info", + "re_build_tools", "re_log", "re_mp4", "re_rav1d", diff --git a/crates/build/re_build_info/src/build_info.rs b/crates/build/re_build_info/src/build_info.rs index 55abb7290e60..e81cc03dab01 100644 --- a/crates/build/re_build_info/src/build_info.rs +++ b/crates/build/re_build_info/src/build_info.rs @@ -14,6 +14,9 @@ pub struct BuildInfo { /// `CARGO_PKG_NAME` pub crate_name: &'static str, + /// Space-separated names of all features enabled for this crate. + pub features: &'static str, + /// Crate version, parsed from `CARGO_PKG_VERSION`, ignoring any `+metadata` suffix. pub version: super::CrateVersion, @@ -74,6 +77,7 @@ impl std::fmt::Display for BuildInfo { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let Self { crate_name, + features, version, rustc_version, llvm_version, @@ -89,6 +93,10 @@ impl std::fmt::Display for BuildInfo { write!(f, "{crate_name} {version}")?; + if !features.is_empty() { + write!(f, " ({features})")?; + } + if let Some(rustc_version) = rustc_version { write!(f, " [{rustc_version}")?; if let Some(llvm_version) = llvm_version { @@ -147,6 +155,7 @@ impl CrateVersion { fn crate_version_from_build_info_string() { let build_info = BuildInfo { crate_name: "re_build_info", + features: "default extra", version: CrateVersion { major: 0, minor: 10, diff --git a/crates/build/re_build_info/src/lib.rs b/crates/build/re_build_info/src/lib.rs index 42501cd64243..d7b4208e6a76 100644 --- a/crates/build/re_build_info/src/lib.rs +++ b/crates/build/re_build_info/src/lib.rs @@ -15,6 +15,7 @@ macro_rules! build_info { () => { $crate::BuildInfo { crate_name: env!("CARGO_PKG_NAME"), + features: env!("RE_BUILD_FEATURES"), version: $crate::CrateVersion::parse(env!("CARGO_PKG_VERSION")), rustc_version: env!("RE_BUILD_RUSTC_VERSION"), llvm_version: env!("RE_BUILD_LLVM_VERSION"), diff --git a/crates/build/re_build_tools/src/lib.rs b/crates/build/re_build_tools/src/lib.rs index 316e335f58aa..3bf2da9c7d08 100644 --- a/crates/build/re_build_tools/src/lib.rs +++ b/crates/build/re_build_tools/src/lib.rs @@ -194,6 +194,16 @@ pub fn export_build_info_vars_for_crate(crate_name: &str) { ); } } + + if environment == Environment::PublishingCrates { + // We can't query this during `cargo publish`, but we also don't need the info. + set_env("RE_BUILD_FEATURES", ""); + } else { + set_env( + "RE_BUILD_FEATURES", + &enabled_features_of(crate_name).unwrap().join(" "), + ); + } } /// ISO 8601 / RFC 3339 build time. @@ -269,7 +279,39 @@ fn rust_llvm_versions() -> anyhow::Result<(String, String)> { )) } -/// Returns info parsed from an invocation of the `cargo metadata` command +/// Returns info parsed from an invocation of the `cargo metadata` command. +/// +/// You may not run this during crate publishing. pub fn cargo_metadata() -> anyhow::Result { + // See https://github.com/rerun-io/rerun/pull/7885 + anyhow::ensure!( + Environment::detect() != Environment::PublishingCrates, + "Can't get metadata during crate publishing - it would create a Cargo.lock file" + ); + Ok(cargo_metadata::MetadataCommand::new().exec()?) } + +/// Returns a list of all the enabled features of the given package. +/// +/// You may not run this during crate publishing. +pub fn enabled_features_of(crate_name: &str) -> anyhow::Result> { + let metadata = cargo_metadata()?; + + let mut features = vec![]; + for package in &metadata.packages { + if package.name == crate_name { + for feature in package.features.keys() { + println!("Checking if feature is enabled: {feature:?}"); + let feature_in_screaming_snake_case = + feature.to_ascii_uppercase().replace('-', "_"); + if std::env::var(format!("CARGO_FEATURE_{feature_in_screaming_snake_case}")).is_ok() + { + features.push(feature.clone()); + } + } + } + } + + Ok(features) +} diff --git a/crates/store/re_video/Cargo.toml b/crates/store/re_video/Cargo.toml index 4d84f4380f16..e47edb47bbe5 100644 --- a/crates/store/re_video/Cargo.toml +++ b/crates/store/re_video/Cargo.toml @@ -37,6 +37,7 @@ nasm = [ [dependencies] +re_build_info.workspace = true re_log.workspace = true re_tracing.workspace = true @@ -66,6 +67,7 @@ criterion.workspace = true # For build.rs: [build-dependencies] +re_build_tools.workspace = true cfg_aliases.workspace = true diff --git a/crates/store/re_video/build.rs b/crates/store/re_video/build.rs index 773e9ed9afa4..261ccb770ba3 100644 --- a/crates/store/re_video/build.rs +++ b/crates/store/re_video/build.rs @@ -1,4 +1,6 @@ fn main() { + re_build_tools::export_build_info_vars_for_crate(env!("CARGO_PKG_NAME")); + // uncomment these when we update to Rust 1.80: https://blog.rust-lang.org/2024/05/06/check-cfg.html // println!("cargo::rustc-check-cfg=cfg(native)"); // println!("cargo::rustc-check-cfg=cfg(linux_arm64)"); diff --git a/crates/store/re_video/src/lib.rs b/crates/store/re_video/src/lib.rs index b007518fb2f4..d38a194da8c9 100644 --- a/crates/store/re_video/src/lib.rs +++ b/crates/store/re_video/src/lib.rs @@ -13,15 +13,7 @@ pub use self::{ time::{Time, Timescale}, }; -/// Which features was this crate compiled with? -pub fn features() -> Vec<&'static str> { - // TODO(emilk): is there a helper crate for this? - let mut features = vec![]; - if cfg!(feature = "av1") { - features.push("av1"); - } - if cfg!(feature = "nasm") { - features.push("nasm"); - } - features +/// Returns information about this crate +pub fn build_info() -> re_build_info::BuildInfo { + re_build_info::build_info!() } diff --git a/crates/top/rerun/src/commands/entrypoint.rs b/crates/top/rerun/src/commands/entrypoint.rs index a081b6f6419a..6c3b6389907e 100644 --- a/crates/top/rerun/src/commands/entrypoint.rs +++ b/crates/top/rerun/src/commands/entrypoint.rs @@ -553,7 +553,7 @@ where if args.version { println!("{build_info}"); - println!("Video features: {}", re_video::features().join(" ")); + println!("Video features: {}", re_video::build_info().features); return Ok(0); } diff --git a/crates/utils/re_analytics/src/lib.rs b/crates/utils/re_analytics/src/lib.rs index 99dd49fc573b..a0a10c8e7b0d 100644 --- a/crates/utils/re_analytics/src/lib.rs +++ b/crates/utils/re_analytics/src/lib.rs @@ -345,6 +345,7 @@ impl Properties for re_build_info::BuildInfo { let git_hash = self.git_hash_or_tag(); let Self { crate_name: _, + features, version, rustc_version, llvm_version, @@ -355,6 +356,7 @@ impl Properties for re_build_info::BuildInfo { datetime, } = self; + event.insert("features", features); event.insert("git_hash", git_hash); event.insert("rerun_version", version.to_string()); event.insert("rust_version", rustc_version); diff --git a/crates/viewer/re_viewer/src/ui/rerun_menu.rs b/crates/viewer/re_viewer/src/ui/rerun_menu.rs index 5d75274b4a49..6143c70428e9 100644 --- a/crates/viewer/re_viewer/src/ui/rerun_menu.rs +++ b/crates/viewer/re_viewer/src/ui/rerun_menu.rs @@ -114,6 +114,7 @@ impl App { fn about_rerun_ui(&self, frame: &eframe::Frame, ui: &mut egui::Ui) { let re_build_info::BuildInfo { crate_name, + features, version, rustc_version, llvm_version, @@ -138,6 +139,12 @@ impl App { {target_triple}" ); + // It is really the features of `rerun-cli` (the `rerun` binary) that are interesting. + // For the web-viewer we get `crate_name: "re_viewer"` here, which is much less interesting. + if crate_name == "rerun-cli" && !features.is_empty() { + label += &format!("\n{crate_name} features: {features}"); + } + if !rustc_version.is_empty() { label += &format!("\nrustc {rustc_version}"); if !llvm_version.is_empty() {