Skip to content

Commit

Permalink
Merge pull request #70 from Techcable/feature/rustc-check-cfg
Browse files Browse the repository at this point in the history
Automatically emit `rustc-check-cfg` directives for AutoCfg
  • Loading branch information
cuviper authored Sep 27, 2024
2 parents 1953a17 + 52a995b commit 8af60ec
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 11 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ jobs:
matrix:
rust: [1.0.0, 1.5.0, 1.10.0, 1.15.0, 1.20.0, 1.25.0, 1.30.0, 1.35.0,
1.40.0, 1.45.0, 1.50.0, 1.55.0, 1.60.0, 1.65.0, 1.70.0, 1.75.0,
1.80.0, # first version with rustc-check-cfg
stable, beta, nightly]
steps:
- uses: actions/checkout@v4
Expand All @@ -22,6 +23,8 @@ jobs:
toolchain: ${{ matrix.rust }}
- run: cargo build --verbose
- run: cargo test --verbose
- run: cargo run
working-directory: ./ci/verify-check-cfg

# try probing a target that doesn't have std at all
no_std:
Expand Down
3 changes: 3 additions & 0 deletions ci/verify-check-cfg/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Rust
/target
/Cargo.lock
14 changes: 14 additions & 0 deletions ci/verify-check-cfg/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
# NOTE: Cannot be in workspace because of rustc 1.0 support
name = "autocfg-verify-check-cfg"
description = "A dummy crate to verify autocfg is emitting check-cfg directives"
version = "0.1.0"
edition = "2015"
# only for testing
publish = false

build = "build.rs"

[build-dependencies]
autocfg = { path = "../.." }

45 changes: 45 additions & 0 deletions ci/verify-check-cfg/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
extern crate autocfg;

pub fn main() {
let cfg = autocfg::AutoCfg::new().unwrap();

//
// tests
//

// always true
cfg.emit_rustc_version(1, 0);
// should always be false
cfg.emit_rustc_version(7, std::u32::MAX as usize);

// always true
cfg.emit_has_path("std::vec::Vec");
cfg.emit_path_cfg("std::vec::Vec", "has_path_std_vec");
// always false
cfg.emit_has_path("dummy::DummyPath");
cfg.emit_path_cfg("dummy::DummyPath", "has_path_dummy");

// always true
cfg.emit_has_trait("std::ops::Add");
cfg.emit_trait_cfg("std::ops::Add", "has_trait_add");
// always false
cfg.emit_has_trait("dummy::DummyTrait");
cfg.emit_trait_cfg("dummy::DummyTrait", "has_trait_dummy");

// always true
cfg.emit_has_type("i32");
cfg.emit_type_cfg("i32", "has_type_i32");
// always false
cfg.emit_has_type("i7billion");
cfg.emit_type_cfg("i7billion", "has_type_i7billion");

// always true
cfg.emit_expression_cfg("3 + 7", "has_working_addition");
// always false
cfg.emit_expression_cfg("3 ^^^^^ 12", "has_working_5xor");

// always true
cfg.emit_constant_cfg("7", "has_const_7");
// false - Opening file should never be `const`
cfg.emit_constant_cfg("std::fs::File::open(\"foo.txt\")", "has_const_file_open");
}
43 changes: 43 additions & 0 deletions ci/verify-check-cfg/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#![allow(unknown_lints)]
#![deny(unexpected_cfgs)]

macro_rules! test_cfgs {
($($cfg:ident,)*) => {$({
let cfg_desc = format!("cfg!({})", stringify!($cfg));
if cfg!($cfg) {
println!("Enabled: {}", cfg_desc);
} else {
println!("Disabled: {}", cfg_desc);
}
})*};

}

