|
1 |
| -## Conditional compilation |
| 1 | +# Conditional compilation |
2 | 2 |
|
3 |
| -Sometimes one wants to have different compiler outputs from the same code, |
4 |
| -depending on build target, such as targeted operating system, or to enable |
5 |
| -release builds. |
| 3 | +> **<sup>Syntax</sup>**\ |
| 4 | +> _ConfigurationPredicate_ :\ |
| 5 | +> _ConfigurationOption_\ |
| 6 | +> | _ConfigurationAll_\ |
| 7 | +> | _ConfigurationAny_\ |
| 8 | +> | _ConfigurationNot_ |
| 9 | +> |
| 10 | +> _ConfigurationOption_ :\ |
| 11 | +> [IDENTIFIER] (`=` ([STRING_LITERAL] | [RAW_STRING_LITERAL]))<sup>?</sup> |
| 12 | +> |
| 13 | +> _ConfigurationAll_\ |
| 14 | +> `all` `(` _ConfigurationPredicateList_<sup>?</sup> `)` |
| 15 | +> |
| 16 | +> _ConfigurationAny_\ |
| 17 | +> `any` `(` _ConfigurationPredicateList_<sup>?</sup> `)` |
| 18 | +> |
| 19 | +> _ConfigurationNot_\ |
| 20 | +> `not` `(` _ConfigurationPredicate_ `)` |
| 21 | +> |
| 22 | +> _ConfigurationPredicateList_\ |
| 23 | +> _ConfigurationPredicate_ (`,` _ConfigurationPredicate_)<sup>\*</sup> `,`<sup>?</sup> |
6 | 24 |
|
7 |
| -Configuration options are boolean (on or off) and are named either with a |
8 |
| -single identifier (e.g. `foo`) or an identifier and a string (e.g. `foo = "bar"`; |
9 |
| -the quotes are required and spaces around the `=` are unimportant). Note that |
10 |
| -similarly-named options, such as `foo`, `foo="bar"` and `foo="baz"` may each be |
11 |
| -set or unset independently. |
| 25 | +*Conditionally compiled source code* is source code that may or may not be |
| 26 | +considered a part of the source code depending on certain conditions. <!-- This |
| 27 | +definition is sort of vacuous --> Source code can be conditionally compiled |
| 28 | +using [attributes], [`cfg`] and [`cfg_attr`], and the built-in [`cfg` macro]. |
| 29 | +These conditions are based on the target architecture of the compiled crate, |
| 30 | +arbitrary values passed to the compiler, and a few other miscellaneous things |
| 31 | +further described below in detail. |
12 | 32 |
|
13 |
| -Configuration options are either provided by the compiler or passed in on the |
14 |
| -command line using `--cfg` (e.g. `rustc main.rs --cfg foo --cfg 'bar="baz"'`). |
15 |
| -Rust code then checks for their presence using the `#[cfg(...)]` [attribute]: |
| 33 | +Each form of conditional compilation takes a _configuration predicate_ that |
| 34 | +evaluates to true or false. The predicate is one of the following: |
| 35 | + |
| 36 | +* A configuration option. It is true if the option is set and false if it is |
| 37 | + unset. |
| 38 | +* `all()` with a comma separated list of configuration predicates. It is false |
| 39 | + if at least one predicate is false. If there are no predicates, it is true. |
| 40 | +* `any()` with a comma separated list of configuration predicates. It is true |
| 41 | + if at least one predicate is true. If there are no predicates, it is false. |
| 42 | +* `not()` with a configuration predicate. It is true if its predicate is false |
| 43 | + and false if its predicate is true. |
| 44 | + |
| 45 | +_Configuration options_ are names and key-value pairs that are either set or |
| 46 | +unset. Names are written as a single identifier such as, for example, `unix`. |
| 47 | +Key-value pairs are written as an identifier, `=`, and then a string. For |
| 48 | +example, `target_arch = "x86_64"` is a configuration option. |
| 49 | + |
| 50 | +> **Note**: Whitespace around the `=` is ignored. `foo="bar"` and `foo = "bar"` |
| 51 | +> are equivalent configuration options. |
| 52 | +
|
| 53 | +Keys are not unique in the set of key-value configuration options. For example, |
| 54 | +both `feature = "std"` and `feature = "serde"` can be set at the same time. |
| 55 | + |
| 56 | +## Set Configuration Options |
| 57 | + |
| 58 | +Which configuration options are set is determined statically during the |
| 59 | +compilation of the crate. Certain options are _compiler-set_ based on data |
| 60 | +about the compilation. Other options are _arbitrarily-set_, set based on input |
| 61 | +passed to the compiler outside of the code. It is not possible to set a |
| 62 | +configuration option from within the source code of the crate being compiled. |
| 63 | + |
| 64 | +> **Note**: For `rustc`, arbitrary-set configuration options are set using the |
| 65 | +> [`--cfg`] flag. |
| 66 | +
|
| 67 | +<div class="warning"> |
| 68 | + |
| 69 | +Warning: It is possible for arbitrarily-set configuration options to have the |
| 70 | +same value as compiler-set configuration options. For example, it is possible |
| 71 | +to do `rustc --cfg "unix" program.rs` while compiling to a Windows target, and |
| 72 | +have both `unix` and `windows` configuration options set at the same time. It |
| 73 | +is unwise to actually do this. |
| 74 | + |
| 75 | +</div> |
| 76 | + |
| 77 | +### `target_arch` |
| 78 | + |
| 79 | +Key-value option set once with the target's CPU architecture. The value is |
| 80 | +similar to the first element of the platform's target triple, but not |
| 81 | +identical. |
| 82 | + |
| 83 | +Example values: |
| 84 | + |
| 85 | +* `"x86"` |
| 86 | +* `"x86_64"` |
| 87 | +* `"mips"` |
| 88 | +* `"powerpc"` |
| 89 | +* `"powerpc64"` |
| 90 | +* `"arm"` |
| 91 | +* `"aarch64"` |
| 92 | + |
| 93 | +### `target_os` |
| 94 | + |
| 95 | +Key-value option set once with the target's operating system. This value is |
| 96 | +similar to the second and third element of the platform's target triple. |
| 97 | + |
| 98 | +Example values: |
| 99 | + |
| 100 | +* `"windows"` |
| 101 | +* `"macos"` |
| 102 | +* `"ios"` |
| 103 | +* `"linux"` |
| 104 | +* `"android"` |
| 105 | +* `"freebsd"` |
| 106 | +* `"dragonfly"` |
| 107 | +* `"bitrig"` |
| 108 | +* `"openbsd"` |
| 109 | +* `"netbsd"` |
| 110 | + |
| 111 | +### `target_family` |
| 112 | + |
| 113 | +Key-value option set at most once with the target's operating system value. |
| 114 | + |
| 115 | +Example values: |
| 116 | + |
| 117 | +* `"unix"` |
| 118 | +* `"windows"` |
| 119 | + |
| 120 | +### `unix` and `windows` |
| 121 | + |
| 122 | +`unix` is set if `target_family = "unix"` is set and `windows` is set if |
| 123 | +`target_family = "windows"` is set. |
| 124 | + |
| 125 | +### `target_env` |
| 126 | + |
| 127 | +Key-value option set with further disambiguating information about the target |
| 128 | +platform with information about the ABI or `libc` used. For historical reasons, |
| 129 | +this value is only defined as not the empty-string when actually needed for |
| 130 | +disambiguation. Thus, for example, on many GNU platforms, this value will be |
| 131 | +empty. This value is similar to the fourth element of the platform's target |
| 132 | +triple. One difference is that embedded ABIs such as `gnueabihf` will simply |
| 133 | +define `target_env` as `"gnu"`. |
| 134 | + |
| 135 | +Example values: |
| 136 | + |
| 137 | +* `""` |
| 138 | +* `"gnu"` |
| 139 | +* `"msvc"` |
| 140 | +* `"musl"` |
| 141 | + |
| 142 | +### `target_endian` |
| 143 | + |
| 144 | +Key-value option set once with either a value of "little" or "big" depending |
| 145 | +on the endianness of the target's CPU. |
| 146 | + |
| 147 | +### `target_pointer_width` |
| 148 | + |
| 149 | +Key-value option set once with the target's pointer width in bits. For example, |
| 150 | +for targets with 32-bit pointers, this is set to `"32"`. Likewise, it is set |
| 151 | +to `"64"` for targets with 64-bit pointers. |
| 152 | + |
| 153 | +<!-- Are there targets that have a different bit number? --> |
| 154 | + |
| 155 | +### `target_has_atomic` |
| 156 | + |
| 157 | +Key-value option set for each integer size on which the target can perform |
| 158 | +atomic operations. |
| 159 | + |
| 160 | +Possible values: |
| 161 | + |
| 162 | +* `"8"` |
| 163 | +* `"16"` |
| 164 | +* `"32"` |
| 165 | +* `"64"` |
| 166 | +* `"ptr"` |
| 167 | + |
| 168 | +### `target_vendor` |
| 169 | + |
| 170 | +Key-value option set once with the vendor of the target. |
| 171 | + |
| 172 | +Possible values: |
| 173 | + |
| 174 | +* `"apple"` |
| 175 | +* `"pc"` |
| 176 | +* `"unknown"` |
| 177 | + |
| 178 | +### `test` |
| 179 | + |
| 180 | +Enabled when compiling the test harness. Done with `rustc` by using the |
| 181 | +[`--test`] flag. |
| 182 | + |
| 183 | +### `debug_assertions` |
| 184 | + |
| 185 | +Enabled by default when compiling without optimizations. |
| 186 | +This can be used to enable extra debugging code in development but not in |
| 187 | +production. For example, it controls the behavior of the standard library's |
| 188 | +[`debug_assert!`] macro. |
| 189 | + |
| 190 | +### `proc_macro` |
| 191 | + |
| 192 | +Set when the crate being compiled is being compiled with the `proc_macro` |
| 193 | +[crate type]. |
| 194 | + |
| 195 | +## Forms of conditional compilation |
| 196 | + |
| 197 | +### The `cfg` attribute |
| 198 | + |
| 199 | +> **<sup>Syntax</sup>**\ |
| 200 | +> _CfgAttrAttribute_ :\ |
| 201 | +> `cfg` `(` _ConfigurationPredicate_ `)` |
| 202 | +
|
| 203 | +<!-- should we say they're active attributes here? --> |
| 204 | + |
| 205 | +The `cfg` [attribute] conditionally includes the thing it is attached to based |
| 206 | +on a configuration predicate. |
| 207 | + |
| 208 | +It is written as `cfg`, `(`, a configuration predicate, and finally `)`. |
| 209 | + |
| 210 | +If the predicate is true, the thing is rewritten to not have the `cfg` attribute |
| 211 | +on it. If the predicate is false, the thing is removed from the source code. |
| 212 | + |
| 213 | +Some examples on functions: |
16 | 214 |
|
17 | 215 | ```rust
|
18 | 216 | // The function is only included in the build when compiling for macOS
|
@@ -41,62 +239,72 @@ fn needs_not_foo() {
|
41 | 239 | }
|
42 | 240 | ```
|
43 | 241 |
|
44 |
| -This illustrates some conditional compilation can be achieved using the |
45 |
| -`#[cfg(...)]` [attribute]. `any`, `all` and `not` can be used to assemble |
46 |
| -arbitrarily complex configurations through nesting. |
47 |
| - |
48 |
| -The following configurations must be defined by the implementation: |
49 |
| - |
50 |
| -* `target_arch = "..."` - Target CPU architecture, such as `"x86"`, |
51 |
| - `"x86_64"` `"mips"`, `"powerpc"`, `"powerpc64"`, `"arm"`, or |
52 |
| - `"aarch64"`. This value is closely related to the first element of |
53 |
| - the platform target triple, though it is not identical. |
54 |
| -* `target_os = "..."` - Operating system of the target, examples |
55 |
| - include `"windows"`, `"macos"`, `"ios"`, `"linux"`, `"android"`, |
56 |
| - `"freebsd"`, `"dragonfly"`, `"bitrig"` , `"openbsd"` or |
57 |
| - `"netbsd"`. This value is closely related to the second and third |
58 |
| - element of the platform target triple, though it is not identical. |
59 |
| -* `target_family = "..."` - Operating system family of the target, e. g. |
60 |
| - `"unix"` or `"windows"`. The value of this configuration option is defined |
61 |
| - as a configuration itself, like `unix` or `windows`. |
62 |
| -* `unix` - See `target_family`. |
63 |
| -* `windows` - See `target_family`. |
64 |
| -* `target_env = ".."` - Further disambiguates the target platform with |
65 |
| - information about the ABI/libc. Presently this value is either |
66 |
| - `"gnu"`, `"msvc"`, `"musl"`, or the empty string. For historical |
67 |
| - reasons this value has only been defined as non-empty when needed |
68 |
| - for disambiguation. Thus on many GNU platforms this value will be |
69 |
| - empty. This value is closely related to the fourth element of the |
70 |
| - platform target triple, though it is not identical. For example, |
71 |
| - embedded ABIs such as `gnueabihf` will simply define `target_env` as |
72 |
| - `"gnu"`. |
73 |
| -* `target_endian = "..."` - Endianness of the target CPU, either `"little"` or |
74 |
| - `"big"`. |
75 |
| -* `target_pointer_width = "..."` - Target pointer width in bits. This is set |
76 |
| - to `"32"` for targets with 32-bit pointers, and likewise set to `"64"` for |
77 |
| - 64-bit pointers. |
78 |
| -* `target_has_atomic = "..."` - Set of integer sizes on which the target can perform |
79 |
| - atomic operations. Values are `"8"`, `"16"`, `"32"`, `"64"` and `"ptr"`. |
80 |
| -* `target_vendor = "..."` - Vendor of the target, for example `apple`, `pc`, or |
81 |
| - simply `"unknown"`. |
82 |
| -* `test` - Enabled when compiling the test harness (using the `--test` flag). |
83 |
| -* `debug_assertions` - Enabled by default when compiling without optimizations. |
84 |
| - This can be used to enable extra debugging code in development but not in |
85 |
| - production. For example, it controls the behavior of the standard library's |
86 |
| - `debug_assert!` macro. |
87 |
| -* `proc_macro` - Set when the crate being compiled is being compiled with the |
88 |
| - `proc_macro` [crate type]. |
89 |
| - |
90 |
| -You can also set another [attribute] based on a `cfg` variable with `cfg_attr`: |
| 242 | +The `cfg` attribute is allowed anywhere attributes are allowed except on |
| 243 | +generic parameters. |
| 244 | + |
| 245 | +### The `cfg_attr` attribute |
| 246 | + |
| 247 | +> **<sup>Syntax</sup>**\ |
| 248 | +> _CfgAttrAttribute_ :\ |
| 249 | +> `cfg_attr` `(` _ConfigurationPredicate_ `,` [_MetaItem_] `,`<sup>?</sup> `)` |
| 250 | +
|
| 251 | +The `cfg_attr` [attribute] conditionally includes [attributes] based on a |
| 252 | +configuration predicate. |
| 253 | + |
| 254 | +It is written as `cfg_attr` followed by `(`, a configuration predicate, a |
| 255 | +[metaitem], an optional `,`, and finally a `)`. |
| 256 | + |
| 257 | +When the configuration predicate is true, this attribute expands out to be an |
| 258 | +attribute of the attribute metaitem. For example, the following module will |
| 259 | +either be found at `linux.rs` or `windows.rs` based on the target. |
91 | 260 |
|
92 | 261 | ```rust,ignore
|
93 |
| -#[cfg_attr(a, b)] |
| 262 | +#[cfg_attr(linux, path = "linux.rs")] |
| 263 | +#[cfg_attr(windows, path = "windows.rs")] |
| 264 | +mod os; |
94 | 265 | ```
|
95 | 266 |
|
96 |
| -This is the same as `#[b]` if `a` is set by `cfg`, and nothing otherwise. |
| 267 | +> **Note**: The `cfg_attr` can expand to another `cfg_attr`. For example, |
| 268 | +> `#[cfg_attr(linux, cfg_attr(feature = "multithreaded", some_other_attribute))` |
| 269 | +> is valid. This example would be equivalent to |
| 270 | +> `#[cfg_attr(all(linux, feature ="multithreaded"), some_other_attribute)]`. |
| 271 | +
|
| 272 | +The `cfg_attr` attribute is allowed anywhere attributes are allowed except on |
| 273 | +generic parameters. |
| 274 | + |
| 275 | +### The `cfg` macro |
| 276 | + |
| 277 | +The built-in `cfg` macro takes in a single configuration predicate and evaluates |
| 278 | +to the `true` literal when the predicate is true and the `false` literal when |
| 279 | +it is false. |
97 | 280 |
|
98 |
| -Lastly, configuration options can be used in expressions by invoking the `cfg!` |
99 |
| -macro: `cfg!(a)` evaluates to `true` if `a` is set, and `false` otherwise. |
| 281 | +For example: |
| 282 | + |
| 283 | +```rust |
| 284 | +let machine_kind = if cfg!(unix) { |
| 285 | + "unix" |
| 286 | +} else if cfg!(windows) { |
| 287 | + "windows" |
| 288 | +} else { |
| 289 | + "unknown" |
| 290 | +}; |
| 291 | + |
| 292 | +println!("I'm running on a {} machine!", machine_kind); |
| 293 | +``` |
100 | 294 |
|
| 295 | +[IDENTIFIER]: identifiers.html |
| 296 | +[RAW_STRING_LITERAL]: tokens.html#raw-string-literals |
| 297 | +[STRING_LITERAL]: tokens.html#string-literals |
| 298 | +[_MetaItem_]: attributes.html |
| 299 | +[`--cfg`]: ../rustc/command-line-arguments.html#a--cfg-configure-the-compilation-environment |
| 300 | +[`--test`]: ../rustc/command-line-arguments.html#a--test-build-a-test-harness |
| 301 | +[`cfg`]: #the-cfg-attribute |
| 302 | +[`cfg` macro]: #the-cfg-macro |
| 303 | +[`cfg_attr`]: #the-cfg_attr-attribute |
| 304 | +[`debug_assert!`]: ../std/macro.debug_assert.html |
101 | 305 | [attribute]: attributes.html
|
102 |
| -[crate type]: linkage.html |
| 306 | +[attributes]: attributes.html |
| 307 | +[crate type]: linkage.html |
| 308 | +[expressions]: expressions.html |
| 309 | +[items]: items.html |
| 310 | +[metaitem]: attributes.html |
0 commit comments