Skip to content

The C library layer declares the C environment it presents, the engine realises and checks it - #668

Open
Sunrisepeak wants to merge 7 commits into
mainfrom
feat/c-environment
Open

Sunrisepeak wants to merge 7 commits into
mainfrom
feat/c-environment

Conversation

@Sunrisepeak

@Sunrisepeak Sunrisepeak commented Sep 17, 2026

Copy link
Copy Markdown
Member

Summary

Implements the mcpp side of "C environment declared by the C library layer"
(design 2026-09-18): a mcpp:c-abi=<impl> provider can declare, in a new
[c-abi] block, the C environment it actually presents to source — which
environment-identity macros are defined, the data model, wchar_t width,
and whether the compiler may assume platform-C-library extensions. mcpp
turns that declaration into compiler configuration for every target-side
unit, verifies the result against the real compiler rather than trusting
the declaration, and folds it into the build fingerprint.

Design: .agents/docs/2026-09-18-openkal-c-environment-and-personalities-design.md
in mcpplibs/openkal (§2, §3.2, §3.2.1, §3.3, §3.4, §5.4, §6, §8, §11, §12).

What's implemented

  1. [c-abi] manifest blockpresents (posix/windows/none),
    data-model (arch-default/lp64/llp64/ilp32), wchar (16/32),
    builtins (iso/platform, default platform). Only a package that
    also lists mcpp:c-abi=<impl> in provides may declare it — anything
    else is a parse error. presents/data-model/wchar carry no default;
    an unknown key or value is always a parse error naming the key. Absent
    block = today's behaviour, byte for byte.
  2. Realisation (src/toolchain/cenv.cppm) — a pure, table-driven
    mapping from (request, target) to compiler tokens, generic knowledge
    with no package names. The flagship case: presents = "posix" on
    Windows/x86_64 realises as a Cygwin-flavoured compile-only identity
    switch (--target=x86_64-pc-cygwin), leaving the link line on the
    graph's own resolved triple, because the two triples produce identical
    machine code (measured, design §1.4). __CYGWIN__/__CYGWIN32__ are
    left DEFINED under this switch — a design revision from the openkal-musl
    spike, not the original design text; see the dedicated note below.
    Reaches C, C++, assembly (.S, via its own broadcast channel — see the
    dedicated note below) and the dependency scan via each package's own
    build inputs, and the std module precompile via Toolchain. A request
    this engine cannot realise is refused, naming the target/request/what's
    missing. [package] c-environment = "platform" opts a package out of
    the realisation entirely — and is now INFERRED (not merely permitted) for
    any package that provides mcpp:kernel-abi=<impl>; see the dedicated
    note below.
  3. Verification, not trust (src/toolchain/cenv_probe.cppm) — one
    -E -dM predefined-macro dump (no codegen, no execution — the realised
    environment is routinely a cross target) compiled with the exact
    identity-affecting tokens, checked against the declaration
    (__SIZEOF_LONG__, __SIZEOF_WCHAR_T__, environment-identity macros).
    A mismatch fails the build printing both declared and measured. Cached
    per configuration.
  4. __openkal__ — defined for every target-side unit whenever the
    resolved kernel-abi layer's interface name is openkal (read from the
    layer, never a package name), independent of c-environment.
  5. Closure visibility — a package declares itself a platform dependency
    with the ordinary capability provides = ["platform-sdk"]; the Target
    report gains a platform-deps line (empty when none), and
    [build] platform-dependencies = "refuse" fails the build outright when
    one is present.
  6. Fingerprint — the realised environment and __openkal__ fold into
    the build fingerprint, so an LP64 and an LLP64 build of the same
    source/manifest never share an output directory.

What's designed but not implemented (documented as a known gap)

  • Store key for install-hook artifacts — traced to the code path, not
    left as a line in a gap table.
    An install hook CAN and does compile
    target-side code into the shared store (confirmed from
    install_hook_env/prepare.cppm), and the store is keyed by package +
    version only. This is NOT fixable the way the build-cache key above was:
    a hook runs BEFORE the toolchain resolves — prepare.cppm resolves tc
    only after the dependency graph installs, because resolving the target
    side can itself depend on which package the graph supplies a layer from
    — so at the moment a hook runs, no realised environment exists yet for it
    to consult. The failure mode, plainly: a hook compiling
    environment-sensitive C code has no way to ask what this build realised,
    so an inconsistent graph gets objects sized for one wchar_t linked
    against headers sized for another, with nothing checking it — the store
    records no environment for what it holds. This is the SAME shape as the
    already-shipped requires = ["mcpp:c++-abi=<impl>"] store-key gap, not a
    new one this PR introduces. Closing it for real needs either a two-phase
    install (defer target-side compilation in a hook until after target-side
    resolution) or extending the c++-abi requires-check pattern to
    c-abi/c-environment; both are out of this PR's scope. Full write-up:
    docs/22, "Store key — not yet closed".
  • The xpkg/index descriptor format (modules/manifest/src/xpkg.cppm) does
    not yet parse [c-abi]/c-environment — only mcpp.toml does. A package
    consumed as a local/git/path dependency is fully covered; one resolved
    through the package index is not yet. Flagged for follow-up.

