Skip to content

Latest commit

 

History

History
380 lines (316 loc) · 8.21 KB

attributes.md

File metadata and controls

380 lines (316 loc) · 8.21 KB

Table of contents


Attributes

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

Inner attributes apply to all items within the scope where attribute is declared.

Example

mod Bar {
    #![bar]
}

Here, the #![bar] attribute applies to all items inside module Bar.


Outer attributes

Outer attributes apply only to 1 item following the attribute.

Example

#[foo]
struct Foo;

Here, the #[foo] attribute applies only to the next item Foo.


Attributes arguments

Some attributes require arguments, some attributes can be used without arguments.

Attributes without arguments

// A unit test
#[test]
fn check() {
    assert_eq!(2, 1 + 1);
}

Attributes with arguments

// A conditional compilation
#[cfg(target_os = "linux")]
mod bar {
    /* ... */
}

// A lint attribute
#[allow(non_camel_case_types)]
type int8_t = i8;

Kinds of attributes

  • built-in attributes;
  • tool attributes;
  • macro attributes;
  • derive macro helper attributes.

Built-in 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

Attr: derive

The derive attribute allows certain traits to be automatically implemented for data structures.

#[derive(PartialEq, Clone)]
struct Foo<T> {
    a: i32,
    b: T,
}

Attr: path

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.


Conditional compilation

Configuration options

Configuration options are either names or key-value pairs, and are either set or unset.


Key-value options

  • 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"
  • 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";
  • 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:

#[cfg(target_feature = "crt-static")]
compile_error!("Detected crt-static mode");

Names options:

  • test enabled when compiling the test;
  • unix
    • unix is set if target_family = "unix" is set.
  • windows
    • windows is set if target_family = "windows" is set.

Examples

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"

Attr: cfg

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, and false 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;

Attr: cfg_attr

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 cfg! macro

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);