Feature Flagを使用してコンパイルする機能を切り替える
概要
ライブラリクレートを作成する際に利用者が必要な機能だけをコンパイルしたり、コンパイルされる機能を切り替えたりすることができると便利です。これを実現するために、RustではFeature Flagという機能が用意されています。
何が便利なの?
実用例としては画像処理ライブラリを作成した時に、JPEGを処理する機能とPNGを処理する機能を切り替えることができるようにするといったことが挙げられます。また、実装によっては関数の内部処理すらも切り替えることができる為ユーザーニーズに合わせた最適なライブラリを提供することができます。
設定方法
以下2点を設定することでFeature Flagを利用することができます。
-
Cargo.toml
でFeature Flagを定義する -
#[cfg(feature = "feature_name")]
でFeature Flagの対象を指定する
Cargo.toml
[package]
name = "mylib"
version = "0.1.0"
edition = "2021"
[features]
default = ['basic']
basic = []
extra = []
この場合、extra
とbasic
というFeature Flagが定義されます。default
は特別なFeature Flagで、cargo build
などのコマンドを実行した際にデフォルトで有効になるFeature Flagを指定します。上記の例ではbasic
がデフォルトで有効になります。
#[cfg(feature = "feature_name")]
#[cfg(feature = "basic")]
pub fn basic() {
println!("basic");
}
#[cfg(feature = "extra")]
pub fn extra() {
println!("extra");
}
#[cfg(not(feature = "extra"))]
pub fn not_extra() {
println!("not extra");
}
#[cfg(not(any(feature = "basic", feature = "extra")))]
pub fn very_basic() {
println!("very basic");
}
解説
上記の例では4つの関数がFeature Flagによってコンパイルされるかどうかが切り替わります。
-
basic
関数はbasic
が有効な場合のみコンパイルされます、今回はbasic
がデフォルトで有効なので未指定でもコンパイルされます。 -
extra
関数はextra
が有効な場合のみコンパイルされます。未指定ではコンパイルされません。 -
not_extra
関数はextra
が無効な場合のみコンパイルされます。未指定=extra
が無効なのでコンパイルされます。 -
very_basic
関数はbasic
とextra
が無効な場合のみコンパイルされます。未指定=basic
が有効なのでコンパイルされず、basic
を明示的に無効にするとコンパイルされます。
利用方法
実装したライブラリを使用する場合は、呼び出し側のCargo.toml
に以下のように記述します。
[dependencies]
mylib = { version = "0.1.0", features = ["extra"] }
この場合、デフォルトとextra
が有効になります。
デフォルトを無効にする場合は以下のように記述します。
[dependencies]
mylib = { version = "0.1.0", default-features = false, features = ["extra"] }
この場合デフォルトに含まれる全てのFeature Flagが無効になります(今回はbasic
)。
ちなみに現時点ではデフォルトの一部のみを無効化することはできないようです。
https://github.com/rust-lang/cargo/issues/3126
おまけ
難しい話ですが、あるFeatureが外部クレートのFeatureに依存している場合、外部クレートのFeatureが有効になっていないとコンパイルエラーになります。なので、Feature Flagを利用する際は依存関係を記述することでコンパイル時に自動設定してくれます。
[features]
default = ['basic']
basic = []
extra = ['rand/serde-1']
[dependencies]
rand = { version = "0.8"}
// rand = { version = "0.8", features = ["serde-1"]} extra時はこれと等しくなる
Discussion