Five design revisions from the openkal-musl spike, mid-PR

  • __CYGWIN__/__CYGWIN32__ stay defined, not undefined as originally
    designed. Portable third-party code that needs to know the object
    format
    — not the C environment, not the platform API — has no name for
    "PE format with a POSIX-presenting C environment" other than __CYGWIN__,
    and such code cannot be patched the way this ecosystem's own packages can.
    This is a trade-off for the 30-member measurement to settle, not a
    settled fact
    : a library reaching for __CYGWIN__ may also reach for a
    real Cygwin interface (sys/cygwin.h, cygwin_conv_path) that does not
    exist here, and the answer flips if that costs more than it fixes.

  • The realisation now reaches assembly (.S) units, not only C/C++. A
    .S unit's command line is assembled independently
    (mcpp.build.flags::CompileFlags::as), and only inherits the
    -D/-U/-I words of a package's C flags on purpose — a -std=/-O
    token meant for the C compiler is meaningless to GAS — so the broadcast
    into privateBuild.cflags/cxxflags never reached it. Real code
    (openkal-musl's okm_setjmp.S, upstream libunwind's assembly.h) selects
    register-save sets on these macros, so a .c unit and a .S unit in the
    same package disagreeing about _WIN32 is exactly the silent-mismatch
    class this feature exists to remove. Fixed with a new,
    broadcast-only UsageRequirements::asmflags channel, applied to GAS units
    only — NASM has no --target= concept and accepts none of these flags, so
    it must never receive them (Scanner.ResolvedCEnvAsmflagsReachGasUnitsOnlyNotNasm
    pins the split).

  • c-environment = "platform" is INFERRED for any mcpp:kernel-abi=<impl>
    provider, not merely permitted.
    Such a package is BY DEFINITION the
    platform boundary — its whole job is to speak the platform's ABI, so it
    can never be the package that wants the graph's presented environment
    instead. Measured without this: openkal-windows, compiled under the POSIX
    substitution like everything else in its graph, got a 32-bit wchar_t
    from -fno-short-wchar while the Win32 calls it makes hand back genuine
    16-bit UTF-16 — a wchar_t* loop then read two UTF-16 units as one code
    point. Inferred rather than required so every already-released
    implementation (openkal-windows 0.8.0, -macos 0.10.0, -linux 0.13.0, and
    whatever comes next) gets the boundary right with no new release and no
    coordinated version bump. Implemented in BOTH manifest parsers
    (modules/manifest/src/toml.cppm and xpkg.cppm — the latter matters
    because that is how a released implementation is actually consumed). An
    explicit c-environment in the package's own manifest still wins;
    precedence is written down in docs/22.

  • The global build cache's key (~/.mcpp/build-cache/v1,
    mcpp.build.cache_key) did not cover the realised environment at all —
    a release blocker, not a footnote.
    It read only a package's OWN
    declared cflags/cxxflags; the realised environment reaches a
    package's actual command line entirely through an engine broadcast
    (privateBuild.cflags/cxxflags, the same channel targetSideUsage and
    -D__openkal__ use). Two builds of the identical package realising two
    different environments therefore produced the identical key. Measured:
    upgrading mcpp in place, with the cache directory left alone, served
    objects compiled under the OLD realised environment into an image built
    under the new one — the exact invariant this whole design exists to
    protect, with no diagnosis. fill_package_config now folds in
    privateBuild.cflags/cxxflags/a new asmflags axis (post-broadcast)
    alongside the declared ones, exactly as it already did for include
    directories.

  • The cache-key fix above orphans the whole build cache: kCacheEpoch
    moves 2 → 3, so the first build after upgrading to this release is
    cold.
    A corrected key does not make an entry written under the old,
    wrong derivation safe to keep — an entry is poisoned exactly when its
    recorded key and its actual compiled inputs already disagreed at write
    time. The package most likely to still show an UNCHANGED key after the
    fix is precisely the one this same PR newly exempts from the realisation
    (a kernel-abi provider inferred into c-environment = "platform"): its
    privateBuild.cflags is now empty, so the new key is computed from
    nothing — matching the old key, which was also computed from nothing,
    while the object on disk was compiled WITH the substitution. No cheaper
    mechanism tells a pre-fix entry from a post-fix one. Also adds
    CacheKey.EveryPrivateBuildBroadcastFieldReachesTheKey, a durable guard
    for the class rather than only this instance: every member of
    PackageRoot::privateBuild has to move the cache key, and the two
    members nothing broadcasts into yet (ldflags, modules) are asserted
    uncovered on purpose, with an instruction to flip that assertion in the
    same change that adds their broadcast — this predates the c-abi wave
    (targetSideUsage's own broadcast and -D__openkal__ had the identical
    exposure before [c-abi] existed).

