このセクションでは、コンパイルできる最小限の#![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}}