注意: 最新版のドキュメントをご覧ください。この第1版ドキュメントは古くなっており、最新情報が反映されていません。リンク先のドキュメントが現在の Rust の最新のドキュメントです。
Rustの標準ライブラリはたくさんの有用な機能を提供していますが、スレッド、ネットワーク、ヒープ割り当てなど、さまざまな機能についてホストシステムのサポートがあることを前提としています。しかし、それらの機能を持たないシステムは存在しますし、Rustはそういったシステム上でも動作します。そのためには、 #![no_std]
アトリビュートを使って標準ライブラリを使用しないことを示します。
注記: このフィーチャは技術的には安定していますが、いくつかの注意点があります。例えば、
#![no_std]
を含んだ ライブラリ は安定版でビルドできますが、 バイナリ はそうではありません。標準ライブラリを使用しないライブラリについての詳細は#![no_std]
についてのドキュメント を参照してください。
当然のことですが、ライブラリだけが全てではなく、実行可能形式においても #[no_std]
は使用できます。このときエントリポイントを指定する方法には2種類あり、1つは #[start]
アトリビュート、もう1つはCの main
関数の上書きです。
#[start]
のついた関数へはCと同じフォーマットでコマンドライン引数が渡されます。
#![feature(lang_items)] #![feature(start)] #![no_std] // crt0.oが必要としていると思われるもののためにシステムのlibcライブラリを参照します。 extern crate libc; // このプログラムのエントリポイントです #[start] fn start(_argc: isize, _argv: *const *const u8) -> isize { 0 } // これらの関数とトレイトは必要最小限のhello worldのようなプログラムが // 使うのではなく、コンパイラが使います。通常これらはlibstdにより提供されます。 #[lang = "eh_personality"] extern fn eh_personality() {} #[lang = "panic_fmt"] extern fn panic_fmt() -> ! { loop {} }
コンパイラによって挿入される main
を上書きするには、まず #![no_main]
によってコンパイラによる挿入を無効にします。その上で、正しいABIと正しい名前を備えたシンボルを作成します。これにはコンパイラの名前マングリングを上書きする必要もあります。
#![feature(lang_items)] #![feature(start)] #![no_std] #![no_main] extern crate libc; #[no_mangle] // 出力結果においてこのシンボル名が `main` になることを保証します。 pub extern fn main(argc: i32, argv: *const *const u8) -> i32 { 0 } #[lang = "eh_personality"] extern fn eh_personality() {} #[lang = "panic_fmt"] extern fn panic_fmt() -> ! { loop {} }
今のところ、コンパイラは実行可能形式においていくつかのシンボルが呼び出し可能であるという前提を置いています。通常、これらの関数は標準ライブラリが提供しますが、それを使わない場合自分で定義しなければなりません。
2つある関数のうち1つ目は eh_personality
で、コンパイラの失敗メカニズムに使われます。これはしばしばGCCのpersonality関数に割り当てられますが(詳細はlibstd実装を参照してください)、パニックを発生させないクレートではこの関数は呼ばれないことが保証されています。2つ目の関数は panic_fmt
で、こちらもコンパイラの失敗メカニズムのために使われます。