2 分で読了 #rust #cargo-and-build
このページの目次

条件付きコンパイルと cfg

#[cfg(target_os = "linux")] により、コードをコンパイル時にプラットフォーム/アーキテクチャ/feature ごとに選択的に存在させたり削除したりできる——実行時の if ではなく、条件付きコンパイルのこと。feature flags と cfg を組み合わせることで、1つの crate がオプショナルなモジュールや依存関係を提供でき、cfg_attr はマルチプラットフォームでの重複する注釈を減らす。

cfg: コンパイル時の条件

#[cfg(target_os = "linux")]
fn platform_specific() { /* Linux impl */ }

#[cfg(not(target_os = "linux"))]
fn platform_specific() { /* fallback impl */ }

cfg は実行時のチェックではない——cfg にマッチしないコードはコンパイルされない⁠。cfg ブロック内では、そのプラットフォームでのみ利用可能な型や関数を使用できる。

一般的な cfg 述語

target_os:        "linux", "macos", "windows", "android", "freebsd"
target_arch:      "x86_64", "aarch64", "riscv64", "wasm32"
target_env:       "gnu", "musl", "msvc"
target_feature:   "avx2", "sse2", "neon"
target_pointer_width: "64", "32"
target_vendor:    "apple", "pc", "unknown"
debug_assertions: true (dev), false (release)
test:             true (cargo test 実行時)
feature:          カスタム feature flag (Cargo.toml から)

cfg_attr: 条件付き属性

#[cfg_attr(debug_assertions, derive(Debug))]    // dev ビルド時のみ Debug を実装
struct InternalState { ... }

#[cfg_attr(target_arch = "x86_64", repr(align(64)))]  // x86 上で 64 バイト境界にアライン
struct CacheLine { ... }

Feature Flags

# Cargo.toml
[features]
json = ["serde", "serde_json"]
#[cfg(feature = "json")]
mod json_support { ... }

#[cfg(not(feature = "json"))]
mod json_support { ... }             // json feature がない場合のスタブ

cfg! マクロ: コンパイル時定数

if cfg!(target_os = "linux") {       // コンパイル時に評価 → 未到達コードは最適化で除去
    linux_path()
} else {
    generic_path()
}

コンパイラは cfg! に対して定数畳み込みを行う——false ブランチは release ビルドでは通常除去される(デッドコードの除去)。同じ関数内でプラットフォーム固有の分岐を行いたい場合に適している。

参考

  • Cargo Book: Conditional Compilation
  • Rust Reference: cfg, cfg_attr

Keywords: cfg, cfg_attr, target_os, feature flag, conditional compilation, dead code elimination