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