Skip to content

Commit 31fa043

Browse files
committed
2026.8.27.1 —— 目标侧被解析出来了,只发给了一个编译单元
⭐ 与 2026.8.25.x / 2026.8.26.1 是同一族的下一层。那两批修的是「谓词问错了」 与「答案没接到决定上」;这一批里,答案接上了一个消费者,而它有五个。 ## ⭐⭐ 编译侧的谓词是 2026.8.26.1 在链接侧修掉的那条的孪生兄弟 `hostflags.cppm` 问 `!crossTargetFlag.empty()`——「命令行上有没有 `--target=`」—— 而它自己的注释写的是「目标侧来自图」。同机、同编译器、同目标,只差写不写 `--target`,编译线少六个 token: --no-default-config -nostdinc++ -isystem <payload>/include/c++/v1 -isystem <payload>/include/<triple>/c++/v1 -isystem <glibc>/include -isystem <linux-headers>/include ⇒ 头文件来自一个库,目标文件链自另一个库。两侧现在读同一个 `plan.targetSide.cAbi.prebuilt()`,由 prepare 记在 `Toolchain` 上供三个生产者共用。 ⚠️ `--no-default-config` 从该条件里拆出来无条件发:它不是载荷头文件集合的一部分, 而 cfg 按 post_install.cppm 自己的说法是「per-machine, per-install-path artifact」。 这也解释了报告者那个手写 `<triple>-clang++.cfg` 的 workaround 为什么有效。 ⚠️ e2e 295 写的就是这条恒等式,而它只比对 `^ldflags` ⇒ 恒等式在下一行不成立而测试 看不见。现在两条都比,并断言两侧非空。 ## ⭐⭐ 载荷目录名是 LLVM 词汇,查找用的是 mcpp 词汇,且失配静默 `include/<triple>/c++/v1` 由 LLVM 的构建写下(`x86_64-unknown-linux-gnu`), `tc.targetTriple` 是 mcpp 的(`x86_64-linux-gnu`)。两者只在三元组是探测来的时候 恰好相同。查找是 `if (exists) push_back`,找不到就什么也不发生 —— 而那个目录里 只有 `__config_site`,它的缺席产生的报错读起来像载荷坏了。两种拼法都试。 ## ⭐⭐ 由图供给的目标侧只到达一个编译单元(mcpp#514 §A) 提供 `mcpp:` 层的包发布的是整个目标编译时所依据的头文件集合,而它以 publicUsage 的形态沿依赖边传播 ⇒ 根与 provider 自己的单元拿得到,兄弟依赖包拿不到。结果是 一次构建里两种口味的 BMI(`reference to 'space' is ambiguous`)。 目标侧解析后,`fromGraph()` 的层的 publicUsage 并入每一个包的 privateBuild; std 模块的命令行改读同一个集合,不再自己推一遍。 ## ⭐⭐ 缓存键描述了编译器,没描述它被指向的头文件集合(mcpp#514 §B) `driverIdentity` 按设计覆盖不了它 —— `normalize_driver_output` 故意抹掉路径, 好让一个条目能被两个 home 共享。新增 `targetHeaderSet` 轴,取自已解析的 linkmodel,store-相对化。不 bump kCacheEpoch:旧条目是 miss 不是不可用。 ## ⭐ home 发现有第四份拷贝,而且会伸到别的 home 去 `active_home_xpkgs()` 自己重推一遍 home(漏掉自包含安装那一档); `find_sibling_package` 无条件回落 `~/.xlings/data/xpkgs` ⇒ 密闭构建可以从另一棵树 取载荷,结果直接进每条编译命令的 `-isystem`。前者改读 `mcpp::home::root()`, 后者删除 —— 找不到会说话,找错了不会。 ## 新增 `[build] private_include_dirs` 指出 include_dirs 中在本包边界处停住的条目。publicUsage 此前整份接过 privateBuild,于是内嵌带内部头覆盖层的库(musl 的 src/include 定义 hidden/weak/weak_alias)会把那些宏发给每个消费者。openkal-musl 的 port/include/features.h 自己写下了这个缺口和它的第一优解。 ⚠️ 它是 include_dirs 的子集而不是第二个列表:两类目录的相对顺序是承重的, 而两个 TOML 数组表达不了一个顺序。 ## 判据 - 单元 93 passed / 0 failed(新增 3 条,均确认真的在跑,非 SKIP) - e2e 295 扩到 cxxflags:修复后两工具链四条全绿;未修二进制上退出码 1 并列出六个丢失 token - e2e 304(新):目标侧到达兄弟依赖包 —— 未修二进制上变红 - e2e 305(新):编译用/发布用分开 —— 未修二进制上变红 - 三条 e2e 均带分母(CDB 行数),空 CDB 不会假绿 Closes #514
1 parent 078631d commit 31fa043

