Skip to content

Commit

Permalink
Auto merge of #3037 - ferrocene:pa-check-cfg, r=JohnTitor
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
bors committed Mar 8, 2023
2 parents 3363d43 + d63eedc commit 89ec881
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 25 deletions.
17 changes: 17 additions & 0 deletions .github/workflows/bors.yml
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,23 @@ jobs:
run: LIBC_CI=1 TOOLCHAIN=${{ matrix.toolchain }} WIN_TARGET=${{ matrix.target }} sh ./ci/build.sh
shell: bash

check_cfg:
permissions:
actions: write # to cancel workflows (rust-lang/simpleinfra/github-actions/cancel-outdated-builds)
contents: read # to fetch code (actions/checkout)

name: "Check #[cfg]s"
runs-on: ubuntu-22.04
steps:
- uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
with:
github_token: "${{ secrets.GITHUB_TOKEN }}"
- uses: actions/checkout@v3
- name: Setup Rust toolchain
run: TOOLCHAIN=nightly sh ./ci/install-rust.sh
- name: Build with check-cfg
run: LIBC_CI=1 LIBC_CHECK_CFG=1 cargo build -Z unstable-options -Z check-cfg=features,names,values,output

docs:
permissions:
actions: write # to cancel workflows (rust-lang/simpleinfra/github-actions/cancel-outdated-builds)
Expand Down
105 changes: 80 additions & 25 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,40 @@ use std::env;
use std::process::Command;
use std::str;

// List of cfgs this build script is allowed to set. The list is needed to support check-cfg, as we
// need to know all the possible cfgs that this script will set. If you need to set another cfg
// make sure to add it to this list as well.
const ALLOWED_CFGS: &'static [&'static str] = &[
"freebsd10",
"freebsd11",
"freebsd12",
"freebsd13",
"freebsd14",
"libc_align",
"libc_cfg_target_vendor",
"libc_const_extern_fn",
"libc_const_extern_fn_unstable",
"libc_const_size_of",
"libc_core_cvoid",
"libc_deny_warnings",
"libc_int128",
"libc_long_array",
"libc_non_exhaustive",
"libc_packedN",
"libc_priv_mod_use",
"libc_ptr_addr_of",
"libc_thread_local",
"libc_underscore_const_names",
"libc_union",
];

// Extra values to allow for check-cfg.
const CHECK_CFG_EXTRA: &'static [(&'static str, &'static [&'static str])] = &[
("target_os", &["switch", "aix", "ohos"]),
("target_env", &["illumos", "wasi", "aix", "ohos"]),
("target_arch", &["loongarch64"]),
];

fn main() {
// Avoid unnecessary re-building.
println!("cargo:rerun-if-changed=build.rs");
Expand All @@ -11,6 +45,7 @@ fn main() {
let align_cargo_feature = env::var("CARGO_FEATURE_ALIGN").is_ok();
let const_extern_fn_cargo_feature = env::var("CARGO_FEATURE_CONST_EXTERN_FN").is_ok();
let libc_ci = env::var("LIBC_CI").is_ok();
let libc_check_cfg = env::var("LIBC_CHECK_CFG").is_ok();

if env::var("CARGO_FEATURE_USE_STD").is_ok() {
println!(
Expand All @@ -25,94 +60,107 @@ fn main() {
// On CI, we detect the actual FreeBSD version and match its ABI exactly,
// running tests to ensure that the ABI is correct.
match which_freebsd() {
Some(10) if libc_ci || rustc_dep_of_std => {
println!("cargo:rustc-cfg=freebsd10")
}
Some(11) if libc_ci => println!("cargo:rustc-cfg=freebsd11"),
Some(12) if libc_ci => println!("cargo:rustc-cfg=freebsd12"),
Some(13) if libc_ci => println!("cargo:rustc-cfg=freebsd13"),
Some(14) if libc_ci => println!("cargo:rustc-cfg=freebsd14"),
Some(_) | None => println!("cargo:rustc-cfg=freebsd11"),
Some(10) if libc_ci || rustc_dep_of_std => set_cfg("freebsd10"),
Some(11) if libc_ci => set_cfg("freebsd11"),
Some(12) if libc_ci => set_cfg("freebsd12"),
Some(13) if libc_ci => set_cfg("freebsd13"),
Some(14) if libc_ci => set_cfg("freebsd14"),
Some(_) | None => set_cfg("freebsd11"),
}

// On CI: deny all warnings
if libc_ci {
println!("cargo:rustc-cfg=libc_deny_warnings");
set_cfg("libc_deny_warnings");
}

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

// Rust >= 1.19 supports unions:
if rustc_minor_ver >= 19 || rustc_dep_of_std {
println!("cargo:rustc-cfg=libc_union");
set_cfg("libc_union");
}

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

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

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

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

// Rust >= 1.33 supports repr(packed(N)) and cfg(target_vendor).
if rustc_minor_ver >= 33 || rustc_dep_of_std {
println!("cargo:rustc-cfg=libc_packedN");
println!("cargo:rustc-cfg=libc_cfg_target_vendor");
set_cfg("libc_packedN");
set_cfg("libc_cfg_target_vendor");
}

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

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

if rustc_minor_ver >= 51 || rustc_dep_of_std {
println!("cargo:rustc-cfg=libc_ptr_addr_of");
set_cfg("libc_ptr_addr_of");
}

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

// #[thread_local] is currently unstable
if rustc_dep_of_std {
println!("cargo:rustc-cfg=libc_thread_local");
set_cfg("libc_thread_local");
}

// Rust >= 1.62.0 allows to use `const_extern_fn` for "Rust" and "C".
if rustc_minor_ver >= 62 {
println!("cargo:rustc-cfg=libc_const_extern_fn");
set_cfg("libc_const_extern_fn");
} else {
// Rust < 1.62.0 requires a crate feature and feature gate.
if const_extern_fn_cargo_feature {
if !is_nightly || rustc_minor_ver < 40 {
panic!("const-extern-fn requires a nightly compiler >= 1.40");
}
println!("cargo:rustc-cfg=libc_const_extern_fn_unstable");
println!("cargo:rustc-cfg=libc_const_extern_fn");
set_cfg("libc_const_extern_fn_unstable");
set_cfg("libc_const_extern_fn");
}
}

// check-cfg is a nightly cargo/rustc feature to warn when unknown cfgs are used across the
// codebase. libc can configure it if the appropriate environment variable is passed. Since
// rust-lang/rust enforces it, this is useful when using a custom libc fork there.
//
// https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg
if libc_check_cfg {
for cfg in ALLOWED_CFGS {
println!("cargo:rustc-check-cfg=values({})", cfg);
}
for &(name, values) in CHECK_CFG_EXTRA {
let values = values.join("\",\"");
println!("cargo:rustc-check-cfg=values({},\"{}\")", name, values);
}
}
}
Expand Down Expand Up @@ -181,3 +229,10 @@ fn which_freebsd() -> Option<i32> {
_ => None,
}
}

fn set_cfg(cfg: &str) {
if !ALLOWED_CFGS.contains(&cfg) {
panic!("trying to set cfg {}, but it is not in ALLOWED_CFGS", cfg);
}
println!("cargo:rustc-cfg={}", cfg);
}

0 comments on commit 89ec881

Please sign in to comment.