前言
我为什么需要使用rust进行交叉编译,因为想使用rust编译和运行web程序,所以使用Dockerfile时需要分为构建和运行两个步骤进行,但是编译出的程序并不能直接运行,所以改用交叉编译的方式来打包,就可以在对应架构下的容器内直接运行。
配置环境
我这里直接使用docker镜像,搭建一个专门用来编译docker的容器。
首先在pwd/rust-build目录下准备好apt souce的源文件。apt更换源
1
docker run -it --name rust-build -v `pwd`/rust-build:/web rust:1.73.0-slim-buster /bin/bash
使用目前最新的rust版本,然后在用户目录下映射常用来编译的目录。然后先更新源,再开始下载编译环境。
这里需要使用rustup,也需要添加镜像源rustup更换源
1
rustup target add x86_64-unknown-linux-musl
编译
1
cargo build --release --target x86_64-unknown-linux-musl
常见报错
musl-tools
编译过程报错
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
error: failed to run custom build command for `ring v0.16.20`
Caused by:
process didn't exit successfully: `/web/house-monitor/target/release/build/ring-59b47e2d18302b2c/build-script-build` (exit status: 101)
--- stdout
OPT_LEVEL = Some("3")
TARGET = Some("x86_64-unknown-linux-musl")
HOST = Some("x86_64-unknown-linux-gnu")
cargo:rerun-if-env-changed=CC_x86_64-unknown-linux-musl
CC_x86_64-unknown-linux-musl = None
cargo:rerun-if-env-changed=CC_x86_64_unknown_linux_musl
CC_x86_64_unknown_linux_musl = None
cargo:rerun-if-env-changed=TARGET_CC
TARGET_CC = None
cargo:rerun-if-env-changed=CC
CC = None
RUSTC_LINKER = None
cargo:rerun-if-env-changed=CROSS_COMPILE
CROSS_COMPILE = None
cargo:rerun-if-env-changed=CRATE_CC_NO_DEFAULTS
CRATE_CC_NO_DEFAULTS = None
DEBUG = Some("false")
CARGO_CFG_TARGET_FEATURE = Some("fxsr,sse,sse2")
cargo:rerun-if-env-changed=CFLAGS_x86_64-unknown-linux-musl
CFLAGS_x86_64-unknown-linux-musl = None
cargo:rerun-if-env-changed=CFLAGS_x86_64_unknown_linux_musl
CFLAGS_x86_64_unknown_linux_musl = None
cargo:rerun-if-env-changed=TARGET_CFLAGS
TARGET_CFLAGS = None
cargo:rerun-if-env-changed=CFLAGS
CFLAGS = None
--- stderr
running "musl-gcc" "-O3" "-ffunction-sections" "-fdata-sections" "-fPIC" "-m64" "-I" "include" "-Wall" "-Wextra" "-pedantic" "-pedantic-errors" "-Wall" "-Wextra" "-Wcast-align" "-Wcast-qual" "-Wconversion" "-Wenum-compare" "-Wfloat-equal" "-Wformat=2" "-Winline" "-Winvalid-pch" "-Wmissing-field-initializers" "-Wmissing-include-dirs" "-Wredundant-decls" "-Wshadow" "-Wsign-compare" "-Wsign-conversion" "-Wundef" "-Wuninitialized" "-Wwrite-strings" "-fno-strict-aliasing" "-fvisibility=hidden" "-fstack-protector" "-g3" "-U_FORTIFY_SOURCE" "-DNDEBUG" "-c" "-o/web/house-monitor/target/x86_64-unknown-linux-musl/release/build/ring-95fb3f38509657d3/out/aesni-x86_64-elf.o" "/usr/local/cargo/registry/src/index.crates.io-6f17d22bba15001f/ring-0.16.20/pregenerated/aesni-x86_64-elf.S"
thread 'main' panicked at /usr/local/cargo/registry/src/index.crates.io-6f17d22bba15001f/ring-0.16.20/build.rs:653:9:
failed to execute ["musl-gcc" "-O3" "-ffunction-sections" "-fdata-sections" "-fPIC" "-m64" "-I" "include" "-Wall" "-Wextra" "-pedantic" "-pedantic-errors" "-Wall" "-Wextra" "-Wcast-align" "-Wcast-qual" "-Wconversion" "-Wenum-compare" "-Wfloat-equal" "-Wformat=2" "-Winline" "-Winvalid-pch" "-Wmissing-field-initializers" "-Wmissing-include-dirs" "-Wredundant-decls" "-Wshadow" "-Wsign-compare" "-Wsign-conversion" "-Wundef" "-Wuninitialized" "-Wwrite-strings" "-fno-strict-aliasing" "-fvisibility=hidden" "-fstack-protector" "-g3" "-U_FORTIFY_SOURCE" "-DNDEBUG" "-c" "-o/web/house-monitor/target/x86_64-unknown-linux-musl/release/build/ring-95fb3f38509657d3/out/aesni-x86_64-elf.o" "/usr/local/cargo/registry/src/index.crates.io-6f17d22bba15001f/ring-0.16.20/pregenerated/aesni-x86_64-elf.S"]: No such file or directory (os error 2)
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
warning: build failed, waiting for other jobs to finish...
下载
1
apt-get install musl-tools
openssl-sys
报错信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
error: failed to run custom build command for `openssl-sys v0.9.93`
Caused by:
process didn't exit successfully: `/web/house-monitor/target/release/build/openssl-sys-8c5cac0f00469e9a/build-script-main` (exit status: 101)
--- stdout
cargo:rerun-if-env-changed=X86_64_UNKNOWN_LINUX_MUSL_OPENSSL_LIB_DIR
X86_64_UNKNOWN_LINUX_MUSL_OPENSSL_LIB_DIR unset
cargo:rerun-if-env-changed=OPENSSL_LIB_DIR
OPENSSL_LIB_DIR unset
cargo:rerun-if-env-changed=X86_64_UNKNOWN_LINUX_MUSL_OPENSSL_INCLUDE_DIR
X86_64_UNKNOWN_LINUX_MUSL_OPENSSL_INCLUDE_DIR unset
cargo:rerun-if-env-changed=OPENSSL_INCLUDE_DIR
OPENSSL_INCLUDE_DIR unset
cargo:rerun-if-env-changed=X86_64_UNKNOWN_LINUX_MUSL_OPENSSL_DIR
X86_64_UNKNOWN_LINUX_MUSL_OPENSSL_DIR unset
cargo:rerun-if-env-changed=OPENSSL_DIR
OPENSSL_DIR unset
cargo:rerun-if-env-changed=OPENSSL_NO_PKG_CONFIG
cargo:rerun-if-env-changed=PKG_CONFIG_ALLOW_CROSS_x86_64-unknown-linux-musl
cargo:rerun-if-env-changed=PKG_CONFIG_ALLOW_CROSS_x86_64_unknown_linux_musl
cargo:rerun-if-env-changed=TARGET_PKG_CONFIG_ALLOW_CROSS
cargo:rerun-if-env-changed=PKG_CONFIG_ALLOW_CROSS
cargo:rerun-if-env-changed=PKG_CONFIG_x86_64-unknown-linux-musl
cargo:rerun-if-env-changed=PKG_CONFIG_x86_64_unknown_linux_musl
cargo:rerun-if-env-changed=TARGET_PKG_CONFIG
cargo:rerun-if-env-changed=PKG_CONFIG
cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR_x86_64-unknown-linux-musl
cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR_x86_64_unknown_linux_musl
cargo:rerun-if-env-changed=TARGET_PKG_CONFIG_SYSROOT_DIR
cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR
run pkg_config fail: pkg-config has not been configured to support cross-compilation.
Install a sysroot for the target platform and configure it via
PKG_CONFIG_SYSROOT_DIR and PKG_CONFIG_PATH, or install a
cross-compiling wrapper for pkg-config and set it via
PKG_CONFIG environment variable.
--- stderr
thread 'main' panicked at /usr/local/cargo/registry/src/index.crates.io-6f17d22bba15001f/openssl-sys-0.9.93/build/find_normal.rs:190:5:
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.
Make sure you also have the development packages of openssl installed.
For example, `libssl-dev` on Ubuntu or `openssl-devel` on Fedora.
If you're in a situation where you think the directory *should* be found
automatically, please open a bug at https://github.com/sfackler/rust-openssl
and include information about your system as well as this message.
$HOST = x86_64-unknown-linux-gnu
$TARGET = x86_64-unknown-linux-musl
openssl-sys = 0.9.93
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
warning: build failed, waiting for other jobs to finish...
尽管看提示说可以下载libssl-dev来解决这个问题,但是实际上,如果是交叉编译,下载了这个也一样编译不过。所以我们这里需要手动编译openssl
解决
以下这些步骤都是不可或缺的,最好挨着依次配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
mkdir /musl && cd /musl
apt-get install -y wget pkg-config make musl-tools
wget https://www.openssl.org/source/openssl-1.1.1w.tar.gz
tar -zxvf openssl-1.1.1w.tar.gz
cd openssl-1.1.1w
ln -s /usr/include/x86_64-linux-gnu/asm /usr/include/x86_64-linux-musl/asm
ln -s /usr/include/asm-generic /usr/include/x86_64-linux-musl/asm-generic
ln -s /usr/include/linux /usr/include/x86_64-linux-musl/linux
CC="musl-gcc -fPIE -pie" ./Configure no-shared no-async --prefix=/musl --openssldir=/musl/ssl linux-x86_64
make depend
make -j$(nproc)
make install
export PKG_CONFIG_ALLOW_CROSS=1
export OPENSSL_STATIC=true
export OPENSSL_DIR=/musl
这里可以看到,实际不需要下载libssl-dev,当然下载了也无妨
pkg-config
如果没有下载这个,可能会出现
1
2
3
root@88b11af69d55:/musl/openssl-1.1.1w# CC="musl-gcc -fPIE -pie" ./Configure no-shared no-async --prefix=/musl --openssldir=/musl/ssl linux-x86_64
Can't locate FindBin.pm in @INC (you may need to install the FindBin module) (@INC contains: /etc/perl /usr/local/lib/x86_64-linux-gnu/perl/5.28.1 /usr/local/share/perl/5.28.1 /usr/lib/x86_64-linux-gnu/perl5/5.28 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl/5.28 /usr/share/perl/5.28 /usr/local/lib/site_perl /usr/lib/x86_64-linux-gnu/perl-base) at ./Configure line 15.
BEGIN failed--compilation aborted at ./Configure line 15.
安装过后的话命令就可以正常运行通过了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
root@88b11af69d55:/musl/openssl-1.1.1w# CC="musl-gcc -fPIE -pie" ./Configure no-shared no-async --prefix=/musl --openssldir=/musl/ssl linux-x86_64
Configuring OpenSSL version 1.1.1w (0x1010117fL) for linux-x86_64
Using os-specific seed configuration
Creating configdata.pm
Creating Makefile
**********************************************************************
*** ***
*** OpenSSL has been successfully configured ***
*** ***
*** If you encounter a problem while building, please open an ***
*** issue on GitHub <https://github.com/openssl/openssl/issues> ***
*** and include the output from the following command: ***
*** ***
*** perl configdata.pm --dump ***
*** ***
*** (If you are new to OpenSSL, you might want to consult the ***
*** 'Troubleshooting' section in the INSTALL file first) ***
*** ***
**********************************************************************
musl-gcc: not found
一般正常很多编译都需要这个,可以看到如果没有安装这个,make命令在执行-j以及install时都会报错
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
root@88b11af69d55:/musl/openssl-1.1.1w# make -j$(nproc)
/usr/bin/perl "-I." -Mconfigdata "util/dofile.pl" \
"-oMakefile" include/crypto/bn_conf.h.in > include/crypto/bn_conf.h
/usr/bin/perl "-I." -Mconfigdata "util/dofile.pl" \
"-oMakefile" include/crypto/dso_conf.h.in > include/crypto/dso_conf.h
/usr/bin/perl "-I." -Mconfigdata "util/dofile.pl" \
"-oMakefile" include/openssl/opensslconf.h.in > include/openssl/opensslconf.h
make depend && make _all
make[1]: Entering directory '/musl/openssl-1.1.1w'
make[1]: Leaving directory '/musl/openssl-1.1.1w'
make[1]: Entering directory '/musl/openssl-1.1.1w'
musl-gcc -fPIE -pie -I. -Iinclude -fPIC -pthread -m64 -Wall -O3 -DOPENSSL_USE_NODELETE -DL_ENDIAN -DOPENSSL_PIC -DOPENSSL_CPUID_OBJ -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DKECCAK1600_ASM -DRC4_ASM -DMD5_ASM -DAESNI_ASM -DVPAES_ASM -DGHASH_ASM -DECP_NISTZ256_ASM -DX25519_ASM -DPOLY1305_ASM -DOPENSSLDIR="\"/musl/ssl\"" -DENGINESDIR="\"/musl/lib/engines-1.1\"" -DNDEBUG -c -o apps/app_rand.o apps/app_rand.c
musl-gcc -fPIE -pie -I. -Iinclude -fPIC -pthread -m64 -Wall -O3 -DOPENSSL_USE_NODELETE -DL_ENDIAN -DOPENSSL_PIC -DOPENSSL_CPUID_OBJ -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DKECCAK1600_ASM -DRC4_ASM -DMD5_ASM -DAESNI_ASM -DVPAES_ASM -DGHASH_ASM -DECP_NISTZ256_ASM -DX25519_ASM -DPOLY1305_ASM -DOPENSSLDIR="\"/musl/ssl\"" -DENGINESDIR="\"/musl/lib/engines-1.1\"" -DNDEBUG -c -o apps/apps.o apps/apps.c
musl-gcc -fPIE -pie -I. -Iinclude -fPIC -pthread -m64 -Wall -O3 -DOPENSSL_USE_NODELETE -DL_ENDIAN -DOPENSSL_PIC -DOPENSSL_CPUID_OBJ -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DKECCAK1600_ASM -DRC4_ASM -DMD5_ASM -DAESNI_ASM -DVPAES_ASM -DGHASH_ASM -DECP_NISTZ256_ASM -DX25519_ASM -DPOLY1305_ASM -DOPENSSLDIR="\"/musl/ssl\"" -DENGINESDIR="\"/musl/lib/engines-1.1\"" -DNDEBUG -c -o apps/bf_prefix.o apps/bf_prefix.c
/bin/sh: 1: musl-gcc: not found
make[1]: *** [Makefile:671: apps/app_rand.o] Error 127
make[1]: *** Waiting for unfinished jobs....
/bin/sh: 1: musl-gcc: not found
make[1]: *** [Makefile:673: apps/apps.o] Error 127
/bin/sh: 1: musl-gcc: not found
make[1]: *** [Makefile:675: apps/bf_prefix.o] Error 127
make[1]: Leaving directory '/musl/openssl-1.1.1w'
make: *** [Makefile:172: all] Error 2
unable to get local issuer certificate
如果使用了reqwest(http库),当交叉编译完成后,在一个很精简的debian docker容器中运行时,在请求接口时可能会有如下报错
1
2
3
thread 'main' panicked at src/service/xxx.rs:18:16:
called `Result::unwrap()` on an `Err` value: reqwest::Error { kind: Request, url: Url { scheme: "https", cannot_be_a_base: false, username: "", password: None, host: Some(Domain("xxx.com")), port: None, path: "/xxx/xxx", query: Some("xxx=xxx&xxx=xxx"), fragment: None }, source: hyper::Error(Connect, Ssl(Error { code: ErrorCode(1), cause: Some(Ssl(ErrorStack([Error { code: 337047686, library: "SSL routines", function: "tls_process_server_certificate", reason: "certificate verify failed", file: "ssl/statem/statem_clnt.c", line: 1921 }]))) }, X509VerifyResult { code: 20, error: "unable to get local issuer certificate" })) }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
how to fix?
1
apt-get install ca-certificates
参考
How to build openssl-sys crate for musl in Rust Why rust is failing to build command for openssl-sys v0.9.60 even after local installation? Ubuntu 18: failed to run custom build command for openssl-sys v0.9.39