Skip to content

Commit 7072ea6

Browse files
committed
fix(#519): 依赖目标的 feature 门只管库目标 —— 主机工具不是被门控的对象
`187_dep_host_tool.sh` 红。上一版的门抹掉了依赖包里**任何**种类的 feature-gated 目标,并附了一句「主机工具那条路会以依赖为根重进 prepare_build,所以到不了这里」—— 那句是**凭印象写的,不是读出来的**: 工具的查找在这段代码**下面几百行**,对着的正是这份 manifest,于是它读到 一个空的目标表。 被请求为主机工具的目标是**被要求的东西**,它的 `required_features` 是那次 子构建的**输入**而不是门(docs/05 §2.2 原文如此)。 收窄到库目标不是绕过,而是规则本身:依赖包的 `bin` 目标在本次构建里不产生 任何链接单元(make_plan 只走根的目标),留着它零成本;门要管的是「一个目标 仅仅存在就改变整个包对所有消费者的链接方式」,而那恰好就是 `shared` / `lib`。 本机:187 与 308 同时绿。
1 parent ab778e8 commit 7072ea6

1 file changed

Lines changed: 30 additions & 5 deletions

File tree

src/build/prepare.cppm

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5768,13 +5768,29 @@ prepare_build(bool print_fingerprint,
57685768
// feature name is package-scoped, so the root's set is a different
57695769
// vocabulary that happens to share a type.
57705770
//
5771-
// ⚠️ ONE EXCEPTION, and it is not a second rule: a target
5772-
// requested as a host tool is what was ASKED FOR, so its
5773-
// `required_features` become that sub-build's inputs instead of a
5774-
// gate (docs/05 §2.2). That path re-enters prepare_build with the
5775-
// dependency as the ROOT, so it never reaches this code.
5771+
// ⚠️⚠️ LIBRARY TARGETS ONLY, and the exclusion is load-bearing.
5772+
//
5773+
// A target requested as a HOST TOOL is what was ASKED FOR, so its
5774+
// `required_features` become that sub-build's INPUTS instead of a
5775+
// gate — docs/05 §2.2 says so in as many words. An earlier
5776+
// revision of this gate erased every kind, with a comment claiming
5777+
// the tool path "re-enters prepare_build with the dependency as
5778+
// the ROOT, so it never reaches this code". That was written from
5779+
// memory rather than read: the tool LOOKUP runs several hundred
5780+
// lines BELOW this point, against this very manifest, and it found
5781+
// an empty target list. `187_dep_host_tool.sh` caught it.
5782+
//
5783+
// Restricting the gate to libraries is not a workaround, it is the
5784+
// rule: a dependency's `bin` target produces no link unit in this
5785+
// build (make_plan only walks the ROOT's targets), so leaving it in
5786+
// place costs nothing. What the gate exists for is the shape where
5787+
// a target's mere presence changes how the package is linked into
5788+
// every consumer — and that is exactly a `shared` or `lib` target.
57765789
std::erase_if(pkg.manifest.targets,
57775790
[&](const mcpp::manifest::Target& t) {
5791+
if (t.kind != mcpp::manifest::Target::Library
5792+
&& t.kind != mcpp::manifest::Target::SharedLibrary)
5793+
return false;
57785794
for (auto const& rf : t.requiredFeatures)
57795795
if (std::find(active.begin(), active.end(), rf) == active.end())
57805796
return true;
@@ -7840,6 +7856,15 @@ prepare_build(bool print_fingerprint,
78407856

78417857
if (answer.linkage != lf::DepLinkage::Shared) continue;
78427858
if (facts.isDistribution) continue; // nothing here to build
7859+
// ⚠️ A package that ALREADY declares a shared target has decided
7860+
// for itself, and its remaining library targets are not part of
7861+
// that decision. Flipping them would change what such a package
7862+
// builds under the DEFAULT request, which is the one property this
7863+
// axis promises never to touch. (No package in mcpp-index has both
7864+
// shapes at once — compat.vulkan's `lib` is overridden to `shared`
7865+
// on Linux rather than joined by it — but "unreachable today" is
7866+
// how the last few of these got in.)
7867+
if (facts.declaredShared) continue;
78437868
for (auto* t : libraryTargets)
78447869
t->kind = mcpp::manifest::Target::SharedLibrary;
78457870
}

0 commit comments

Comments
 (0)