赞
踩
在此前的一篇文章中,笔者对Rust的交叉编译开发环境的安装作了说明,演示了简单Hello World
应用的交叉编译。笔者在该文章中记录了较为复杂的rust
应用(paho.mqtt.rust)的编译过程,目柡设备为运行openwrt系统的MT7628
设备。此处简要重复笔者安装嵌入式MIPS
的rust
交叉编译工具链的过程。首先,以根用户权限安装rust
编译器:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs -o sh.rust.rs
export CARGO_HOME=/opt/rust-lang/cargo
export RUSTUP_HOME=/opt/rust-lang/rustup
sh ./sh.rust.rs # 选择`(default)以完成安装
source /opt/rust-lang/cargo/env
rustup target add mipsel-unknown-linux-musl # 安装MIPS架构的rust柡准库
之后下载并安装openwrt
官方提供的交叉编译器至/opt
目录下:
wget https://mirror.sjtu.edu.cn/openwrt/releases/21.02.3/targets/ramips/mt76x8/openwrt-sdk-21.02.3-ramips-mt76x8_gcc-8.4.0_musl.Linux-x86_64.tar.xz
sudo tar -Jxf openwrt-sdk-ramips-mt76x8_gcc-11.2.0_musl.Linux-x86_64.tar.xz -C /opt
如果在本地已有构建了的openwrt
工程,可以不下载官方的编译器,直接采用本地的编译器;这一点笔者在后面会简要说明。编译paho.mqtt.rust
需要依赖openssl
库,一种方案是使用下载的gcc
编译器交叉编译openssl
,另一种是直接复用现有的openwrt
编译结果的openssl
库。笔者采用了第二种方案:
/opt/openwrt-sdk-21.02.3-ramips-mt76x8_gcc-8.4.0_musl.Linux-x86_64/staging_dir/target-mipsel_24kc_musl$ find .
.
./usr
./usr/include
./include
/opt/openwrt-sdk-21.02.3-ramips-mt76x8_gcc-8.4.0_musl.Linux-x86_64/staging_dir/target-mipsel_24kc_musl$ sudo rm -rf *
~/8.06.4/build_dir/target-mipsel_24kc_musl/openssl-1.0.2s/ipkg-install$ ls
etc usr
~/openwrt-18.06.4/build_dir/target-mipsel_24kc_musl/openssl-1.0.2s/ipkg-install$ sudo cp -r -p -P * \
> /opt/openwrt-sdk-21.02.3-ramips-mt76x8_gcc-8.4.0_musl.Linux-x86_64/staging_dir/target-mipsel_24kc_musl/
笔者使用的openssl
库源于openwrt-18.04
编译工程,其版本为1.0.2s
,与目柡设备已安装的openssl
库版本不同,后面需要将该版本的动态库复制到设备上。
在之前的博客中笔者提到,需要编辑~/.cargo/config
文件,增加交叉编译时的链接器选项。不过本次编译通过环境变量指定交叉编译器;为加速crates
包的下载,~/.cargo/config
文件的全部内容为:
[source.crates-io]
replace-with = 'tuna'
[source.tuna]
registry = "https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git"
以上配置文件创建后,需要手动创建/opt/rust-lang/cargo/registry
目录,该目录为crates
包的下载路径;创建后需要将属主设置为普通用户:
sudo mkdir /opt/rust-lang/cargo/registry
sudo chown username:username /opt/rust-lang/cargo/registry
之后,修改用户的环境变量,在~/.profile
中增加:
export CARGO_HOME=/opt/rust-lang/cargo
export RUSTUP_HOME=/opt/rust-lang/rustup
export PATH=${CARGO_HOME}/bin:${PATH}
不过以上环境变量的修改,仅用于基本的rust
编程开发(如主机端的rust
应用开发),不足以交叉构建paho.rust.mqtt
;它需要的环境变量要复杂一些,笔者编写了rust-mips-env.sh
用于配置环境变量,其内容如下:
#!/bin/bash
# rust-mips-env.sh
export OPENWRT_DIR="/opt/openwrt-sdk-21.02.3-ramips-mt76x8_gcc-8.4.0_musl.Linux-x86_64"
export STAGING_DIR="${OPENWRT_DIR}/staging_dir/target-mipsel_24kc_musl"
export OPENSSL_DIR="${STAGING_DIR}/usr"
export PATH="${OPENWRT_DIR}/staging_dir/toolchain-mipsel_24kc_gcc-8.4.0_musl/bin"
export PATH="${PATH}:/opt/rust-lang/cargo/bin:/usr/local/bin:/bin:/sbin:/usr/bin:/usr/sbin:/snap/bin"
export TARGET_CC=mipsel-openwrt-linux-musl-gcc
export CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_MUSL_LINKER="${TARGET_CC}"
export TARGET_CFLAGS="-pipe -mno-branch-likely -mips32r2 -mtune=24kc -msoft-float -mips16 -minterlink-mips16"
值得强调的是上面的CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_MUSL_LINKER
环境变量,它替代了~/.cargo/config
中相应交叉编译的链接器配置选项,这样可以通过环境变量动态地指定不同的交叉构建中的链接器,更灵活地实现rust
软件项目的构建;与rust
交叉编译相关的环境变量请参考官方文根档。执行source ./rust-mips-env.sh
后,就可以编译paho.rust.mqtt
了;编译分为两个步骤,先编译paho.mqtt.rust
库,之后再编译演示例程(--examples
):
~/paho.mqtt.rust$ source ../rust-mips-env.sh ~/paho.mqtt.rust$ cargo build --release --target=mipsel-unknown-linux-musl Updating `tuna` index Compiling proc-macro2 v1.0.37 .... Compiling paho-mqtt v0.11.0 (/home/username/paho.mqtt.rust) Finished release [optimized] target(s) in 48.27s ~/paho.mqtt.rust$ cargo build --release --target=mipsel-unknown-linux-musl --examples Compiling fastrand v1.7.0 ... Compiling paho-mqtt v0.11.0 (/home/username/paho.mqtt.rust) Finished release [optimized] target(s) in 2m 08s ~/paho.mqtt.rust$ cd target/mipsel-unknown-linux-musl/release ~/paho.mqtt.rust/target/mipsel-unknown-linux-musl/release$ file examples/async_publish examples/async_publish: ELF 32-bit LSB shared object, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, interpreter /lib/ld-musl-mipsel-sf.so.1, with debug_info, not stripped ~/paho.mqtt.rust/target/mipsel-unknown-linux-musl/release$ patchelf --print-needed examples/async_publish libssl.so.1.0.0 libcrypto.so.1.0.0 libgcc_s.so.1 libc.so
async_publish
首先,将上面复制的openssl-1.0.2s
库复制到目柡设备的/tmp
目录下,再确认async_publish
的依赖库都存在:
root@OpenWrt:/tmp# export LD_LIBRARY_PATH=/tmp
root@OpenWrt:/tmp# ldd ./async_publish
/lib/ld-musl-mipsel-sf.so.1 (0x77df3000)
libssl.so.1.0.0 => /tmp/libssl.so.1.0.0 (0x77bd6000)
libcrypto.so.1.0.0 => /tmp/libcrypto.so.1.0.0 (0x77a73000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x77a4f000)
libc.so => /lib/ld-musl-mipsel-sf.so.1 (0x77df3000)
之后,在网关上访问一个带有公网IP的broker
(笔者这里选择了一台带有IPv6地址的openwrt
路由器),订阅所有的消息:
root@OpenWrt:~# mosquitto_sub -h '2409:8a28:e77:6740:5870:XXXX:XXXX:XXXX' -p 1883 -v -t '#'
test Hello Rust MQTT world!
上面第二行为接收到的async_publish
发布的消息。最后,运行async_publish
的操作为:
root@OpenWrt:/tmp# ./async_publish tcp://[2409:8a28:e77:6740:5870:XXXX:XXXX:XXXX]:1883
Connecting to the MQTT server
Publishing a message on the topic 'test'
Disconnecting
如果本地已经编译了openwrt
,构建paho.mqtt.rust
所需的环境变量与上面大同小异,内容如下:
#!/bin/bash
# rust-mips.sh
export TARGET_CC=mipsel-openwrt-linux-musl-gcc
export TARGET_CFLAGS='-mno-branch-likely -mips32r2 -mtune=24kc'
export CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_MUSL_LINKER="${TARGET_CC}"
export OPENWRT_DIR=$HOME/openwrt-18.06.4
export STAGING_DIR=${OPENWRT_DIR}/staging_dir/target-mipsel_24kc_musl
export OPENSSL_DIR=${STAGING_DIR}/usr
export PATH="${OPENWRT_DIR}/staging_dir/host/bin:${PATH}"
export PATH="${OPENWRT_DIR}/staging_dir/hostpkg/bin:${PATH}"
export PATH="${OPENWRT_DIR}/staging_dir/toolchain-mipsel_24kc_gcc-7.3.0_musl/bin:${PATH}"
如果需要在openwrt
增加rust
的软件包,以上某些环境变量(例如STAGING_DIR
)已经定义了,不需重复定义。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。