构建Rust与C混合静态库:如何确定需链接的原生库
构建可被C调用的自包含Rust静态库问题
我想要创建一个能在C程序里调用的Rust静态库,而且这个库得是完全自包含的(所有依赖都内置)。一开始我在Cargo.toml里加了crate-type = ["staticlib"],但这招只在Rust代码没外部依赖的简单场景下管用。
如果是带外部依赖的复杂Rust代码,这么做虽然能编译成功,但生成的库没法被C程序调用。我试过用命令:
RUSTFLAGS='-C target-feature=+crt-static' cargo build --release --target=x86_64-unknown-linux-gnu
来构建自包含库,结果编译失败,报错信息如下:
error: linking with `cc` failed: exit status: 1 | = note: LC_ALL="C" PATH="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" /usr/bin/ld: /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2: error adding symbols: DSO missing from command line collect2: error: ld returned 1 exit status note: some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified = 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
查了官方文档后知道,得用类似这样的命令链接原生库:
RUSTFLAGS='-C target-feature=+crt-static -L /path/to/nativelibrary' cargo build --release --target=x86_64-unknown-linux-gnu
但我的Rust代码依赖了几十个外部crate,根本搞不清/path/to/nativelibrary该填什么。现在有两个问题:
- 有没有更自动化的方法生成完全自包含的静态库?
- 如果必须指定原生库路径,怎么确定需要链接哪些原生库?
问题解答
1. 自动化生成自包含静态库的方法
- 使用
x86_64-unknown-linux-musl目标:这个目标本身就是为静态编译设计的,默认会把所有依赖(包括C标准库)都静态链接进去,不需要额外加crt-static参数。直接执行:
生成的静态库在cargo build --release --target=x86_64-unknown-linux-musltarget/x86_64-unknown-linux-musl/release/目录下,基本是完全自包含的。如果你的依赖里有需要原生库的crate,musl工具链会优先找静态版本的原生库,只要系统里装了对应的静态开发包,就能自动链接进去。 - 用
cargo-zigbuild辅助编译:如果musl目标遇到某些原生库静态链接的问题(比如OpenSSL),可以用cargo-zigbuild工具,它基于Zig的交叉编译能力,能更轻松地处理静态链接,命令如下:
这个工具会自动处理很多原生库的静态依赖问题,不需要手动指定路径。cargo install cargo-zigbuild cargo zigbuild --release --target=x86_64-unknown-linux-musl
2. 确定需要链接的原生库的方法
如果一定要用x86_64-unknown-linux-gnu目标,你可以通过以下方式找出依赖的原生库:
- 查看Cargo的构建输出:执行构建命令时加上
-v( verbose)参数,比如:
在输出里找RUSTFLAGS='-C target-feature=+crt-static' cargo build --release --target=x86_64-unknown-linux-gnu -vrustc调用的参数,里面会有-l开头的选项,这些就是需要链接的原生库名(比如-lssl、-lcrypto)。 - 用
ldd分析临时目标文件:先不加crt-static参数编译出动态链接的库,然后用ldd命令查看它依赖的动态库:
输出里的动态库就是你需要找静态版本的库,比如输出里的ldd target/x86_64-unknown-linux-gnu/release/libyourlib.solibssl.so.1.1对应的静态库是libssl.a,你需要确保系统里安装了该库的静态开发包,然后Cargo会自动找到它们的路径,不需要手动加-L参数,只要在RUSTFLAGS里保留-C target-feature=+crt-static即可。 - 查看依赖crate的构建脚本:很多依赖原生库的crate会有
build.rs脚本,里面会用cargo:rustc-link-lib指令指定要链接的库,你可以直接查看这些脚本,里面会明确写出需要的原生库名称。
内容的提问来源于stack exchange,提问作者xc wang
相关产品推荐
相关产品推荐

