Skip to content

Commit f02e72b

Browse files
committed
docs+report: the segment selects an ABI, and that ABI is not any row
复查时被问住两处,量了一遍,其中一处是我写错的。 **`musl 是 gnu ABI 吗?`** 不是,而且 `gnu` 也没在说 C 库。 对该次构建的产物实测: 导入的库 ntdll、KERNEL32、SHELL32 —— 无 msvcrt,无 ucrtbase _Z… 符号 4507 ?… 符号 0 第一行说明 `c-abi musl` 是老实的:MinGW 的 C 运行时一点没链进来。 **`libc++ 是 gnu?`** ⚠️ **不是,而我在上一版里写反了。** 我说 「`gnu` 对应的是 `c++-abi libc++` 那一行」,这是错的:`gnu` 选中的是 **Itanium C++ ABI**(那 4507 个 `_Z` 就是它),而 libc++ 是标准库的一个 实现,libstdc++ 是另一个,**两者都坐在同一套 ABI 上**。 ⭐ 真相是它**不对应任何一行**,而这正是要点。五层记录的是每一层 **由谁供给**;`gnu` 命名的是这些**对象遵循哪套约定** —— 若干层必须一致的 横切事项,不是一层。于是提示改为命名那套 ABI 本身: (gnu selects the Itanium C++ ABI, not a C library) `Itanium` 与 `MSVC` 不出现在任何一行里,因此不会像「the C++ ABI」那样 被误当成 `c++-abi` 那一层。这是把一个错误答案换成正确答案, 而不是把含糊换成含糊。 ⚠️ **名词取自值而非仅取自轴。** `gnu` 与 `msvc` 同轴而选中相反的 ABI, 按轴取名会给 MSVC 构建打印「Itanium」—— 那不只是含糊,是假的。 新增测试断言这一点,并断言提示里的名字**不等于任何一层的实现名**, 否则同一种混淆会换个地方重现。 三处带着那句错话的文本(model.cppm 注释、docs/15 中英)一并改掉。 targetside 单元测试 45 → 47,93 通过 / 0 失败。
1 parent 3afbc4f commit f02e72b

5 files changed

Lines changed: 138 additions & 20 deletions

File tree

CHANGELOG.md

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,29 @@
1919
读者在其中找不到一行叫 `gnu`,于是把它映到最像 C 库名字的那一行。
2020
它真正对应的是 `c++-abi`
2121

22-
于是在该段不命名 C 库的平台上,报告直接说出它命名的是什么:
22+
于是在该段不命名 C 库的平台上,报告直接说出它选中的是什么:
2323

2424
```
25-
Target x86_64-windows-gnu → x86_64-w64-windows-gnu (gnu names the object ABI, not a C library)
25+
Target x86_64-windows-gnu → x86_64-w64-windows-gnu (gnu selects the Itanium C++ ABI, not a C library)
2626
```
2727

28+
**它不对应报告里的任何一行,而这正是要点。** 对这次构建的产物实测:
29+
30+
| 观测 ||
31+
|---|---|
32+
| 导入的库 | `ntdll``KERNEL32``SHELL32` —— 无 `msvcrt`,无 `ucrtbase` |
33+
| Itanium 修饰符号(`_Z…`) | 4507 |
34+
| MSVC 修饰符号(`?…`) | 0 |
35+
36+
第一行说明 `c-abi musl` 是老实的:MinGW 的 C 运行时一点没链进来。
37+
五层记录的是每一层**由谁供给**;`gnu` 命名的是这些**对象遵循哪套约定**
38+
把它读成 `c++-abi libc++` 是第二个错误答案 —— libstdc++ 同样坐在
39+
Itanium ABI 上。因此报告命名那套 **ABI 本身**,它的名字不出现在任何一行里,
40+
于是不会被误当成某一层。
41+
42+
⚠️ 名词取自****而非仅取自轴:`gnu``msvc` 同轴而选中相反的 ABI,
43+
按轴取名会给 MSVC 构建打印「Itanium」—— 那不只是含糊,是假的。
44+
2845
内部把 `envNamesCAbi` 这个布尔换成 `EnvAxis`,因为布尔是对事实的有损编码:
2946
该段在 Linux 上是 C 库、Windows 上是对象 ABI、无操作系统时是对象格式。
3047
一个只回答「是否为第一种」的布尔,能压住错误的警告,却给不出正确的名字。

