2026.9.21.1: the borrowed __CYGWIN__ is withdrawn, by measurement - #680
Conversation
`presents = "posix"` on Windows realises as a Cygwin-flavoured target. The
previous release LEFT `__CYGWIN__`/`__CYGWIN32__` defined, so that portable
third-party code needing to know the OBJECT FORMAT would keep a name for "PE
format with a POSIX-presenting C environment", and it wrote its own condition
for reversal: a trade-off for the 30-member measurement to settle, flipping if
defining them produced more failures than it fixed.
IT PRODUCED FOUR AND FIXED NONE. Across 60 member-target combinations,
archive, sqlite3, mimalloc and c-ares each stopped at `#include <windows.h>`,
reached through a guard of the shape `#if defined(_WIN32) || defined(__CYGWIN__)`.
Nothing in the same run failed for want of the macro.
Upstream says what it means by the name. mimalloc puts it in the guard's own
comment --- `we use windows locks on cygwin, but otherwise treat it at unix`
--- and sqlite3 lists it in the `SQLITE_OS_WIN` detection set before including
`windows.h`. A BORROWED NAME MEANS WHAT THE LENDER'S HISTORY MADE IT MEAN, not
what the borrower intended by it.
The object-format question keeps no macro at all: a package asks
`cfg(os = "windows")`, which needs none. If a third party is ever found that
can only ask in the preprocessor, mcpp defines a name of its own.
WHAT CARRIES THE CHANGE IS NOT THE TWO `-U` TOKENS. It is the two entries added
to `expectUndefined`: `cenv_probe::verify` compares the realised
configuration's predefines against those lists and refuses on a mismatch, so a
`-U` that failed to take effect is a verification failure rather than a silent
one. Measured directly with the pinned clang, in the order mcpp emits them:
echo | clang -dM -E -x c - -U__CYGWIN__ -U__CYGWIN32__ \
--target=x86_64-pc-cygwin -U__CYGWIN__ -U__CYGWIN32__
-> __unix__ defined, __CYGWIN__ absent, _WIN32 absent
The unit test and e2e 741 now assert the opposite side, and both record that
this module has held both answers and what flipped it. The pair appears twice
on a `.S` command line and once on `.c`/`.cpp`, because `cEnvTokens` reaches
asmflags directly and `-D`/`-U`/`-I`-shaped tokens also arrive through the
channel that carries defines into assembly; `-U X` twice is `-U X`, and the
probe is the judge, so no count is asserted.
Also in this release, as documents rather than engine changes:
* `.agents/docs/2026-09-21-openkal-ecosystem-completion-and-acceptance.md`
--- the nine items this wave did not implement, each with its criterion,
its owner and what blocks it; why `lsp-mcpp-private` is the acceptance
vehicle (its platform surface is six constants, none of them a POSIX
facility, and it makes no direct POSIX call); and a cross-repository
verification protocol: an engine PR is built by the ecosystem through
`MCPP_SOURCE_REF` and both sides must be green BEFORE it merges. That
protocol exists because this very change needed a second release --- a
reading the thirty member graphs could have produced before the first one.
…or it The plan listed `memset_pattern16` as an openkal-musl gap and the hard blocker for macOS acceptance, on the strength of a report that the link still fails on the new stack. The engine already does the thing that should prevent it: `cenv.cppm` emits `-fno-builtin-memset_pattern16` for `builtins = "iso"` on macOS and iOS, and openkal-musl declares exactly that. AND THE FLAG REACHES THE PACKAGES NAMED. Measured by emitting a build database for `aarch64-macos` with 2026.9.21.1: all 29 of zstd's translation units carry it, including the one on the chain the report named. Three explanations survive, none of them decidable here --- a Linux host cannot compile for macOS, there being no SDK: the report predates the flag; the synthesised idiom is `memset_pattern4`/`8`, for which the engine emits no flag (clang's `-fno-builtin-` family is one flag per idiom) though the report names `16`; or the flag does not reach LLVM's loop-idiom pass. So the next step is a reading, not an implementation. `lsp-mcpp-private`'s `aarch64-macos --profile release` leg answers it directly, and each surviving explanation has its own follow-up. Adding the symbol to openkal-musl now would be repairing a gap that may not exist.
…tself The first shape of this change simply withdrew `__CYGWIN__`. It was green here and green in four of five ecosystem repositories built against this branch; openkal-llvm-runtime failed, libunwind's `static_assert` reporting that `Registers_x86_64` does not fit `unw_context_t`. TWO INSTALLED HEADERS IN THIS ECOSYSTEM READ THAT MACRO ON PURPOSE, each saying so in its own source: `openkal-musl`'s `bits/setjmp.h` sizes `jmp_buf` by it, and `openkal-llvm-runtime`'s `__libunwind_config.h` sizes `unw_context_t`. Both are INSTALLED --- an application's own compile reads them --- so neither can use the package-private define its sibling `.S` files use, and `__CYGWIN__` was the only name mcpp kept defined target-wide. The 30-member measurement that justified withdrawal had counted THIRD-PARTY readers of the macro and not ours. Ours are load-bearing, and wrong is silent where it matters most: `setjmp.h`'s own comment says "a mismatch nothing reports until the record overruns". libunwind having a `static_assert` is what made this loud, not anything the measurement did. So mcpp states the fact itself. `-D__mcpp_target_windows__=1` answers the question those headers ask --- is this target Windows, whatever C environment is presented above it --- and being mcpp's own name, its meaning is not decided by anyone else's history. It is emitted only under this substitution; an ordinary Windows build still has `_WIN64`. `expectDefined` carries it, so a `-D` that failed to take effect is a verification failure rather than a silent one. The name differs from the design's proposed `__mcpp_format_pe__` because the two consumers do not want the object format: they size Win64 register save areas, which is the calling convention. The two co-vary on this target, and naming it for the question actually asked is the honest form. `__CYGWIN__` REMAINS DEFINED, as step one of three: this release adds the new name, those packages move onto it while still accepting the old one, and only then does a release stop defining the borrowed one. Step three taken first would leave every published copy of those headers falling to its `#else` --- the wrong record size, reported by nothing. Four loudly failing third-party members is the better state to hold for one release.
`src/toolchain/predefines.cppm` is the specification and the implementation of one thing. The contract is data in that module (`kContract`), the emission is a function beside it (`define_tokens`), and `tests/unit/test_predefines.cpp` asserts the two agree in BOTH directions: a macro emitted and unlisted is a promise nobody can rely on, a row listing a macro nothing emits is one a reader waits for forever. This wave already paid once for a rule kept in a document while the code moved --- the reason-token table was "the four it was missing" twice over. GENERALISED PAST WINDOWS. `__mcpp_target_<os>__` is spelt from the triple's own `os` field, so the ENGINE LEARNS NO OPERATING-SYSTEM NAME and a target added to the triple parser gets its macro with no change here --- the same discipline `[kernel-abi]` interface names follow. Measured: `x86_64-linux-gnu` gives `__mcpp_target_linux__`, `x86_64-windows-gnu` gives `__mcpp_target_windows__`, `riscv64-none-elf` gives `__mcpp_target_none__`. DEFINED ALWAYS, not only where a realisation suppressed something. Conditional emission would make its absence ambiguous: "not Windows" and "Windows, but nothing hid its macros" would read the same, which is the shape of every defect where a "no" and a "never asked" share a reading. Lowercase, `__mcpp_`-prefixed. Two conventions exist --- vendor and product names upper (`__APPLE__`, `_WIN32`), kind-of-system names lower (`__linux__`, `__unix__`) --- and these name kinds of target, sitting beside the second family in real guards. The prefix is load-bearing: a name mcpp owns means what mcpp says it means, which is exactly what `__CYGWIN__` could not offer. `__openkal__` joins the same contract; `__unix__` is listed as SUPPLIED rather than owned, so it keeps the standard spelling and mcpp may not redefine it. THE SEPARATION IS ITSELF A TESTED PROPERTY. The macro was first realised in `mcpp.toolchain.cenv`, which made it derived from a declaration --- yet whether a target is Windows does not depend on any `[c-abi]` block existing. Moving it out turned the cenv test red, correctly; that test now asserts the realisation does NOT carry it, because a token with two owners is a token that will disagree with itself. docs/21 renders the contract in both languages, and docs/24's note that the `__CYGWIN__` trade-off "may flip" is updated: it has, and the replacement has a name.
生态级 review(协议 §6.4)合入门槛的第四项。五个问题逐条回答,每条都给判据而不是判断。 1. 这次改动改变了哪些包的命令行?每一个目标侧包,多一个 这不构成额外的重建代价,而我一开始算错了。 量到旧版与本版指纹目录不同( 2. 有没有包的清单因此需要改?没有。改动是纯增量,不动任何清单键。 两个包应当迁移到新名字( 3. 索引
|
…rong
`aarch64-macos --profile release` over the openkal stack links, and the
artefact references no `memset_pattern` symbol at all. Measured here, on this
Linux host, with mcpp 2026.9.21.1 and llvm@22.1.8 through openkal-macos
0.12.0 / openkal-musl 0.18.0 / openkal-llvm-runtime 0.13.0:
zstd 1.5.7 compiles, links; Mach-O 64-bit arm64, NOUNDEFS; 0 refs
xz 5.8.3 compiles, links
Both are on the chain the report named. The engine has emitted
`-fno-builtin-memset_pattern16` for `builtins = "iso"` on macOS since before
this branch, and that report was taken on an engine that did not. Nothing is
implemented for C4, and nothing should be: adding the symbol to openkal-musl
would have repaired a gap that does not exist.
THE BELIEF THAT KEPT THIS UNMEASURED IS THE MORE USEFUL FINDING. Both this
plan and the previous wave's self-review stated that macOS facts need a macOS
runner, because a probe targeting `aarch64-macos` failed here. That probe
declared no openkal dependency, so it took the PLATFORM path, which does need
an Apple SDK. The openkal path does not --- universal cross-building is the
premise of the whole system, and a Linux host reaches `arm64-apple-macos14.0`
through it with every layer resolved from the graph.
The cost of that belief compounded: it filed C4 as unmeasurable, and it filed
openkal-macos's `provides-interfaces` as needing a runner when 0.12.0 derived
it mechanically. Both corrected, with the rule beside them --- a claim that
some platform cannot be measured locally has to be tested with a probe that
goes THROUGH the stack under test, not one that bypasses it.
The change
presents = "posix"on Windows realises as a Cygwin-flavoured target. The previous release left__CYGWIN__/__CYGWIN32__defined, so that portable third-party code needing to know the object format would keep a name for "PE format with a POSIX-presenting C environment" — and it wrote its own condition for reversal:It produced four and fixed none
Across 60 member-target combinations,
archive,sqlite3,mimallocandc-areseach stopped at#include <windows.h>, reached through a guard of the shape#if defined(_WIN32) || defined(__CYGWIN__). Nothing in the same run failed for want of the macro.Upstream states what it means by the name:
A borrowed name means what the lender history made it mean, not what the borrower intended. The object-format question therefore keeps no macro at all — a package asks
cfg(os = "windows"), which needs none.What carries the change is not the two
-UtokensIt is the two entries added to
expectUndefined.cenv_probe::verifycompares the realised configuration predefines against those lists and refuses on a mismatch, so a-Uthat failed to take effect is a verification failure rather than a silent one.Measured directly with the pinned clang, in the order mcpp emits them:
The unit test and e2e 741 now assert the opposite side, and both record that this module has held both answers and what flipped it.
The pair appears twice on a
.Sline and once on.c/.cpp:cEnvTokensreaches asmflags directly, and-D/-U/-I-shaped tokens also arrive through the channel carrying defines into assembly.-U Xtwice is-U X, and the probe is the judge, so no count is asserted.Verification
__CYGWIN__absent,__unix__present,_WIN32absentAlso in this release (documents, not engine changes)
.agents/docs/2026-09-21-openkal-ecosystem-completion-and-acceptance.md:MCPP_SOURCE_REF, and both sides must be green before it mergesThat protocol exists because this very change needed a second release, a day after the first — a reading the thirty member graphs could have produced before the first one merged. mcpp-index#452 closes the mechanism gap that prevented it.