RustをmacOS上でLinuxのバイナリにクロスコンパイルする

この記事ではmacOS上でRustをLinuxのバイナリにクロスコンパイルする方法を説明します。

まずx86_64-unknown-linux-gnuパッケージをbrewでインストールします。

```sh
brew install SergioBenitez/osxct/x86_64-unknown-linux-gnu
```

aarch64の場合はこっち

```sh
brew tap messense/macos-cross-toolchains
brew install aarch64-unknown-linux-gnu
```

つぎにrustにtargetを追加します。

```sh
rustup target add x86_64-unknown-linux-gnu

# aarch64
rustup target add aarch64-unknown-linux-gnu
```

そして ~/.cargo/config.toml`にlinkerの設定を追加します。

```toml:~/.cargo/config.toml
[target.x86_64-unknown-linux-gnu]
linker = "x86_64-unknown-linux-gnu-gcc"

# aarch64
# [target.aarch64-unknown-linux-gnu]
# linker = "aarch64-unknown-linux-gnu-gcc"
```

## OpenSSLライブラリの設定

適当なディレクトリを作ります。

```
mkdir ~/rust/lib && cd ~/rust/lib
```

OpenSSLライブラリを取得して展開します。

```sh
curl -O https://debian.sipwise.com/debian-security/pool/main/o/openssl/libssl-dev_1.1.1d-0+deb10u6_amd64.deb
ar p libssl-dev_1.1.1d-0+deb10u6_amd64.deb data.tar.xz | tar xvf -
rm -rf libssl-dev_1.1.1d-0+deb10u6_amd64.deb
```

Aarch64の場合はこっち

```sh
curl -O https://debian.ignum.cz/debian-security/pool/main/o/openssl/libssl-dev_1.1.1d-0+deb10u6_arm64.deb
ar p libssl-dev_1.1.1d-0+deb10u6_arm64.deb data.tar.xz | tar xvf -
rm -rf libssl-dev_1.1.1d-0+deb10u6_arm64.deb
```

## ビルド用環境変数の設定

```sh
export LIB_OPENSSL_DIR=~/rust/lib

# Linker for the target platform
# (cc can also be updated using .cargo/config)
export TARGET_CC="x86_64-unknown-linux-gnu-gcc"

# Library headers to link against
export TARGET_CFLAGS="-I ${LIB_OPENSSL_DIR}/usr/include/x86_64-linux-gnu -isystem ${LIB_OPENSSL_DIR}/usr/include"
# Libraries (shared objects) to link against
export LD_LIBRARY_PATH="${LIB_OPENSSL_DIR}/usr/lib/x86_64-linux-gnu;${LIB_OPENSSL_DIR}/lib/x86_64-linux-gnu"

# openssl-sys specific build flags
export OPENSSL_DIR="${LIB_OPENSSL_DIR}/usr/"
export OPENSSL_LIB_DIR="${LIB_OPENSSL_DIR}/usr/lib/x86_64-linux-gnu/"
```

```sh
# Aarch64
#!/bin/sh

export LIB_OPENSSL_DIR=$(pwd)/build

# Linker for the target platform
# (cc can also be updated using .cargo/config)
export TARGET_CC="aarch64-unknown-linux-gnu-gcc"

# Library headers to link against
export TARGET_CFLAGS="-I ${LIB_OPENSSL_DIR}/usr/include/aarch64-linux-gnu -isystem ${LIB_OPENSSL_DIR}/usr/include"
# Libraries (shared objects) to link against
export LD_LIBRARY_PATH="${LIB_OPENSSL_DIR}/usr/lib/aarch64-linux-gnu;${LIB_OPENSSL_DIR}/lib/aarch64-linux-gnu"

# openssl-sys specific build flags
export OPENSSL_DIR="${LIB_OPENSSL_DIR}/usr/"
export OPENSSL_LIB_DIR="${LIB_OPENSSL_DIR}/usr/lib/aarch64-linux-gnu/"

export CC_Aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnu-gcc
export CXX_Aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnu-g++
export AR_Aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnu-ar
export CARGO_TARGET_Aarch64_UNKNOWN_LINUX_GNU_LINKER=aarch64-unknown-linux-gnu-gcc
```

## ビルド

最後にビルドを実行します。

```sh
cargo build --target=x86_64-unknown-linux-gnu

# aarch64
cargo build --target=aarch64-unknown-linux-gnu
```

## コンパイル結果

下記ディレクトリにバイナリが出力されています。

```
target/x86_64-unknown-linux-gnu/debug/hoge

# aarch64
target/aarch64-unknown-linux-gnu/debug/hoge
```

fileコマンドでちゃんとELFになっているか確認してみます。

```
file target/x86_64-unknown-linux-gnu/debug/hoge

# aarch64
file target/aarch64-unknown-linux-gnu/debug/hoge
```

> target/x86_64-unknown-linux-gnu/debug/h: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, with debug_info, not stripped

なってますね!!😄

## 参考

- [Index of /debian-security/pool/main/o/openssl](https://debian.sipwise.com/debian-security/pool/main/o/openssl/?C=M;O=A)
- https://debian.ignum.cz/debian-security/pool/main/o/openssl/
- [chinedufn/cross-compile-rust-from-mac-to-linux: An example of how to cross compile Rust from \`macOS\` to Linux \`x86\_64-unknown-linux-gnu\`](https://github.com/chinedufn/cross-compile-rust-from-mac-to-linux)
- [A “rustup target” Example: Using a Mac to cross-compile Linux binaries | Non-Recurring Engineering](https://timryan.org/2018/07/27/cross-compiling-linux-binaries-from-macos.html)
- [Cross-compiling Rust From Mac to Linux | by Merlin Fuchs | Better Programming](https://betterprogramming.pub/cross-compiling-rust-from-mac-to-linux-7fad5a454ab1)