本文记录了将一个依赖 libpcap
的 Rust 小工具编译到 mipsel 架构的过程。具体地,目标设备是一台运行 OpenWrt 22.03 的小米 AC2100 路由器,使用经典的联发科 MT7621 芯片,系统的 host triple 是 mipsel-unknown-linux-muslsf
(注意必须是 sf
,即软件浮点)。
文中的部分内容参考了 Building Rust code for my OpenWrt Wi-Fi router 和 min-sized-rust,在此表示感谢。
下载 musl 工具链
在
wget http://musl.cc/mipsel-linux-muslsf-cross.tgz
tar xf mipsel-linux-muslsf-cross.tgz
export PATH=$PATH:/path/to/mipsel-linux-muslsf-cross/bin
可以通过 mipsel-linux-muslsf-gcc -v
来验证是否能正常执行,也可以编译一个 Hello World 试试。
编译依赖库
上述的工具链已经自带了 C 和 C++ 标准库。我的工具依赖 libpcap
,因此需要额外编译。其他库的编译过程也是类似的,注意需要设置 CC
环境变量使用交叉编译工具链:
cd /path/to/libpcap
export CC=mipsel-linux-muslsf-gcc
./configure --host=mipsel-linux-muslsf --with-pcap=linux --prefix=/path/to/prefix/mipsel
make && make install
配置 Rust 工具链
运行 rustup target add mipsel-unknown-linux-musl
添加对应的标准库。注意到 Rust 的 mipsel 相关 triple 中并没有涉及浮点数支持(而 ARM 就有 hf
版本),因此很可能引发一些 ABI 问题(见 #34922 和 #50890)。但实际测试结果是,只要使用工具链中的 linker,在链接时就能正确使用 libgcc 中的软浮点相关支持,不会引发运行时错误。
而后编译 .cargo/config
(可以是项目级别,或者用户级别),增加工具链配置:
[target.mipsel-unknown-linux-musl]
linker = "/path/to/mipsel-linux-muslsf-cross/bin/mipsel-linux-muslsf-gcc"
为了链接到自行编译的 libpcap
,可选择多种办法,包括:
- 在编译时指定环境变量:
RUSTFLAGS="-L/path/to/prefix/mipsel/lib"
,或者; - 在
build.rs
中增加书写cargo:rustc-link-search=/path/to/prefix/mipsel/lib
,但需要注意判断架构。
最后使用 cargo build --target mipsel-unknown-linux-musl
即可得到二进制。
缩减二进制体积
即使使用 release 模式,编译出的二进制文件体积也较大。通过调整编译 profile 可以进一步减少体积。在 Cargo.toml
中增加:
[profile.minsize]
inherits = "release"
strip = true
lto = true
opt-level = "z"
panic = "abort"
可以有效减小二进制文件体积。
问题
虽然编译、链接、运行看起来没有大问题,但我的工具在 MIPS 平台上遇到了一个奇怪的问题:调用 libpcap
时,获得的包大小有误,是一个明显太大的正数(几十万)。具体原因尚待进一步调查可见此文章。