docs/15-openkal-cross.md

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,31 @@ Target x86_64-windows-gnu → x86_64-w64-windows-gnu
137137
```
138138

139139
finds no row called `gnu`, and maps it to the nearest thing that resembles a C
140-
library name. The row it belongs to is `c++-abi`. Where the segment does not
141-
name a C library, the report therefore names what it does:
140+
library name.
141+
142+
Measured on the artefact of exactly that build:
143+
144+
| Observation | Value |
145+
|---|---|
146+
| imported libraries | `ntdll`, `KERNEL32`, `SHELL32` — no `msvcrt`, no `ucrtbase` |
147+
| Itanium-mangled symbols (`_Z…`) | 4507 |
148+
| MSVC-mangled symbols (`?…`) | 0 |
149+
150+
The first row is why `c-abi musl` is honest: none of MinGW's C runtime is
151+
linked. The other two are what `gnu` selected — the Itanium C++ ABI rather than
152+
Microsoft's.
153+
154+
That correspondence is to no row of the report, and the absence is the point.
155+
The five layers record who **supplies** each layer; `gnu` names a convention the
156+
**objects follow**, which several layers must agree on. Reading it as `c++-abi
157+
libc++` is a second wrong answer: libc++ is one implementation of the standard
158+
library and libstdc++ is another, and both sit on the Itanium ABI.
159+
160+
The report therefore names the ABI itself, whose name appears in no row and so
161+
cannot be mistaken for one:
142162

143163
```
144-
Target x86_64-windows-gnu → x86_64-w64-windows-gnu (gnu names the object ABI, not a C library)
164+
Target x86_64-windows-gnu → x86_64-w64-windows-gnu (gnu selects the Itanium C++ ABI, not a C library)
145165
```
146166

147167
The segment carries a different axis on each platform — the C library on Linux,

docs/zh/15-openkal-cross.md

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,28 @@ Target x86_64-windows-gnu → x86_64-w64-windows-gnu
118118
```
119119

120120
在其中找不到一行叫 `gnu`,于是把它映到最像 C 库名字的那一行。
121-
它真正对应的是 `c++-abi`。因此在该段不命名 C 库的平台上,
122-
报告直接说出它命名的是什么:
121+
122+
对这次构建的产物实测:
123+
124+
| 观测 ||
125+
|---|---|
126+
| 导入的库 | `ntdll``KERNEL32``SHELL32` —— 无 `msvcrt`,无 `ucrtbase` |
127+
| Itanium 修饰符号(`_Z…`) | 4507 |
128+
| MSVC 修饰符号(`?…`) | 0 |
129+
130+
第一行说明 `c-abi musl` 是老实的:MinGW 的 C 运行时一点没链进来。
131+
后两行是 `gnu` 实际选中的东西 —— Itanium C++ ABI,而不是微软那套。
132+
133+
⭐ 而它**不对应报告里的任何一行**,这正是要点。五层记录的是每一层
134+
**由谁供给**;`gnu` 命名的是这些**对象遵循哪套约定**,是若干层必须一致的
135+
横切事项。把它读成 `c++-abi libc++` 是第二个错误答案:libc++ 是标准库的
136+
一个实现,libstdc++ 是另一个,两者都坐在 Itanium ABI 上。
137+
138+
因此报告直接说出那套 ABI 本身 —— 它的名字不出现在任何一行里,
139+
于是不会被误当成某一层:
123140

124141
```
125-
Target x86_64-windows-gnu → x86_64-w64-windows-gnu (gnu names the object ABI, not a C library)
142+
Target x86_64-windows-gnu → x86_64-w64-windows-gnu (gnu selects the Itanium C++ ABI, not a C library)
126143
```
127144

128145
该段在每个平台上承载不同的轴 —— Linux 上是 C 库,Windows 上是对象 ABI,

