
rustc 的 --check-cfg 如何检查条件编译为 Cargo 项目声明期望的 cfg 名称与取值【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust#[cfg]条件写错了名字或取值——比如把windows拼成widnows、用了一个不存在的 feature——编译不会报错那段代码只是静默地不再参与编译。rustc的--check-cfg就是用来堵住这类问题的你用 check cfg 声明式在编译前声明哪些 cfg 名称和取值是预期的编译时所有可达的#[cfg]都会对照这份期望清单不匹配的名称或取值会触发unexpected_cfgslint默认级别为Warn。本文基于 Checking conditional configurations 与 Cargo Specifics 两篇 rustc 文档讲清楚如何在 rustc 命令行直接声明期望以及 Cargo 项目Cargo.toml、build.rs中的三种对应机制。--check-cfg 的声明语法基本形式rustc --check-cfg cfg(name, values(value1, value2, ... valueN))其中name是裸标识符不带引号values()里每一项是带引号的字符串字面量。name对应条件名称如feature、my_cfg每个value是该条件允许的取值之一。几种常用变体期望无值条件即#[cfg(foo)]这种写法在values()内使用none()谓词它可以和任意数量的value混排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()表示启用检查且没有任何用户自定义期望。几点行为边界来自文档的明确说明使用--cfg激活某个配置不会隐式加入期望清单所有期望名称和取值都必须通过 check cfg 声明式显式给出。同一条件的--check-cfg参数可以重复出现重复时各取值集合会合并values(any())优先。命令行上已经激活的--cfg参数本身目前不被检查文档注明未来可能改变。检查范围rustc承诺至少检查所有可达的reachable#[cfg]不可达的#[cfg]当前不检查但未来可能开始检查且不算破坏性变更。哪些写法会被检查、诊断长什么样只要指定了cfg(...)选项以下四种写法都会逐一对照期望清单#[cfg(name value)]属性#[cfg_attr(name value)]属性#[link(name a, cfg(name value))]属性cfg!(name value)宏调用当条件中出现不在期望清单里的取值或名称时编译器报告unexpected_cfgslint 诊断。下面是文档给出的诊断示例示例结果warning: unexpected cfg condition name: widnows -- lint_example.rs:1:7 | 1 | #[cfg(widnows)] | ^^^^^^^ | note: #[warn(unexpected_cfgs)] on by default也就是说验证方式是观察编译输出中是否出现unexpected_cfgs警告拼错的条件名、未声明的取值都会逐条列出文件位置编译通过且无此警告说明代码里用到的#[cfg]条件都落在声明的期望范围内。文档示例带 feature 的完整命令文档给出的一条可参考的命令example.rs为示意文件名替换为你要检查的文件rustc --check-cfg cfg(feature, values(lion, zebra)) \ --cfg featurelion example.rs这条命令行表示crate 有两个 featurelion和zebra当前启用的是lion。对应源码中的检查结果#[cfg(feature lion)] // 预期内lion 在期望取值列表中 fn tame_lion(lion: Lion) {} #[cfg(feature zebra)] // 预期内zebra 是期望取值只是本次未激活条件求值为 false fn ride_zebra(z: Zebra) {} #[cfg(feature platypus)] // 预期外platypus 不在期望取值中触发 unexpected_cfgs fn poke_platypus() {} #[cfg(feechure lion)] // 预期外feechure 不是已声明的条件名称触发 unexpected_cfgs fn tame_lion() {} #[cfg(windows unix)] // 预期外well known 的 windows cfg 不接受任何值触发 unexpected_cfgs fn tame_windows() {}这个例子顺带展示了--check-cfg与--cfg的分工--cfg负责激活某个条件决定条件是否为真--check-cfg负责声明预期决定条件是否合法。Well known names一批名称无需手动声明rustc维护了一份 well-known 名称及其取值的内置清单只要至少传入一个--check-cfg参数这些名称就会隐式加入期望。文档给出的清单截至 2026-08-11包括clippy、debug_assertions、doc、doctest、fmt_debug、miri、overflow_checks、panic、proc_macro、relocation_model、rust_analyzer、rustfmt、sanitize、sanitizer_cfi_generalize_pointers、sanitizer_cfi_normalize_integers、target_abi、target_arch、target_endian、target_env、target_family、target_object_format、target_feature、target_has_atomic、target_has_atomic_primitive_alignment、target_has_atomic_load_store、target_os、target_pointer_width、target_thread_local、target_vendor、ub_checks、contract_checks、unix、windows。因此#[cfg(target_arch x86_64)]这类目标相关条件不需要你逐个声明但要注意内置的windows/unix这类名称本身不带值写成#[cfg(windows unix)]仍然会触发 lint。与values(any())类似也可以给--check-cfg传入cfg(any())来关闭对 well-known 名称的检查。另有一条版本相关的说明从 1.85.0 起testcfg 被归为userspace配置——尽管它同样由rustc设置但文档认为它应当由构建系统自行管理即由构建系统在--check-cfg中声明。Cargo 项目中的三种声明方式Cargo 生态下期望清单有三个声明位置按配置来源的确定程度选择方式一feature 由 Cargo 自动声明Cargo.toml的[features]表中每个 featureCargo 都会自动把对应 cfg 声明为期望[features] serde [dep:serde] my_feature []所以对 feature 条件通常不需要再手动写--check-cfg只需检查代码中使用的 feature 名是否真的存在于[features]表。方式二Cargo.toml的[lints.rust]表静态已知的自定义 cfg当自定义配置是静态已知、不依赖 build script 时可以在[lints.rust]下用unexpected_cfgs的check-cfg项写入自定义静态--check-cfg参数[lints.rust] unexpected_cfgs { level warn, check-cfg [cfg(has_foo)] }方式三build.rs输出cargo::rustc-check-cfg动态决定的自定义 cfg当自定义配置由 build script 动态决定、通过cargo::rustc-cfg激活时对应的期望要用cargo::rustc-check-cfg指令声明Cargo 1.80 新增fn main() { println!(cargo::rustc-check-cfgcfg(has_foo)); // ^^^^^^^^^^^^^^^^^^^^^^ new with Cargo 1.80 if has_foo() { println!(cargo::rustc-cfghas_foo); } }排查与限制激活了但没声明--cfg只激活条件、不产生期望。代码里用到#[cfg(my_cfg)]时必须另有--check-cfg cfg(my_cfg)或 Cargo 侧对应机制声明否则触发 lint。--cfg与--check-cfg的对应关系文档给出了等价对照表转换时按此表核对--cfg对应的--check-cfg无无或--check-cfgcfg()仅启用检查--cfg foo--check-cfgcfg(foo)或--check-cfgcfg(foo, values(none()))--cfg foo--check-cfgcfg(foo, values())--cfg foobar--check-cfgcfg(foo, values(bar))--cfg foo1 --cfg foo2--check-cfgcfg(foo, values(1, 2))--cfg foo1 --cfg bar2--check-cfgcfg(foo, values(1)) --check-cfgcfg(bar, values(2))--cfg foo --cfg foobar--check-cfgcfg(foo, values(none(), bar))检查范围是可达的#[cfg]不可达条件当前不检查但文档明确保留未来开始检查的可能声明期望时不要依赖这个豁免。nightly 辅助手段--printcheck-cfg配合-Zunstable-options见 print-check-cfg可以把编译器当前使用的配置输出为可复用的--check-cfg参数适合用来核对实际生效的配置这是 nightly 不稳定选项不适用于稳定版构建流程。配置完成后跑一次编译编译输出里不再出现unexpected_cfgs警告、且代码中每个可达的#[cfg]名称与取值都在声明清单内即说明期望声明与实际使用一致新增 feature 或自定义 cfg 时记得同步更新[features]表、[lints.rust]或 build script 中的声明。【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考