交叉编译 Rust 到 mipsel 架构

 

本文记录了将一个依赖 libpcapRust 小工具编译到 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 工具链

下载对应的工具链,并加入 PATH。

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 时,获得的包大小有误,是一个明显太大的正数(几十万)。具体原因尚待进一步调查可见此文章