Rust 交叉编译指南
Rust 支持跨平台编译,允许在一个平台上编译生成另一个平台的可执行文件。以下是实现交叉编译的详细步骤,最后提供了一个自动编译批处理脚本,通过脚本命令可直接编译目标文件,缺少环境可以自动安装
1.基本概念
交叉编译指在一种计算机平台上生成另一种平台可执行代码的过程。开发主机(Host)与目标机(Target)的处理器架构或操作系统不同,需通过特定工具链实现跨平台编译。
2.运行机制
交叉编译器在执行时会做两件核心工作:
-
生成目标平台的机器码
-
编译器后端负责把中间代码翻译成目标平台的 CPU 指令(如 ARM、MIPS、RISC-V)。
-
与宿主平台(Host)的 CPU 指令不同。
-
-
** 链接目标平台的系统库 **
-
交叉编译工具链包含针对目标平台的 libc / libstdc++ / 动态库、编译器、链接器等工具,而不是宿主机的库。
-
通常通过 --sysroot 或 -I、-L 指定目标库和头文件路径,确保链接正确的库版本。
-
3.交叉编译器
交叉编译器其实是一套专门的 工具链(Toolchain),它包含:
| 组件 | 作用 |
|---|---|
| g*** / g++(交叉编译器) | 把源码编译成目标平台的机器码 |
| as(汇编器) | 把汇编代码转为目标平台机器码 |
| ld(链接器) | 把多个目标文件链接成可执行程序 |
| ar / ranlib(静态库工具) | 打包或索引库文件 |
| strip / objdump / nm | 查看或精简目标二进制文件 |
| sysroot(目标系统库和头文件) | 提供编译时的依赖环境(如 libc、头文件等) |
这些工具被称为一整套交叉编译工具链,通常以目标平台命名:
- aarch64-apple-darwin
- x86_64-apple-darwin
- x86_64-unknown-linux-gnu
- x86_64-pc-windows-gnu
- arm-linux-gnueabihf-g***
- aarch64-linux-gnu-g***
4.典型的安装工作流程
1).安装目标平台的工具链
查看所有支持的目标平台:
rustup target list
使用 rustup target add 命令安装目标平台的工具链。例如,编译到 x86_64-unknown-linux-gnu:
rustup target add x86_64-unknown-linux-gnu
2).配置链接器
某些目标平台需要额外的链接器配置。在 ~/.cargo/config 中添加目标平台的链接器路径。例如,为 x86_64-unknown-linux-gnu 配置:
[target.x86_64-unknown-linux-gnu]
linker = "x86_64-unknown-linux-gnu-g***"
ar = "x86_64-unknown-linux-gnu-g***-ar"
ar = archiver,是一个用来把多个目标文件 (.o) 打包成一个静态库 (.a) 的工具。
Rust 编译时,如果你的依赖包含 静态库,或者用 build.rs 生成 .a 文件,就会调用 ar。因为你正在交叉编译到 x86_64-unknown-linux-gnu,如果你不指定,Rust 可能会用系统默认的 ar(Mac 的 ar),结果生成的 .a 库是 macOS 格式,链接 Linux 可执行文件时就报错。
3).验证目标链接器
❯ x86_64-linux-gnu-g*** --version
x86_64-linux-gnu-g*** (G***) 13.3.0
Copyright (C) 2023 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
❯ x86_64-linux-gnu-g***-ar --version
GNU ar (GNU Binutils) 2.40
Copyright (C) 2023 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or (at your option) any later version.
This program has absolutely no warranty.
4).编译代码
使用 --target 参数指定目标平台:
cargo build --target x86_64-linux-gnu-g***
5).验证输出文件
编译完后,用 file 命令检查生成的二进制是否正确:
file target/x86_64-unknown-linux-gnu/debug/your_binary
你应该看到
ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=e64cf75762a2b16f7775a7f30985bf4699eca987, for GNU/Linux 2.6.16, not stripped
通过以上步骤,可以实现 Rust 项目的交叉编译。
5.自动脚本
这里准备了一个自动脚本,可以自动检测要编译的目标平台,如果工具没有安装会自动安装
1).先配置config.toml
# ~/.cargo/config.toml
# 统一配置不同平台的 linker 和 ar
# ======================
# macOS (Apple Silicon)
# ======================
[target.aarch64-apple-darwin]
linker = "clang"
ar = "llvm-ar"
# ======================
# macOS (Intel Mac)
# ======================
[target.x86_64-apple-darwin]
linker = "clang"
ar = "llvm-ar"
# ======================
# Linux (x86_64)
# 安装:
# brew tap messense/macos-cross-toolchains
# brew install x86_64-unknown-linux-gnu
[target.x86_64-unknown-linux-gnu]
linker = "x86_64-unknown-linux-gnu-g***"
ar = "x86_64-unknown-linux-gnu-g***-ar"
# ======================
# Windows (x86_64, GNU toolchain)
# 安装:
# brew install mingw-w64
[target.x86_64-pc-windows-gnu]
linker = "x86_64-w64-mingw32-g***"
ar = "x86_64-w64-mingw32-g***-ar"
# ======================
# 通用构建优化
# ======================
[build]
# 默认开启并行编译(也可以手动用 -j 覆盖)
# jobs = 0
# 可选:默认用 release 构建
# default-run = "release"
2).自动编译脚本build.sh
#!/usr/bin/env bash
set -e
set -u
TARGET=""
MODE="debug"
PROJECT_DIR="."
detect_default_target() {
if [[ "$(uname)" == "Darwin" ]]; then
ARCH=$(uname -m)
if [[ "$ARCH" == "arm64" ]]; then
echo "aarch64-apple-darwin"
else
echo "x86_64-apple-darwin"
fi
else
echo ""
fi
}
show_usage() {
echo "用法: $0 [mac-arm|mac-x86|linux-x86|win-x86] [release] [--project /path/to/project]"
echo "不传目标会自动检测 macOS 架构。"
exit 1
}
# 解析参数
while [[ $# -gt 0 ]]; do
case "$1" in
mac-arm|mac-x86|linux-x86|win-x86)
TARGET="$1"
shift
;;
release)
MODE="release"
shift
;;
--project)
PROJECT_DIR="$2"
shift 2
;;
*)
echo "未知参数: $1"
show_usage
;;
esac
done
# 如果没指定 TARGET,自动检测
if [[ -z "$TARGET" ]]; then
TARGET=$(detect_default_target)
if [[ -z "$TARGET" ]]; then
echo "无法自动检测目标,请手动指定。"
show_usage
fi
fi
# 映射 TARGET 到 Rust triple
case "$TARGET" in
mac-arm) TARGET_TRIPLE="aarch64-apple-darwin" ;;
mac-x86) TARGET_TRIPLE="x86_64-apple-darwin" ;;
linux-x86) TARGET_TRIPLE="x86_64-unknown-linux-gnu" ;;
win-x86) TARGET_TRIPLE="x86_64-pc-windows-gnu" ;;
esac
# 安装目标
if ! rustup target list | grep -q "${TARGET_TRIPLE} (installed)"; then
echo "目标 ${TARGET_TRIPLE} 未安装,正在安装..."
rustup target add $TARGET_TRIPLE
fi
# Windows 特殊配置
if [ "$TARGET_TRIPLE" = "x86_64-pc-windows-gnu" ]; then
if ! ***mand -v x86_64-w64-mingw32-g*** &>/dev/null; then
echo "⚠️ Windows 交叉编译需要 MinGW-w64 工具链,正在安装..."
brew install mingw-w64
fi
export RUSTFLAGS=""
fi
# 开始编译
echo "🚀 编译项目: $PROJECT_DIR"
echo "目标: $TARGET_TRIPLE [$MODE]"
if [ "$MODE" = "release" ]; then
cargo build --manifest-path "$PROJECT_DIR/Cargo.toml" --target $TARGET_TRIPLE --release -j $(sysctl -n hw.logicalcpu)
else
cargo build --manifest-path "$PROJECT_DIR/Cargo.toml" --target $TARGET_TRIPLE -j $(sysctl -n hw.logicalcpu)
fi
echo "✅ 编译完成: $PROJECT_DIR/target/$TARGET_TRIPLE/$MODE/"
3).使用build.sh编译项目
将build.sh放在项目或工作空间的根目录下
- 编译当前目录项目
# 不指定参数,则根据默认参数detect_default_target中的设置进行编译
./build.sh
./build.sh mac-arm
./build.sh mac-arm release
- 编译指定项目
./build.sh mac-arm release --project /path/to/project