M1 Mac上のRustでクロスコンパイルする
作成日:
最近RustでCGIを書くなんてことをしていたのですが、諸事情でサーバー側にRustのコンパイラを入れられず、別のマシンでビルドしたバイナリをコピーして動かしました。その時はLinuxの別マシンでビルドしたのですが、開発機であるM1 Macでビルドできた方が楽なので、その方法を調べました。
クロスコンパイラをインストールする
まずは別のCPUを対象としてコンパイルするためのコンパイラ(クロスコンパイラ)をインストールする必要があります。今回は messense/homebrew-macos-cross-toolchains を使わせてもらいます。Homebrewでもインストールできるようですが、Release にあるビルド済みバイナリを用いるとお手軽です1。
Releaseのページにはたくさんのtar.gzが並んでいるので、目的にあったバイナリをダウンロードします。私の場合は「M1 Mac (aarch64-darwin)上で」「x86_64のLinuxで動く、CライブラリとしてMUSLを使ったバイナリ(x86_64-unknown-linux-musl)を作る」ため、x86_64-unknown-linux-musl-aarch64-darwin.tar.gz
をダウンロードしました2。
そして、これを解凍し、中のbin
ディレクトリにパスを通します。
現時点(2021/05/16)での最新版(v10.3.0)を使う場合、以上のことをするコマンドは次の通りです。
$ mkdir -p $HOME/tools && cd $HOME/tools # 適当なディレクトリ
$ wget https://github.com/messense/homebrew-macos-cross-toolchains/releases/download/v10.3.0/x86_64-unknown-linux-musl-aarch64-darwin.tar.gz
$ tar xf x86_64-unknown-linux-musl-aarch64-darwin.tar.gz # 解凍
$ export PATH="$HOME/tools/x86_64-unknown-linux-musl/bin:$PATH" # パスを通す
$ x86_64-unknown-linux-musl-gcc # パスが通っているか確かめる
x86_64-unknown-linux-musl-gcc: fatal error: no input files
compilation terminated.
なお、永続的に設定したい場合はexport
は.zshrc
なりのシェル設定ファイルに書いて下さい(以下同じ)。
Rustでクロスコンパイルできるようにする
まず、Rust側でターゲットを追加します。
$ rustup target add x86_64-unknown-linux-musl
これだけではRustがクロスコンパイラを見つけてくれないため、messense/homebrew-macos-cross-toolchainsのREADMEに従って次のように環境変数を設定します。
$ export CC_x86_64_unknown_linux_musl=x86_64-unknown-linux-musl-gcc
$ export CXX_x86_64_unknown_linux_musl=x86_64-unknown-linux-musl-g++
$ export AR_x86_64_unknown_linux_musl=x86_64-unknown-linux-musl-ar
$ export CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_LINKER=x86_64-unknown-linux-musl-gcc
クロスコンパイルしてみる
以上で設定ができたはずなので、Hello worldプロジェクトで確かめてみます。
$ cargo new etude-cross
$ cd etude-cross
$ cargo build --target x86_64-unknown-linux-musl --release # クロスコンパイル
$ file target/x86_64-unknown-linux-musl/release/etude-cross # ファイル形式を確かめる
target/x86_64-unknown-linux-musl/release/etude-cross: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, with debug_info, not stripped
確かにELF 64-bitのバイナリができあがりました。
参考文献
- Cross-Compiling Rust from macOS To Linux
- この記事では FiloSottile/homebrew-musl-cross を使っていますが、これはM1 Macでは動かなかったので(Apple silicon support? · Issue #23)、代わりに messense/homebrew-macos-cross-toolchains を使いました。
- Cross-compilation - The rustup book