Skip to content

Commit bbab43f

Browse files
committed
Referenceify conditional compilation
1 parent 084fa05 commit bbab43f

File tree

1 file changed

+269
-64
lines changed

1 file changed

+269
-64
lines changed

src/conditional-compilation.md

Lines changed: 269 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,213 @@
1-
## Conditional compilation
1+
# Conditional compilation
22

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+
> &nbsp;&nbsp; &nbsp;&nbsp; _ConfigurationOption_\
6+
> &nbsp;&nbsp; | _ConfigurationAll_\
7+
> &nbsp;&nbsp; | _ConfigurationAny_\
8+
> &nbsp;&nbsp; | _ConfigurationNot_
9+
>
10+
> _ConfigurationOption_ :\
11+
> &nbsp;&nbsp; [IDENTIFIER]&nbsp;(`=` ([STRING_LITERAL] | [RAW_STRING_LITERAL]))<sup>?</sup>
12+
>
13+
> _ConfigurationAll_\
14+
> &nbsp;&nbsp; `all` `(` _ConfigurationPredicate_ (`,` _ConfigurationPredicate_)<sup>\*</sup> `,`<sup>?</sup> `)`
15+
>
16+
> _ConfigurationAny_\
17+
> &nbsp;&nbsp; `any` `(` _ConfigurationPredicate_ (`,` _ConfigurationPredicate_)<sup>\*</sup> `,`<sup>?</sup> `)`
18+
>
19+
> _ConfigurationNot_\
20+
> &nbsp;&nbsp; `not` `(` _ConfigurationPredicate_ `)`
621
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.
22+
*Conditionally compiled source code* is source code that may or may not be
23+
considered a part of the source code depending on certain conditions. <!-- This
24+
definition is sort of vacuous --> Source code can be conditionally compiled
25+
using [attributes], [`cfg`] and [`cfg_attr`], and the built-in [`cfg` macro].
26+
These conditions are based on the target architecture of the compiled crate,
27+
arbitrary values passed to the compiler, and a few other miscellaneous things
28+
further described below in detail.
1229

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]:
30+
Each form of conditional compilation takes a _configuration predicate_ that
31+
evaluates to true or false. The predicate is one of the following:
32+
33+
* A configuration option. It is true if the option is set and false if it is
34+
unset.
35+
* `all()` with a comma separated list of configuration predicates. It is false
36+
if at least one predicate is false. If there are no predicates, it is true.
37+
* `any()` with a comma separated list of configuration predicates. It is true
38+
if at least one predicate is true. If there are no predicates, it is false.
39+
* `not()` with a configuration predicate. It is true if its predicate is false
40+
and false if its predicate is true.
41+
42+
_Configuration options_ are names and key-value pairs that are either set or
43+
unset. Names are written as a single identifier such as, for example, `unix`.
44+
Key-value pairs are written as an identifier, `=`, and then a string. For
45+
example, `target_arch = "x86_64"` is a configuration option.
46+
47+
> **Note**: Whitespace around the `=` is ignored. `foo="bar"` and `foo = "bar"`
48+
> are equivalent configuration options.
49+
50+
Keys are not unique in the set of key-value configuration options. For example,
51+
both `feature = "std"` and `feature = "serde"` can be set at the same time.
52+
53+
## Set Configuration Options
54+
55+
Which configuration options are set is determined statically during the
56+
compilation of the crate. Certain options are _compiler-set_ based on data
57+
about the compilation. Other options are _arbitrarily-set_, set based on input
58+
passed to the compiler outside of the code. It is not possible to set a
59+
configuration option from within the source code of the crate being compiled.
60+
61+
> **Note**: For `rustc`, arbitrary-set configuration options are set using the
62+
> [`--cfg`] flag.
63+
64+
<div class="warning">
65+
66+
Warning: It is possible for arbitrarily-set configuration options to have the
67+
same value as compiler-set configuration options. For example, it is possible
68+
to do `rustc --cfg "unix" program.rs` while compiling to a Windows target, and
69+
have both `unix` and `windows` configuration options set at the same time. It
70+
is unwise to actually do this.
71+
72+
</div>
73+
74+
### `target_arch`
75+
76+
Key-value option set once with the target's CPU architecture. The value is
77+
similar to the first element of the platform's target triple, but not
78+
identical.
79+
80+
Example values:
81+
82+
* `"x86"`,
83+
* `"x86_64"`
84+
* `"mips"`
85+
* `"powerpc"`
86+
* `"powerpc64"`
87+
* `"arm"`,
88+
* `"aarch64"`
89+
90+
### `target_os`
91+
92+
Key-value option set once with the target's operating system. This value is
93+
similar to the second and third element of the platform's target triple.
94+
95+
Example values:
96+
97+
* `"windows"`
98+
* `"macos"`
99+
* `"ios"`
100+
* `"linux"`
101+
* `"android"`
102+
* `"freebsd"`
103+
* `"dragonfly"`
104+
* `"bitrig"`
105+
* `"openbsd"`
106+
* `"netbsd"`
107+
108+
### `target_family`
109+
110+
Key-value option set at most once with the target's operating system value.
111+
112+
Example values:
113+
114+
* `"unix"`
115+
* `"windows"`
116+
117+
### `unix` and `windows`
118+
119+
`unix` is set if `target_family = "unix"` is set and `windows` is set if
120+
`target_family = "windows"` is set.
121+
122+
### `target_env`
123+
124+
Key-value option set with further disambiguating information about the target
125+
platform with information about the ABI or `libc` used. For historical reasons,
126+
this value is only defined as not the empty-string when actually needed for
127+
disambiguation. Thus, for example, on many GNU platforms, this value will be
128+
empty. This value is similar to the fourth element of the platform's target
129+
triple. One difference is that embedded ABIs such as `gnueabihf` will simply
130+
define `target_env` as `"gnu"`.
131+
132+
Example values:
133+
134+
* `""`
135+
* `"gnu"`
136+
* `"msvc"`
137+
* `"musl"`
138+
139+
### `target_endian`
140+
141+
Key-value option set once with either a value of "little" or "big" depending
142+
on the endianness of the target's CPU.
143+
144+
### `target_pointer_width`
145+
146+
Key-value option set once with the target's pointer width in bits. For example,
147+
for targets with 32-bit pointers, this is set to `"32"`. Likewise, it is set
148+
to `"64"` for targets with 64-bit pointers.
149+
150+
<!-- Are there targets that have a different bit number? -->
151+
152+
### `target_has_atomic`
153+
154+
Key-value option set for each integer size on which the target can perform
155+
atomic operations.
156+
157+
Possible values:
158+
159+
* `"8"`
160+
* `"16"`
161+
* `"32"`
162+
* `"64"`
163+
* `"ptr"`
164+
165+
### `target_vendor`
166+
167+
Key-value option set once with the vendor of the target.
168+
169+
Possible values:
170+
171+
* `"apple"`
172+
* `"pc"`
173+
* `"unknown"`
174+
175+
### `test`
176+
177+
Enabled when compiling the test harness. Done with `rustc` by using the
178+
[`--test`] flag.
179+
180+
### `debug_assertions`
181+
182+
Enabled by default when compiling without optimizations.
183+
This can be used to enable extra debugging code in development but not in
184+
production. For example, it controls the behavior of the standard library's
185+
[`debug_assert!`] macro.
186+
187+
### `proc_macro`
188+
189+
Set when the crate being compiled is being compiled with the `proc_macro`
190+
[crate type].
191+
192+
## Forms of conditional compilation
193+
194+
### The `cfg` attribute
195+
196+
> **<sup>Syntax</sup>**\
197+
> _CfgAttrAttribute_ :\
198+
> &nbsp;&nbsp; `cfg` `(` _ConfigurationPredicate_ `)`
199+
200+
<!-- should we say they're active attributes here? -->
201+
202+
The `cfg` [attribute] conditionally includes the thing it is attached to based
203+
on a configuration predicate.
204+
205+
It is written as `cfg`, `(`, a configuration predicate, and finally `)`.
206+
207+
If the predicate is true, the thing is rewritten to not have the `cfg` attribute
208+
on it. If the predicate is false, the thing is removed from the source code.
209+
210+
Some examples on functions:
16211

