如何在Cargo工作区的构建脚本间传递环境变量?
工作区中跨build.rs共享环境变量的解决方案
问题场景
在包含lib1和lib2的Cargo工作区中,希望通过lib2的build.rs设置环境变量TEST_VAR,并在lib1的build.rs中读取该变量,但直接使用env::set_var无法实现——执行cargo build时lib1的build.rs找不到该变量,构建失败。
原代码如下:
lib1/build.rs
use std::env; fn main() { match env::var("TEST_VAR") { Ok(value) => println!("cargo:warning={}", value), Err(_) => panic!(":("), } }
lib2/build.rs
use std::env; fn main() { env::set_var("TEST_VAR", "HELLO"); }
lib1/Cargo.toml
[package] name = "lib1" version = "0.1.0" edition.workspace = true build = "build.rs" [build-dependencies] lib2 = { path = "../lib2" }
lib2/Cargo.toml
[package] name = "lib2" version = "0.1.0" edition.workspace = true build = "build.rs" [dependencies]
问题根源
每个Crate的build.rs都是独立运行的操作系统进程,env::set_var仅能修改当前进程的环境变量,无法影响其他独立进程。lib2的build.rs进程结束后,其设置的变量会被销毁,lib1的build.rs作为新进程自然无法读取。
解决方案
方案1:利用Cargo原生指令传递变量
Cargo提供了cargo:rustc-env指令,允许build.rs向Cargo传递环境变量,Cargo会自动将这些变量暴露给依赖该Crate的其他build.rs(变量名会添加DEP_<依赖名大写>_前缀)。
修改lib2的build.rs:
fn main() { // 通过Cargo指令传递变量 println!("cargo:rustc-env=TEST_VAR=HELLO"); }
修改lib1的build.rs,读取带前缀的变量:
use std::env; fn main() { // 读取Cargo自动映射的变量,前缀为DEP_LIB2_ match env::var("DEP_LIB2_TEST_VAR") { Ok(value) => println!("cargo:warning={}", value), Err(_) => panic!("无法读取TEST_VAR"), } }
方案2:文件传递(适用于复杂数据场景)
如果需要传递非字符串数据或有复杂需求,可以让lib2的build.rs生成数据文件,再让lib1的build.rs读取该文件。
修改lib2的build.rs:
use std::env; use std::fs; use std::path::Path; fn main() { // 获取Cargo输出目录,确保文件路径正确 let out_dir = env::var("OUT_DIR").unwrap(); let dest_path = Path::new(&out_dir).join("test_var.txt"); fs::write(dest_path, "HELLO").unwrap(); // 将输出目录路径传递给依赖的Crate println!("cargo:rustc-env=LIB2_OUT_DIR={}", out_dir); }
修改lib1的build.rs:
use std::env; use std::fs; use std::path::Path; fn main() { // 读取lib2的输出目录路径 let lib2_out_dir = env::var("DEP_LIB2_LIB2_OUT_DIR").unwrap(); let file_path = Path::new(&lib2_out_dir).join("test_var.txt"); let test_var = fs::read_to_string(file_path).unwrap(); println!("cargo:warning={}", test_var); }
关键注意事项
- 跨build.rs共享数据必须通过Cargo机制或文件等跨进程方式,直接修改进程环境变量无效。
- 使用
cargo:rustc-env时,依赖方读取变量必须添加DEP_<依赖名大写>_前缀,Cargo会自动完成映射。 - 文件传递时,务必通过
cargo:rustc-env传递输出目录路径,避免硬编码路径导致的构建错误。
内容的提问来源于stack exchange,提问作者Martin
相关产品推荐
相关产品推荐

