3-1. Cargo

Rustでの開発にCargoは欠かせません。Cargoは、Rustのパッケージマネージャですが、それ以上のことができます。3rd party製のサブコマンド拡張をインストールすることで、Cargoの機能を拡張できます。ここでは、組込み / ベアメタルでのRust開発をより便利にするCargoに機能やサブコマンド拡張について紹介します。

設定ファイル

まず、欠かせないのが、設定ファイルです。どのような設定項目が書けるか、はCargo: 3.3 Configurationに掲載されています。

Cargo設定ファイルはTOML形式で記述し、プロジェクトの.cargo/configに作成することが多いです。実際は、階層的な作りになっています。どのような階層構造になっているか、はCargo: 3.3 Configuration 階層構造を参照して下さい。

組込み / ベアメタルでよく使う設定項目は、targetbuildです。

target.$triple

target.$tripleはターゲットトリプルごとに、カスタムする内容を設定します。$tripleの部分に、有効なターゲットトリプルを指定します。カスタムランナーの設定やコンパイルオプションの指定などに使います。例えば、Cortex-M3ターゲットの時はqemu-system-armで、RISC-Vターゲットの時はqmue-system-riscv32を、それぞれカスタムランナーにしたい場合、次のように設定ファイルを記述します。

[target.thumbv7m-none-eabi]
runner = "qemu-system-arm -machine lm3s6965evb -nographic -kernel"

[target.riscv32imac-unknown-none-elf]
runner = "qemu-system-riscv32 -nographic -machine sifive_u -kernel"

これで、cargo run --target thumbv7m-none-eabicargo run --target riscv32imac-unknown-none-elfというコマンドを実行すると、QEMUでビルドしたバイナリを実行します。

次の4項目が設定できます。

  • linker = ".."
  • ar = ".."
  • runner = ".."
  • rustflags = ["..", ".."]

target.'cfg

target.$tripleは、ターゲットトリプルを完全に指定する方法です。一方、target.'cfgは、条件を複数指定して、カスタマイズできます。

下記の例は、ターゲットアーキテクチャが32bitのARMで、OSなしのターゲットトリプル全てに適用されます。

[target.'cfg(all(target_arch = "arm", target_os = "none"))']
rustflags = [
  "-C", "link-arg=-Tlink.x",
]

build

デフォルトのターゲットシステムが固定の場合、cargo run --target thumbv7m-none-eabiという長いコマンドを毎回入力するのは面倒です。そこで、build設定でデフォルトターゲットシステムを指定できます。

[build]
target = "thumbv7m-none-eabi"

cargo runで、cargo run --target thumbv7m-none-eabiと等価になります。

binutils

組込み / ベアメタルの開発において、バイナリを調査することは、息をするより自然なことです。バイナリの調査を行う際、objdumpsizereadelfnmなどのツールを利用します。GNUのbinutilsを使用しても良いのですが、LLVMのものを利用すると、rustcがサポートするターゲットアーキテクチャ全てに対応しており、便利です。

Cargoのサブコマンドであるcargo binutilsが提供されており、Cargoからobjdumpsizeコマンドを利用できます。

インストールも非常に簡単です。

$ cargo install cargo-binutils
$ rustup component add llvm-tools-preview

プロジェクトバイナリ名がappの場合、次のように使用します。

$ cargo size --target thumbv7m-none-eabi --bin app

Cargo設定ファイルで、buildターゲットを指定している場合、次のコマンドで同じことができます。

$ cargo size --bin app

リリースビルドしたバイナリを調査する場合、--releaseを追加します。

$ cargo size --bin app --release

LLVMツール自体のオプションを使用する場合、空の--を入力した後にLLVMのオプションを指定します。

$ cargo objdump --bin app -- -d -no-show-raw-insn
#                         ^^^^^^^^^^^^^^^^^^^^^^^