- Table of contents
- Attributes
- Built-in attributes
- Conditional compilation
- Key-value options
- The
cfg!
macro
Declaration of any item in a Rust can be decorated (annotated) with one or more attribute.
Each attribute contains instructions for compiler.
In Rust items are
- Functions
- Types (structs, enums, unions, type aliases)
- Traits
- Impl blocks
- Macros
- Constants and statics
- Extern blocks
- Extern crates
- Imports
- Modules
There are 2 types of attributes:
- inner attributes;
- outer attributes.
To attach attribute to whole crate include inner atribute to the root module: main.rs
or lib.rs
.
Inner attributes apply to all items within the scope where attribute is declared.
mod Bar {
#![bar]
}
Here, the #![bar]
attribute applies to all items inside module Bar
.
Outer attributes apply only to 1 item following the attribute.
#[foo]
struct Foo;
Here, the #[foo]
attribute applies only to the next item Foo
.
Some attributes require arguments, some attributes can be used without arguments.
// A unit test
#[test]
fn check() {
assert_eq!(2, 1 + 1);
}
// A conditional compilation
#[cfg(target_os = "linux")]
mod bar {
/* ... */
}
// A lint attribute
#[allow(non_camel_case_types)]
type int8_t = i8;
- built-in attributes;
- tool attributes;
- macro attributes;
- derive macro helper attributes.
Built-in attributes per categories:
- Conditional compilation
cfg
cfg_attr
- Testing
test
- Derive
derive
- Macros
proc_macro
- Lint
allow
warn
deny
forbid
deprecated
must_use
- Code generation
inline
- Documentation
doc
- Preludes
no_std
- Modules
path
- Limits
recursion_limit
type_length_limit
- Runtime
panic_handler
global_allocator
- ABI, linking, symbols, and FFI
The derive
attribute allows certain traits to be automatically implemented for data structures.
#[derive(PartialEq, Clone)]
struct Foo<T> {
a: i32,
b: T,
}
The path
attribute specifies the filename for a module.
#[path = "foo.rs"]
mod c;
It means file foo.rs
will be included into module tree as c
module.
Configuration options are either names or key-value pairs, and are either set or unset.
target_abi
target_arch
set once with the target’s CPU architecture, it is similar to the first element of the target triple, but not identical;- example values:
"x86"
"x86_64"
"mips"
"powerpc"
"powerpc64"
"arm"
"aarch64"
- example values:
target_endian
set once with either a value of"little"
or"big"
depending on the endianness of the target’s CPU;target_env
target_family
defines the family of the operating systems or architectures, any number of target_family key-value pairs can be set;- example values:
"unix"
;"windows"
;"wasm"
;- Both
"unix"
and"wasm"
;
- example values:
target_feature
set feature available for the current target triple;- each target triple has a set of features that may be enabled;
- example values:
"avx"
"avx2"
"crt-static"
"rdrand"
"sse"
"sse2"
"sse4.1"
target_os
set once with the target’s operating system;target_vendor
panic
set once with the panic strategy;- example values:
"abort"
"unwind"
- example values:
Example:
#[cfg(target_feature = "crt-static")]
compile_error!("Detected crt-static mode");
Names options:
test
enabled when compiling the test;unix
unix
is set iftarget_family = "unix"
is set.
windows
windows
is set iftarget_family = "windows"
is set.
Print out all set configuration options:
rustup default
1.76.0-aarch64-apple-darwin (default)
rustc --print cfg
debug_assertions
panic="unwind"
target_arch="aarch64"
target_endian="little"
target_env=""
target_family="unix"
target_feature="aes"
target_feature="crc"
target_feature="dit"
target_feature="dotprod"
target_feature="dpb"
target_feature="dpb2"
target_feature="fcma"
target_feature="fhm"
target_feature="flagm"
target_feature="fp16"
target_feature="frintts"
target_feature="jsconv"
target_feature="lor"
target_feature="lse"
target_feature="neon"
target_feature="paca"
target_feature="pacg"
target_feature="pan"
target_feature="pmuv3"
target_feature="ras"
target_feature="rcpc"
target_feature="rcpc2"
target_feature="rdm"
target_feature="sb"
target_feature="sha2"
target_feature="sha3"
target_feature="ssbs"
target_feature="vh"
target_has_atomic="128"
target_has_atomic="16"
target_has_atomic="32"
target_has_atomic="64"
target_has_atomic="8"
target_has_atomic="ptr"
target_os="macos"
target_pointer_width="64"
target_vendor="apple"
unix
On MacOS:
rustc -C target-feature=+crt-static --print cfg | grep crt
On Linux:
rustc -C target-feature=+crt-static --print cfg | grep crt
target_feature="crt-static"
Cargo sets features in the package using the rustc --cfg
flag. If feature is set it is added to configuration options list:
rustc --cfg 'feature="foo"' --cfg 'feature="bar"' --print cfg | grep 'foo\|bar'
feature="bar"
feature="foo"
The cfg
attribute conditionally includes the thing it is attached to based on a configuration predicate.
If the predicate is false
, the thing is removed from the source code.
#[cfg(target_os = "macos")]
fn macos_only() {
// ...
}
The predicate is one of the following:
- a configuration option: the predicate is
true
if the option is set, andfalse
if it is unset; all()
with a comma-separated list of configuration predicates;any()
with a comma-separated list of configuration predicates;not()
with a configuration predicate;
The cfg_attr
conditionally includes other attributes based on a configuration predicate.
When the configuration predicate is true, this attribute expands out to the attributes listed after the predicate.
For example, depending on target_os
the module os
corresponds to different .rs
files:
#[cfg_attr(target_os = "linux", path = "linux.rs")]
#[cfg_attr(windows, path = "windows.rs")]
mod os;
Enother example:
#[cfg_attr(feature = "magic", sparkles, crackles)]
fn bewitched() {}
When the magic
feature flag is enabled, the above will expand to:
#[sparkles]
#[crackles]
fn bewitched() {}
The built-in cfg!
macro takes in a single configuration predicate and evaluates to the true
literal when the predicate is true
and the false
literal when it is false
:
let machine_kind = if cfg!(unix) {
"unix"
} else if cfg!(windows) {
"windows"
} else {
"unknown"
};
println!("I'm running on a {} machine!", machine_kind);