标签 编译期配置 下的文章

背景

ESP32 的 Rust 教程示例项目中,第一个项目 hardware-check 演示了如何利用开发板自带的 WIFI 连接无线网。像 WIFI SSID 与密码 这样的变量当然不应该直接写进代码,示例中利用了 toml-cfg#toml_config 宏,读取 cfg.toml 中的值并注入代码(cfg.toml git ignore),以做到在运行时使用这些变量。

这里示例代码稍有误导:在 build.rs 中声明 struct 并调用了一次 #[toml_cfg::toml_config],随即对获取到的值做了一些简单检查。然后在 main.rs 中用完全一样的方法再次声明 struct 并调用宏,并在后续连接 WIFI 时使用。在 main.rs 中还加了一段注释:/// This configuration is picked up at compile time by build.rs from the file cfg.toml 。这似乎意味着在这两处相同的 struct 声明及宏调用处存在着某种魔法,使得编译期读取到的配置文件内容可以被传递到运行期使用。

但这里并不存在 build.rs 把值 “传给” main.rs 的魔法。toml_cfg::toml_config 是过程宏,它在编译期读取配置并生成 CONFIG 常量;示例里 build.rs 只是重复生成一份用于构建时校验,运行时真正使用的是应用 crate 中那份 CONFIG

我一不习惯 TOML,二不想为此多引一个包,于是想试试能否利用更简单直接的办法实现。

Cargo build-scripts

The Cargo book 3.8 Build Scripts 中介绍了构建脚本的一些常见用法与场景,其中就包含了 “使用 rustc-env 指令将指定的环境变量在编译时注入到编译后的 crate,并利用 env! 宏获取这些变量”。

那么类似的,我自然可以将所需的配置项,例如 WIFI 密码写入 .env (当然,git ignore)并在 build.rs 中读取解析,并 println!("cargo:rustc-env={}={}", key, value);

而在程序代码中,使用 let env_foo = env!("FOO").to_string() 将其展开。如此,配置文件中的值在编译期就会确定并注入到代码成为常量。

当然要注意,这里的 “环境变量” 始终仅发生在编译期。一旦编译结束,所有的值都已确定,被 env! 展开的值成为字符串字面量,连同代码一起被编译成二进制。

以上。


📌 转载信息
原作者:
Qi_Nark
转载时间:
2026/1/11 08:42:51