手元の良いマシンでRustのコンパイルして,それをRaspberry Pi3へ持っていって実行したい...
だけど,手元のマシンは x86_64 で,Raspberry Pi3は aarch64(ARM) だから持っていくだけでは実行できない...
ということで,Rustでクロスコンパイルをしてx86_64上でaarch64向けのバイナリを作りましょう!
環境
- ビルド環境
- Ubuntu 16.04.2 LTS 64bit
x86_64
- Raspberry Pi3
- ArchLinux ARM
aarch64
前提
Rust周りの開発環境は整っていることとします.(cargo buildで自分のアーキテクチャ向けのコンパイルは出来る.)
サマリ
別のアーキテクチャ向けにコンパイルできればよいので,cargo build --target <another architecture>ができるのがゴール.
RaspberryPi3はaarch64だったので,aarch64-unknown-linux-gnuに向けてコンパイル出来るようにする.
-
rustupでaarch64向けのtoolchainをインストールrustup install nightly-aarch64-unknown-linux-gnu- ここでは
nightlyを使ってますが,お好みに合わせてどうぞ
-
aarch64向けのリンカが必要なので,aarch64向けのgccをインストールsudo apt install gcc-aarch64-linux-gnu
-
デフォルトで
aarch64向けにビルドするようにプロジェクト配下の.cargo/configに次のものを追加.cargo/config[build] target="aarch64-unknown-linux-gnu" [target.aarch64-unknown-linux-gnu] linker = "aarch64-linux-gnu-gcc" -
cargo buildすると,aarch64向けのバイナリが生成されます
Raspberry Pi3に持っていって実行しましょう!!!
説明
rustupでaarch64向けのtoolchainをインストール
通常だと,以下のようにその環境向け(例えばx86_64)のtoolchainしかインストールされていません.
$ rustup toolchain list
stable-x86_64-unknown-linux-gnu
nightly-x86_64-unknown-linux-gnu (default)
がしかし,RaspberryPi3上でuname -mを叩くとaarch64と表示されるので,aarch64向けのtoolchainが必要そうです.
これを探すために$rustup target list | grep aarch64と叩くと以下のようになります.
$ rustup target list | grep aarch64
aarch64-apple-ios
aarch64-linux-android
aarch64-unknown-linux-gnu
linux向けのaarch64-unknown-linux-gnuが見つかりました!これを使うこととしますのでインストールします.
$ rustup install stable-aarch64-unknown-linux-gnu
$ rustup install nightly-aarch64-unknown-linux-gnu
これで一旦整ったと思い,おもむろに
$ cargo build --target=aarch64-unknown-linux-gnu
と叩くと,ld周りでエラーが出て,リンカがおかしいみたいだということがわかります.
aarch64向けのリンカが必要なので,aarch64向けのgccをインストール
ここ(https://github.com/japaric/ruststrap/blob/master/1-how-to-cross-compile.md) を見ていると,どうやら rustc がリンクを行うときにシステムのアーキテクチャのリンカをデフォルトで使ってしまうようで,指定してあげなければならないとのこと.
そこでまず,aarch64向けのリンカをインストールするためにgccごと入れちゃいます
$ sudo apt install gcc-aarch64-linux-gnu
デフォルトで aarch64 向けにビルドするようにプロジェクト配下の .cargo/config に次のものを追加
先の作業でリンカが手に入ったのでcargoに使うリンカを教えてあげましょう.
そのためにプロジェクト配下の.cargo/configを以下のように書き換えます.
[build]
target="aarch64-unknown-linux-gnu"
[target.aarch64-unknown-linux-gnu]
linker = "aarch64-linux-gnu-gcc"
このようにすることで,cargo buildの際のデフォルトtargetがaarch64-unknown-linux-gnuになり一々指定しなくて良くなります.
また,targetがaarch64-unknown-linux-gnuの時のlinkerを指定してあげることでaarch64向けのビルドの際にはaarch64向けのリンカを使ってくれる様になります.
結論
Write once in Rust, run anywhere!
(極めて言い過ぎ