Rust Cross Compilation | 8lovelife's life
0%

Rust Cross Compilation

最近在用Rust语言写一个轻量级的数据同步工具(DP),由于是在MacBook Pro M2上做的开发,通过cargo build –release编译后的执行文件,无法在x86_64架构的Linux系统上运行。虽然rustup提供了交叉编译的能力,但开发环境安装不同架构平台的工具链,很容易导致混乱,于是我决定通过Dockerfile来进行DP的”交叉”编译

静态链接

通过使用x86_64-musl镜像,构建静态链接执行文件

1
2
3
4
5
6
7
8
9
10
FROM messense/rust-musl-cross:x86_64-musl as build
RUN USER=root cargo new --bin ep-dp
WORKDIR /ep-dp
COPY ./Cargo.lock ./Cargo.lock
COPY ./Cargo.toml ./Cargo.toml
COPY ./src ./src
RUN cargo build --release

FROM scratch AS export-stage
COPY --from=build /ep-dp/target/x86_64-unknown-linux-musl/release/ep-dp .

导出构建文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
DOCKER_BUILDKIT=1 docker build -f Dockerfile . --output . && mv ep-dp ep-dp:musl

# 编译报错如下
# error: failed to run custom build command for `openssl-sys v0.9.90`
# ...
# run pkg_config fail: pkg-config has not been configured to support cross-compilation.
# ...
# Could not find directory of OpenSSL installation, and this `-sys` crate cannot
# proceed without this knowledge. If OpenSSL is installed and this crate had
# trouble finding it, you can set the `OPENSSL_DIR` environment variable for the
# compilation process.

# 解决方法
# 在Cargo.toml中添加 openssl = { version = "0.10", features = ["vendored"] }
1
2
3
# on centos
[root@m dp]# ldd ep-dp:musl
statically linked

动态链接

直接使用目标平台镜像,构建动态链接执行文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
FROM --platform=linux/amd64 centos:7.6.1810 as build
RUN yum install -y gcc gcc-c++ openssl-devel pkg-config
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | bash -s -- -y
ENV PATH="/root/.cargo/bin:${PATH}"
RUN USER=root cargo new --bin ep-dp
WORKDIR /ep-dp
COPY ./Cargo.lock ./Cargo.lock
COPY ./Cargo.toml ./Cargo.toml
# 缓存依赖包
RUN cargo build --release
RUN rm src/*.rs
COPY ./src ./src
# 构建
RUN rm ./target/release/deps/ep_dp*
RUN cargo build --release
# 裁剪
RUN strip target/release/ep-dp

FROM scratch AS export-stage
COPY --from=build /ep-dp/target/release/ep-dp .

导出构建文件

1
DOCKER_BUILDKIT=1 docker build -f Dockerfile . --output . && mv ep-dp ep-dp:centos
1
2
3
4
5
6
7
8
9
10
11
# on centos
[root@m dp]# ldd ep-dp:centos
linux-vdso.so.1 => (0x00007ffd22bc1000)
libz.so.1 => /lib64/libz.so.1 (0x00007f7d961fa000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f7d95fe4000)
librt.so.1 => /lib64/librt.so.1 (0x00007f7d95ddc000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f7d95bc0000)
libm.so.6 => /lib64/libm.so.6 (0x00007f7d958be000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f7d956ba000)
libc.so.6 => /lib64/libc.so.6 (0x00007f7d952ed000)
/lib64/ld-linux-x86-64.so.2 (0x00007f7d96e96000)

DP Image

构建DP镜像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
FROM messense/rust-musl-cross:x86_64-musl as build
RUN USER=root cargo new --bin ep-dp
WORKDIR /ep-dp
COPY ./Cargo.lock ./Cargo.lock
COPY ./Cargo.toml ./Cargo.toml
COPY ./src ./src
RUN cargo build --release

FROM --platform=linux/amd64 alpine
COPY --from=build /ep-dp/target/x86_64-unknown-linux-musl/release/ep-dp .
ENV RUST_LOG=ep_dp=info
RUN mkdir /config
WORKDIR /data
ENTRYPOINT ["/ep-dp"]
1
2
[root@x dp]# docker image ls | grep ep-dp
ep-dp latest 5b0e6e989f8b 36 seconds ago 16.3MB

动态链接 VS 静态链接

静态链接执行文件是一个完整的可执行文件,包含所有的依赖库。动态链接执行文件需要依赖共享库才能正确运行

文件大小

静态链接执行文件的size要大于动态链接执行文件的size

1
2
3
4
[root@m dp]# ls -lah ep-dp:musl
-rwxr-xr-x 1 x x 15M Aug 7 09:44 ep-dp:musl
[root@m dp]# ls -lah ep-dp:centos
-rwxr-xr-x 1 x x 8.6M Aug 7 16:04 ep-dp:centos

系统兼容

静态链接执行文件拥有更好的兼容性,而动态链接执行文件的运行环境需要包含所需依赖库

1
2
3
4
5
6
7
8
9
10
11
12
13
# on Alpine
[root@x dp]# ldd ep-dp:centos
/lib64/ld-linux-x86-64.so.2 (0x7ffffff65000)
libz.so.1 => /lib/libz.so.1 (0x7fffff4c5000)
Error loading shared library libgcc_s.so.1: No such file or directory (needed by ep-dp:centos)
librt.so.1 => /lib64/ld-linux-x86-64.so.2 (0x7ffffff65000)
libpthread.so.0 => /lib64/ld-linux-x86-64.so.2 (0x7ffffff65000)
libm.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7ffffff65000)
libdl.so.2 => /lib64/ld-linux-x86-64.so.2 (0x7ffffff65000)
libc.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7ffffff65000)

[root@m dp]# ldd ep-dp:musl
statically linked