Featured image of post Rust 交叉编译 macOS 为 Linux 和 Windows

Rust 交叉编译 macOS 为 Linux 和 Windows

Rust 支持交叉编译,可以 macOS 平台编译出 Linux 或者 Windows 可运行的程序,或者在 Linux 平台编译 macOS 或者 Windows 可运行的程序。

这篇文章主要讲解 Mac 平台编译为其他平台的二进制程序。

想要实现跨平台编译并且可运行的程序,那么我们就需要静态链接,这样生成程序才不会因为动态链接库的原因运行失败。

在默认情况下,Rust 静态连接所有 Rust 代码。如果程序中使用了标准库,Rust 会连接到系统的 libc 实现。

环境

  • macOS:
    • OS:macOS 12.3.1 21E258 x86_64
    • rustc:rustc 1.60.0 (7737e0b5c 2022-04-04)
    • rustup:rustup 1.24.3 (ce5817a94 2021-05-31)
  • Linux:
    • OS:EndeavourOS Linux x86_64
    • kernel:5.17.1-arch1-1
    • rustc:rustc 1.60.0 (7737e0b5c 2022-04-04)
    • rustup:rustup 1.24.3 (ce5817a94 2021-05-31)

首先需要安装 Rust,这个这里就不要说了。

示例准备

使用 Cargo 新建二进制项目:

1
cargo new --bin hello

文件 main.rs

1
2
3
fn main() {
  println!("Hello World!\n");
}

macOS 编译为 Linux 和 Windows 可用二进制程序

编译为 Linux 平台

要实现 Linux 平台可以运行的程序,那么需要使用 musl 来替代 glibcmusl 实现了 Linux libc

musl 在 macOS 上使用 musl-cross,musl-cross 是用来专门编译到 Linux 的工具链,下面进行安装:

1
brew install FiloSottile/musl-cross/musl-cross

还需要创建 musl-gcc

1
ln -s /usr/local/bin/x86_64-linux-musl-gcc /usr/local/bin/musl-gcc

添加对应的 Target,只需要执行一次就可以了:

1
rustup target add x86_64-unknown-linux-musl

修改配置文件 ~/.cargo/config (如果没有可以新建),添加如下内容:

1
2
[target.x86_64-unknown-linux-musl]
linker = "x86_64-linux-musl-gcc"

也可在项目根目录下创建 .cargo/config 文件,只对当前项目生效

编译:

1
2
# 使用
cargo build --release --target x86_64-unknown-linux-musl

结果:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
$ tree -L 2 target/x86_64-unknown-linux-musl
target/x86_64-unknown-linux-musl
├── CACHEDIR.TAG
└── debug
    ├── build
    ├── deps
    ├── examples
    ├── hello
    ├── hello.d
    └── incremental

5 directories, 3 files
$ file target/x86_64-unknown-linux-musl/debug/hello
target/x86_64-unknown-linux-musl/debug/hello: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), static-pie linked, with debug_info, not stripped

编译为 Windows 平台

mingw-w64 是用来编译到 Windows 的工具链,使用如下命令进行安装:

1
brew install mingw-w64

接下来添加 mingw-64 对应的 Target,只需要执行一次就可以了:

1
$ rustup target add x86_64-pc-windows-gnu

修改配置文件 ~/.cargo/config (如果没有可以新建),设置 Linker,添加如下内容:

1
2
3
[target.x86_64-pc-windows-gnu]
linker = "x86_64-w64-mingw32-gcc"
ar = "x86_64-w64-mingw32-gcc-ar"

编译:

1
2
# 使用
$ cargo build --release --target x86_64-unknown-linux-musl

结果:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
$ tree -L 2 target/x86_64-pc-windows-gnu
target/x86_64-pc-windows-gnu
├── CACHEDIR.TAG
└── debug
    ├── build
    ├── deps
    ├── examples
    ├── hello.d
    ├── hello.exe
    └── incremental

5 directories, 3 files
$ file target/x86_64-pc-windows-gnu/debug/hello.exe
target/x86_64-pc-windows-gnu/debug/hello.exe: PE32+ executable (console) x86-64, for MS Windows

在 Linux 编译为 macOS 和 Windows

编译为 macOS 平台

在 Linux 编译 macOS 平台使用 osxcrossosxcross 可以在 Linux/FreeBSD/OpenBSD 以及 Android (Termux) 交叉编译 macOS 平台的工具。

我看了下 osxcross 编译为 macOS 平台真的还是挺麻烦的,我决定不编译为 macOS 版本,何必为难自己呢,何况自己有 Mac 电脑呢 😂。

编译为 Windows 平台

mingw-w64 是用来编译到 Windows 的工具链,Arch 对应的包为 mingw-w64-gcc,接下来进行安装:

1
sudo pacman -S mingw-w64-gcc

接下来就容易了,和 “macOS 编译为 Linux 和 Windows” 一样了,就是添加 Target,修改配置文件,然后编译就可以了。

FAQ

x86_64-unknown-freebsd target may not be installed

自己在 Mac 平台的时候,把上述所有的操作都做了,但是还是包如下错误:

1
2
3
4
5
6
error[E0463]: can't find crate for `std`
  |
  = note: the `x86_64-unknown-freebsd` target may not be installed
  = help: consider downloading the target with `rustup target add x86_64-unknown-freebsd`

error: requires `sized` lang_item

那么怎么解决的呢,我发现自己之前使用 Homebrew 安装过 rust,而且还使用官方命令 curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh 再次进行安装,导致 rust 工具链对不上,只需要做如下操作就可以了:

  1. 先完全卸载
1
2
$ brew uninstall rust
$ rustup self uninstall
  1. 重新安装:
1
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

error:linking with cc failed:exit status:1

配置 ~/.cargo/config 或者在项目内 .cargo/config 文件就可以解决这个问题。

总结

介绍了在 macOS 编译为 Linux/Windows 以及 Linux 平台编译为 macOS/Windows,其实就两个三个步骤:

  1. 添加相应的 Target
  2. 安装对应的 Linker
  3. 修改配置文件

从 macOS 编译其他的平台,其实是比较容易的,从其他平台编译为 macOS 平台却不那么简单,最终自己放弃了。

Reference


comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计