Rustプログラミングにおけるデバッグ入門
これはRust Language Advent Calendar 2014の第1日目となります。
尚、本情報はRust 0.13.0-nightly@fac5a0767
時点の情報を基にしております。
現実においてプログラムを書くにあたりデバッグを行わないということはありません。ですので、通常、我々はデバッグ技法というものを習得しなければなりません。
デバッガ
RustではDWARF形式のデバッグシンボルを出力できるため
- gdb
- lldb
といったツールの使用が可能です。WinおよびLinuxではgdbを使えばいいでしょう。OSXでは、個人的にはlldbを使えばいいと思います(尚、gdb向けの拡張スクリプトもrustリポジトリの中には存在しています)
また、DWARF形式のシンボルを用いた各種ツールチェインも使用が可能となっていますが、各種バグには注意を配る必要があるかもしれません。
log
crate
デバッガを用いずとも、変数の内容などをダンプするデバッグというのも非常に有用あるのは皆さんご存知のことと思います。殊、Rustのように平行・並列実行を指向したコードを記述する場合、デバッガでアタッチしたりrrのようなツールチェインを使わずとも済ませたい・もしくは前述のツールチェインを使いことが困難なこともあると思うので、この手法にはお世話にならざるを得ません。
そこで使うのがこの log
crateです。
詳細な使い方はリンク先を参照していただくとして(安定度もexperimentalですしそちらの方が確実でしょう)、概要を説明しますと、
- log
- debug
- info
- warn
- error
のレベルに分けてログを出力することができます。
出力にあたっては、実行時にRUST_LOG=path::to::module=log_level
と環境変数を設定することで、「ログのレベル」と「ログを出力する対象であるモジュール」の指定が可能です。
この指定は、正規表現および用いた複雑な表現が可能であり、/
の後にwarn/bar*foo
のように続けることで「ログレベルwarn以上で、正規表現bar*foo
にマッチするメッセージを含むログを出力する」などのような指定を環境変数経由で実行時に指定することが可能です。
また、原則としてmacroで実装されているので、現在の実装では、debug!
に関しては--cfg ndebug
をコンパイルオプションとしてrustc
に指定した場合に、自動で無効化されます.
アサーション
Rustには実行時アサーションが複数デフォルトで存在しています.
debug_assert
系では、--cfg ndebug
をrustc
に対して渡すことにより、これらのアサーションを無効にしたコードの生成が行われます。
ユニットテスト、ベンチマーク
Rustではコード中に#[test]
または#[bench]
といった指定を行ってコードを記述することで、コンパイルオプションによりユニットテストまたはマイクロベンチマーク用のバイナリを簡単に生成することが可能です。
詳しくはThe Rust Testing Guideを参照するのが良いでしょう。
バックトレース
実行時に環境変数としてRUST_BACKTRACE=1
を設定することで、クラッシュ時の詳細なバックトレースを得ることができます。
cargo build
でrustc —cfg ndebug
相当のことをする
cargoの設定のprofileで明示的に指定を行えば、対応するビルドプロファイルに反映されます。
デフォルトでは--release
をつけた場合にrustc —cfg ndebug
相当となります
- https://github.com/rust-lang/cargo/blob/641c5c2c1fcf98e38490c7b45ff81ce652f6658b/src/cargo/core/manifest.rs#L150
- https://github.com/rust-lang/cargo/blob/641c5c2c1fcf98e38490c7b45ff81ce652f6658b/src/cargo/core/manifest.rs#L150
まとめ
よいRustプログラミングをお楽しみください. 明日の担当予定は@omasanoriさんです。