// ESP-IDF 的环境导出 + 固件版本信息注入。 // // # 版本号为什么在这里注入 // // 固件的版本必须和客户端、和 `version.json` 是**同一个数**。手工在 `src/` 里写一个 // 常量,第一次忘了改就分叉了,而且没有任何东西会报错——现场只会表现为"界面说固件 0.2.0, // 实际烧的是别的"。 // // 所以这里在编译期把 `version.json` 读进来,导出成 `cargo:rustc-env`,源码里用 // `env!()` 取。`version.json` 由 `scripts/version.mjs` 从 git 历史算出来,于是 // 一条链是通的:git → version.json → 固件二进制 → Hello 报文 → 客户端界面。 use std::fs; use std::path::Path; fn main() { embuild::espidf::sysenv::output(); emit_version_env(); } /// 把 `version.json` 里的版本拆成几个编译期常量。 fn emit_version_env() { let manifest = std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR"); let path = Path::new(&manifest).join("version.json"); // 这个文件改了要重新编译,否则版本号会停在旧值上而二进制看起来是新的。 println!("cargo:rerun-if-changed={}", path.display()); // 没有 version.json 也要能编:直接 cargo build 的人可能还没跑过生成脚本。 // 这时退回 0.0.0+0 并留一条编译器警告——比编不过友好,比编出一个假的版本诚实。 let (major, minor, patch, build) = match fs::read_to_string(&path) { Ok(text) => match parse(&text) { Some(parsed) => parsed, None => { println!("cargo:warning=version.json 解析失败,固件版本回退为 0.0.0+0"); (0, 0, 0, 0) } }, Err(_) => { println!( "cargo:warning=找不到 version.json,固件版本回退为 0.0.0+0(先跑 node scripts/version.mjs --write)" ); (0, 0, 0, 0) } }; let packed = ((major as u32) << 16) | (((minor as u32) & 0xff) << 8) | ((patch as u32) & 0xff); println!("cargo:rustc-env=RMIC_VERSION={major}.{minor}.{patch}"); println!("cargo:rustc-env=RMIC_VERSION_PACKED={packed}"); println!("cargo:rustc-env=RMIC_BUILD={build}"); } /// 从 `version.json` 里抠出四段数字。 /// /// 刻意不引入 `serde_json`:解析四个字段不值得多一个编译期依赖,而固件的构建时间本来 /// 就是这个项目里最贵的东西。 fn parse(text: &str) -> Option<(u64, u64, u64, u64)> { let field = |name: &str| -> Option { let key = format!("\"{name}\""); let at = text.find(&key)?; let rest = &text[at + key.len()..]; let colon = rest.find(':')?; let rest = &rest[colon + 1..]; let start = rest.find(|c: char| c.is_ascii_digit())?; let digits: String = rest[start..] .chars() .take_while(|c| c.is_ascii_digit()) .collect(); digits.parse().ok() }; Some(( field("major")?, field("minor")?, field("patch")?, field("build")?, )) }