3-1. no_std

ベアメタルを想定したRustプログラムには、#![no_std]アトリビュートが必須です。この#![no_std]アトリビュートを指定すると、stdクレートではなく、coreクレートをリンクします。

stdクレートは、Rustの標準ライブラリです。例えば、皆さんが次のようなRustプログラムを書いた場合、stdクレートが使われています。

fn main() {
    let vector = vec!(1, 2, 3);
    println!("vector contains {:?}", vector);
}

上記プログラムの1行目に、#![no_std]を追加した後、ボタンをクリックしてプログラムを実行してみて下さい。次のようなコンパイルエラーが発生したはずです。

error: cannot find macro `println!` in this scope
 --> src/main.rs:5:5
  |
5 |     println!("vector contains {:?}", vector);
  |     ^^^^^^^

error: cannot find macro `vec!` in this scope
 --> src/main.rs:4:18
  |
4 |     let vector = vec!(1, 2, 3);
  |                  ^^^

error: `#[panic_handler]` function required, but not found

error: language item required, but not found: `eh_personality`

println!は、標準出力にフォーマットされた文字列を表示するマクロです。ベアメタル環境では、標準出力なるものは存在しません (OSが提供するものだからです) 。そのため、標準出力を利用するprintln!マクロも利用できません。

RustのVecは、ヒープにメモリ領域を確保します。ベアメタル環境では、ヒープメモリの確保 / 解放の機能が提供されていません。そのため、Vecのオブジェクトを作成するvec!マクロも、stdクレートをリンクするアプリケーションと同じようには、使えません。少し手を加えれば、ベアメタル環境でもVecのようなコレクションを使うことが可能です。これは、メモリアロケータで解説します。

さらに、言語仕様上、パニック発生時の動作を定義する必要があります。panicの主な処理はstdクレートで定義されています。詳しくは、panicで説明します。

coreクレートは、stdクレートのサブセットで、環境 (アーキテクチャ、OS) に依存せず使えるコードが含まれています。coreクレートは、文字列やスライスのような言語プリミティブと、アトミック操作のようなプロセッサ機能を利用するためのAPIを提供しています。

先程コンパイルエラーになったことからわかるように、coreクレートを使ったベアメタルプログラミングは、stdを利用したプログラミングとは一味違ったものになります。

出典

  • Embedonomicon: [最小限の#![no_std]プログラム]

[最小限の#![no_std]プログラム]: https://tomoyuki-nakabayashi.github.io/embedonomicon/smallest-no-std.html