// NOTE: this file is copy-pasted between several Embassy crates, because there is no // straightforward way to share this code: // - it cannot be placed into the root of the repo and linked from each build.rs using `#[path = // "../build_common.rs"]`, because `cargo publish` requires that all files published with a crate // reside in the crate's directory, // - it cannot be symlinked from `embassy-xxx/build_common.rs` to `../build_common.rs`, because // symlinks don't work on Windows. use std::collections::HashSet; use std::env; /// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring /// them (`cargo:rust-check-cfg=cfg(X)`). #[derive(Debug)] pub struct CfgSet { enabled: HashSet, declared: HashSet, } impl CfgSet { pub fn new() -> Self { Self { enabled: HashSet::new(), declared: HashSet::new(), } } /// Enable a config, which can then be used in `#[cfg(...)]` for conditional compilation. /// /// All configs that can potentially be enabled should be unconditionally declared using /// [`Self::declare()`]. pub fn enable(&mut self, cfg: impl AsRef) { if self.enabled.insert(cfg.as_ref().to_owned()) { println!("cargo:rustc-cfg={}", cfg.as_ref()); } } pub fn enable_all(&mut self, cfgs: &[impl AsRef]) { for cfg in cfgs.iter() { self.enable(cfg.as_ref()); } } /// Declare a valid config for conditional compilation, without enabling it. /// /// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid. pub fn declare(&mut self, cfg: impl AsRef) { if self.declared.insert(cfg.as_ref().to_owned()) { println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref()); } } pub fn declare_all(&mut self, cfgs: &[impl AsRef]) { for cfg in cfgs.iter() { self.declare(cfg.as_ref()); } } pub fn set(&mut self, cfg: impl Into, enable: bool) { let cfg = cfg.into(); if enable { self.enable(cfg.clone()); } self.declare(cfg); } } /// Sets configs that describe the target platform. pub fn set_target_cfgs(cfgs: &mut CfgSet) { let target = env::var("TARGET").unwrap(); if target.starts_with("thumbv6m-") { cfgs.enable_all(&["cortex_m", "armv6m"]); } else if target.starts_with("thumbv7m-") { cfgs.enable_all(&["cortex_m", "armv7m"]); } else if target.starts_with("thumbv7em-") { cfgs.enable_all(&["cortex_m", "armv7m", "armv7em"]); } else if target.starts_with("thumbv8m.base") { cfgs.enable_all(&["cortex_m", "armv8m", "armv8m_base"]); } else if target.starts_with("thumbv8m.main") { cfgs.enable_all(&["cortex_m", "armv8m", "armv8m_main"]); } cfgs.declare_all(&[ "cortex_m", "armv6m", "armv7m", "armv7em", "armv8m", "armv8m_base", "armv8m_main", ]); cfgs.set("has_fpu", target.ends_with("-eabihf")); } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct CompilerDate { year: u16, month: u8, day: u8, } impl CompilerDate { fn parse(date: &str) -> Option { let mut parts = date.split('-'); let year = parts.next()?.parse().ok()?; let month = parts.next()?.parse().ok()?; let day = parts.next()?.parse().ok()?; Some(Self { year, month, day }) } } impl PartialEq<&str> for CompilerDate { fn eq(&self, other: &&str) -> bool { let Some(other) = Self::parse(other) else { return false; }; self.eq(&other) } } impl PartialOrd<&str> for CompilerDate { fn partial_cmp(&self, other: &&str) -> Option { Self::parse(other).map(|other| self.cmp(&other)) } } pub struct CompilerInfo { #[allow(unused)] pub version: rustc_version::Version, pub channel: rustc_version::Channel, pub commit_date: Option, } pub fn compiler_info() -> Option { let Ok(meta) = rustc_version::version_meta() else { return None; }; Some(CompilerInfo { version: meta.semver, channel: meta.channel, commit_date: meta.commit_date.as_deref().and_then(CompilerDate::parse), }) }