使用Cargo交叉编译Rust时误链接主机库的问题求助
问题背景
从FreeBSD 13.1 x86_64主机交叉编译Rust crate到FreeBSD 13.1 aarch64目标,此前在FreeBSD 12.1 x86_64到FreeBSD 12.1 aarch64的交叉编译流程完全正常,但FreeBSD 13.1下出现链接错误。
环境配置
cargo version cargo 1.67.0-nightly (f6e737b1e 2022-12-02) rustc --version rustc 1.67.0-nightly (01fbc5ae7 2022-12-07) export AARCH64_SYSROOT=/path/to/aarch64/root export PKG_CONFIG_SYSROOT_DIR=$AARCH64_SYSROOT export RUSTFLAGS="-C link-args=-fuse-ld=lld -C link-args=-L$AARCH64_SYSROOT/usr/lib -C link-args=-L$AARCH64_SYSROOT/lib -C link-args=-L$AARCH64_SYSROOT/usr/local/lib -C link-args=--sysroot=$AARCH64_SYSROOT"
编译错误
执行编译命令:
cargo build -Z build-std --release --target aarch64-unknown-freebsd
出现以下架构不兼容的链接错误:
ld.lld: error: /usr/local/lib/libssl.so is incompatible with $AARCH64_SYSROOT/usr/lib/Scrt1.o ld.lld: error: /usr/local/lib/libcrypto.so is incompatible with $AARCH64_SYSROOT/usr/lib/Scrt1.o ld.lld: error: /usr/local/lib/libcurl.so is incompatible with $AARCH64_SYSROOT/usr/lib/Scrt1.o cc: error: linker command failed with exit code 1 (use -v to see invocation)
问题排查
通过--verbose参数查看编译命令发现:
- FreeBSD 13.1的编译命令中包含
-L native=/usr/local/lib(主机x86_64的库路径) - FreeBSD 12.1中对应的参数是
-L native=$AARCH64_SYSROOT/usr/local/lib(交叉目标的库路径)
手动调用rustc并移除-L native=/usr/local/lib参数可成功编译,但依赖较多时无法脱离Cargo操作。
解决方案
1. 配置目标专属RUSTFLAGS
在项目的.cargo/config.toml中添加针对aarch64-unknown-freebsd的配置,强制使用交叉目标的库路径:
[target.aarch64-unknown-freebsd] rustflags = [ "-C", "link-args=-fuse-ld=lld", "-C", "link-args=-L${env:AARCH64_SYSROOT}/usr/lib", "-C", "link-args=-L${env:AARCH64_SYSROOT}/lib", "-C", "link-args=-L${env:AARCH64_SYSROOT}/usr/local/lib", "-C", "link-args=--sysroot=${env:AARCH64_SYSROOT}", "-L", "native=${env:AARCH64_SYSROOT}/usr/local/lib", "-L", "native=${env:AARCH64_SYSROOT}/usr/lib", "-L", "native=${env:AARCH64_SYSROOT}/lib", ]
该配置会覆盖Cargo默认添加的主机库路径,确保链接器只搜索交叉目标的库。
2. 限制pkg-config的搜索范围
避免pkg-config读取主机系统的库配置,仅搜索交叉sysroot中的路径:
export PKG_CONFIG_LIBDIR="${AARCH64_SYSROOT}/usr/local/lib/pkgconfig:${AARCH64_SYSROOT}/usr/lib/pkgconfig" export PKG_CONFIG_PATH=""
这样pkg-config不会向Cargo传递主机的库路径信息。
3. 编译时指定sysroot
在编译命令中添加--sysroot参数,明确告知rustc使用交叉编译的sysroot:
cargo build -Z build-std --release --target aarch64-unknown-freebsd --sysroot $AARCH64_SYSROOT
此参数会让rustc默认使用指定sysroot下的库路径,减少主机路径的干扰。
原因分析
FreeBSD 13.1的系统库路径配置或rustc/cargo对FreeBSD 13目标的处理逻辑发生了变化,导致交叉编译时Cargo默认引入了主机的/usr/local/lib路径。相比FreeBSD 12.1,rustc对FreeBSD 13目标的默认链接路径设置不同,或是系统级的库搜索优先级调整引发了该问题。
内容的提问来源于stack exchange,提问作者Luc Techer

