Rust: Xargoとarm-binutils無しでCortex-Mターゲットのファームウェアをビルドする
2018年4月、Rustでの組み込みプログラミング環境に2つの大きなニュースが舞い込んできた。
Xargo と arm-none-eabi-lld 無しでCortex-M向けのビルドが可能に
PSA: You no longer need Xargo to do ARM Cortex-M development#rustlanghttps://t.co/C6VhbyM0tW
— $ cargo uninstall xargo (@japaricious) April 8, 2018
1つ目は、rustupのターゲットに thumbv*m-none-eabi*
(Cortex-MのTarget Triple)が追加されたというニュース。
今まではrustupでは、thumbv*m-none-eabi*
ターゲットがサポートされておらず、Xargo というツールを使ってlibcoreを thumbv*m-none-eabi*
用にビルドしなくてはならなかった。
しかし、nightly (nightly-2018-04-08) 以降のRustでは thumbv*m-none-eabi*
が追加されたため、Xargoを使って自前でlibcoreをビルドする必要はなくなる。
nightly 2018-04-09で確認したところ、確かにターゲットリストに thumbv*m-none-eabi*
が追加されていた。
$ rustup show Default host: x86_64-unknown-linux-gnu ... active toolchain ---------------- nightly-x86_64-unknown-linux-gnu (default) rustc 1.27.0-nightly (4b9b70c39 2018-04-09) $ rustup target list | pr -w 90 --columns=2 aarch64-apple-ios mips64el-unknown-linux-gnuabi64 aarch64-linux-android mipsel-unknown-linux-gnu aarch64-unknown-fuchsia mipsel-unknown-linux-musl aarch64-unknown-linux-gnu powerpc-unknown-linux-gnu aarch64-unknown-linux-musl powerpc64-unknown-linux-gnu arm-linux-androideabi powerpc64le-unknown-linux-gnu arm-unknown-linux-gnueabi s390x-unknown-linux-gnu arm-unknown-linux-gnueabihf sparc64-unknown-linux-gnu arm-unknown-linux-musleabi sparcv9-sun-solaris arm-unknown-linux-musleabihf thumbv6m-none-eabi armv5te-unknown-linux-gnueabi thumbv7em-none-eabi armv7-apple-ios thumbv7em-none-eabihf armv7-linux-androideabi thumbv7m-none-eabi armv7-unknown-linux-gnueabihf wasm32-unknown-emscripten armv7-unknown-linux-musleabihf wasm32-unknown-unknown armv7s-apple-ios x86_64-apple-darwin asmjs-unknown-emscripten x86_64-apple-ios i386-apple-ios x86_64-linux-android i586-pc-windows-msvc x86_64-pc-windows-gnu i586-unknown-linux-gnu x86_64-pc-windows-msvc i586-unknown-linux-musl x86_64-rumprun-netbsd i686-apple-darwin x86_64-sun-solaris i686-linux-android x86_64-unknown-cloudabi i686-pc-windows-gnu x86_64-unknown-freebsd i686-pc-windows-msvc x86_64-unknown-fuchsia i686-unknown-freebsd x86_64-unknown-linux-gnu (default) i686-unknown-linux-gnu x86_64-unknown-linux-gnux32 i686-unknown-linux-musl x86_64-unknown-linux-musl mips-unknown-linux-gnu x86_64-unknown-netbsd mips-unknown-linux-musl x86_64-unknown-redox mips64-unknown-linux-gnuabi64
cortex-m-rt v0.4.0 has been released! 🎉
— $ cargo uninstall xargo (@japaricious) April 9, 2018
With it you can link ARM Cortex-M programs using LLD.
And since the #rustlang toolchain includes LLD you no longer need to install arm-none-eabi-ld to link your #embedded programshttps://t.co/VgRVh1VEFE
2つ目は、Cortex-Mバイナリ用のリンクにlldを使えるようになったというニュース。
今までは最後のリンクにはarm-binutilsのarm-none-eabi-ldを使ってリンクを行なっていたが、それをlldに置き換えられるようになった。 これはcoretex-m-rtクレートに含まれているリンカスクリプトの記述をlldに対応させたことで可能になったようだ。
この2つの変更によって、RustでのCortex-Mターゲット向けの開発のために必要なツールが減り、開発環境構築のハードルが大きく下がった印象だ。 (あとはgdbをlldbに置き換えることができれば、arm-binutilsは一切不要になる)
このニュースを報告しているJaparicさんはXargoの作者でもあり、Rustでの組み込み開発環境をずっとリードし続けている。 この方がいなかったら、今のRustはここまで組み込み分野を視野に入れたものになっていただろうか…。
nightly-2018-04-08 以降でのCortex-Mターゲットのファームウェアビルド方法
Xargo無し、arm-binutils無しでのビルド手順についてメモしておく。
動作確認には、STM32F401 Nucleo-64ボード(Cortex-M4F)を使用する。
大まかな手順は次のとおり。
- rustupを最新にする
- rustupから対象となるarm MCUの
thumbv*m-none-eabi*
ターゲットを追加する - Rustプロジェクトを作成する。
.cargo/config
にリンカの設定を記述する- 必要なクレートを
Cargo.toml
に追記する - コードを書いてビルドする
rustupを最新にする
$ rustup update
また、ビルドにはnightlyが要求されるので、デフォルトをnightlyに変更しておく。
$ rustup default nightly
thumbv*m-none-eabi*
をターゲットに追加する
今回動作確認を行うMCUはCortex-M4Fなので、rustupから thumbv7em-none-eabihf
をターゲットとして追加する。
$ rustup target add thumbv7em-none-eabihf info: downloading component 'rust-std' for 'thumbv7em-none-eabihf' info: installing component 'rust-std' for 'thumbv7em-none-eabihf'
自分が使うCortex-M MCUがどのTarget Tripleを選べばよいかについては次のとおり。
Target Triple | Target MCUs |
---|---|
thumbv6m-none-eabi |
Targets the Cortex-M0, Cortex-M0+ and Cortex-M1 processors (ARMv6-M architecture) |
thumbv7em-none-eabi |
Targets the Cortex-M4 and Cortex-M7 processors (ARMv7E-M) |
thumbv7em-none-eabihf |
Targets the Cortex-M4F and Cortex-M7F processors (ARMv7E-M) |
thumbv7m-none-eabi |
Targets the Cortex-M3 processor (ARMv7-M) |
Rustプロジェクトを作成する
LEDを点滅させる簡易プログラムのリポジトリを作成したため、この手順ではこちらを使う。
ryochack/Rust_NUCLEO-F401RE_Led_Blink
$ git clone https://github.com/ryochack/Rust_NUCLEO-F401RE_Led_Blink.git
一から作る場合には、 cargo new
でプロジェクトを作成する。
.cargo/config
にリンカの設定を記述する
.cargo/config
にターゲット毎にリンカの設定を記述する。
ここではリンカにlldを指定している。
.cargo/config
[target.thumbv7em-none-eabihf] runner = 'arm-none-eabi-gdb' rustflags = [ "-C", "link-arg=-Tlink.x", "-C", "linker=lld", "-Z", "linker-flavor=ld.lld", "-Z", "thinlto=no", ]
必要なクレートを Cargo.toml
に追記する
thumbv*m-none-eabi*
のビルドに必要なクレートを Cargo.toml
にそれぞれ追加する。
Cargo.toml
[package] name = "nucleo-f401re_led_blink" authors = ["ryochack"] version = "0.1.0" [dependencies] cortex-m = "0.4.0" cortex-m-rt = "0.4.0" panic-abort = "0.1.1" volatile-register = "0.2.0"
コードを書いてビルドする
コードが書けたら(ここではRust_NUCLEO-F401RE_Led_Blinkリポジトリのコードを使う想定)、次のコマンドでターゲットを指定してビルドする。
$ cargo build --target thumbv7em-none-eabihf
これでSTM32F401用のELFファイルが target/thumbv7em-none-eabihf/debug/nucleo-f401re_led_blink
として出力される。
$ file nucleo-f401re_led_blink nucleo-f401re_led_blink: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, with debug_info, not stripped
このELFファイルを次の記事の内容に従ってSTM32F401 Nucleo-64ボードに書き込むことで動作が確認できる。
OpenOCD + ST-LinkでFirmware書き込み - ryochack.blog