Commit b0747c9
authored
* feat(toolchain): linkmodel — single resolver for the C-library link axis
ToolchainLinkModel (CRT dir / lib dirs / loader / system includes, payload-first
with --sysroot fallback) + ClangDriverModel (cfg-bypass driver flags), replacing
the four divergent copies of this knowledge. Loader names come from data:
declared payload exports (.xpkg-exports.json) -> per-arch triple map -> glob,
never a hardcoded x86_64 string.
Part of the hermetic toolchain link model
(.agents/docs/2026-07-07-hermetic-toolchain-link-model-design.md, issue #195).
* fix(build): CRT discovery via linkmodel — payload link gains -B (fixes #195)
flags.cppm, stdmod.cppm and build_program.cppm host_base_flags now derive
their sysroot/payload flags from the shared link model. The clang-with-cfg
payload link path previously emitted only -L/-rpath/--dynamic-linker; the
driver resolves Scrt1.o/crti.o/crtn.o through -B prefixes and sysroot paths
only, so on hosts without a system toolchain it passed bare CRT names that
lld cannot open (issue #195), and on hosts with one it silently linked the
host's CRT. The model's link_flags carry -B<glibc-payload-lib>, so CRT
objects now resolve inside the payload everywhere.
build.mcpp host compiles stop trusting the sibling clang cfg (an
install-time-generated, per-machine artifact) and use the same explicit
flags as the main build.
* refactor(toolchain): one post-install fixup pipeline + deterministic cfg regeneration
ensure_post_install_fixup(cfg, payloadRoot, pkg) is now the single entry for
toolchain post-install fixups (gcc: patchelf + specs; llvm: patchelf(lib) +
cfg), called from all three install paths — explicit `toolchain install`,
default-toolchain auto-install, and manifest [toolchain] auto-install. The
manifest path previously ran NO fixup, so a fresh llvm auto-install kept its
stale install-time cfg and unpatched runtime libs (how the #195 reporter's
cfg still carried an install-time --sysroot while other installs didn't).
Idempotent via a content-fingerprinted marker (<payload>/.mcpp-fixup.json:
schema + kind + fixup rev + glibc lib) — drifted inputs re-run the fixup.
The ownership guard (inherited/symlinked payloads are not ours to patch) now
covers llvm too.
fixup_clang_cfg no longer line-patches whatever a given install produced: it
regenerates the cfg deterministically from the link model, so the same
payload yields byte-identical cfgs on every machine and install path — and a
human running clang++ directly now gets hermetic CRT discovery (-B) too.
All loader paths come from resolve_loader (no ld-linux-x86-64 hardcodes).
* refactor(probe): stop mining the clang cfg for --sysroot (diagnostic only)
The cfg-mined sysroot was dead trust: mcpp's fixup pipeline regenerates the
cfg without a --sysroot line (the C library comes from the payload link
model), so the mined value existed only on never-fixed-up installs and
pointed at an environment directory the payload doesn't own. Builds derive
everything from the link model; the cfg serves humans running clang++
directly. The parse is kept as a debug log.
* feat(build): hermetic link check — assert CRT/loader resolve inside the sandbox
Dry-run the driver (-###) with the exact ldflags the build will use and
assert every CRT object plus the EFFECTIVE dynamic linker (last occurrence
wins — the driver emits its built-in default before the -Wl override)
resolve under the sandbox's xpkgs registry or the toolchain sysroot.
This converts two previously silent failure modes into one actionable
build-time diagnostic: on hosts WITH a system toolchain the driver would
quietly link the host's CRT (contamination that made CI green a false
signal), and on hosts WITHOUT one it passed bare CRT names lld cannot open
(issue #195). Sandbox toolchains only — a PATH/system compiler is the
user's explicit choice of the host world. Verdict cached per flag-set
(.mcpp-hermetic-ok). Escape hatches: [build] allow_host_libs = true or
MCPP_ALLOW_HOST_LIBS=1.
* refactor: loader paths from data everywhere — no ld-linux-x86-64 hardcodes
fixup_gcc_specs detects the baked loader name from the specs content and
replaces it with resolve_loader()'s answer (any glibc arch); the specs dir is
discovered instead of assuming x86_64-linux-gnu. mcpp pack derives the
BundleProject PT_INTERP distro path from the loader soname ldd resolved for
the binary being packed (LSB /lib64 vs /lib), instead of a hardcoded x86_64
string. The only remaining literal loader names live in linkmodel.cppm's
per-arch triple map.
* test(e2e): 86_llvm_hermetic_link + llvm suite unpinned from 20.1.7
86 asserts, via a -### dry-run with the exact ldflags mcpp generated, that
every CRT object and the effective dynamic linker resolve inside the sandbox
(an xpkgs path) — failing on both regression modes of issue #195: bare CRT
names (link failure on hosts without a system toolchain) and host-CRT
contamination (silent on hosts with one).
The llvm e2e scripts (36-41, 47, 65) source the new _llvm_env.sh instead of
hardcoding llvm@20.1.7: MCPP_E2E_LLVM_VERSION overrides, default is the
newest installed payload — so new toolchain versions get coverage the day
they're installed instead of never.
* ci: hermetic e2e job — no host toolchain container
debian:stable-slim with NO compiler and NO host Scrt1.o: the only
environment class that faithfully reproduces issue #195 (standard runners
ship libc6-dev, so a sandbox toolchain leaking to the host CRT still links
green there). Bootstraps xlings + released mcpp, builds the PR code with the
sandbox gcc only, then runs the #195 manifest-llvm reproduction plus the
hermetic e2e subset.
* chore: 0.0.83 + changelog (hermetic toolchain link model)
* fix(hermetic): allow the canonical xpkgs registry for symlink-inherited payloads
mcpp passes symlink-view paths on the command line, but the clang driver
reports its own resource dir (clang_rt.crt*) through the canonical path;
with payloads symlink-inherited from another MCPP_HOME (the e2e isolation
pattern) that canonical registry must be allowed too.
* docs: hermetic toolchain link model design (issue #195)
* fix(fixup): specs-grammar-safe loader detection + macOS keeps cfg-trust semantics
Two regressions the first CI round caught (exactly the environments local
verification can't fake):
1. gcc specs corruption (linux): the rewritten detect walked the loader
path to 'whitespace/:;' — but specs embed the baked loader inside
%-spec conditionals (%{mmusl:...;:/baked/ld-linux-x86-64.so.2}), so the
scan swallowed closing braces and the rewrite corrupted the spec
grammar ('braced spec body ... is invalid' from every g++ run after).
Now: path-character whitelist scan, skip pristine /lib* multilib
defaults, unit-tested against the real spec grammar (incl. aarch64
loader names). detect_baked_loader is exported for the tests.
Fixup rev bumped (hermetic-2) so payloads stamped by the broken pass
re-run the fixup.
2. macOS host/cfg semantics: the cfg-bypass host flags and the
-nostdinc++/-stdlib=libc++ cfg regeneration are LINUX semantics; a bare
macOS link has no libc++abi handling (that lives in the main build's
needs_explicit_libcxx path) and died with undefined __cxa_* /
__gxx_personality_v0. build.mcpp host compiles keep trusting the cfg
off-Linux, and the macOS cfg keeps its historical shape
(--sysroot=<sdk> + payload libc++ headers only).
* ci: TEMP-DEBUG — capture core backtrace for the exit-time segfault (#196)
* fix(fixup): patchelf a copy + atomic rename — never rewrite live mappings
The fixup pipeline now runs on every toolchain install path, which means
the process executing it can itself be linked against the very libraries
being patched (a self-hosted mcpp loads the sandbox glibc/libgcc_s).
In-place patchelf rewrites the backing file of those live mappings and
corrupts the running process — reproduced deterministically on fresh-
sandbox CI as an exit-time SIGSEGV in _dl_fini jumping to an unrelocated
address (0x45a0), while a control run of main on the same fresh sandbox
passed (the old code only ever patched from the statically-linked
bootstrap mcpp, so the hazard was structural but unexposed).
patchelf now operates on a copy and atomically rename()s it into place:
the patched content gets a fresh inode, live processes keep the old one.
* Revert "ci: TEMP-DEBUG — capture core backtrace for the exit-time segfault (#196)"
This reverts commit 24d138e.
1 parent 5bfb2a1 commit b0747c9
29 files changed
Lines changed: 1886 additions & 467 deletions
File tree
- .agents/docs
- .github/workflows
- src
- build
- pack
- toolchain
- tests
- e2e
- unit
Lines changed: 347 additions & 0 deletions
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
117 | 117 | | |
118 | 118 | | |
119 | 119 | | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
6 | 37 | | |
7 | 38 | | |
8 | 39 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | | - | |
| 3 | + | |
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
| 17 | + | |
17 | 18 | | |
18 | 19 | | |
| 20 | + | |
19 | 21 | | |
20 | 22 | | |
21 | 23 | | |
| |||
116 | 118 | | |
117 | 119 | | |
118 | 120 | | |
119 | | - | |
120 | | - | |
121 | | - | |
122 | | - | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
123 | 167 | | |
124 | 168 | | |
125 | 169 | | |
126 | | - | |
127 | | - | |
128 | | - | |
129 | | - | |
130 | | - | |
131 | | - | |
132 | | - | |
133 | | - | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
134 | 178 | | |
135 | 179 | | |
136 | 180 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
| 19 | + | |
19 | 20 | | |
20 | 21 | | |
21 | 22 | | |
| |||
153 | 154 | | |
154 | 155 | | |
155 | 156 | | |
156 | | - | |
157 | | - | |
158 | | - | |
159 | | - | |
160 | | - | |
161 | | - | |
162 | | - | |
163 | | - | |
164 | | - | |
165 | | - | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
166 | 169 | | |
167 | 170 | | |
168 | | - | |
169 | | - | |
| 171 | + | |
170 | 172 | | |
171 | 173 | | |
172 | 174 | | |
173 | | - | |
174 | | - | |
175 | | - | |
176 | | - | |
177 | | - | |
178 | 175 | | |
179 | 176 | | |
180 | | - | |
181 | | - | |
182 | | - | |
183 | | - | |
| 177 | + | |
| 178 | + | |
184 | 179 | | |
185 | 180 | | |
186 | 181 | | |
| |||
193 | 188 | | |
194 | 189 | | |
195 | 190 | | |
196 | | - | |
197 | | - | |
198 | | - | |
199 | | - | |
200 | | - | |
201 | | - | |
202 | | - | |
203 | | - | |
204 | | - | |
205 | | - | |
206 | | - | |
207 | | - | |
208 | | - | |
209 | | - | |
210 | | - | |
211 | | - | |
212 | | - | |
213 | | - | |
214 | | - | |
215 | | - | |
216 | | - | |
217 | | - | |
218 | | - | |
219 | | - | |
220 | | - | |
221 | | - | |
222 | | - | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
223 | 201 | | |
224 | | - | |
225 | | - | |
226 | | - | |
227 | | - | |
228 | | - | |
229 | | - | |
230 | | - | |
231 | | - | |
232 | | - | |
233 | | - | |
234 | | - | |
235 | | - | |
236 | | - | |
237 | | - | |
238 | | - | |
239 | | - | |
240 | | - | |
241 | | - | |
242 | | - | |
243 | | - | |
244 | | - | |
245 | | - | |
246 | | - | |
247 | | - | |
248 | | - | |
249 | | - | |
250 | | - | |
251 | | - | |
252 | | - | |
253 | | - | |
254 | | - | |
255 | | - | |
256 | | - | |
257 | | - | |
258 | | - | |
259 | | - | |
260 | | - | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
261 | 207 | | |
262 | 208 | | |
263 | 209 | | |
| |||
358 | 304 | | |
359 | 305 | | |
360 | 306 | | |
361 | | - | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
362 | 313 | | |
363 | | - | |
364 | | - | |
365 | | - | |
366 | | - | |
367 | | - | |
368 | | - | |
369 | | - | |
370 | | - | |
| 314 | + | |
| 315 | + | |
371 | 316 | | |
372 | 317 | | |
373 | 318 | | |
| |||
0 commit comments