src/targetside/model.cppm

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,21 @@ constexpr std::string_view origin_name(Origin o) {
7878
// reading `c-abi musl` is not left to work out which row `gnu` belongs to.
7979
enum class EnvAxis { Unknown, CLibrary, ObjectAbi, ObjectFormat };
8080

81-
// The noun for an axis, as it appears in the report. Empty for `Unknown`,
81+
// The noun for a segment, as it appears in the report. Empty for `Unknown`,
8282
// because a report that cannot name the axis says nothing rather than guessing.
83-
inline std::string_view env_axis_noun(EnvAxis a) {
83+
//
84+
// ⚠️ THE VALUE, NOT ONLY THE AXIS. `gnu` and `msvc` sit on the same axis and
85+
// select opposite ABIs, so a noun fixed per axis would print "the Itanium C++
86+
// ABI" for an MSVC build. Naming the ABI rather than the axis is deliberate:
87+
// `Itanium` and `MSVC` appear in no row of the report, so neither can be
88+
// mistaken for a layer the way "the C++ ABI" would be.
89+
inline std::string_view env_axis_noun(EnvAxis a, std::string_view segment = {}) {
8490
switch (a) {
8591
case EnvAxis::CLibrary: return "a C library";
86-
case EnvAxis::ObjectAbi: return "the object ABI";
92+
case EnvAxis::ObjectAbi:
93+
if (segment == "gnu") return "the Itanium C++ ABI";
94+
if (segment == "msvc") return "the MSVC C++ ABI";
95+
return "the object ABI";
8796
case EnvAxis::ObjectFormat: return "the object format";
8897
case EnvAxis::Unknown: break;
8998
}
@@ -751,11 +760,23 @@ inline std::string format_report(const TargetSide& ts, std::string_view targetNa
751760
// READER IS LOOKING AT IT.
752761
//
753762
// `x86_64-windows-gnu` above a line reading `c-abi musl` is not a
754-
// contradiction: on Windows `gnu` names the object ABI, and the row it
755-
// actually corresponds to is `c++-abi`. But the report contains no row
756-
// called `gnu`, so a reader maps it to the nearest thing that looks like a
757-
// C library name and concludes the build disagrees with itself. Measured
758-
// twice, by the same reader, on two different days.
763+
// contradiction. Measured on the artefact of exactly that build:
764+
//
765+
// imports ntdll, KERNEL32, SHELL32 — no msvcrt, no ucrtbase
766+
// `_Z…` symbols 4507
767+
// `?…` symbols 0
768+
//
769+
// The first line is why `c-abi musl` is honest: none of MinGW's C runtime
770+
// is linked. The other two are what `gnu` actually selected — the Itanium
771+
// C++ ABI rather than Microsoft's.
772+
//
773+
// ⭐ AND IT CORRESPONDS TO NO ROW OF THIS REPORT, WHICH IS THE POINT. The
774+
// five layers record who SUPPLIES each layer; `gnu` names a convention the
775+
// OBJECTS FOLLOW, and several layers must agree on it. Pointing the reader
776+
// at `c++-abi libc++` would be a second wrong answer: libc++ is one
777+
// implementation of the standard library, libstdc++ is another, and both
778+
// sit on the Itanium ABI. The gloss therefore names the ABI itself, whose
779+
// name appears in no row and so cannot be mistaken for one.
759780
//
760781
// A warning would be wrong — it would fire on every legitimate MinGW build
761782
// and would say something false. A noun on the head line is not a
@@ -770,8 +791,9 @@ inline std::string format_report(const TargetSide& ts, std::string_view targetNa
770791
&& !ts.requestedCAbi.empty()
771792
&& !ts.cAbi.absent() && ts.cAbi.fromGraph()
772793
&& ts.cAbi.interfaceName != ts.requestedCAbi) {
773-
head += std::format(" ({} names {}, not a C library)",
774-
ts.requestedCAbi, env_axis_noun(ts.envAxis));
794+
head += std::format(" ({} selects {}, not a C library)",
795+
ts.requestedCAbi,
796+
env_axis_noun(ts.envAxis, ts.requestedCAbi));
775797
}
776798
head += '\n';
777799

tests/unit/test_targetside.cpp

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,7 @@ TEST(TargetSideReport, AnEnvSegmentThatIsNotACLibraryIsGlossed) {
476476
in.envAxis = ts::EnvAxis::ObjectAbi;
477477

478478
auto r = ts::format_report(ts::resolve(in), "x86_64-windows-gnu");
479-
EXPECT_NE(r.find("gnu names the object ABI, not a C library"),
479+
EXPECT_NE(r.find("gnu selects the Itanium C++ ABI, not a C library"),
480480
std::string::npos) << r;
481481
}
482482

@@ -492,10 +492,52 @@ TEST(TargetSideReport, OnBareMetalTheSegmentNamesTheObjectFormat) {
492492
in.envAxis = ts::EnvAxis::ObjectFormat;
493493

494494
auto r = ts::format_report(ts::resolve(in), "riscv64-none-elf");
495-
EXPECT_NE(r.find("elf names the object format, not a C library"),
495+
EXPECT_NE(r.find("elf selects the object format, not a C library"),
496496
std::string::npos) << r;
497497
}
498498

499+
// ⚠️ THE NOUN COMES FROM THE VALUE, NOT ONLY FROM THE AXIS.
500+
//
501+
// `gnu` and `msvc` sit on the same axis and select OPPOSITE ABIs. A noun fixed
502+
// per axis would print "the Itanium C++ ABI" for an MSVC build — a statement
503+
// that is not merely vague but false.
504+
TEST(TargetSideReport, TheOppositeValueOnTheSameAxisGetsTheOppositeName) {
505+
auto in = payload_linux();
506+
in.targetOs = "windows";
507+
in.compilerFamily = "llvm";
508+
in.cAbi = provider("openkal-musl", "0.3.3", "musl");
509+
in.requestedCAbi = "msvc";
510+
in.requestFreeTarget = "x86_64-windows";
511+
in.envAxis = ts::EnvAxis::ObjectAbi;
512+
513+
auto r = ts::format_report(ts::resolve(in), "x86_64-windows-msvc");
514+
EXPECT_NE(r.find("msvc selects the MSVC C++ ABI"), std::string::npos) << r;
515+
EXPECT_EQ(r.find("Itanium"), std::string::npos) << r;
516+
}
517+
518+
// ⭐ AND THE NAME IT PRINTS MUST NOT BE ANY ROW'S VALUE.
519+
//
520+
// Naming the ABI rather than the axis is what stops a reader mapping `gnu` to
521+
// `c++-abi libc++` — a second wrong answer, since libstdc++ sits on the same
522+
// ABI. If the gloss ever printed a string that also appears as a layer's
523+
// implementation name, the confusion would return in a new place.
524+
TEST(TargetSideReport, TheGlossNamesNothingThatAppearsAsALayerValue) {
525+
auto in = payload_linux();
526+
in.targetOs = "windows";
527+
in.compilerFamily = "llvm";
528+
in.cAbi = provider("openkal-musl", "0.3.3", "musl");
529+
in.cxxAbi = provider("openkal-llvm-runtime", "0.1.2", "libc++");
530+
in.requestedCAbi = "gnu";
531+
in.requestFreeTarget = "x86_64-windows";
532+
in.envAxis = ts::EnvAxis::ObjectAbi;
533+
534+
auto r = ts::format_report(ts::resolve(in), "x86_64-windows-gnu");
535+
auto head = r.substr(0, r.find('\n'));
536+
EXPECT_NE(head.find("Itanium"), std::string::npos) << head;
537+
EXPECT_EQ(head.find("libc++"), std::string::npos) << head;
538+
EXPECT_EQ(head.find("musl"), std::string::npos) << head;
539+
}
540+
499541
// ⚠️ AND IT DOES NOT FIRE WHEN THE C LIBRARY CAME FROM A PAYLOAD.
500542
//
501543
// A payload C library IS what the triple selected — the triple is how it was

0 commit comments

Comments
 (0)