Cargo 和编译器团队很高兴宣布,从 Rust 1.80(或 nightly-2024-05-05)开始,每个**可达到的** #[cfg]
都将**自动检查**它们是否匹配**预期的配置名称和值**。
这有助于验证 crate 是否为不同的目标平台或特性正确处理了条件编译。它确保了 cfg 设置在预期和实际使用之间保持一致,有助于在开发过程早期捕获潜在的错误。
这解决了新手和高级用户的一个常见陷阱。
这是我们提供以用户为中心的工具的承诺的又一步,经过两年多的时间,我们很高兴终于看到它被修复,自从最初的 RFC 30131 以来。
特性一览
每次声明一个 Cargo 特性时,该特性都会被转换为一个配置,传递给 rustc
(Rust 编译器),以便它可以与已知 cfgs 一起验证任何 #[cfg]
、#![cfg_attr]
和 cfg!
是否包含非预期的配置,并报告 unexpected_cfgs
lint 警告。
Cargo.toml
:
[]
= "foo"
[]
= []
= []
src/lib.rs
:
// This condition is expected
// as "lasers" is an expected value
// of the `feature` cfg
// This condition is UNEXPECTED
// as "monkeys" is NOT an expected
// value of the `feature` cfg
// This condition is UNEXPECTED
// it's supposed to be `windows`
cargo check
:
声明预期的自定义 cfgs
更新:本节是在 nightly-2024-05-19 版本发布时添加的。
从 Cargo 的角度来看:自定义 cfg 是指既不由
rustc
定义,也不由 Cargo 特性定义的 cfg。例如tokio_unstable
,has_foo
, ... 但不包括feature = "lasers"
,unix
或debug_assertions
。
有些 crate 可能会使用自定义 cfgs,例如 loom
, fuzzing
或 tokio_unstable
,它们预期来自环境(RUSTFLAGS
或其他方式),并且在编译时总是静态已知的。对于这些情况,Cargo 通过 [lints]
表提供了一种静态声明这些 cfgs 为预期的方式。
通过 [lints.rust.unexpected_cfgs]
下的特殊 check-cfg
配置来声明这些自定义 cfgs 为预期。
Cargo.toml
[]
= { = "warn", = ['cfg(loom)', 'cfg(fuzzing)'] }
build scripts 中的自定义 cfgs
另一方面,有些 crate 使用通过 crate 的 build.rs
中的一些逻辑启用的自定义 cfgs。对于这些 crate,Cargo 提供了一个新指令:cargo::rustc-check-cfg
2(对于旧版本 Cargo 则是 cargo:rustc-check-cfg
)。
使用语法在rustc book 的 checking configuration 一节中描述,但简而言之,--check-cfg
的基本语法是:
cfg(name, values("value1", "value2", ..., "valueN"))
注意,每个自定义 cfgs 都必须总是被声明为预期的,无论该 cfg 是否处于活动状态!
build.rs
示例
build.rs
:
每个
cargo::rustc-cfg
都应该有一个配套的**无条件的**cargo::rustc-check-cfg
指令,以避免像unexpected cfg condition name: has_foo
这样的警告。
等价表
|
|
---|---|
| cfg(foo) 或 cfg(foo, values(none())) |
|
|
|
|
foo="1" 和 foo="2" |
|
foo="1" 和 bar="2" | cfg(foo, values("1")) 和 cfg(bar, values("2")) |
foo 和 foo="bar" |
|
更多详细信息可以在rustc
book 中找到。
常见问题
可以禁用吗?
对于 Cargo 用户来说,该特性**始终开启**且*不能*被禁用,但像其他 lint 一样,它可以被控制:#![warn(unexpected_cfgs)]
。
这个 lint 会影响依赖项吗?
不会,像大多数 lint 一样,由于 cap-lints,unexpected_cfgs
只会针对本地包报告。
RUSTFLAGS
环境变量交互?
它如何与 你应该可以像以前一样使用 RUSTFLAGS
环境变量。*目前 `--cfg` 参数不受检查,只有代码中的使用才受检查。*
这意味着执行 RUSTFLAGS="--cfg tokio_unstable" cargo check
不会报告任何警告,除非 tokio_unstable
在你的本地 crate 中被使用,在这种情况下,crate 作者需要在该 crate 的 build.rs
中使用 cargo::rustc-check-cfg
来确保该自定义 cfg 是预期的。
build.rs
的情况下声明预期的自定义 cfgs?
如何在没有 更新:Cargo 从 nightly-2024-05-19 开始提供了 [lints.rust.unexpected_cfgs.check-cfg]
配置来解决静态已知自定义 cfgs 的问题。
**目前没有其他方法**来声明预期的自定义 cfg,只能通过 build.rs
中的 cargo::rustc-check-cfg
。
不想使用 build.rs
且不能使用 [lints.rust.unexpected_cfgs.check-cfg]
的 crate 作者,建议改用 Cargo 特性。
它如何与其他构建系统交互?
非 Cargo 的构建系统默认不受此 lint 影响。希望获得相同功能的构建系统作者应查阅 rustc
文档中关于 --check-cfg
标志的详细解释,了解如何实现相同的功能。