检查条件配置

rustc 接受 --check-cfg 选项,该选项指定是否检查条件以及如何检查。--check-cfg 选项接受一个值,称为 *检查 cfg 规范*。此规范具有一种形式

  1. --check-cfg cfg(...) 将配置及其预期值标记为预期。

使用 --cfg 时不会添加隐式期望。用户应使用 *检查 cfg 规范* 传递所有预期名称和值。

cfg(...) 形式

cfg(...) 形式允许检查列表值条件中的值。它具有以下基本形式

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

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

当指定 cfg(...) 选项时,rustc 将检查每个 #[cfg(name = "value")] 属性、#[cfg_attr(name = "value")] 属性、#[link(name = "a", cfg(name = "value"))] 属性和 cfg!(name = "value") 宏调用。它将检查指定的 "value" 是否存在于预期值的列表中。如果 "value" 不在其中,则 rustc 将报告 unexpected_cfgs 警告诊断。此警告的默认诊断级别为 Warn

命令行 --cfg 参数目前 *未* 检查,但将来可能会检查。

要检查 *none* 值(即 #[cfg(foo)]),可以在 values() 中使用 none() 谓词:values(none())。它可以位于任何数量的 "value" 之前或之后。

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

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

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

  • 没有预期值(*将在每个值上发出警告*)

    rustc --check-cfg 'cfg(name, values())'
    
  • 未知预期值(*将永远不会发出警告*)

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

要避免重复相同的价值观,请使用以下形式

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

--check-cfg cfg(...) 选项可以重复,既可以针对相同的条件名称,也可以针对不同的名称。如果它针对相同的条件名称重复,则该条件的值集将合并在一起(优先级将赋予 values(any()))。

众所周知的名称和值

rustc 具有一个内部列表,其中包含众所周知的名称及其对应值。这些众所周知的名称和值遵循与其引用的内容相同的稳定性。

只要存在至少一个 --check-cfg 参数,就会始终启用众所周知的名称和值检查。

截至 2024-04-06T,已知名称列表如下

  • clippy
  • debug_assertions
  • doc
  • doctest
  • miri
  • overflow_checks
  • panic
  • proc_macro
  • relocation_model
  • 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
  • test
  • ub_checks
  • unix
  • windows

values(any()) 一样,可以通过将 cfg(any()) 作为参数传递给 --check-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"' -Z unstable-options example.rs

此命令行表明此板条箱具有两个功能:lionzebralion 功能已启用,而 zebra 功能已禁用。鉴于 --check-cfg 参数,已启用对名称和值的详尽检查。

example.rs:

#[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 still 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 compiler warning (by default).
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 while 'windows' is a well known
                             // condition name, it 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"' -Z unstable-options
#[cfg(is_embedded)]         // This condition is expected, as 'is_embedded' was provided in --check-cfg
fn do_embedded() {}         // and doesn't take any value

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

#[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 -Z unstable-options
#[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 in
                                 // 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() {}