|
| 1 | +- Feature Name: `cfg-target` |
| 2 | +- Start Date: 2020-09-27 |
| 3 | +- RFC PR: [rust-lang/rfcs#3239](https://github.com/rust-lang/rfcs/pull/3239) |
| 4 | +- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/96901) |
| 5 | + |
| 6 | +# Summary |
| 7 | +[summary]: #summary |
| 8 | + |
| 9 | +This proposes a new `cfg`: `target`, which matches the entire target triple |
| 10 | +string (e.g. `arm-unknown-linux-gnueabihf`). This also adds a `CARGO_CFG_TARGET` |
| 11 | +environment variable for parity with other `CARGO_CFG_*` variables. |
| 12 | + |
| 13 | +In addition, this proposes a shorthand `cfg(target(...))` to match multiple |
| 14 | +components of a target string at once. |
| 15 | + |
| 16 | +# Motivation |
| 17 | +[motivation]: #motivation |
| 18 | + |
| 19 | +To `#[cfg]` against a specific target, a `build.rs` script is required to emit a |
| 20 | +custom `cfg` based on the `TARGET` environment variable. Adding a build script |
| 21 | +increases compile time and makes a crate incompatible with certain build |
| 22 | +systems. |
| 23 | + |
| 24 | +Otherwise, all available components would need to be specified separately: |
| 25 | +`target_arch`, `target_vendor`, `target_os`, `target_env` and `target_abi`. |
| 26 | +This can be very cumbersome. Note that the target ABI cannot currently be |
| 27 | +`#[cfg]`-ed against, so a `build.rs` is still necessary to match all target |
| 28 | +components. |
| 29 | + |
| 30 | +# Guide-level explanation |
| 31 | +[guide-level-explanation]: #guide-level-explanation |
| 32 | + |
| 33 | +This would act like existing `target_*` configurations (except `target_feature`) |
| 34 | +but match against all components. |
| 35 | + |
| 36 | +```rust |
| 37 | +#[cfg(target = "x86_64-apple-ios-macabi")] |
| 38 | +mod mac_catalyst; |
| 39 | +``` |
| 40 | + |
| 41 | +This includes `#[cfg_attr(target = "...", attr)]`. |
| 42 | + |
| 43 | +It would also support to specify each `target_*` inside a new `target` |
| 44 | +attribute as follows: |
| 45 | + |
| 46 | +```rust |
| 47 | +// So we can for example rewrite: |
| 48 | +#[cfg(all(target_os = "linux", target_arch = "arm"))] |
| 49 | +// as: |
| 50 | +#[cfg(target(os = "linux", arch = "arm"))] |
| 51 | +``` |
| 52 | + |
| 53 | +# Reference-level explanation |
| 54 | +[reference-level-explanation]: #reference-level-explanation |
| 55 | + |
| 56 | +`target` is a key-value option set once with the target's Rust triple. |
| 57 | + |
| 58 | +Example values: |
| 59 | + |
| 60 | +- `"aarch64-apple-darwin"` |
| 61 | +- `"arm-unknown-linux-gnueabihf"` |
| 62 | +- `"x86_64-apple-ios-macabi"` |
| 63 | +- `"x86_64-pc-windows-gnu"` |
| 64 | +- `"x86_64-pc-windows-msvc"` |
| 65 | +- `"x86_64-unknown-linux-gnu"` |
| 66 | + |
| 67 | +## Semantics of target with attributes |
| 68 | + |
| 69 | +The shorthand form of `#[cfg(target(os = "linux))]` is expanded and entirely |
| 70 | +equivalent to `#[cfg(target_os = "linux")]` (and so on for `arch` and the other |
| 71 | +potential attributes). |
| 72 | + |
| 73 | +# Drawbacks |
| 74 | +[drawbacks]: #drawbacks |
| 75 | + |
| 76 | +- Configuring against specific targets can be overly strict and could make |
| 77 | + certain `#[cfg]`s miss similar configurations with small changes. |
| 78 | + |
| 79 | + For example: `aarch64-unknown-none` does not match |
| 80 | + `aarch64-unknown-none-softfloat`, yet one would likely want to include ABI |
| 81 | + variants. The same concern applies to the target vendor. |
| 82 | + |
| 83 | + A potential solution would be to allow glob matching (e.g. |
| 84 | + `aarch64-unknown-none*`), but that is not within the scope of this proposal |
| 85 | + because it is not currently used in other `#[cfg]`s. |
| 86 | + |
| 87 | +- The `CARGO_CFG_TARGET` environment variable is redundant with the existing |
| 88 | + `TARGET`. However, including it would be consistent with other `CARGO_CFG_*` |
| 89 | + variables. |
| 90 | + |
| 91 | +# Rationale and alternatives |
| 92 | +[rationale-and-alternatives]: #rationale-and-alternatives |
| 93 | + |
| 94 | +We can keep the existing work-around of checking the `TARGET` environment |
| 95 | +variable in a `build.rs` script. However, that increases compile time and makes |
| 96 | +a crate incompatible with certain build systems. |
| 97 | + |
| 98 | +# Prior art |
| 99 | +[prior-art]: #prior-art |
| 100 | + |
| 101 | +- [Target component configurations](https://doc.rust-lang.org/reference/conditional-compilation.html#set-configuration-options): |
| 102 | + `target_arch`, `target_vendor`, `target_os`, and `target_env`. |
| 103 | + |
| 104 | +- `TARGET` and `CARGO_CFG_TARGET_*` |
| 105 | + [environment variables for `build.rs`](https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts). |
| 106 | + |
| 107 | +# Unresolved questions |
| 108 | +[unresolved-questions]: #unresolved-questions |
| 109 | + |
| 110 | +- How do we ensure a project does not miss configurations similar to the ones |
| 111 | + being `#[cfg]`-ed against with this feature? Perhaps this should be added as a |
| 112 | + Clippy lint that's off by default. |
| 113 | + |
| 114 | +# Future possibilities |
| 115 | +[future-possibilities]: #future-possibilities |
| 116 | + |
| 117 | +This would enable `#[cfg]`-ing against a specific target ABI (e.g. `macabi`, |
| 118 | +`eabihf`). However, that is not the motivation for this proposal and should be |
| 119 | +handled separately. |
0 commit comments