% Условная компиляция
В Rust есть специальный атрибут, #[cfg]
, который позволяет компилировать код в
зависимости от флагов, переданных компилятору. Он имеет две формы:
#[cfg(foo)]
# fn foo() {}
#[cfg(bar = "baz")]
# fn bar() {}
Над атрибутами конфигурации определены логические операции:
#[cfg(any(unix, windows))]
# fn foo() {}
#[cfg(all(unix, target_pointer_width = "32"))]
# fn bar() {}
#[cfg(not(foo))]
# fn not_foo() {}
Они могут быть как угодно вложены:
#[cfg(any(not(unix), all(target_os="macos", target_arch = "powerpc")))]
# fn foo() {}
Что же касается того, как включить или отключить эти флаги: если вы используете
Cargo, то они устанавливаются в разделе [features]
вашего
Cargo.toml
:
[features]
# по умолчанию, никаких дополнительных возможностей
default = []
# возможность «secure-password» зависит от пакета bcrypt
secure-password = ["bcrypt"]
Если вы определите такие возможности, Cargo передаст флаг в rustc
:
--cfg feature="${feature_name}"
Совокупность этих флагов конфигурации (cfg
) будет определять, какие из них
будут активны, и, следовательно, какой код будет скомпилирован. Давайте
рассмотрим такой код:
#[cfg(feature = "foo")]
mod foo {
}
Если скомпилировать его с помощью cargo build --features "foo"
, то в rustc
будет передан флаг --cfg feature="foo"
, и результат будет содержать
модуль mod foo
. Если скомпилировать его с помощью обычной команды cargo build
, то никаких дополнительных флагов передано не будет, и поэтому, модуль
mod foo
будет отсутствовать.
Вы также можете установить другой атрибут в зависимости от переменной cfg
с
помощью атрибута cfg_attr
:
#[cfg_attr(a, b)]
# fn foo() {}
Этот код будет равносилен атрибуту #[b]
, если в атрибуте cfg
установлен флаг
a
, или «без атрибута» в противном случае.
Расширение синтаксиса cfg!
позволяет использовать данные
виды флагов и в другом месте в коде:
if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
println!("Think Different!");
}
Значение флага будет заменено на true
или false
во время компиляции, в
зависимости от настройки конфигурации.