手元の良いマシンで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!
(極めて言い過ぎ