Skip to content

Latest commit

 

History

History
115 lines (76 loc) · 5.38 KB

File metadata and controls

115 lines (76 loc) · 5.38 KB
layout post
title Automatic checking of cfgs at compile-time
author Urgau
team The Cargo Team <https://www.rust-lang.org/governance/teams/dev-tools#cargo>

Automatic checking of cfgs at compile-time

The Cargo and Compiler team are delighted to announce that starting with Rust 1.80 (or nightly-2024-04-XX) every reachable #[cfg]s will be automatically checked for expected config names and values.

This can help with verifying that the crate is correctly handling conditional compilation for different target platforms or features. It ensures that the cfg settings are consistent between what is intended and what is used, helping to catch potential bugs or errors early in the development process.

Addressing a common pitfall for new and advanced users.

This is another step to our commitment to provide user-focused tooling and we are eager and excited to finally see it fixed, more than two years since the original RFC 30131.

A look at the feature

Every time a Cargo feature is declared that feature is transformed into a config that is passed to rustc (the Rust compiler) so it can verify with its well known cfgs if any of the #[cfg], #![cfg_attr] and cfg! have unexpected configs and report a warning with the unexpected_cfgs lint.

Cargo.toml:

[package]
name = "foo"

[features]
lasers = []
zapping = []

src/lib.rs:

#[cfg(feature = "lasers")]  // This condition is expected
                            //   as "lasers" is an expected value of `feature`
fn shoot_lasers() {}

#[cfg(feature = "monkeys")] // This condition is UNEXPECTED
                            //   as "monkeys" is NOT an expected value of `feature`
fn write_shakespeare() {}

#[cfg(windosw)]             // This condition is UNEXPECTED
                            //   it's supposed to be `windows`
fn win() {}

cargo check: cargo-check

Custom cfgs and build scripts

In Cargo point-of-view: a custom cfg is one that is neither defined by rustc nor by a Cargo feature. Think of tokio_unstable, has_foo, ... but not feature = "lasers", unix, ...

Some crates use custom cfgs that they either expected from the environment (RUSTFLAGSor other means) or is enabled by some logic in the crate build.rs. For those crates Cargo provides a new instruction: cargo::rustc-check-cfg2 (or cargo:rustc-check-cfg for older Cargo version).

The syntax to use is described in the rustc book section checking configuration, but in a nut shell the basic syntax of --check-cfg is:

cfg(name, values("value1", "value2", ..., "valueN"))

Note that every custom cfgs must always be expected, regardless if the cfg is active or not!

build.rs example

build.rs:

fn main() {
    println!("cargo::rustc-check-cfg=cfg(has_foo)"); // <-- new with Cargo 1.80
    if has_foo() {
        println!("cargo::rustc-cfg=has_foo");
    }
}

Note: Each cargo::rustc-cfg must always have a accompanying unconditional cargo::rustc-check-cfg directive otherwise you risk having warnings like this:unexpected cfg condition name: has_foo.

Equivalence table

cargo::rustc-cfg cargo::rustc-check-cfg
foo cfg(foo) or cfg(foo, values(none()))
foo="" cfg(foo, values(""))
foo="bar" cfg(foo, values("bar"))
foo="1" and foo="2" cfg(foo, values("1", "2"))
foo="1" and bar="2" cfg(foo, values("1")) and cfg(bar, values("2"))
foo and foo="bar" cfg(foo, values(none(), "bar"))

More details can be found on the rustc book.

Frequently asked questions

Can it be disabled?

No, it's always on for Cargo and cannot be disabled.

How does it interact with the RUSTFLAGS env ?

You should be able to use the RUSTFLAGS environment variable like it was before. Currently --cfg arguments are not checked, only usage in code are.

This means that doing RUSTFLAGS="--cfg tokio_unstable" cargo check will not report any warnings, unless tokio_unstable is used within your local crates, in which case crate author will need to make sure that that custom cfg is expected with cargo::rustc-check-cfg in the build.rs of that crate.

How to expect custom cfgs without a build.rs ?

There is not currently no way to expect a custom cfg other than with cargo::rustc-check-cfg in a build.rs.

Crate author that don't want to use a build.rs are encouraged to use Cargo features instead.

Does it affect dependencies ?

No, the lint only affects local packages; only those will report the lint.

Footnotes

  1. The stabilized implementation and RFC 3013 diverge significantly, in particular there is only one form for --check-cfg: cfg() (instead of values() and names() being incomplete and subtlety incompatible with each other). ↩

  2. cargo::rustc-check-cfg take action since Rust 1.80, between Rust 1.77 and Rust 1.79 (included) it silently did nothing and before that (so Rust 1.76 and below) it warned when used without the unstable Cargo -Zcheck-cfg. ↩