检查条件配置

rustc 支持检查每个可到达的1 #[cfg] 是否与预期的配置名称和值列表匹配。

这有助于验证 crate 是否为不同的目标平台或特性正确处理了条件编译。它确保 cfg 设置在预期用途和实际使用之间保持一致,有助于在开发过程早期捕获潜在的错误或问题。

为了实现这一目标,rustc 接受 --check-cfg 标志,该标志指定是否检查条件以及如何检查它们。

注意: 关于通过 Cargo 与此交互,请参阅Cargo 细节页面。

1

rustc 承诺至少检查可到达的 #[cfg],尽管目前不检查不可到达的 #[cfg],但将来很可能会检查它们,这不会构成破坏性变更。

指定预期的名称和值

要指定预期的名称和值,check cfg 规范提供了 cfg(...) 选项,该选项允许指定预期的配置名称及其预期值。

注意: 使用 --cfg 时不会添加隐式预期。用户应使用check cfg 规范传递所有预期的名称和值。

其基本形式如下

rustc --check-cfg 'cfg(name, values("value1", "value2", ... "valueN"))'

其中 name 是一个裸标识符(没有引号),每个 "value" 项都是一个带引号的字面量字符串。name 指定条件的名称,例如 featuremy_cfg"value" 指定该条件名称的某个值。

指定 cfg(...) 选项时,rustc 将检查每个1

  • #[cfg(name = "value")] 属性
  • #[cfg_attr(name = "value")] 属性
  • #[link(name = "a", cfg(name = "value"))] 属性
  • cfg!(name = "value") 宏调用

命令行 --cfg 参数目前不被检查,但将来很可能会被检查。

rustc 将检查指定的 "value" 是否存在于预期值列表中。如果 "value" 不在该列表中,则 rustc 将报告一个 unexpected_cfgs lint 诊断信息。此 lint 的默认诊断级别是 Warn