24 files changed

Lines changed: 4354 additions & 54 deletions

.agents/docs/2026-08-27-openkal-ecosystem-design-plan.md

Lines changed: 1842 additions & 0 deletions
Large diffs are not rendered by default.

.agents/docs/2026-08-27-openkal-native-path-three-issues.md

Lines changed: 1426 additions & 0 deletions
Large diffs are not rendered by default.

CHANGELOG.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,80 @@
33
> 本文件追踪 `mcpp-community/mcpp` 公开仓的版本演进。
44
> 格式参考 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/)
55
6+
## [2026.8.27.1] — 2026-08-27
7+
8+
目标侧被解析出来了,只发给了一个编译单元。完整分析见
9+
[`.agents/docs/2026-08-27-openkal-native-path-three-issues.md`](.agents/docs/2026-08-27-openkal-native-path-three-issues.md)
10+
11+
**`2026.8.25.x`/`2026.8.26.1` 是同一族的下一层。** 那两批修的是「谓词问错了」
12+
与「答案没接到决定上」;这一批里,答案**接上了一个消费者,而它有五个**
13+
14+
### 修复
15+
16+
- **⭐⭐ 编译侧的谓词,是 `2026.8.26.1` 在链接侧修掉的那条的孪生兄弟。**
17+
18+
`hostflags.cppm` 问的是 `!crossTargetFlag.empty()` ——「命令行上有没有
19+
`--target=`」——而它的注释写的是「目标侧来自图」。同一台机器、同一个编译器、
20+
同一个目标,只差写不写 `--target`,编译线少了**六个 token**:
21+
22+
```
23+
--no-default-config -nostdinc++
24+
-isystem <payload>/include/c++/v1
25+
-isystem <payload>/include/<triple>/c++/v1
26+
-isystem <glibc>/include
27+
-isystem <linux-headers>/include
28+
```
29+
30+
⇒ 头文件来自一个库,目标文件链自另一个库。两侧现在读同一个
31+
`plan.targetSide.cAbi.prebuilt()`。⚠️ `--no-default-config` 从这个条件里
32+
**拆了出来无条件发** —— 它不是载荷头文件集合的一部分,而 cfg 文件按
33+
`post_install.cppm` 自己的说法是「per-machine, per-install-path artifact」。
34+
35+
⚠️ `e2e 295` 写的就是这条恒等式,而它只比对 `^ldflags`,所以恒等式在**下一行**
36+
不成立而测试看不见。现在两条都比。
37+
38+
- **⭐⭐ 载荷目录名是 LLVM 词汇,而查找用的是 mcpp 词汇 —— 而且失配是静默的。**
39+
40+
`include/<triple>/c++/v1``lib/<triple>` 由 LLVM 的构建写下,带的是
41+
`x86_64-unknown-linux-gnu`;`tc.targetTriple` 是 mcpp 的
42+
`x86_64-linux-gnu`。两者只在三元组是**探测来的**时候恰好相同。查找是
43+
`if (exists) push_back`,所以找不到就什么也不发生 —— 而那个目录里只有一个文件,
44+
`__config_site`,它的缺席产生的报错读起来像载荷坏了。两种拼法现在都试。
45+
46+
- **⭐⭐ 由图供给的目标侧,只到达了一个编译单元(mcpp#514 §A)。**
47+
48+
提供 `mcpp:` 层的包发布的是**整个目标**编译时所依据的头文件集合,而它今天以
49+
`publicUsage` 的形态**沿依赖边**传播。于是根与 provider 自己的单元拿得到,而
50+
**兄弟依赖包**拿不到 —— `nlohmann.json` 不在 `openkal-llvm-runtime` 的下游,
51+
它在它旁边。结果是一次构建里两种口味的 BMI,任何同时导入两者的 TU 在第一个
52+
模板实例化处炸掉(`reference to 'space' is ambiguous`)。
53+
54+
⭐ 目标侧解析之后,`fromGraph()` 的层的 `publicUsage` 并入**每一个**包的
55+
`privateBuild`;`std` 模块的命令行也改读同一个集合,不再自己推一遍。
56+
57+
- **⭐⭐ 缓存键描述了编译器,没有描述它被指向的头文件集合(mcpp#514 §B)。**
58+
59+
A 轴上的每一项都在描述**编译器**,没有一项描述它编译时所依据的**** ——
60+
而两者是分开安装的。`driverIdentity` 按设计也覆盖不了它:
61+
`normalize_driver_output` **故意**抹掉路径,好让一个条目能被两个 home 共享。
62+
新增 `targetHeaderSet` 轴,取自已经解析好的 `linkmodel`,并 store-相对化。
63+
⚠️ 不 bump `kCacheEpoch` —— 旧条目是 miss 而不是不可用。
64+
65+
- **⭐ home 发现有第四份拷贝,而且会伸到别的 home 里去。**
66+
67+
`active_home_xpkgs()` 自己重推了一遍 home(漏掉自包含安装那一档);
68+
`find_sibling_package` 找不到时**无条件回落** `~/.xlings/data/xpkgs`
69+
后者意味着一次密闭构建可以从**另一棵树**取载荷,而结果直接进每条编译命令的
70+
`-isystem`。前者改为 `mcpp::home::root()`,后者删除 —— 找不到会说话,找错了不会。
71+
72+
### 新增
73+
74+
- **`[build] private_include_dirs`** —— 指出 `include_dirs` 中在本包边界处停住的
75+
条目。`publicUsage` 此前整份接过 `privateBuild` 的目录,于是一个内嵌了带内部头
76+
覆盖层的库(musl 的 `src/include` 定义 `hidden`/`weak`/`weak_alias`)会把那些宏
77+
发给每一个消费者。⚠️ 它是 `include_dirs`**子集**而不是第二个列表:两类目录的
78+
相对顺序是承重的,而两个 TOML 数组表达不了一个顺序。
79+
680
## [2026.8.26.2] — 2026-08-26
781

882
已经解析出的答案,没有被用来做决定。完整分析见

docs/05-mcpp-toml.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ module_extensions = [".ixx"] # Extra extensions used by module INTERFACES (
176176
build_program_timeout = 1800 # Seconds a build.mcpp may run; 0 = no limit (§ below)
177177
include_dirs = ["include", "third_party/include"] # Header search paths
178178
include_dirs_after = ["*"] # Header dirs searched AFTER system dirs (-idirafter)
179+
private_include_dirs = ["vendor/src/include"] # Of `include_dirs`, the ones a consumer must NOT get
179180
c_standard = "c11" # Standard for C source files (default c11)
180181
cflags = ["-DFOO=1"] # Extra C compile flags
181182
cxxflags = ["-DBAR=2"] # Extra C++ compile flags (do not put -std=... here)
@@ -190,6 +191,34 @@ jobs = "auto" # Concurrent compiles: a positive number, or "
190191
bmi_schedule = "auto" # Module-edge scheduling: auto (= off) | on | off (§ below)
191192
```
192193

194+
`private_include_dirs` names the entries **of `include_dirs`** that stop at this
195+
package's own boundary: this package compiles with them, and a consumer never
196+
receives them.
197+
198+
Almost every package publishes exactly the set it is built from, which is why
199+
`include_dirs` alone was enough for a long time. The shape where the two differ
200+
is a package that vendors a library with an *internal header overlay*. musl
201+
reaches its own declarations through `src/include`, whose headers define
202+
`hidden`, `weak` and `weak_alias` — names that mean something only to musl's own
203+
sources. Publishing that directory hands those macros to every consumer, and a
204+
consumer that uses `hidden` as an ordinary identifier stops compiling for a
205+
reason it has no way to see.
206+
207+
```toml
208+
[build]
209+
# ⚠️ The relative ORDER of the two kinds is load-bearing: the internal overlay
210+
# must precede the public headers for this package's own build. That is why
211+
# this is a SUBSET of `include_dirs` rather than a second list — two arrays
212+
# cannot express one order.
213+
include_dirs = ["port/include", "musl/src/include", "musl/include"]
214+
private_include_dirs = ["musl/src/include"]
215+
```
216+
217+
Entries take the same `*` glob convention as `include_dirs`, and are matched
218+
after expansion — so a glob may name exactly the directories it expands to. An
219+
entry that is not among this package's `include_dirs` withholds nothing and is
220+
reported as such rather than passing in silence.
221+
193222
`include_dirs_after` (#249) lists header directories that are searched **after**
194223
the toolchain's system directories (emitted as `-idirafter` on GCC/Clang, as
195224
trailing `/I` under the MSVC dialect, and as plain `-I` for NASM

docs/zh/05-mcpp-toml.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ module_extensions = [".ixx"] # 模块**接口**额外使用的扩展名(见
166166
build_program_timeout = 1800 # build.mcpp 的运行上限(秒);0 = 不限(见下节)
167167
include_dirs = ["include", "third_party/include"] # 头文件搜索路径
168168
include_dirs_after = ["*"] # 排在系统目录之后搜索的头文件目录(-idirafter)
169+
private_include_dirs = ["vendor/src/include"] # `include_dirs` 中不发布给消费者的那些
169170
c_standard = "c11" # C 源文件的标准(默认 c11)
170171
cflags = ["-DFOO=1"] # 额外 C 编译参数
171172
cxxflags = ["-DBAR=2"] # 额外 C++ 编译参数(不要放 -std=...)
@@ -178,6 +179,28 @@ jobs = "auto" # 并发编译数:正整数,或 "auto"(见下
178179
bmi_schedule = "auto" # 模块边调度:auto(= 关)| on | off(见下节)
179180
```
180181

182+
`private_include_dirs` 指出 **`include_dirs`**在本包边界处停住的那些条目:
183+
本包用它们编译,消费者永远收不到。
184+
185+
绝大多数包发布的就是它编译时用的那一套,所以长期以来只有 `include_dirs` 就够了。
186+
两者不同的形状只有一种 —— 一个包**内嵌了带内部头覆盖层的库**。musl 通过
187+
`src/include` 到达它自己的声明,而那些头定义了 `hidden``weak``weak_alias`,
188+
这些名字只对 musl 自己的源码有意义。把那个目录发布出去,等于把这些宏交给每一个
189+
消费者;而一个把 `hidden` 当普通标识符用的消费者会编不过,且看不出原因。
190+
191+
```toml
192+
[build]
193+
# ⚠️ 两类目录的**相对顺序**是承重的:本包自己构建时,内部覆盖层必须排在公共头之前。
194+
# 这正是它被设计成 `include_dirs` 的**子集**而不是第二个列表的原因 ——
195+
# 两个数组表达不了一个顺序。
196+
include_dirs = ["port/include", "musl/src/include", "musl/include"]
197+
private_include_dirs = ["musl/src/include"]
198+
```
199+
200+
条目支持与 `include_dirs` 相同的 `*` glob 约定,并在**展开之后**比对 ——
201+
所以一个 glob 可以恰好指名它展开出的那些目录。若某条目不在本包的 `include_dirs`
202+
里,它什么也没扣下,mcpp 会把这件事说出来而不是让它悄悄通过。
203+
181204
`include_dirs_after`(#249)列出**排在工具链系统目录之后**搜索的头文件目录
182205
(GCC/Clang 发射为 `-idirafter`;MSVC 方言退化为排在末尾的 `/I`,NASM 汇编
183206
单元退化为普通 `-I`——两者都没有对应 flag,也都没有需要保护的系统头搜索链)。当目录是解压后的源码 tarball 根目录、且其中的文件名会与标准头冲突时,

mcpp.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mcpp"
3-
version = "2026.8.26.2"
3+
version = "2026.8.27.1"
44
description = "Modern C++ build & package management tool"
55
license = "Apache-2.0"
66
authors = ["mcpp-community"]

src/build/build_program.cppm

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,15 @@ std::vector<std::string> host_base_flags(const mcpp::toolchain::Toolchain& tc,
291291
// undefined __cxa_* / __gxx_personality_v0.
292292
opt.cfgBypass = mcpp::toolchain::HostFlagOptions::CfgBypass::LinuxOnly;
293293
opt.clangStdlibSelect = true;
294+
// ⭐ `cAbiPrebuilt` is left at its default (true), and that is a statement
295+
// rather than an omission: `tc` here is always HOST-targeting (see this
296+
// function's header), so the helper's C library is the payload's whatever
297+
// the project's target side turns out to be.
298+
//
299+
// ⚠️ It also corrects a latent defect. The predicate this replaced was
300+
// `!tc.crossTargetFlag.empty()`, and a host toolchain resolved for a cross
301+
// build could carry one — in which case the helper lost the payload's own
302+
// headers for a reason that had nothing to do with it.
294303
// binutils -B so the driver finds ld/as (GCC; musl and MinGW ship their own).
295304
opt.binutilsPrefix = !mcpp::toolchain::is_musl_target(tc)
296305
&& !mcpp::toolchain::is_mingw_target(tc);

src/build/cache_key.cppm

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ import mcpp.manifest;
5656
import mcpp.modgraph.scanner;
5757
import mcpp.toolchain.detect;
5858
import mcpp.toolchain.fingerprint;
59+
import mcpp.toolchain.linkmodel;
5960
import mcpp.toolchain.triple;
6061
import mcpp.freestanding.target; // the flags a bare-metal triple implies
6162

@@ -97,6 +98,36 @@ struct BuildAxes {
9798
// Measured on exactly that upgrade. Empty for hosted targets, so nothing
9899
// else's key moves.
99100
std::vector<std::string> targetImpliedFlags;
101+
// ⭐⭐ THE HEADER SET THE DRIVER IS POINTED AT — not the driver.
102+
//
103+
// Everything else on this axis describes the COMPILER. Nothing described
104+
// the LIBRARY it compiles against, and the two are separately installed:
105+
// one clang payload sits above whichever `xim:glibc` and
106+
// `xim:linux-headers` the home happens to carry.
107+
//
108+
// ⚠️ AND `driverIdentity` CANNOT COVER IT, BY DESIGN.
109+
// `normalize_driver_output` deliberately strips `/home/`, `/tmp/` and
110+
// `/var/` paths out of `clang --version`, which is what lets one entry be
111+
// shared between two homes. Correct — and it means two homes carrying the
112+
// same clang above DIFFERENT glibc payloads produce the same
113+
// `driver_identity`, the same key, and one entry serving two header sets.
114+
//
115+
// Measured (mcpp#514 §B, third direction): two host builds resolving glibc
116+
// 2.39 and 2.44 hit one entry, and the mixed BMIs then crash the clang
117+
// frontend outright — SIGSEGV in
118+
// `ASTReader::FindExternalVisibleDeclsByName` during deserialization —
119+
// rather than producing a readable diagnostic. BMIs carry no cross-check
120+
// against each other.
121+
//
122+
// ⭐ THE `std` CACHE ON THE SAME MACHINE HAS ALWAYS HAD THIS. Its identity
123+
// folds in `std_build_commands`, the whole command line, `-isystem` rows
124+
// included. Two caches, one machine, two notions of "the same inputs"; the
125+
// dependency one was the short one.
126+
//
127+
// Store-relative, for the same reason the include dirs below are: the key
128+
// must survive a different MCPP_HOME, and what matters is WHICH payloads,
129+
// not where the home is.
130+
std::vector<std::string> targetHeaderSet;
100131
std::string stdlibId;
101132
std::string stdlibVersion;
102133
// B
@@ -163,7 +194,8 @@ BuildAxes build_axes(const mcpp::toolchain::Toolchain& tc,
163194
const mcpp::manifest::Manifest& rootManifest,
164195
std::string_view cppStandardFlag,
165196
const std::vector<std::string>& dialectFlags,
166-
std::string_view macosDeploymentTarget);
197+
std::string_view macosDeploymentTarget,
198+
const std::filesystem::path& storeRoot = {});
167199

168200
// Axes E from one PackageRoot. `storeRoot` is stripped off absolute include
169201
// dirs so the key survives a different MCPP_HOME (the payload paths are
@@ -217,6 +249,7 @@ nlohmann::json to_json(const BuildAxes& b, const PackageAxes& p) {
217249
{"driver_identity", b.driverIdentity},
218250
{"target_triple", b.targetTriple},
219251
{"target_implied_flags", b.targetImpliedFlags},
252+
{"target_header_set", b.targetHeaderSet},
220253
{"stdlib", b.stdlibId},
221254
{"stdlib_version", b.stdlibVersion},
222255
};
@@ -264,6 +297,7 @@ std::string key_hex(const BuildAxes& b, const PackageAxes& p) {
264297
put(s, "driver", b.driverIdentity);
265298
put(s, "triple", b.targetTriple);
266299
put_list(s, "targetflags", b.targetImpliedFlags);
300+
put_list(s, "hdrset", b.targetHeaderSet);
267301
put(s, "stdlib", b.stdlibId);
268302
put(s, "stdlibv", b.stdlibVersion);
269303
// B
@@ -302,7 +336,8 @@ BuildAxes build_axes(const mcpp::toolchain::Toolchain& tc,
302336
const mcpp::manifest::Manifest& rootManifest,
303337
std::string_view cppStandardFlag,
304338
const std::vector<std::string>& dialectFlags,
305-
std::string_view macosDeploymentTarget)
339+
std::string_view macosDeploymentTarget,
340+
const std::filesystem::path& storeRoot)
306341
{
307342
BuildAxes b;
308343
b.compilerId = std::string(tc.compiler_name());
@@ -349,6 +384,36 @@ BuildAxes build_axes(const mcpp::toolchain::Toolchain& tc,
349384
b.stdlibId = tc.stdlibId;
350385
b.stdlibVersion = tc.stdlibVersion;
351386

387+
// ⭐ THE HEADER SET, TAKEN FROM THE RESOLVERS THAT PRODUCE THE COMMAND
388+
// LINE — not derived a second time.
389+
//
390+
// `mcpp.toolchain.linkmodel` is already the single answer to "where does
391+
// this toolchain's C library and libc++ come from"; every consumer of a
392+
// compile line reads it. Asking it here means the key describes the header
393+
// set that will actually be used, and cannot drift from it.
394+
//
395+
// ⚠️ Store-relative. The absolute form names this machine's home, and the
396+
// whole point of `normalize_driver_output` stripping paths is that one
397+
// entry can serve two homes carrying the same payloads. Leaving these
398+
// absolute would undo that; folding them in relative distinguishes
399+
// DIFFERENT payloads while still sharing between homes.
400+
{
401+
const auto storeStr = storeRoot.generic_string();
402+
const mcpp::toolchain::PathEscape relativize =
403+
[&](const std::filesystem::path& p) -> std::string {
404+
auto str = p.generic_string();
405+
if (!storeStr.empty() && str.starts_with(storeStr))
406+
return "<store>" + str.substr(storeStr.size());
407+
return str;
408+
};
409+
for (auto& t : mcpp::toolchain::resolve_clang_driver(tc)
410+
.compile_tokens(relativize))
411+
b.targetHeaderSet.push_back(t);
412+
for (auto& t : mcpp::toolchain::resolve_link_model(tc)
413+
.compile_tokens(relativize))
414+
b.targetHeaderSet.push_back(t);
415+
}
416+
352417
b.cppStandard = rootManifest.package.standard;
353418
b.cppStandardFlag = std::string(cppStandardFlag);
354419
b.dialectFlags = dialectFlags;

src/build/flags.cppm

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,11 @@ CompileFlags compute_flags(const BuildPlan& plan) {
593593
mcpp::toolchain::HostFlagOptions hopt;
594594
hopt.cfgBypass = mcpp::toolchain::HostFlagOptions::CfgBypass::Always;
595595
hopt.macosDeploymentTarget = macosDeploymentTarget;
596+
// ⭐ THE SAME EXPRESSION THE LINK SIDE ASKS, twenty lines further down
597+
// (`plan.targetSide.cAbi.prebuilt()`). Reading one value at both sites
598+
// is what makes it impossible for them to disagree — which they did,
599+
// from #511 until now, because only the link side was corrected.
600+
hopt.cAbiPrebuilt = plan.targetSide.cAbi.prebuilt();
596601
compile_toolchain_flags = mcpp::toolchain::render_tokens(
597602
mcpp::toolchain::host_compile_tokens(plan.toolchain, hopt, ninjaEsc));
598603
} else {

0 commit comments

Comments
 (0)