Two pre-existing defects found while verifying this, filed separately

Neither is caused by or fixed in this PR — both reproduce on unmodified
main.

The release binaries below are GCC-built to sidestep #666.

Two macOS CI jobs on THIS PR fail with a malformed-TAPI-file SDK error
("e2e suite (macOS ARM64, self-host, xcode-27)" and "macOS ARM64 — xlings
LLVM end-to-end (xcode-27)") — both out of scope, both pre-existing.
Run
35213851816 on main, from before this PR existed, fails the same job
("macOS ARM64 — xlings LLVM end-to-end (xcode-27)") with the identical
signature (ld64.lld: error: could not load TAPI file at .../MacOSX.sdk/usr/lib/libc++.tbd: malformed file). It's the runner-image
SDK problem already recorded in
.agents/docs/2026-09-17-openkal-0.13-ecosystem-record.md (open-limits
table); #665 already moved the raw compiles off that SDK, and the "xlings
LLVM end-to-end" job is the one still reading it directly.

Testing

  • tests/unit/test_manifest.cpp[c-abi]/c-environment parsing,
    validation, closed value sets, the provides-gate refusal, and that
    omitting [c-abi] leaves every read [package] key warning-free.
  • tests/unit/test_cenv.cpp — the full realisation mapping table (14
    cases): the three realisable rows, the builtins = "iso" survey result,
    and every refusal this table names, including the LP64/LLP64
    identity-switch contradiction the verification probe caught during
    development (see commit history) and which the mapping now refuses
    directly.
  • tests/e2e/741_c_abi_environment_declared_by_the_c_library.sh — a fake
    c-abi provider on x86_64-windows-gnu declaring
    presents=posix, wchar=32, builtins=iso; asserts via
    mcpp emit build-database that an ordinary consumer AND the provider's
    own units carry the realised tokens, that a c-environment = "platform"
    package does not, that a real GAS (.S) unit in the ordinary consumer
    carries the same tokens a .c/.cpp unit in the same package does, and
    that a presents=posix, data-model=llp64 declaration (unrealisable once
    the identity switch is in play) is refused naming the target and the
    request.
  • tests/unit/test_modgraph.cpp
    Scanner.ResolvedCEnvAsmflagsReachGasUnitsOnlyNotNasm: a resolved
    package's privateBuild.asmflags reaches a GAS unit's packageAsmflags
    and does NOT reach a NASM unit's, in the same package, in the same scan.
  • tests/unit/test_manifest.cpp
    Manifest.CEnvironmentIsInferredForAKernelAbiProvider and
    SynthesizeFromXpkgLua.CEnvironmentIsInferredForAKernelAbiProvider: a
    mcpp:kernel-abi=<impl> provider infers c-environment = "platform"
    with no key of its own, in both manifest parsers; an ordinary package and
    a mcpp:c-abi=<impl> provider do not.
  • tests/unit/test_cache_key.cpp
    CacheKey.TwoDifferentRealisedCEnvironmentsDoNotShareASlot: the same
    package and version, realising two different environments, produce two
    different cache keys (this failed before the cache-key fix, confirming it
    reproduces the defect the coordinator's experiment found).
    CacheKey.EveryPrivateBuildBroadcastFieldReachesTheKey: every current
    member of PackageRoot::privateBuild (includeDirs, includeDirsAfter,
    cflags, cxxflags, asmflags) individually moves the key, and the two
    that nothing broadcasts into yet (ldflags, modules) are asserted NOT
    to, on purpose — a documented, testable contract for the next broadcast
    channel someone adds.
  • tests/unit/test_cenv_probe.cpp (NEW — cenv_probe::verify had zero
    direct test coverage before this) — calls the verification probe directly
    against a real host compiler with deliberately wrong expectations: a
    declared sizeof(long)/wchar_t width the compiler disagrees with, a
    macro declared defined that isn't and vice versa. Each confirms the exact
    Mismatch{fact, declared, measured} prepare.cppm renders into its
    refusal text, plus the probe's cache hit/miss behavior across two
    different argv strings.
  • tests/unit/test_targetside.cpp — unaffected, 45/45 still pass (confirms
    moving CAbiDecl/the new enums ahead of Layer/TargetSide in
    targetside_model.cppm, required for declaration order, changed nothing
    observable).
  • Full local mcpp test (test binaries compiled with --toolchain llvm@22.1.8; the driver binary itself is GCC-built, sidestepping Clang-built mcpp SIGSEGVs in ELF runtime inspection (validate_changed_artifacts); GCC-built does not #666):
    121/122 unit tests pass. The one failure, unit/test_elf_runtime
    (std::bad_alloc / SIGSEGV), is Clang-built mcpp SIGSEGVs in ELF runtime inspection (validate_changed_artifacts); GCC-built does not #666, reproduced on unmodified main,
    not a regression from this PR
    — I did not touch, weaken or adjust that
    test. CI's own build-test job compiles its test binaries with the
    project's default (GCC) toolchain, so it is not expected to hit Clang-built mcpp SIGSEGVs in ELF runtime inspection (validate_changed_artifacts); GCC-built does not #666 at
    all; if it does, that failure is Clang-built mcpp SIGSEGVs in ELF runtime inspection (validate_changed_artifacts); GCC-built does not #666, not this PR.

Spike support

Per the coordinator's request, a release-mode binary was built and reported
as soon as items 1/2/3/5 worked end to end, ahead of the rest of this list;
see the conversation record. The binary path in the final report below is
the last one built from the tip of this branch.

…e realises and checks it

Until now the compiler payload's target triple implied the environment a C
program compiles against. The moment a package supplies the C library
instead (mcpp:c-abi=<impl>), that stops being true: openkal-musl on
x86_64-windows-gnu generates PE/Win64 code while presenting a POSIX
environment, and every #ifdef _WIN32 above it is asking the wrong layer.

- [c-abi] manifest block: presents (posix/windows/none), data-model
  (arch-default/lp64/llp64/ilp32), wchar (16/32), builtins (iso/platform).
  Only a package that also provides mcpp:c-abi=<impl> may declare it.
  presents/data-model/wchar carry no default; an unknown key or value is
  always a parse error naming the key. Absent block changes nothing.
  (modules/manifest/src/{targetside_model,toml,types}.cppm)

- Realisation (src/toolchain/cenv.cppm): a pure, table-driven mapping from
  request to compiler tokens with no package names. The flagship case --
  presents=posix on Windows/x86_64 -- realises as a Cygwin-flavoured
  compile-only identity switch (--target=x86_64-pc-cygwin,
  -U__CYGWIN__ -U__CYGWIN32__), leaving the link line on the graph's
  resolved triple, because the two triples measure identical machine code.
  Reaches C, C++, the dependency scan and the std module precompile.
  A request this engine cannot realise is refused naming the target,
  request and what is missing. [package] c-environment = "platform" opts a
  package out of the realisation entirely.

- Verification, not trust (src/toolchain/cenv_probe.cppm): one -E -dM
  predefined-macro dump, no codegen and no execution, checked against the
  declaration and cached per configuration. Caught a real mapping bug
  during development (data-model = "llp64" alongside presents = "posix" on
  Windows silently read as already-satisfied); the mapping now refuses that
  combination directly instead of relying on the probe to catch it late.

- __openkal__ defined for every target-side unit when the resolved
  kernel-abi layer's interface is openkal, read from the layer's value.

- Closure visibility: provides = ["platform-sdk"] is a package's own
  statement; the Target report gains a platform-deps line, and
  [build] platform-dependencies = "refuse" fails the build when one is
  present. (src/build/prepare.cppm)

- The realised environment and __openkal__ fold into the build fingerprint,
  so LP64 and LLP64 builds of one source/manifest never share a directory.
  The equivalent store-key gap for install-hook artifacts is designed but
  not built here -- documented in docs/22 as a known gap.

Two pre-existing defects found while verifying this are filed separately,
not fixed here: #666 (a Clang-built mcpp binary SIGSEGVs
in its own ELF runtime inspector; GCC-built does not) and #667 (a GCC
self-host ICE importing mcpp.targetside from a new consumer under a
parallel build; -j1 avoids it).

Docs: docs/22 ([c-abi], verification, fingerprint), docs/21 (a declared
environment moves the compiled triple, not the linked one), docs/24 (the
three macro families, the __openkal__ rule, platform units), docs/06
(platform-sdk), and their zh mirrors. Tests: test_manifest.cpp,
test_cenv.cpp (14 cases covering the whole mapping table), e2e 741.

Design: mcpplibs/openkal .agents/docs/2026-09-18-openkal-c-environment-and-personalities-design.md
- docs/zh/21-the-target-triple.md was missing the zh mirror of the new
  "a declared environment can move the compiled triple" note; heading
  count parity with the English document now holds (25/25).
- docs/zh/24-openkal-cross.md's macro-family table header "由谁定义"
  reads as a question (contains 谁); renamed to the noun phrase "定义者".
- Three cross-file anchors in the zh docs pointed at the ENGLISH heading
  slug of their target section instead of the zh one
  (#adaptation-to-the-resolved-target-side, #closure-visibility) — fixed
  to the zh anchors check_docs_structure.sh actually validates against.

Caught by CI on #668 ("build + unit tests" job's doc-lint step); verified
locally afterwards with check_docs_style.sh, check_docs_structure.sh,
check_version_pins.sh, check_target_tiers.py and check_modules_wiring.sh.
Design revision from the openkal-musl spike. The Cygwin-flavoured Windows
realisation no longer undefines __CYGWIN__/__CYGWIN32__ -- the -U tokens are
dropped, everything else (the --target= substitution, LP64, no _WIN32,
-fno-short-wchar for wchar=32) is unchanged.

The reason, stated once and correctly (an earlier private draft of this
change mis-attributed the cause to libunwind's own branch selection; that
was wrong on inspection of the vendored source and is not repeated here):
third-party portable code that needs to know the OBJECT FORMAT -- distinct
from the C environment and from the platform API -- has no other name for
"PE format with a POSIX-presenting C environment" than __CYGWIN__, and such
code cannot be patched the way this ecosystem's own packages can. This is a
trade-off for the 30-member measurement to settle: a library reaching for
__CYGWIN__ may also reach for a real Cygwin interface that does not exist
here, and if defining it produces more new failures than it fixes, the
answer flips.

Updated: the realisation table and its verification expectations
(src/toolchain/cenv.cppm), the unit test and e2e assertions (now checking
__CYGWIN__ stays DEFINED, the opposite of the first version), and the
English + zh docs/CHANGELOG prose.
A .S unit's command line is assembled independently of a .c/.cpp unit's
(mcpp.build.flags::CompileFlags::as, not ::cc/::cxx), and only inherits the
-D/-U/-I subset of a package's C flags on purpose -- a -std= or -O token
meant for the C compiler is meaningless to GAS. The realised environment
broadcast landed only in privateBuild.cflags/cxxflags, so it never reached
that narrower channel: within one package a .c unit saw _WIN32 undefined
while a .S unit still saw it defined, because --target=/-fno-short-wchar
never reached the assembler's command line at all. Found by the openkal-musl
spike (okm_setjmp.S, and upstream libunwind's assembly.h, both select
register-save sets on that macro) -- a jmp_buf written by one save set and
sized by the other header is a silent mismatch, the exact failure class this
feature exists to remove.

Adds UsageRequirements::asmflags, a broadcast-only channel parallel to
cflags/cxxflags (no [build] asmflags manifest key backs it -- per-glob
`flags = [{ asmflags }]` remains the author-facing one), and routes the
realised environment tokens into it for GAS units only: NASM has no
--target= concept and accepts none of these flags, so it must never receive
them, and a unit test pins that split directly. Every token was checked
against clang's assembler-with-cpp front end first; none is rejected, so
nothing is filtered a second time.

e2e 741 gains a .S unit asserting it carries the same tokens main.cpp does.
key now covers the realised environment

A package providing mcpp:kernel-abi=<impl> is by definition the boundary
where the platform's own interfaces are called, so it can never want the
graph's presented [c-abi] environment instead of the triple's own. Rather
than require every kernel-abi implementation to write c-environment =
"platform" (and every already-released one to bump a version to add it),
that value is now inferred from provides alone, in both manifest parsers
(mcpp.toml and the xpkg index descriptor). The explicit key still wins when
present. Measured without it: openkal-windows, compiled under the POSIX
substitution like everything else in its graph, got a 32-bit wchar_t from
-fno-short-wchar while the Win32 calls it makes hand back genuine 16-bit
UTF-16, misreading its own results.

Separately: the global build cache's key (~/.mcpp/build-cache/v1,
mcpp.build.cache_key) read only a package's OWN declared cflags/cxxflags,
never the engine's broadcast channel the realised environment (and
__openkal__, and targetSideUsage) actually travels through. Two builds
realising different environments for the identical package produced the
identical key. Measured: upgrading mcpp in place, with the cache directory
left alone, served objects compiled under the old realised environment into
an image built under the new one. fill_package_config now folds in
privateBuild.cflags/cxxflags/asmflags (the post-broadcast values) alongside
the declared ones, exactly as it already did for include directories.
from a trustworthy one

