Rust ha un attributo speciale, #[cfg]
, che permette di compilare del codice
a seconda di un'opzione passata al compilatore. Ha due forme:
#[cfg(foo)] #[cfg(bar = "baz")]
Ci sono anche alcune funzioni d'aiuto:
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))]
Tali funzioni possono annidarsi arbitrariamente:
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")))]
Per abilitare o disabilitare questi interruttori, se si usa Cargo,
li si imposta nella sezione [features]
del file Cargo.toml
:
[features]
# Di default, nessuna feature
default = []
# Qui si aggiunge la feature "foo", per poterla usare dopo.
# La nostra feature "foo" non dipende da nient'altro.
foo = []
Quando lo si fa, Cargo passa un'opzione a rustc
:
--cfg feature="${feature_name}"
La somma di queste opzioni cfg
determinerà quali vengono attivate, e quindi,
quale codice viene compilato. Prendiamo questo codice:
#[cfg(feature = "foo")] mod foo { }
Se lo compiliamo con cargo build --features "foo"
, Cargo manderà l'opzione
--cfg feature="foo"
a rustc
, e l'output conterrà il modulo foo
.
Se lo compiliamo con un normale cargo build
, nessun'altra opzione verrà
passata, e quindi, il modulo foo
non esisterà.
Se può anche impostare un altro attributo basato su una variabile cfg
usando cfg_attr
:
#[cfg_attr(a, b)]
Sarò lo stesso di #[b]
se a
è impostato dall'attributo cfg
, e niente
altrimenti.
L'estensione sintattica cfg!
permette di usare
questo genere di opzioni anche altrove nel codice:
if cfg!(target_os = "macos") || cfg!(target_os = "ios") { println!("Think Different!"); }
Questi saranno sostituiti da un true
o false
in fase di compilazione,
a seconda delle impostazioni di configurazione.