直接回答:feature 在设计上是“纯增量”的:同一个 crate 在一次构建中只会编译一份,其 feature 集合是依赖图中所有使用方请求 feature 的并集。这意味着工作区里 crate A 开了某个依赖的 feature-foo,crate B 即使没声明,最终二进制里 B 看到的该依赖也带 foo。当 B 的代码用 #[cfg(feature)] 做条件编译或依赖 feature 不存在时的行为,就会出现“单独编译 B 没问题、合进工作区就挂(或行为改变)”的诡异现象。
展开解析:经典事故:no_std 库里某依赖默认带 std feature,工作区里另一个 crate 开启了它,导致整体无法再编译到嵌入式目标;或 feature 改变依赖的 MSRV/平台支持,间接破坏无关 crate。防御手段:feature 设计遵守加法原则——feature 只能开启能力,不能改变已有 API 语义(semver 要求);依赖声明时关掉 default-features 按需开启;用 cargo tree -f '{p} {f}' 审查实际启用的 feature 集合;resolver = "2"(edition 2021 默认)让构建依赖、开发依赖与目标特定依赖不参与统一,缓解但不根治同一目标的统一。发布库时配合 cargo hack test --each-feature / --feature-powerset 做 feature 组合测试,CI 里跑 --no-default-features 与全 feature 两端。理解这一点的元认知:feature 是构建图的属性而非单个 crate 的属性,排障时先怀疑“谁把 feature 带进来的”。
追问方向:弱依赖特性(dep: 与 ?/)语法解决什么?workspace 依赖如何统一版本?
(约 480 字)