构建依赖libcuda多依赖项的Rust crate时解决链接错误
问题描述
我有一个名为foo的Rust crate,依赖两个库:
cudarc:对应CUDA驱动API的libcuda的sys craters-smctrl:我为调用libcuda的C库libsmctrl编写的sys crate
单独构建cudarc或rs-smctrl都能成功,foo只依赖其中一个时也可正常编译,但同时引入两个依赖就会触发链接器错误。我的目标是让foo静态链接libsmctrl,动态链接libcuda。
链接错误详情
... = note: /usr/bin/ld: /h/bez/work/rs-smctrl/target/debug/deps/librs_smctrl-ee6526e2da5cab52.rlib(libsmctrl.o): in function `setup_g_sm_control_10': /h/bez/work/rs-smctrl/src/libsmctrl.c:53: undefined reference to `cudbgReportDriverApiErrorFlags' clang: error: linker command failed with exit code 1 (use -v to see invocation) = note: some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified = note: use the `-l` flag to specify native libraries to link = note: use the `cargo:rustc-link-lib` directive to specify the native libraries to link with Cargo (see https://doc.rust-lang.org/cargo/reference/build-scripts.html#cargorustc-link-libkindname) error: could not compile `rs-smctrl` (bin "rs-smctrl") due to previous error
rs-smctrl的build.rs代码
# `build.rs` for `rs-smctrl` fn main() { println!("cargo:rustc-link-lib=dylib=cuda"); let src = ["src/libsmctrl.c"]; let mut builder = cc::Build::new(); let build = builder .files(src.iter()) .include("/usr/local/cuda/include") .flag("-Wno-unused-parameter") .flag("-Wno-parentheses") .flag("-Wno-sign-compare"); build.compile("libsmctrl"); }
foo的配置(注释cudarc即可正常构建)
Cargo.toml
# `Cargo.toml` for `foo`: [package] name = "foo" version = "0.1.0" edition = "2021" [dependencies] cudarc = { version="0.9.15", features=["std", "driver"], default-features = false } rs-smctrl = { git = "https://github.com/atomicapple0/rs-smctrl.git" }
main.rs
# `main.rs` for `foo` fn main() { unsafe { rs_smctrl::libsmctrl_set_global_mask(0) }; println!("Hello, world!"); }
解决方案
这个问题本质是链接顺序冲突:同时引入两个依赖时,Cargo自动排序的链接顺序可能导致libcuda的符号在rs-smctrl之后被处理,导致rs-smctrl找不到cudbgReportDriverApiErrorFlags这类符号。以下是几个实用解法:
方法1:强制调整libcuda的链接顺序
修改rs-smctrl的build.rs,把原来的cargo:rustc-link-lib=dylib=cuda换成直接指定链接参数,强制让libcuda排在前面:
fn main() { // 用link-arg强制指定链接顺序,确保libcuda先被处理 println!("cargo:rustc-link-arg=-lcuda"); let src = ["src/libsmctrl.c"]; let mut builder = cc::Build::new(); let build = builder .files(src.iter()) .include("/usr/local/cuda/include") .flag("-Wno-unused-parameter") .flag("-Wno-parentheses") .flag("-Wno-sign-compare"); build.compile("libsmctrl"); }
方法2:全局声明libcuda链接
在foo的根目录新建build.rs,添加全局的libcuda链接指令,确保所有依赖都能找到完整的符号:
// foo的build.rs fn main() { println!("cargo:rustc-link-lib=dylib=cuda"); }
方法3:让rs-smctrl依赖cudarc调整链接顺序
在rs-smctrl的Cargo.toml中添加cudarc作为构建依赖,让Cargo自动调整链接顺序:
[build-dependencies] cudarc = { version="0.9.15", features=["driver"], default-features = false }
同时保留原build.rs中的cargo:rustc-link-lib=dylib=cuda即可。
内容的提问来源于stack exchange,提问作者atomicapple0
相关产品推荐
相关产品推荐