17212
```rust
18213
// The function is only included in the build when compiling for macOS
@@ -41,62 +236,72 @@ fn needs_not_foo() {
41236
}
42237
```
43238

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`:
239+
The `cfg` attribute is allowed anywhere attributes are allowed except on
240+
generic parameters.
241+
242+
### The `cfg_attr` attribute
243+
244+
> **<sup>Syntax</sup>**\
245+
> _CfgAttrAttribute_ :\
246+
> &nbsp;&nbsp; `cfg_attr` `(` _ConfigurationPredicate_ `,` [_MetaItem_] `,`<sup>?</sup> `)`
247+
248+
The `cfg_attr` [attribute] conditionally includes [attributes] based on a
249+
configuration predicate.
250+
251+
It is written as `cfg_attr` followed by `(`, a configuration predicate, a
252+
[metaitem], an optional `,`, and finally a `)`.
253+
254+
When the configuration predicate is true, this attribute expands out to be an
255+
attribute of the attribute metaitem. For example, the following module will
256+
either be found at `linux.rs` or `windows.rs` based on the target.
91257

92258
```rust,ignore
93-
#[cfg_attr(a, b)]
259+
#[cfg_attr(linux, path = "linux.rs")]
260+
#[cfg_attr(windows, path = "windows.rs")]
261+
mod os;
94262
```
95263

96-
This is the same as `#[b]` if `a` is set by `cfg`, and nothing otherwise.
264+
> **Note**: The `cfg_attr` can expand to another `cfg_attr`. For example,
265+
> `#[cfg_attr(linux, cfg_attr(feature = "multithreaded", some_other_attribute))`
266+
> is valid. This example would be equivalent to
267+
> `#[cfg_attr(and(linux, feaure ="multithreaded"), some_other_attribute)]`.
268+
269+
The `cfg_attr` attribute is allowed anywhere attributes are allowed except on
270+
generic parameters.
271+
272+
### The `cfg` macro
273+
274+
The built-in `cfg` macro takes in a single configuration predicate and evaluates
275+
to the `true` literal when the predicate is true and the `false` literal when
276+
it is false.
97277

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.
278+
For example:
279+
280+
```rust
281+
let machine_kind = if cfg!(unix) {
282+
"unix"
283+
} else if cfg!(windows) {
284+
"windows"
285+
} else {
286+
"unknown"
287+
};
288+
289+
println!("I'm running on a {} machine!", machine_kind);
290+
```
100291

292+
[IDENTIFIER]: identifiers.html
293+
[RAW_STRING_LITERAL]: tokens.html#raw-string-literals
294+
[STRING_LITERAL]: tokens.html#string-literals
295+
[_MetaItem_]: attributes.html
296+
[`--cfg`]: ../rustc/command-line-arguments.html#a--cfg-configure-the-compilation-environment
297+
[`--test`]: ../rustc/command-line-arguments.html#a--test-build-a-test-harness
298+
[`cfg`]: #the-cfg-attribute
299+
[`cfg` macro]: #the-cfg-macro
300+
[`cfg_attr`]: #the-cfg_attr-attribute
301+
[`debug_assert!`]: ../std/macro.debug_assert.html
101302
[attribute]: attributes.html
102-
[crate type]: linkage.html
303+
[attributes]: attributes.html
304+
[crate type]: linkage.html
305+
[expressions]: expressions.html
306+
[items]: items.html
307+
[metaitem]: attributes.html

0 commit comments

Comments
 (0)