% デバッグ
rustc は、マクロをデバッグするためのツールを数多く提供しています。最も便利なものの 1 つが trace_macros! です。これは、展開前のすべてのマクロ呼び出しをダンプするようコンパイラに指示するディレクティブです。たとえば、次のようなコードがあるとします。
// 注: nightly チャネルのコンパイラを使用してください。 #![feature(trace_macros)] macro_rules! each_tt { () => {}; ($_tt:tt $($rest:tt)*) => {each_tt!($($rest)*);}; } each_tt!(foo bar baz quux); trace_macros!(true); each_tt!(spim wak plee whum); trace_macros!(false); each_tt!(trom qlip winp xod); fn main() {}
出力は次のようになります。
each_tt! { spim wak plee whum }
each_tt! { wak plee whum }
each_tt! { plee whum }
each_tt! { whum }
each_tt! { }
これは、深く再帰するマクロをデバッグする際に特に非常に有用です。コンパイラのコマンドラインに -Z trace-macros を追加することで、コマンドラインからこれを有効にすることもできます。
次に、log_syntax! があります。これは、渡されたすべてのトークンをコンパイラに出力させます。たとえば、これはコンパイラに歌を歌わせます。
// 注: nightly チャネルのコンパイラを使用してください。 #![feature(log_syntax)] macro_rules! sing { () => {}; ($tt:tt $($rest:tt)*) => {log_syntax!($tt); sing!($($rest)*);}; } sing! { ^ < @ < . @ * '\x08' '{' '"' _ # ' ' - @ '$' && / _ % ! ( '\t' @ | = > ; '\x08' '\'' + '$' ? '\x7f' , # '"' ~ | ) '\x07' } fn main() {}
これは、trace_macros! よりもやや対象を絞ったデバッグを行うために使用できます。
時には、問題があることが判明するのは、マクロが展開された結果です。このためには、コンパイラの --pretty 引数を使用できます。次のコードがあるとします。
// `String` を初期化するための省略表記。
macro_rules! S {
($e:expr) => {String::from($e)};
}
fn main() {
let world = S!("World");
println!("Hello, {}!", world);
}
次のコマンドでコンパイルすると、
rustc -Z unstable-options --pretty expanded hello.rs
次の出力が生成されます(整形のために変更されています)。
#![feature(no_std, prelude_import)]
#![no_std]
#[prelude_import]
use std::prelude::v1::*;
#[macro_use]
extern crate std as std;
// `String` を初期化するための省略表記。
fn main() {
let world = String::from("World");
::std::io::_print(::std::fmt::Arguments::new_v1(
{
static __STATIC_FMTSTR: &'static [&'static str]
= &["Hello, ", "!\n"];
__STATIC_FMTSTR
},
&match (&world,) {
(__arg0,) => [
::std::fmt::ArgumentV1::new(__arg0, ::std::fmt::Display::fmt)
],
}
));
}
--pretty のその他のオプションは、rustc -Z unstable-options --help -v を使用して一覧表示できます。名前が示すとおり、そのような一覧はいつでも変更される可能性があるため、完全な一覧は提供していません。