Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatically emit rustc-check-cfg directives for AutoCfg #70

Merged
merged 6 commits into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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

cuviper marked this conversation as resolved.
Show resolved Hide resolved
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)]
cuviper marked this conversation as resolved.
Show resolved Hide resolved

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].
Techcable marked this conversation as resolved.
Show resolved Hide resolved
/// 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