pub fn main() {
test_cfgs!(
// emit_rustc_version
rustc_1_0,
rustc_7_4294967295,
// emit_has_path, emit_path_cfg
has_std__vec__Vec,
has_path_std_vec,
has_dummy__DummyPath,
has_path_dummy,
// emit_has_trait, emit_trait_cfg
has_std__ops__Add,
has_trait_add,
has_dummy__DummyTrait,
has_trait_dummy,
// emit_has_type, has_type_i32
has_i32,
has_type_i32,
has_i7billion,
has_type_i7billion,
// emit_expression_cfg
has_working_addition,
has_working_5xor,
// emit_constant_cfg
has_const_7,
has_const_file_open,
);
}
50 changes: 39 additions & 11 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ pub struct AutoCfg {
/// This looks like: `cargo:rustc-cfg=CFG`
///
/// Cargo will use this in arguments to rustc, like `--cfg CFG`.
///
/// This does not automatically call [`emit_possibility`]
/// so the compiler my generate an [`unexpected_cfgs` warning][check-cfg-flags].
/// However, all the builtin emit methods on [`AutoCfg`] call [`emit_possibility`] automatically.
///
/// [check-cfg-flags]: https://blog.rust-lang.org/2024/05/06/check-cfg.html
pub fn emit(cfg: &str) {
println!("cargo:rustc-cfg={}", cfg);
}
Expand All @@ -125,6 +131,25 @@ pub fn rerun_env(var: &str) {
println!("cargo:rerun-if-env-changed={}", var);
}

/// Indicates to rustc that a config flag should not generate an [`unexpected_cfgs` warning][check-cfg-flags]
///
/// This looks like `cargo:rustc-check-cfg=cfg(VAR)`
///
/// As of rust 1.80, the compiler does [automatic checking of cfgs at compile time][check-cfg-flags].
/// All custom configuration flags must be known to rustc, or they will generate a warning.
/// This is done automatically when calling the builtin emit methods on [`AutoCfg`],
/// but not when calling [`autocfg::emit`](crate::emit) directly.
///
/// Versions before rust 1.80 will simply ignore this directive.
///
/// This function indicates to the compiler that the config flag never has a value.
/// If this is not desired, see [the blog post][check-cfg].
///
/// [check-cfg-flags]: https://blog.rust-lang.org/2024/05/06/check-cfg.html
pub fn emit_possibility(cfg: &str) {
println!("cargo:rustc-check-cfg=cfg({})", cfg);
}

/// Creates a new `AutoCfg` instance.
///
/// # Panics
Expand Down Expand Up @@ -230,8 +255,10 @@ impl AutoCfg {
/// Sets a `cfg` value of the form `rustc_major_minor`, like `rustc_1_29`,
/// if the current `rustc` is at least that version.
pub fn emit_rustc_version(&self, major: usize, minor: usize) {
let cfg_flag = format!("rustc_{}_{}", major, minor);
emit_possibility(&cfg_flag);
if self.probe_rustc_version(major, minor) {
emit(&format!("rustc_{}_{}", major, minor));
emit(&cfg_flag);
}
}

Expand Down Expand Up @@ -345,8 +372,10 @@ impl AutoCfg {

/// Emits a config value `has_CRATE` if `probe_sysroot_crate` returns true.
pub fn emit_sysroot_crate(&self, name: &str) {
let cfg_flag = format!("has_{}", mangle(name));
emit_possibility(&cfg_flag);
if self.probe_sysroot_crate(name) {
emit(&format!("has_{}", mangle(name)));
emit(&cfg_flag);
}
}

Expand All @@ -366,13 +395,12 @@ impl AutoCfg {
/// Any non-identifier characters in the `path` will be replaced with
/// `_` in the generated config value.
pub fn emit_has_path(&self, path: &str) {
if self.probe_path(path) {
emit(&format!("has_{}", mangle(path)));
}
self.emit_path_cfg(path, &format!("has_{}", mangle(path)));
}

/// Emits the given `cfg` value if `probe_path` returns true.
pub fn emit_path_cfg(&self, path: &str, cfg: &str) {
emit_possibility(cfg);
if self.probe_path(path) {
emit(cfg);
}
Expand All @@ -394,13 +422,12 @@ impl AutoCfg {
/// Any non-identifier characters in the trait `name` will be replaced with
/// `_` in the generated config value.
pub fn emit_has_trait(&self, name: &str) {
if self.probe_trait(name) {
emit(&format!("has_{}", mangle(name)));
}
self.emit_trait_cfg(name, &format!("has_{}", mangle(name)));
}

/// Emits the given `cfg` value if `probe_trait` returns true.
pub fn emit_trait_cfg(&self, name: &str, cfg: &str) {
emit_possibility(cfg);
if self.probe_trait(name) {
emit(cfg);
}
Expand All @@ -422,13 +449,12 @@ impl AutoCfg {
/// Any non-identifier characters in the type `name` will be replaced with
/// `_` in the generated config value.
pub fn emit_has_type(&self, name: &str) {
if self.probe_type(name) {
emit(&format!("has_{}", mangle(name)));
}
self.emit_type_cfg(name, &format!("has_{}", mangle(name)));
}

/// Emits the given `cfg` value if `probe_type` returns true.
pub fn emit_type_cfg(&self, name: &str, cfg: &str) {
emit_possibility(cfg);
if self.probe_type(name) {
emit(cfg);
}
Expand All @@ -447,6 +473,7 @@ impl AutoCfg {

/// Emits the given `cfg` value if `probe_expression` returns true.
pub fn emit_expression_cfg(&self, expr: &str, cfg: &str) {
emit_possibility(cfg);
if self.probe_expression(expr) {
emit(cfg);
}
Expand All @@ -465,6 +492,7 @@ impl AutoCfg {

/// Emits the given `cfg` value if `probe_constant` returns true.
pub fn emit_constant_cfg(&self, expr: &str, cfg: &str) {
emit_possibility(cfg);
if self.probe_constant(expr) {
emit(cfg);
}
Expand Down

0 comments on commit 8af60ec

Please sign in to comment.