条件付きコンパイル

Rustには #[cfg] という特別なアトリビュートがあり、 コンパイラに渡されたフラグに合わせてコードをコンパイルすることを可能にします。 #[cfg] アトリビュートは以下の2つの形式で利用することができます:

fn main() { #[cfg(foo)] fn foo() {} #[cfg(bar = "baz")] fn bar() {} }
#[cfg(foo)]

#[cfg(bar = "baz")]

また、以下の様なヘルパーが存在します:

fn main() { #[cfg(any(unix, windows))] fn foo() {} #[cfg(all(unix, target_pointer_width = "32"))] fn bar() {} #[cfg(not(foo))] fn not_foo() {} }
#[cfg(any(unix, windows))]

#[cfg(all(unix, target_pointer_width = "32"))]

#[cfg(not(foo))]

ヘルパーは以下のように自由にネストすることが可能です:

fn main() { #[cfg(any(not(unix), all(target_os="macos", target_arch = "powerpc")))] fn foo() {} }
#[cfg(any(not(unix), all(target_os="macos", target_arch = "powerpc")))]

このようなスイッチの有効・無効の切り替えはCargoを利用している場合 Cargo.toml 中の [features] セクション で設定できます。

[features]
# no features by default
default = []

# フィーチャ「secure-password」は bcrypt パッケージに依存しています
secure-password = ["bcrypt"]

もしこのように設定した場合、Cargoは rustc に以下のようにフラグを渡します:

--cfg feature="${feature_name}"

渡されたすべての cfg フラグによってどのフラグが有効に成るか決定され、 それによってどのコードがコンパイルされるかも決定されます。以下のコードを見てみましょう:

fn main() { #[cfg(feature = "foo")] mod foo { } }
#[cfg(feature = "foo")]
mod foo {
}

もしこのコードを cargo build --features "foo" としてコンパイルを行うと、 --cfg features="foo"rustc に渡され、出力には mod foo が含まれます。 もし標準的な cargo build でコンパイルを行った場合、rustc に追加のフラグは渡されず foo モジュールは存在しない事になります。

cfg_attr

また、cfg_attr を用いることで、cfg に設定された値によってアトリビュートを有効にすることができます:

fn main() { #[cfg_attr(a, b)] fn foo() {} }
#[cfg_attr(a, b)]

このようにすると、cfg アトリビュートによって a が有効になっている場合に限り #[b] と設定されている 場合と同じ効果が得られます。

cfg!

cfg! 拡張構文 は以下のようにコード中でフラグを利用することを可能にします:

fn main() { if cfg!(target_os = "macos") || cfg!(target_os = "ios") { println!("Think Different!"); } }
if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
    println!("Think Different!");
}

このようなコードは設定に応じてコンパイル時に true または false に置き換えられます。