Rust C++ FFI问题:如何指定链接库文件的路径?
Rust FFI包装C++库时的链接错误问题
问题详情
使用cmake和bindgen crates为支持CMake构建的C++库制作Rust FFI包装器,运行cargo test时触发链接错误:
error: linking with `cc` failed: exit status: 1 = note: /usr/bin/ld: cannot find -lcppcode: No such file or directory collect2: error: ld returned 1 exit status
但在build目录下能看到生成的库文件:
ls ./target/debug/build/myproject-debe94b9fba6ebdb/out/lib libcppcode.so libcppcode_static.a
build.rs中已添加链接相关代码,但rustc-link-lib仍无法定位库文件:
println!("cargo:rustc-link-search={}", dst.display()); println!("cargo:rustc-link-lib=cppcode");
项目结构:
. ├── build.rs ├── Cargo.lock ├── Cargo.toml ├── ext │ └── cppcode ├── src │ └── lib.rs └── wrapper.h
相关代码文件
build.rs
extern crate cmake; use cmake::Config; use std::env; use std::path::PathBuf; fn main() { let mut cfg = Config::new("ext/cppcode"); let dst = cfg.build(); println!("cargo:rustc-link-search={}", dst.display()); println!("cargo:rustc-link-lib=cppcode"); // Specify the include directory for bindgen let include_dir = "ext/cppcode/include"; let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); // The bindgen::Builder is the main entry point to bindgen, and lets you build up options for the resulting bindings. let bindings = bindgen::Builder::default() // The input header we would like to generate bindings for. .header("wrapper.h") // Set include directory .clang_arg(format!("-I{}", include_dir)) // Finish the builder and generate the bindings. .generate() // Unwrap the Result and panic on failure. .expect("Unable to generate bindings"); // Write the bindings to the $OUT_DIR/bindings.rs file. bindings .write_to_file(out_path.join("bindings.rs")) .expect("Couldn't write bindings!"); }
wrapper.h
#include "cppcode.h"
lib.rs
#![allow(non_upper_case_globals)] #![allow(non_camel_case_types)] #![allow(non_snake_case)] include!(concat!(env!("OUT_DIR"), "/bindings.rs")); #[cfg(test)] mod tests { #[test] fn hello_test() { println!("Hello, tests!"); } }
Cargo.toml
[package] name = "myproject" version = "0.1.0" edition = "2021" build = "build.rs" [dependencies] [build-dependencies] bindgen = "0.58.1" autotools = "0.2" cmake = "0.1.50"
解决方案
1. 修正链接路径
当前cargo:rustc-link-search指向的是dst根目录,但库文件实际在dst/lib子目录下,需调整路径:
println!("cargo:rustc-link-search={}", dst.join("lib").display());
2. 明确指定库类型
rustc默认优先查找动态库,但未指定类型时可能出现匹配歧义,需明确声明链接的是静态库还是动态库:
- 链接静态库:
println!("cargo:rustc-link-lib=static=cppcode"); - 链接动态库:
println!("cargo:rustc-link-lib=dylib=cppcode");
3. 强制CMake生成目标库类型
如果C++库的CMake配置未默认生成所需库类型,可在构建时添加参数强制生成:
let dst = cfg .define("BUILD_SHARED_LIBS", "ON") // 强制生成动态库 // 或 .define("BUILD_STATIC_LIBS", "ON") 强制生成静态库 .build();
4. 验证链接路径有效性
在build.rs中添加调试输出,确认路径是否正确指向库文件所在目录:
let lib_path = dst.join("lib"); println!("cargo:rustc-link-search={}", lib_path.display()); println!("DEBUG: Library path exists? {}", lib_path.exists()); println!("DEBUG: Files in lib path: {:?}", std::fs::read_dir(lib_path).unwrap().collect::<Vec<_>>());
内容的提问来源于stack exchange,提问作者Albatross
相关产品推荐
相关产品推荐