要检查 none 值(即 #[cfg(foo)]),可以在 values() 内部使用 none() 谓词:values(none())。它可以在任意数量的 "value" 之前或之后出现。

要启用对值的检查,但提供一个 none/空集的预期值(即期望 #[cfg(name)]),请使用以下形式

rustc --check-cfg 'cfg(name)'
rustc --check-cfg 'cfg(name, values(none()))'

要启用对名称的检查但不检查值,请使用以下形式之一

  • 没有预期值(将对 name 的每个值进行 lint 检查

    rustc --check-cfg 'cfg(name, values())'
    
  • 未知预期值(永远不会对 name 的值进行 lint 检查

    rustc --check-cfg 'cfg(name, values(any()))'
    

为避免重复相同的数值集,请使用此形式

rustc --check-cfg 'cfg(name1, ..., nameN, values("value1", "value2", ... "valueN"))'

要在不指定任何名称或值的情况下启用检查,请使用此形式

rustc --check-cfg 'cfg()'

--check-cfg cfg(...) 选项可以重复使用,无论是对于相同的条件名称还是不同的名称。如果对相同的条件名称重复使用,则该条件的值集将合并(values(any()) 具有优先权)。

为了提供帮助,提供了 --cfg 参数与 --check-cfg 之间的等效表,请参见下方

已知名称和值

rustc 维护着一个已知名称及其对应值的列表,以避免手动指定它们的需要。

只要存在至少一个 --check-cfg 参数,就会隐式添加已知名称和值。

截至 2025-01-02T,已知名称列表如下

  • clippy
  • debug_assertions
  • doc
  • doctest
  • fmt_debug
  • miri
  • overflow_checks
  • panic
  • proc_macro
  • relocation_model
  • rustfmt
  • sanitize
  • sanitizer_cfi_generalize_pointers
  • sanitizer_cfi_normalize_integers
  • target_abi
  • target_arch
  • target_endian
  • target_env
  • target_family
  • target_feature
  • target_has_atomic
  • target_has_atomic_equal_alignment
  • target_has_atomic_load_store
  • target_os
  • target_pointer_width
  • target_thread_local
  • target_vendor
  • ub_checks
  • unix
  • windows

从 1.85.0 版本开始,test cfg 被视为“用户空间”配置,尽管它也由 rustc 设置,并且应由构建系统自身管理。

values(any()) 类似,可以通过将 cfg(any()) 作为参数传递给 --check-cfg 来禁用已知名称的检查。

--cfg 的等效表

此表描述了 --cfg 参数与 --check-cfg 参数之间的等效关系。

--cfg--check-cfg
--check-cfg=cfg() (用于启用检查)
--cfg foo--check-cfg=cfg(foo)--check-cfg=cfg(foo, values(none()))
--cfg foo=""--check-cfg=cfg(foo, values(""))
--cfg foo="bar"--check-cfg=cfg(foo, values("bar"))
--cfg foo="1" --cfg foo="2"--check-cfg=cfg(foo, values("1", "2"))
--cfg foo="1" --cfg bar="2"--check-cfg=cfg(foo, values("1")) --check-cfg=cfg(bar, values("2"))
--cfg foo --cfg foo="bar"--check-cfg=cfg(foo, values(none(), "bar"))

示例

示例:类似 Cargo 的 feature 示例

考虑此命令行

rustc --check-cfg 'cfg(feature, values("lion", "zebra"))' \
      --cfg 'feature="lion"' example.rs

此命令行表示此 crate 有两个特性:lionzebralion 特性已启用,而 zebra 特性已禁用。

#[cfg(feature = "lion")]     // This condition is expected, as "lion" is an
                             // expected value of `feature`
fn tame_lion(lion: Lion) {}

#[cfg(feature = "zebra")]    // This condition is expected, as "zebra" is an expected
                             // value of `feature` but the condition will evaluate
                             // to false since only --cfg feature="lion" was passed
fn ride_zebra(z: Zebra) {}

#[cfg(feature = "platypus")] // This condition is UNEXPECTED, as "platypus" is NOT
                             // an expected value of `feature` and will cause a
                             // the compiler to emit the `unexpected_cfgs` lint
fn poke_platypus() {}

#[cfg(feechure = "lion")]    // This condition is UNEXPECTED, as 'feechure' is NOT
                             // a expected condition name, no `cfg(feechure, ...)`
                             // was passed in `--check-cfg`
fn tame_lion() {}

#[cfg(windows = "unix")]     // This condition is UNEXPECTED, as the well known
                             // 'windows' cfg doesn't expect any values
fn tame_windows() {}

示例:多个名称和值

rustc --check-cfg 'cfg(is_embedded, has_feathers)' \
      --check-cfg 'cfg(feature, values("zapping", "lasers"))' \
      --cfg has_feathers --cfg 'feature="zapping"'
#[cfg(is_embedded)]         // This condition is expected, as 'is_embedded' was
                            // provided in --check-cfg and doesn't take any value
fn do_embedded() {}

#[cfg(has_feathers)]        // This condition is expected, as 'has_feathers' was
                            // provided in --check-cfg and doesn't take any value
fn do_features() {}

#[cfg(has_mumble_frotz)]    // This condition is UNEXPECTED, as 'has_mumble_frotz'
                            // was NEVER provided in any --check-cfg arguments
fn do_mumble_frotz() {}

#[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() {}

示例:没有值的条件名称

rustc --check-cfg 'cfg(is_embedded, has_feathers, values(any()))' \
      --cfg has_feathers
#[cfg(is_embedded)]      // This condition is expected, as 'is_embedded' was
                         // provided in --check-cfg as condition name
fn do_embedded() {}

#[cfg(has_feathers)]     // This condition is expected, as "has_feathers" was
                         // provided in --check-cfg as condition name
fn do_features() {}

#[cfg(has_feathers = "zapping")] // This condition is expected, as "has_feathers"
                                 // was provided and because *any* values is
                                 // expected for 'has_feathers' no
                                 // warning is emitted for the value "zapping"
fn do_zapping() {}

#[cfg(has_mumble_frotz)] // This condition is UNEXPECTED, as 'has_mumble_frotz'
                         // was not provided in any --check-cfg arguments
fn do_mumble_frotz() {}