关于交叉编译
绝大部分的Rust程序员都会有跟我我一样的需求,写代码用的是Windows
或者Mac
,部署平台是Linux
,这种情况下就需要使用Cross-Compiler
交叉编译,意思是可以在当前平台Host
下编译出目标平台target
的可执行文件,尤其是做ARM
平台开发的同学对这个更为熟悉。
Rust交叉编译在Github上有一个文档Rust核心员工Jorge Aparicio
提供的一份文档https://github.com/japaric/rust-cross,推荐大家仔细的读一读。
对我而言,我的要求比较简单,都是X86_64
架构,从Mac
上编译出unknow-linux
就好
musl工具链
musl实现了Linux libc
,质量可靠,适配所有Linux环境,使用静态连接替换动态链接,这样就能打出一个完整的二进制文件,可以丢到任何Linux环境里运行。
当然,关于静态链接与动态链接各有优缺点,这里不细说。
安装一下
rustup target add x86_64-unknown-linux-musl
main.rs
fn main() {
println!("Hello, world!\r\nwww.qttc.net\r\n");
}
然后这么编译
cargo build --release --target=x86_64-unknown-linux-musl
把结果丢到Linux下执行,没问题
$ ./cross_compile_test
Hello, world!
www.qttc.net
常见问题
要是提示/bin/sh: musl-gcc: command not found
,解决方法是安装musl-cross
brew install filosottile/musl-cross/musl-cross
配置config
$ cat .cargo/config
...
[target.x86_64-unknown-linux-musl]
linker = "x86_64-linux-musl-gcc"
...
要是你的程序依赖原生库,需要设置一个环境变量CC_x86_64_unknown_linux_musl=x86_64-linux-musl-gcc
,所以完整的编译命令如下
CC_x86_64_unknown_linux_musl="x86_64-linux-musl-gcc" cargo build --release --target=x86_64-unknown-linux-musl
要是你的程序使用了OpenSSL类库,这是一个麻烦的事情,目前普遍做法是在Cargo.toml
文件中添加依赖
Cargo.toml
[dependencies]
openssl = { version = "0.10", features = ["vendored"] }
Docker编译
我更愿意推荐使用这种方式,因为使用第一种方式的话,需要安装一些工具链,还得看程序实际依赖的各种类库而做各种调整。其次是部署的时候也可以选择使用Docker部署,这样一来就几乎没有交叉编译的需求了。
Rust官方提供了Docker镜像在hub.docker.com上,根据官方的文档,可以使用以下命令编译出Linux平台的可执行文件
docker run --rm --user "$(id -u)":"$(id -g)" -v "$PWD":/usr/src/myapp -w /usr/src/myapp rust:1.43 cargo build --release
Docker环境下编译也有问题,每次都得重新拉取资源,其次是容易卡,其它都还好。