Skip to content

Commit 89ec881

Browse files
committed
Auto merge of #3037 - ferrocene:pa-check-cfg, r=JohnTitor
Add support for the unstable `check-cfg` feature behind an environment variable `check-cfg` ([Rust](https://doc.rust-lang.org/stable/unstable-book/compiler-flags/check-cfg.html), [Cargo](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg)) is an unstable features that warns when you write an unknown `#[cfg]` (likely due to a typo). The feature works out of the box for default cfgs and features provided by Cargo, but requires providing the list of extra cfgs when custom ones are used. This PR adds the `LIBC_CHECK_CFG` environment variable. When enabled, the build script will use the `cargo:rustc-check-cfg` println to instruct the compiler of all the possible cfgs set by libc. The build script was also refactored to ensure all cfgs are accounted for, and a CI job using `-Z check-cfg` was added. This PR is best reviewed commit-by-commit. ## Why is this needed? The main motivation for this PR is that `rust-lang/rust` enforces `check-cfg` across the whole codebase. Normally this is not a problem for dependencies like `libc`, as Cargo caps the lints and thus doesn't show the generated warnings. When developing support for new targets though, it's helpful to use a custom libc fork to develop the libc port and the std port together. Unfortunately doing that today results in a bunch of compilation errors, since lints are not capped with `path` dependencies. My goal with this PR is to address that shortcoming, as we'd then be able to set the `LIBC_CHECK_CFG=1` environment variable in the Rust build system and remove the compilation errors. This PR might also be helpful for libc maintainers, as the CI check might spot typos in `#[cfg]`s.
2 parents 3363d43 + d63eedc commit 89ec881

File tree

2 files changed

+97
-25
lines changed

2 files changed

+97
-25
lines changed

.github/workflows/bors.yml

+17
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,23 @@ jobs:
317317
run: LIBC_CI=1 TOOLCHAIN=${{ matrix.toolchain }} WIN_TARGET=${{ matrix.target }} sh ./ci/build.sh
318318
shell: bash
319319

320+
check_cfg:
321+
permissions:
322+
actions: write # to cancel workflows (rust-lang/simpleinfra/github-actions/cancel-outdated-builds)
323+
contents: read # to fetch code (actions/checkout)
324+
325+
name: "Check #[cfg]s"
326+
runs-on: ubuntu-22.04
327+
steps:
328+
- uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
329+
with:
330+
github_token: "${{ secrets.GITHUB_TOKEN }}"
331+
- uses: actions/checkout@v3
332+
- name: Setup Rust toolchain
333+
run: TOOLCHAIN=nightly sh ./ci/install-rust.sh
334+
- name: Build with check-cfg
335+
run: LIBC_CI=1 LIBC_CHECK_CFG=1 cargo build -Z unstable-options -Z check-cfg=features,names,values,output
336+
320337
docs:
321338
permissions:
322339
actions: write # to cancel workflows (rust-lang/simpleinfra/github-actions/cancel-outdated-builds)

build.rs

+80-25
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,40 @@ use std::env;
22
use std::process::Command;
33
use std::str;
44

5+
// List of cfgs this build script is allowed to set. The list is needed to support check-cfg, as we
6+
// need to know all the possible cfgs that this script will set. If you need to set another cfg
7+
// make sure to add it to this list as well.
8+
const ALLOWED_CFGS: &'static [&'static str] = &[
9+
"freebsd10",
10+
"freebsd11",
11+
"freebsd12",
12+
"freebsd13",
13+
"freebsd14",
14+
"libc_align",
15+
"libc_cfg_target_vendor",
16+
"libc_const_extern_fn",
17+
"libc_const_extern_fn_unstable",
18+
"libc_const_size_of",
19+
"libc_core_cvoid",
20+
"libc_deny_warnings",
21+
"libc_int128",
22+
"libc_long_array",
23+
"libc_non_exhaustive",
24+
"libc_packedN",
25+
"libc_priv_mod_use",
26+
"libc_ptr_addr_of",
27+
"libc_thread_local",
28+
"libc_underscore_const_names",
29+
"libc_union",
30+
];
31+
32+
// Extra values to allow for check-cfg.
33+
const CHECK_CFG_EXTRA: &'static [(&'static str, &'static [&'static str])] = &[
34+
("target_os", &["switch", "aix", "ohos"]),
35+
("target_env", &["illumos", "wasi", "aix", "ohos"]),
36+
("target_arch", &["loongarch64"]),
37+
];
38+
539
fn main() {
640
// Avoid unnecessary re-building.
741
println!("cargo:rerun-if-changed=build.rs");
@@ -11,6 +45,7 @@ fn main() {
1145
let align_cargo_feature = env::var("CARGO_FEATURE_ALIGN").is_ok();
1246
let const_extern_fn_cargo_feature = env::var("CARGO_FEATURE_CONST_EXTERN_FN").is_ok();
1347
let libc_ci = env::var("LIBC_CI").is_ok();
48+
let libc_check_cfg = env::var("LIBC_CHECK_CFG").is_ok();
1449

1550
if env::var("CARGO_FEATURE_USE_STD").is_ok() {
1651
println!(
@@ -25,94 +60,107 @@ fn main() {
2560
// On CI, we detect the actual FreeBSD version and match its ABI exactly,
2661
// running tests to ensure that the ABI is correct.
2762
match which_freebsd() {
28-
Some(10) if libc_ci || rustc_dep_of_std => {
29-
println!("cargo:rustc-cfg=freebsd10")
30-
}
31-
Some(11) if libc_ci => println!("cargo:rustc-cfg=freebsd11"),
32-
Some(12) if libc_ci => println!("cargo:rustc-cfg=freebsd12"),
33-
Some(13) if libc_ci => println!("cargo:rustc-cfg=freebsd13"),
34-
Some(14) if libc_ci => println!("cargo:rustc-cfg=freebsd14"),
35-
Some(_) | None => println!("cargo:rustc-cfg=freebsd11"),
63+
Some(10) if libc_ci || rustc_dep_of_std => set_cfg("freebsd10"),
64+
Some(11) if libc_ci => set_cfg("freebsd11"),
65+
Some(12) if libc_ci => set_cfg("freebsd12"),
66+
Some(13) if libc_ci => set_cfg("freebsd13"),
67+
Some(14) if libc_ci => set_cfg("freebsd14"),
68+
Some(_) | None => set_cfg("freebsd11"),
3669
}
3770

3871
// On CI: deny all warnings
3972
if libc_ci {
40-
println!("cargo:rustc-cfg=libc_deny_warnings");
73+
set_cfg("libc_deny_warnings");
4174
}
4275

4376
// Rust >= 1.15 supports private module use:
4477
if rustc_minor_ver >= 15 || rustc_dep_of_std {
45-
println!("cargo:rustc-cfg=libc_priv_mod_use");
78+
set_cfg("libc_priv_mod_use");
4679
}
4780

4881
// Rust >= 1.19 supports unions:
4982
if rustc_minor_ver >= 19 || rustc_dep_of_std {
50-
println!("cargo:rustc-cfg=libc_union");
83+
set_cfg("libc_union");
5184
}
5285

5386
// Rust >= 1.24 supports const mem::size_of:
5487
if rustc_minor_ver >= 24 || rustc_dep_of_std {
55-
println!("cargo:rustc-cfg=libc_const_size_of");
88+
set_cfg("libc_const_size_of");
5689
}
5790

5891
// Rust >= 1.25 supports repr(align):
5992
if rustc_minor_ver >= 25 || rustc_dep_of_std || align_cargo_feature {
60-
println!("cargo:rustc-cfg=libc_align");
93+
set_cfg("libc_align");
6194
}
6295

6396
// Rust >= 1.26 supports i128 and u128:
6497
if rustc_minor_ver >= 26 || rustc_dep_of_std {
65-
println!("cargo:rustc-cfg=libc_int128");
98+
set_cfg("libc_int128");
6699
}
67100

68101
// Rust >= 1.30 supports `core::ffi::c_void`, so libc can just re-export it.
69102
// Otherwise, it defines an incompatible type to retaining
70103
// backwards-compatibility.
71104
if rustc_minor_ver >= 30 || rustc_dep_of_std {
72-
println!("cargo:rustc-cfg=libc_core_cvoid");
105+
set_cfg("libc_core_cvoid");
73106
}
74107

75108
// Rust >= 1.33 supports repr(packed(N)) and cfg(target_vendor).
76109
if rustc_minor_ver >= 33 || rustc_dep_of_std {
77-
println!("cargo:rustc-cfg=libc_packedN");
78-
println!("cargo:rustc-cfg=libc_cfg_target_vendor");
110+
set_cfg("libc_packedN");
111+
set_cfg("libc_cfg_target_vendor");
79112
}
80113

81114
// Rust >= 1.40 supports #[non_exhaustive].
82115
if rustc_minor_ver >= 40 || rustc_dep_of_std {
83-
println!("cargo:rustc-cfg=libc_non_exhaustive");
116+
set_cfg("libc_non_exhaustive");
84117
}
85118

86119
// Rust >= 1.47 supports long array:
87120
if rustc_minor_ver >= 47 || rustc_dep_of_std {
88-
println!("cargo:rustc-cfg=libc_long_array");
121+
set_cfg("libc_long_array");
89122
}
90123

91124
if rustc_minor_ver >= 51 || rustc_dep_of_std {
92-
println!("cargo:rustc-cfg=libc_ptr_addr_of");
125+
set_cfg("libc_ptr_addr_of");
93126
}
94127

95128
// Rust >= 1.37.0 allows underscores as anonymous constant names.
96129
if rustc_minor_ver >= 37 || rustc_dep_of_std {
97-
println!("cargo:rustc-cfg=libc_underscore_const_names");
130+
set_cfg("libc_underscore_const_names");
98131
}
99132

100133
// #[thread_local] is currently unstable
101134
if rustc_dep_of_std {
102-
println!("cargo:rustc-cfg=libc_thread_local");
135+
set_cfg("libc_thread_local");
103136
}
104137

105138
// Rust >= 1.62.0 allows to use `const_extern_fn` for "Rust" and "C".
106139
if rustc_minor_ver >= 62 {
107-
println!("cargo:rustc-cfg=libc_const_extern_fn");
140+
set_cfg("libc_const_extern_fn");
108141
} else {
109142
// Rust < 1.62.0 requires a crate feature and feature gate.
110143
if const_extern_fn_cargo_feature {
111144
if !is_nightly || rustc_minor_ver < 40 {
112145
panic!("const-extern-fn requires a nightly compiler >= 1.40");
113146
}
114-
println!("cargo:rustc-cfg=libc_const_extern_fn_unstable");
115-
println!("cargo:rustc-cfg=libc_const_extern_fn");
147+
set_cfg("libc_const_extern_fn_unstable");
148+
set_cfg("libc_const_extern_fn");
149+
}
150+
}
151+
152+
// check-cfg is a nightly cargo/rustc feature to warn when unknown cfgs are used across the
153+
// codebase. libc can configure it if the appropriate environment variable is passed. Since
154+
// rust-lang/rust enforces it, this is useful when using a custom libc fork there.
155+
//
156+
// https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg
157+
if libc_check_cfg {
158+
for cfg in ALLOWED_CFGS {
159+
println!("cargo:rustc-check-cfg=values({})", cfg);
160+
}
161+
for &(name, values) in CHECK_CFG_EXTRA {
162+
let values = values.join("\",\"");
163+
println!("cargo:rustc-check-cfg=values({},\"{}\")", name, values);
116164
}
117165
}
118166
}
@@ -181,3 +229,10 @@ fn which_freebsd() -> Option<i32> {
181229
_ => None,
182230
}
183231
}
232+
233+
fn set_cfg(cfg: &str) {
234+
if !ALLOWED_CFGS.contains(&cfg) {
235+
panic!("trying to set cfg {}, but it is not in ALLOWED_CFGS", cfg);
236+
}
237+
println!("cargo:rustc-cfg={}", cfg);
238+
}

0 commit comments

Comments
 (0)