Skip to content

Commit f2e52db

Browse files
committed
2026.10.5.2: shared-library link lines, native MSVC LTO and export discovery, std.compat on every Default row
- A shared library that is not the root's links with the graph's flags and its owner's closure (#771); the root's private ldflags no longer reach it. - Windows argv quoting doubles the backslashes before a closing quote; WindowsSdkDir is read without its trailing separator. - The COFF reader reads /bigobj objects and names /GL and import objects. - lto = true on cl.exe compiles with /GL and links and archives with /LTCG; export discovery and /GL meet as SPEC-004 §11 states (#770). - std.compat is built only when imported, on the GCC row too; the std and std.compat sources are set as one. - A workspace's [profile.*] is a root-position key, and its own package receives [workspace.package] and [workspace.build]. - [test] windows_code_page; mcpp's unit tests run in UTF-8. Design: .agents/docs/2026-10-05-std-module-pair-msvc-lto-and-export-discovery-design.md
1 parent 8d9bde2 commit f2e52db

58 files changed

Lines changed: 2841 additions & 618 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.agents/docs/2026-10-05-std-module-pair-msvc-lto-and-export-discovery-design.md‎

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

‎.agents/docs/README.md‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ superseded_by: 2026-09-07-....md # when status is superseded
1818
---
1919
```
2020

21-
325 records.
21+
326 records.
2222

2323
## By subject
2424

@@ -30,6 +30,7 @@ Records that declare one. Everything else is listed by date below.
3030

3131
### design
3232

33+
- [下一个版本的发布方案:标准库模块、原生 MSVC LTO 与导出发现、共享库的链接配置、Windows 参数引号(#768 后续、#770、#771)](2026-10-05-std-module-pair-msvc-lto-and-export-discovery-design.md) — active
3334
- [`mcpp run` hands the terminal to the program, and the follow-ups of #761, #763 and #765 (#766)](2026-10-05-run-terminal-handoff-and-766-follow-ups-design.md) — landed
3435
- [PR CI acceleration and the toolchain specification (#756, #757, #669)](2026-10-02-pr-ci-acceleration-and-the-toolchain-specification-design.md) — active
3536
- [工具与工具链的来源:声明、编程决定、可观察](2026-10-01-tool-and-toolchain-sources-design.md) — landed
@@ -116,6 +117,7 @@ Records that declare one. Everything else is listed by date below.
116117

117118
### 2026-10
118119

120+
- [下一个版本的发布方案:标准库模块、原生 MSVC LTO 与导出发现、共享库的链接配置、Windows 参数引号(#768 后续、#770、#771)](2026-10-05-std-module-pair-msvc-lto-and-export-discovery-design.md) — active
119121
- [`mcpp run` hands the terminal to the program, and the follow-ups of #761, #763 and #765 (#766)](2026-10-05-run-terminal-handoff-and-766-follow-ups-design.md) — landed
120122
- [PR CI acceleration and the toolchain specification (#756, #757, #669)](2026-10-02-pr-ci-acceleration-and-the-toolchain-specification-design.md) — active
121123
- [工具与工具链的来源:声明、编程决定、可观察](2026-10-01-tool-and-toolchain-sources-design.md) — landed

‎.gitignore‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,6 @@ examples/*/target/
5353

5454
# `mcpp test` writes a per-invocation scratch dir here.
5555
.mcpp/
56+
57+
# Local review reports (not part of the design record).
58+
/.agents/reviews/

‎CHANGELOG.md‎

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,79 @@
44
> Each `## [<version>]` section is that release's notes. Entries are written in English
55
> from 2026.9.28.3 on; earlier entries remain as written.
66

7+
## [2026.10.5.2] - 2026-10-05
8+
9+
This release closes mcpp#771 and mcpp#770 and the follow-ups of mcpp#768: the
10+
link line of a shared library that is not the root's, native MSVC LTO and its
11+
meeting with export discovery, and `std.compat` on every Default row. It also
12+
fixes the Windows quoting of an argument that ends in a backslash, and makes a
13+
workspace's `[profile.*]` and its own package behave as members do. No default
14+
toolchain changes. The design record is
15+
`.agents/docs/2026-10-05-std-module-pair-msvc-lto-and-export-discovery-design.md`.
16+
17+
### Fixed
18+
19+
- **A shared library links with its own package's flags (#771).** A shared
20+
library that is not the root's linked with the root's link line. In a
21+
workspace a member's `build.mcpp` libraries did not reach the member's own
22+
DLL (`LNK2019` on the symbol), and in every plan the root's private
23+
`ldflags`, and an unrelated member's, reached a dependency's image. Such a
24+
library now links with the graph's flags (the profile's `ldflags`, the words
25+
`[target.<selector>.abi]` renders) and those of the packages its owner
26+
reaches. E2E 884 reads the result from the produced images.
27+
- **Arguments ending in a backslash on Windows.** The quoting of a Windows
28+
command line escaped `"` but not the backslashes before it, so an argument
29+
ending in `\` closed no quote and shifted every argument after it. In a
30+
Visual Studio developer environment, whose `WindowsSdkDir` ends in `\`, the
31+
LLVM row's `import std` failed in the std module precompile. The quoting
32+
follows the argv rules of the Windows runtime, and `WindowsSdkDir` is read
33+
without its trailing separator, so one SDK has one cache key inside and
34+
outside a developer environment. E2E 888.
35+
- **`import std.compat` on the GCC row.** libstdc++'s `bits/std.compat.cc` was
36+
not built, and the first unit importing `std.compat` failed. It is built
37+
beside `std` now, as SPEC-009 §6.2 requires of a Default row. E2E 886.
38+
- **`/bigobj` objects take part in export discovery.** The reader of a DLL's
39+
objects reads the `/bigobj` layout. A `/GL` object, which has no symbol table,
40+
and an import object are reported as what they are; both were reported as
41+
`/bigobj` before.
42+
- **A workspace's `[profile.*]` reaches its members.** A virtual root's profiles
43+
reached no member and were ignored without a diagnostic. Profiles are now
44+
root-position keys, inherited by name, and a member's own table of a name
45+
replaces the workspace's. In a workspace with its own `[package]`, the root
46+
file's profile is the same for every selection, so `--workspace` plans one
47+
graph and compiles a shared library once. E2E 885.
48+
- **The unit tests of mcpp run in mcpp.exe's code page.**
49+
`Glob.EscapedSpellingIsUtf8WhateverTheName` constructed a Windows path from
50+
bytes that only a single-byte code page converts, and failed on a machine in
51+
the Chinese region; it passed on CI, whose code page is 1252. The test is
52+
corrected, and mcpp's tests run in UTF-8 as mcpp.exe does.
53+
54+
### Changed
55+
56+
- **`lto = true` on cl.exe.** It compiled nothing differently while the build
57+
summary said `+ lto`. It now compiles with `/GL` and links and archives with
58+
`/LTCG`. A DLL whose exports are discovered cannot hold `/GL` objects: when
59+
`windows_auto_export` is omitted, the packages linked into it compile with
60+
`/GL-` and the build reports this once (`+ lto (partial)`); a stated `true`,
61+
and `/GL` written into those packages' flags, are refused with
62+
`lto-export-discovery`.
63+
- **The root package's `[build] ldflags` no longer reach a dependency's shared
64+
library.** A dependency that needs a search path or a library states it in
65+
its own `ldflags` or `build.mcpp`. When the root names one and the plan holds
66+
a dependency's shared library, the build notes it under `link/root-flags`.
67+
- **A workspace's own package receives `[workspace.package]` and
68+
`[workspace.build]`** once, as every member does.
69+
- **`std.compat` is built only when a unit imports it**, and an import of it
70+
from a standard library that does not provide it is refused before any
71+
compile, naming the library.
72+
- **`mcpp pack` ships static libraries without LTO intermediate code**, which
73+
only the compiler release that wrote it can read.
74+
75+
### Added
76+
77+
- **`[test] windows_code_page`** states the code page of every discovered test
78+
program on Windows, with the values of the target key of the same name.
79+
780
## [2026.10.5.1] - 2026-10-05
881

982
This release gives the program that `mcpp run` starts the terminal, and closes

‎docs/04-mcpp-toml.md‎

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -343,9 +343,24 @@ executables, ELF, Mach-O and MinGW.
343343
MSVC-ABI target is planned, since `exports` narrows the discovered symbols; the
344344
same manifest builds on ELF and Mach-O.
345345

346-
Discovery reads COFF objects directly and LLVM bitcode (FullLTO and ThinLTO,
347-
alone or mixed with COFF objects) with the selected LLVM compiler and the
348-
`llvm-nm` beside it.
346+
Discovery reads COFF objects directly, including `/bigobj` objects
347+
(2026.10.5.2+), and LLVM bitcode (FullLTO and ThinLTO, alone or mixed with COFF
348+
objects) with the selected LLVM compiler and the `llvm-nm` beside it. An object
349+
compiled by cl.exe with `/GL` holds no symbol table and is reported by name.
350+
351+
**With LTO on cl.exe (2026.10.5.2+).** `lto = true` compiles with `/GL`, which
352+
leaves nothing to discover. The three ways of writing the key behave
353+
differently there, because only an omitted key is mcpp's to decide:
354+
355+
| Written | Result under `lto = true` on cl.exe |
356+
|---|---|
357+
| omitted | the packages whose objects the DLL links (its own and the static libraries placed in it) compile with `/GL-`; the DLL still links with `/LTCG`; the build reports this once and its summary reads `+ lto (partial)` |
358+
| `true` | refused when the target is planned (`lto-export-discovery`) |
359+
| `false` | full `/GL` and `/LTCG`; the sources declare the exports with `__declspec(dllexport)` |
360+
361+
`/GL` written into the flags of a package whose objects such a DLL links is
362+
refused in the same way, with or without `lto`. LLVM LTO on the MSVC ABI emits
363+
bitcode, which discovery reads, and is not affected.
349364

350365
#### `windows_subsystem` and `windows_entry` — a Windows GUI executable (mcpp 2026.9.12.2+)
351366

@@ -550,6 +565,18 @@ root, and a dependency's `ldflags` reach its consumer word by word. An element
550565
escaped for ninja or the shell by hand (`\$ORIGIN`, `'$$ORIGIN'`) now reads as
551566
written; the first plan names such an element under `build/flag-words`.
552567

568+
**Which link a package's `ldflags` reach (2026.10.5.2+).** The root package's
569+
own programs and shared libraries link with its `ldflags` and those of every
570+
package it reaches. A shared library that another package owns links with the
571+
graph's flags (the profile's `ldflags` and the words `[target.<selector>.abi]`
572+
renders for the link) and the `ldflags` of the packages its owner reaches,
573+
`build.mcpp` output included. Before 2026.10.5.2 such a library linked with the
574+
root's line, so the root's private flags and an unrelated workspace member's
575+
reached it, and in a workspace a member's own `build.mcpp` libraries did not
576+
(#771). A dependency that needs a search path or a library states it in its own
577+
`ldflags` or `build.mcpp`; when the root names one and the plan holds a
578+
dependency's shared library, the build notes this under `link/root-flags`.
579+
553580
`compile_commands.json` and `mcpp emit build-database` list the same words in
554581
`arguments`, ready to execute without a shell.
555582

@@ -1386,7 +1413,7 @@ where it would become a BMI path that nothing reports.
13861413
[profile.dist]
13871414
opt = 3 # -O level (a number, or the string "s"/"z")
13881415
debug = false # -g
1389-
lto = true # -flto (note: some packaged gcc builds ship without the LTO plugin)
1416+
lto = true # -flto; /GL + /LTCG on cl.exe (note: some packaged gcc builds ship without the LTO plugin)
13901417
strip = true # -s at link time
13911418
# passthrough escape hatch (fixed keys, open values):
13921419
cflags = ["-fno-plt"]
@@ -1819,6 +1846,7 @@ discover = ["tests/**/*.cpp"] # the default
18191846
| Key | Type | Meaning |
18201847
|---|---|---|
18211848
| `discover` | array of globs | every file a glob matches is one test program; a glob beginning with `!` removes the files it matches; `[]` discovers none |
1849+
| `windows_code_page` | `"utf-8"` or `"legacy"` | the ANSI code page of every test program on Windows, in the meaning of the target key of the same name; the default is `"legacy"`, the system's code page *(2026.10.5.2+)* |
18221850

18231851
The globs use the vocabulary of `[build] sources`. A test's name is its path
18241852
relative to the fixed directory of the first glob that matched it, without the
@@ -1827,6 +1855,12 @@ an array of non-empty strings is an error; any other key in `[test]` is a
18271855
warning, and an error under `--strict`. [08 — Testing](08-testing.md) describes
18281856
the test model.
18291857

1858+
A test program exercises the code it links, and that code may run in a
1859+
declared code page. `windows_code_page = "utf-8"` lets the tests run in the same
1860+
one, so that their result does not depend on the region setting of the machine
1861+
that runs them. The test programs receive the application manifest and nothing
1862+
else of `[resources]`.
1863+
18301864

18311865
## 3. Worked Examples
18321866

‎docs/07-workspace.md‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,30 @@ in the workspace root is already inherited by every member, per triple, with the
282282
member winning. A second spelling for the same capability would be surface with
283283
no function.
284284

285+
**Profiles are inherited by name (2026.10.5.2+).** A `[profile.<name>]` in the
286+
workspace root reaches every member that does not declare a profile of that
287+
name; a member's own table replaces the workspace's whole, as
288+
`[target.<triple>]` does. A profile is one value per graph, so members that
289+
share it are planned and compiled together. Before 2026.10.5.2 a virtual root's
290+
profiles reached no member and were ignored without a diagnostic, and a rooted
291+
workspace's applied only when its own package was the first one selected.
292+
293+
**The root package is a member.** In a workspace whose root carries
294+
`[package]`, the root package receives `[workspace.package]` and
295+
`[workspace.build]` once, as every other member does (2026.10.5.2+), so its
296+
commands are the same in every selection. The root manifest holds three kinds
297+
of keys:
298+
299+
| Keys | Owner | Effect on the root package | Effect on other members |
300+
|---|---|---|---|
301+
| `[workspace]`, `[workspace.dependencies]` | the workspace | through `x.workspace = true` | through `x.workspace = true` |
302+
| `[workspace.package]`, `[workspace.build]` | the workspace | inherited | inherited |
303+
| `[toolchain]`, `[target.<triple>]`, `[indices]`, `[profile.<name>]` | the root position | its own | inherited where the member is the root of a build; the member's own declaration wins |
304+
| `[package]`, `[build]`, `[dependencies]`, `[targets]`, `[features]`, `[resources]`, `[test]` | the root package | its own | none |
305+
306+
The root package's `[build] ldflags` are its own as well: they reach its own
307+
images, and neither the members' images nor a dependency's shared library.
308+
285309
### 4.2 One standard for the whole module graph
286310

287311
A C++ module graph has exactly one standard: BMIs are not compatible across

‎docs/12-binary-distribution.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,14 @@ archive is only ever `--strip-debug`ed, because `--strip-all` removes the
345345
archive symbol index and the consumer's link then fails with `archive has no
346346
index; run ranlib to add one`.
347347

348+
### LTO intermediate code is not shipped (2026.10.5.2+)
349+
350+
A profile with `lto = true` compiles a packed static library's objects without
351+
LTO: no `-flto` intermediate code, and no `/GL` objects on cl.exe. Such code is
352+
readable only by the compiler release that wrote it, and a prebuilt archive is
353+
consumed by other releases. The build reports this once and its summary reads
354+
`+ lto (partial)`. Programs and shared libraries in the same build keep LTO.
355+
348356
## Current limitations
349357

350358
| | status |

‎docs/20-toolchains.md‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,6 +1034,24 @@ The device row keeps `runner` unset. An artifact cannot be run off an iOS
10341034
device without a signature the developer owns, which is not something a build
10351035
tool can supply.
10361036

1037+
## The standard library modules: `std` and `std.compat`
1038+
1039+
A toolchain provides `import std` when its standard library ships the module
1040+
source, and `import std.compat` when it ships the second one beside it. The two
1041+
are read from one directory and offered as a pair (2026.10.5.2+):
1042+
1043+
| Standard library | `std` | `std.compat` |
1044+
|---|---|---|
1045+
| libstdc++ (GCC 15 and later) | `bits/std.cc` | `bits/std.compat.cc` (2026.10.5.2+) |
1046+
| libc++ | `std.cppm` | `std.compat.cppm` |
1047+
| MSVC STL (cl.exe and the llvm row on the MSVC ABI) | `modules/std.ixx` | `modules/std.compat.ixx` (llvm row 2026.10.5.1+) |
1048+
| a package (`[package] std-module`) | its `std-module` | its `std-compat-module`, or none |
1049+
1050+
Each module is compiled once per configuration into the global cache, and
1051+
`std.compat` only when a unit of the build imports it (2026.10.5.2+). A build
1052+
that imports `std.compat` from a library that does not provide it is refused
1053+
before any compile, naming the library.
1054+
10371055
## Project-Level Version Pinning
10381056

10391057
If a project needs to pin a specific version rather than rely on the global default, declare it in the project's `mcpp.toml`:

‎docs/50-machine-output.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,7 @@ a program classifying the outcome reads `reason`:
486486
| `managed-only` | `--managed-only` met a source that is not the ecosystem's: the message names each one and where it was stated *(2026.10.1.3+)* |
487487
| `payload-override` | an `[xlings.overrides]` entry names a path that does not exist, a version a requirement refuses, or is stated by a dependency *(2026.10.1.3+)* |
488488
| `payload-request` | a build program asked for a payload no manifest of this build declares `provision = "on-request"`, or asked again in three consecutive runs *(2026.10.1.3+)* |
489+
| `lto-export-discovery` | a PE shared library whose exports are discovered would be compiled by cl.exe into `/GL` objects, which hold no symbol table: `windows_auto_export = true` stated under `lto = true`, or `/GL` written into the flags of a package it links *(2026.10.5.2+)* |
489490
| `local-toolchain` | a toolchain named by path, or stated by a build program's toolchain phase, cannot be used: no driver, a contradicting family, a missing tool or sysroot *(2026.10.1.3+)* |
490491
| `convention-unreplaced` | the convention was overridden and nothing replaced it |
491492
| `os-mismatch` | the requested and resolved triples name different systems |

‎docs/specs/README.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,12 @@
3333
| [SPEC-001](package-identity.md) | 包身份(`package.namespace` / `package.name`)、`[dependencies]` 选择器与匹配机制 | 评审中 v1.1 | 2026-08-03 | mcpp >= 0.0.106 |
3434
| [SPEC-002](target-side.md) | 目标侧模型与能力声明(`mcpp:` 保留命名空间、五层、三条规则) | 评审中 v1.0 | 2026-08-24 | mcpp >= 2026.8.24.2 |
3535
| [SPEC-003](exit-codes.md) | 退出码契约(分类、语义、稳定性承诺) | 评审中 v1.0 | 2026-09-01 | mcpp >= 2026.9.1.1 |
36-
| [SPEC-004](manifest-semantics.md) | `mcpp.toml` 的平面划分、条件化形状、解析轴与命名规约 | 草案 v1.11 | 2026-10-05 | 条件化形状 mcpp >= 2026.8.29.1;目标轴 mcpp >= 2026.9.6.4;`linkage` 默认值 mcpp >= 2026.9.15.2;链接 flag 的词读法 mcpp >= 2026.9.26.2;条件化的 `dialect_cxxflags` 与 `-p` 的包身份 mcpp >= 2026.9.28.1;条件表按具体程度生效 mcpp >= 2026.9.28.2;平台前缀规约 mcpp >= 2026.10.5.1 |
36+
| [SPEC-004](manifest-semantics.md) | `mcpp.toml` 的平面划分、条件化形状、解析轴与命名规约 | 草案 v1.12 | 2026-10-05 | 条件化形状 mcpp >= 2026.8.29.1;目标轴 mcpp >= 2026.9.6.4;`linkage` 默认值 mcpp >= 2026.9.15.2;链接 flag 的词读法 mcpp >= 2026.9.26.2;条件化的 `dialect_cxxflags` 与 `-p` 的包身份 mcpp >= 2026.9.28.1;条件表按具体程度生效 mcpp >= 2026.9.28.2;平台前缀规约 mcpp >= 2026.10.5.1;根包的继承、根位置的 profile、链接 flag 的作用域、链接期优化与导出发现 mcpp >= 2026.10.5.2 |
3737
| [SPEC-005](build-database.md) | 构建数据库:`mcpp emit build-database` 的内容、取值规则与不写工程目录的保证 | 评审中 v1.6 | 2026-09-29 | mcpp >= 2026.9.15.1;v1.3 条款 mcpp >= 2026.9.26.2;v1.4 条款 mcpp >= 2026.9.27.1;v1.5 条款 mcpp >= 2026.9.28.1;v1.6 条款 mcpp >= 2026.9.29.5 |
3838
| [SPEC-006](toolchain-management.md) | 工具链管理:身份、来源、选择与载荷契约 | 草案 v0.6 | 2026-10-02 | 逐条标注;已实现条款 mcpp >= 2026.9.24.1;§3.7 mcpp >= 2026.9.28.1;§3.7.1 mcpp >= 2026.9.28.2;§2.2.1 与 §3.3 的非缺省来源 mcpp >= 2026.10.1.3 |
3939
| [SPEC-007](build-plugins.md) | 构建插件:配置、施工与校验的分工,运行时与规划期的义务 | 草案 v0.6 | 2026-09-28 | 逐条标注;mcpp >= 2026.9.26.2;v0.3 条款 mcpp >= 2026.9.27.1;v0.4 条款 mcpp >= 2026.9.28.1;v0.5 条款 mcpp >= 2026.9.28.2;v0.6(§9)mcpp >= 2026.9.28.3 |
4040
| [SPEC-008](library-interface.md) | 库的接口:公开模块、发布闭包与两种形态的一致 | 草案 v0.1 | 2026-09-28 | 第一阶段(只警告)mcpp >= 2026.9.28.3 |
41-
| [SPEC-009](toolchain-maintenance.md) | 工具链的支持与维护:版本线、默认值、来源、移动与退役 | 草案 v0.2 | 2026-10-05 | 逐条标注;本版只有规范,多数条款未实现 |
41+
| [SPEC-009](toolchain-maintenance.md) | 工具链的支持与维护:版本线、默认值、来源、移动与退役 | 草案 v0.3 | 2026-10-05 | 逐条标注;本版只有规范,多数条款未实现 |
4242

4343
## 文档约定
4444

0 commit comments

Comments
 (0)