The previous commit made fill_package_config read the realised environment,
but a corrected derivation does not make an entry written under the old,
wrong one safe to keep. An entry is poisoned exactly when its recorded key
and its actual compiled inputs already disagreed at write time, and the
package most likely to still produce an unchanged key after the fix is the
one this same PR newly exempts from the realisation: a kernel-abi provider
inferred into c-environment = "platform" now has an empty
privateBuild.cflags, so its new key is computed from nothing -- matching
its old key, which was also computed from nothing, while the object on disk
was compiled WITH the substitution. No cheaper mechanism distinguishes a
pre-fix entry from a post-fix one, so kCacheEpoch moves (2 -> 3): every
existing ~/.mcpp/build-cache/v1 entry is orphaned unconditionally, one cold
rebuild for everyone, rather than trust a key equality that is wrong for
exactly the entries that matter most.

Also adds CacheKey.EveryPrivateBuildBroadcastFieldReachesTheKey, a durable
guard for the class of defect rather than only this one instance of it:
PackageRoot::privateBuild (UsageRequirements) is the engine's own broadcast
channel, and every one of its members -- today includeDirs, includeDirsAfter,
cflags, cxxflags, asmflags, ldflags, modules -- has to move the cache key,
because the key's only job is to describe what reaches the compiler. This
predates the c-abi wave (targetSideUsage's own broadcast, and __openkal__,
had the identical exposure before [c-abi] existed); the two fields nothing
broadcasts into yet (ldflags, modules) are asserted uncovered on purpose,
with an explicit instruction to flip that assertion in the same change that
adds their broadcast.
mode written out plainly

