Linux
rust
ARM

rustをインストールしてhello world をARM用にクロスコンパイルするまでの手順

最近話題のrustを自分でも勉強しようと思って。

rustのインストール

このページに書いてあることをなぞる。

https://rust-lang-ja.github.io/the-rust-programming-language-ja/1.6/book/getting-started.html

curl https://sh.rustup.rs -sSf | sh

一度ログアウトして再度ログイン。

$ rustc --version
rustc 1.25.0 (84203cac6 2018-03-25)
mkdir hello_world
cd hello_world

hello_world.rs を作成。

hello_world.rs
fn main() {
    println!("Hello, world!");
}

コンパイルして実行。

$ rustc hello_world.rs
$ ./hello_world 
Hello, world!
$ file ./hello_world
./hello_world: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=9671f9cd6d9b1bb7b84022bde4d26af80fe992f4, not stripped
$ ls -lh ./hello_world
-rwxrwxr-x 1 koba koba 4.5M Apr 30 07:41 ./hello_world

ダイナミックリンクなのに、かなりサイズが大きいな。

クロスコンパイルの準備

rustのコンパイラはLLVMベースで構成されていて、いろいろなターゲットを切り換えることができます。追加可能なターゲットの一覧は以下の通り。

$ rustup target list
aarch64-apple-ios
aarch64-linux-android
aarch64-unknown-cloudabi
aarch64-unknown-fuchsia
aarch64-unknown-linux-gnu
aarch64-unknown-linux-musl
arm-linux-androideabi
arm-unknown-linux-gnueabi
arm-unknown-linux-gnueabihf
arm-unknown-linux-musleabi
arm-unknown-linux-musleabihf
armv5te-unknown-linux-gnueabi
armv7-apple-ios
armv7-linux-androideabi
armv7-unknown-cloudabi-eabihf
armv7-unknown-linux-gnueabihf
armv7-unknown-linux-musleabihf
armv7s-apple-ios
asmjs-unknown-emscripten
i386-apple-ios
i586-pc-windows-msvc
i586-unknown-linux-gnu
i586-unknown-linux-musl
i686-apple-darwin
i686-linux-android
i686-pc-windows-gnu
i686-pc-windows-msvc
i686-unknown-cloudabi
i686-unknown-freebsd
i686-unknown-linux-gnu
i686-unknown-linux-musl
mips-unknown-linux-gnu
mips-unknown-linux-musl
mips64-unknown-linux-gnuabi64
mips64el-unknown-linux-gnuabi64
mipsel-unknown-linux-gnu
mipsel-unknown-linux-musl
powerpc-unknown-linux-gnu
powerpc64-unknown-linux-gnu
powerpc64le-unknown-linux-gnu
s390x-unknown-linux-gnu
sparc64-unknown-linux-gnu
sparcv9-sun-solaris
wasm32-unknown-emscripten
wasm32-unknown-unknown
x86_64-apple-darwin
x86_64-apple-ios
x86_64-linux-android
x86_64-pc-windows-gnu
x86_64-pc-windows-msvc
x86_64-rumprun-netbsd
x86_64-sun-solaris
x86_64-unknown-cloudabi
x86_64-unknown-freebsd
x86_64-unknown-fuchsia
x86_64-unknown-linux-gnu (default)
x86_64-unknown-linux-gnux32
x86_64-unknown-linux-musl
x86_64-unknown-netbsd
x86_64-unknown-redox

armv7-unknown-linux-gnueabihf に必要なものを追加でインストール。

$ rustup target add armv7-unknown-linux-gnueabihf
info: downloading component 'rust-std' for 'armv7-unknown-linux-gnueabihf'
 39.6 MiB /  39.6 MiB (100 %)   8.3 MiB/s ETA:   0 s                
info: installing component 'rust-std' for 'armv7-unknown-linux-gnueabihf'

リンカーとしてクロスのgccを使用するので、以下の記事に従ってインストール。
x86_64のUbuntuでC/C++のソースコードをARM/ARM64用にクロスコンパイルしてQEMUで実行する方法のまとめ

クロスコンパイルと実行

以下のようにオプションを指定するとarm用にクロスコンパイルできます。

$ rustc -C linker=arm-linux-gnueabihf-gcc --target=armv7-unknown-linux-gnueabihf hello_world.rs 
$ file ./hello_world
./hello_world: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, BuildID[sha1]=359e7216dc873f9b567c030dde53f825ee07c290, not stripped
$ ls -lh ./hello_world
-rwxrwxr-x 1 koba koba 4.0M Apr 30 07:50 ./hello_world

QEMUをセットアップしてあるので、この実行ファイルはそのまま実行可能です。

$ ./hello_world 
Hello, world!

追記:stripしてみた

実行ファイルのサイズがとても大きいことが気になったのですが、コメントで教えてもらったことを参考に、stripコマンドでシンボル情報を除去してみました。

$ file ./hello_world
./hello_world: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, BuildID[sha1]=359e7216dc873f9b567c030dde53f825ee07c290, not stripped
$ cp ./hello_world hello_world_g
$ arm-linux-gnueabihf-strip ./hello_world
$ ls -lh hello_world*
-rwxrwxr-x 1 koba koba 330K Apr 30 11:09 hello_world
-rwxrwxr-x 1 koba koba 4.0M Apr 30 11:09 hello_world_g
-rw-rw-r-- 1 koba koba   46 Apr 30 07:40 hello_world.rs

1/10以下に小さくなりました。実機にはstrip済みの実行ファイルをインストールします。