このセクションでは、コンパイルできる最小限の#![no_std]
プログラムを書きます。
#![no_std]
は、クレートレベルのアトリビュートです。これは、このクレートにstd
クレートではなくcore
クレートをリンクすることを示します。
しかし、アプリケーションにとって、これは何を意味するのでしょうか?
std
クレートはRustの標準ライブラリです。
標準ライブラリは、プログラムがベアメタルではなく、オペレーティングシステム上で動作することを仮定した機能を、含んでいます。
std
は、オペレーティングシステムが、サーバやデスクトップで使うような汎用オペレーティングシステムであることも仮定します。
この理由から、std
は、スレッド、ファイル、ソケット、ファイルシステム、プロセス、など汎用オペレーティングシステムにある機能に対して標準APIを提供します。
その一方、core
クレートは、std
クレートのサブセットで、プログラムが動作するシステムについて、一切の仮定を置きません。
そのため、core
クレートは、浮動小数点や文字列、スライスのような言語のプリミティブと、
アトミック操作やSIMD命令のようなプロセッサ機能を利用するためのAPIを提供します。
しかし、core
クレートは、ヒープメモリアロケーションやI/Oといったものに対するAPIがありません。
アプリケーションに対しては、std
は単に抽象化されたOS機能へのアクセス方法を提供するだけに留まりません。
std
は、とりわけ、スタックオーバーフロープロテクションの設定、コマンドライン引数の処理、
プログラムのmain
関数が呼び出される前のメインスレッド生成、の面倒をみます。
#![no_std]
アプリケーションは、これらの標準的なランタイムを持ちません。そのため、必要に応じて、自身のランタイムを初期化しなければなりません。
これらの性質から、#![no_std]
アプリケーションは、システム上で動作する最初の / 唯一のコードになれます。
標準のRustアプリケーションでは決して作ることができない、次のようなプログラムを書くことができます。
- OSのカーネル
- ファームウェア
- ブートローダ
この普通でない方法で、コンパイル可能な最小限の#![no_std]
プログラムに取り掛かることができます。
$ cargo new --edition 2018 --bin app
$ cd app
$ # main.rsを下記の内容に修正して下さい
$ cat src/main.rs
{{#include ../ci/smallest-no-std/src/main.rs}}
このプログラムは、標準的なRustプログラムでは目にすることがない内容を含んでいます。
#![no_std]
アトリビュートについては、既に十分に説明しました。
#![no_main]
アトリビュートは、エントリポイントとして標準のmain
関数を使わないプログラムであることを意味します。
本書を書いている時点では、Rustのmain
インタフェースは、プログラムを実行する環境について、いくつかの仮定を置いています。
例えば、コマンドライン引数が存在していることですが、これは一般的に#![no_std]
プログラムにはふさわしくありません。
#[panic_handler]
アトリビュートでマーキングされた関数は、パニック発生時の動作を定義します。
ライブラリレベルのパニック(core::panic!
)と言語レベルのパニック(範囲外のインデックスアクセス)両方が対象です。
このプログラムは、役に立つものではありません。実際、空のバイナリを生成します。
$ $ `size target/thumbv7m-none-eabi/debug/app`と同じです
$ cargo size --target thumbv7m-none-eabi --bin app
{{#include ../ci/smallest-no-std/app.size}}
リンク前、このクレートはパニックのシンボルを含んでいます。
$ cargo rustc --target thumbv7m-none-eabi -- --emit=obj
$ cargo nm -- target/thumbv7m-none-eabi/debug/deps/app-*.o | grep '[0-9]* [^n] '
{{#include ../ci/smallest-no-std/app.o.nm}}
しかしながら、これがスタート地点です。次のセクションでは、役に立つものをビルドします。
しかしその前に、Cargo呼び出しごとに--target
フラグを付けなくて良いように、デフォルトビルドターゲットを設定しましょう。
$ mkdir .cargo
$ # .cargo/configが下記内容になるように修正します
$ cat .cargo/config
{{#include ../ci/smallest-no-std/.cargo/config}}