The declaration probe (mcpp.toolchain.cenv_probe, design 2026-09-18 §3.2)
landed in an earlier commit and is wired into prepare.cppm, but had zero
direct test coverage: e2e 741 only exercises its success path (the build
would not otherwise complete) and its one refusal leg comes from
cenv::realise refusing an unrealisable request before the probe is ever
reached. Adds tests/unit/test_cenv_probe.cpp, calling cenv_probe::verify
directly against a real host compiler with deliberately wrong expectations
-- a declared long/wchar_t width the compiler disagrees with, a macro
declared defined that isn't and vice versa -- confirming each produces the
declared-vs-measured Mismatch entry prepare.cppm renders into its refusal
text, plus the cache's hit/miss behavior. Each test gets its own temp cache
directory: the probe's cache is keyed on (compiler, argv) alone, not on
what expectations are being checked, so two tests sharing a default cache
root and identical argv would have the second read the first's cached dump
rather than genuinely probe.

Separately, traced the install-hook store's code path (prepare.cppm,
install_hook_env) to answer directly: yes, an install hook can and does
compile target-side code into the shared store, and no, there is no way
today for it to know the realised [c-abi] environment, because the hook
runs before the toolchain resolves at all -- prepare.cppm resolves tc only
after the dependency graph installs, since resolving the target side can
itself depend on which package the graph supplies a layer from. This is not
a gap this PR could close with a local fix; docs/22 (+ zh mirror) now states
the failure mode plainly (objects sized for one wchar_t linked against
headers sized for another, with nothing checking it) rather than as a line
in a gap table, names what closing it for real would take, and says
explicitly that this is the same shape as the already-shipped c++-abi
store-key gap, not a new one this PR introduces.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants