检查条件配置

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

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

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

注意: 要通过 Cargo 与此交互,请参阅 Cargo Specifics 页面。

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
nothingnothing--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 有两个 feature:lionzebralion feature 已启用,而 zebra feature 已禁用。

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