如何解决Rust build.rs调用cargo run触发构建目录文件锁阻塞问题
问题根因
你遇到的锁冲突是因为cargo build执行过程中会对当前项目的target构建目录加独占锁,而你在build.rs中再次调用cargo run启动了第二个cargo进程,两个进程争抢同一把锁就会报错。
方案1:直接将bindgen逻辑移到build.rs(最推荐)
大部分bindgen生成代码的场景不需要单独拆出独立二进制包,直接在build.rs中调用bindgen即可,完全避免二次调用cargo的问题。
配置步骤:
- 主项目
Cargo.toml添加build依赖:
[build-dependencies] bindgen = "0.69" # 替换为匹配你需求的版本
- 修改
build.rs内容:
// build.rs use std::path::PathBuf; fn main() { // 告诉cargo头文件变更时重新执行build.rs println!("cargo:rerun-if-changed=wrapper.h"); let bindings = bindgen::Builder::default() // 替换为你实际的C头文件路径 .header("wrapper.h") .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) .generate() .expect("生成FFI绑定失败"); // 输出绑定文件到src目录或者编译输出目录 let out_path = PathBuf::from(std::env::var("OUT_DIR").unwrap()); bindings .write_to_file(out_path.join("bindings.rs")) .expect("写入绑定文件失败"); }
- 业务代码中可以直接通过
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));引入生成的代码。
方案2:使用cargo artifact依赖(需要保留独立生成二进制时用)
如果你必须保留gen-proxy-ffi独立二进制包,可以用Rust 1.62及以上版本支持的artifact依赖特性,让cargo先自动构建好生成工具的二进制,再执行build.rs,不需要你手动调用cargo run。
配置步骤:
- 主项目
Cargo.toml添加build依赖:
[build-dependencies] # path替换为你gen-proxy-ffi包的实际路径 gen-proxy-ffi = { path = "./gen-proxy-ffi", artifact = "bin", version = "0.1.0" }
- 修改
build.rs内容,直接调用cargo预构建的二进制:
// build.rs use std::process::Command; use std::io::Write; fn main() { // 告诉cargo生成工具源码变更时重新执行build.rs println!("cargo:rerun-if-changed=./gen-proxy-ffi/src"); // 直接调用cargo提前构建好的二进制,不需要再跑cargo run let output = Command::new(env!("CARGO_BIN_EXE_gen-proxy-ffi")) .output() .expect("启动gen-proxy-ffi失败"); // 输出执行日志方便排查问题 std::io::stdout().write_all(&output.stdout).unwrap(); std::io::stderr().write_all(&output.stderr).unwrap(); assert!(output.status.success(), "gen-proxy-ffi执行返回非零状态码"); }
方案3:隔离构建目录(兜底备选)
如果用的是不支持artifact依赖的旧版本Rust,可以将gen-proxy-ffi的构建目录和主项目隔离,避免抢锁:
修改make-gen-proxy-ffi.sh中的命令为:
CARGO_TARGET_DIR=./gen-proxy-ffi/target cargo run --package gen-proxy-ffi --bin gen-proxy-ffi
该方案会产生两份构建产物,仅做兜底使用。
内容的提问来源于stack exchange,提问作者calvin
相关产品推荐
相关产品推荐

