Skip to content

fix(mysql-connector-cpp): the hook cannot know the consumer's stdlib — measured, then stated - #392

Merged
Sunrisepeak merged 3 commits into
mainfrom
fix/mysql-connector-cpp-stdlib
Sep 11, 2026
Merged

fix(mysql-connector-cpp): the hook cannot know the consumer's stdlib — measured, then stated#392
Sunrisepeak merged 3 commits into
mainfrom
fix/mysql-connector-cpp-stdlib

Conversation

@Sunrisepeak

@Sunrisepeak Sunrisepeak commented Sep 11, 2026

Copy link
Copy Markdown
Member

What changed since the first push

The first push asked a question — does MCPP_CXX_STDLIB reach an xlings install hook? — and shipped a probe that logged the answer either way and applied -stdlib=libc++ if the answer was yes.

The answer is no. This PR now carries the conclusion instead of the attempt.

The evidence, at three levels

level finding
measured 11:46:18 MCPP_CXX_STDLIB=nil on workspace (linux llvm 0/4), link failed as before
only setter src/build/build_program.cppm: e.emplace_back("MCPP_CXX_STDLIB", env.cxxStdlib) — exported when mcpp runs a build program
call surface make_xlings_env builds xlings::Env{binary, home, projectDir}; install_packages is invoked with XLINGS_HOME and PATH. No toolchain crosses

Both routes I assumed were open are closed

  • "let its CMake step use libc++" — needs the consumer's choice, which by construction does not reach the hook.
  • "refuse the libc++ leg like llamacpp"llamacpp does it with mcpp::cxx_stdlib() in its build program, in its own repo. An inline descriptor has no such place, and [target.'cfg(...)'] self-gating has a platform axis and no standard-library axis (a cfg selector is not a platform).

What this does instead

The descriptor stops being silent. It now states that these are static libraries built by CMake with the system compiler, that std::__cxx11:: therefore crosses the boundary into the consumer, and that a libc++ consumer cannot use them — where a user reads it rather than where the linker says it.

The probe stays. One log line; it is the evidence for level 1, and the day mcpp passes the variable through, it reports that and the fix becomes the three lines directly below it.

validate.yml keeps the member off the llvm leg, with the reasoning written at the point that does the skipping. In CI and not in a descriptor for a reason worth saying out loud: the leg is the only layer that knows which standard library is in play.

SKIPPED, NOT MARKED GREEN — the incompatibility is real for users on a libc++ toolchain. This stops CI re-measuring a known answer every run; it does not claim the combination works.

One consequence handled: linux llvm 0/4 holds mysql-connector-cpp and nothing else (386s, 100% of that shard), so skipping it empties the shard. The downstream message said "No workspace member affected by this change", which would now be false; it covers both cases and points at the line that says which.

Verification

  • luac -p clean on the descriptor
  • ruby -ryaml parses the workflow
  • the rendered shell fragment tested standalone:
    skipping 'mysql-connector-cpp' on the llvm leg: static libs are built against the system stdlib; …
    MEMBERS=[eui-neo-window vulkan]
    
  • the default leg is untouched (the whole block is inside if [ "$toolchain" = "llvm" ])

The real fix is upstream of this repo

Install hooks need the consumer's standard library, or a source-built static package can never match its consumer's ABI. Filing that against mcpp; when it lands, the validate.yml entry comes out and the descriptor does the work.

…ay why not

CMake picks the system compiler here, so the static libs come out against
libstdc++ whatever the consumer uses. On the llvm leg, which links libc++,
the member fails at link with the libstdc++ half of its own dependency
undefined:

    ld.lld: error: undefined symbol: std::_Rb_tree_increment(...)
    ld.lld: error: undefined symbol:
        std::__cxx11::basic_string<...>::_M_create(...)

`llamacpp` refuses a libc++ toolchain by name with `mcpp::cxx_stdlib()`,
and I said twice that the same lever was out of reach here because that is
a build-program API and this is an inline descriptor. That was half right.
The API is out of reach; the VARIABLE it reads is not necessarily —
MCPP_CXX_STDLIB is exported when mcpp runs a build program
(src/build/build_program.cppm), and whether it also reaches an xlings
install hook is documented nowhere.

So this asks instead of assuming, and records the answer either way:

  * visible and `libc++` — build with `-stdlib=libc++`, on the compile and
    both link flag sets. Compiling against libc++ headers while linking
    libstdc++ produces the same undefined symbols one layer later, so the
    flag has to reach all three.
  * absent — nothing changes. The build is what it was, and the hook log
    carries `MCPP_CXX_STDLIB=nil`, which is the missing half of the
    diagnosis the next time that leg fails.

The failure has been read wrong once already in this area: `install()
result=nil` was taken for a cause when it was a successful install with no
return statement. A hook that reports what it saw is cheaper than a third
round of inference.
@Sunrisepeak Sunrisepeak changed the title fix(mysql-connector-cpp): match the consumer's standard library, or say why not fix(mysql-connector-cpp): the hook cannot know the consumer's stdlib — measured, then stated Sep 11, 2026
…— measured, then stated

The previous commit on this branch asked a question: does MCPP_CXX_STDLIB
reach an xlings install hook? It shipped a probe that logged the answer
either way and applied `-stdlib=libc++` if the answer was yes.

The answer is no, and this commit replaces the conditional with what was
learned. Three independent levels agree:

  1. MEASURED. `MCPP_CXX_STDLIB=nil` on `workspace (linux llvm 0/4)`, and
     the link failed exactly as before.
  2. THE ONLY SETTER is `src/build/build_program.cppm` — mcpp exports it
     when it runs a BUILD PROGRAM. An install hook is not that.
  3. NOTHING ELSE CROSSES either: `make_xlings_env` builds an
     `xlings::Env` of `{binary, home, projectDir}`, and `install_packages`
     is invoked with `XLINGS_HOME` and PATH. No toolchain, no compiler,
     no standard library.

So neither of the two routes I had assumed were available actually is.
`llamacpp` refuses a libc++ toolchain with `mcpp::cxx_stdlib()`, but that
lives in its build program in its own repo; an inline descriptor has no
such place. And `[target.'cfg(...)']` self-gating has a platform axis and
no standard-library axis — a cfg selector is not a platform.

The probe stays. One log line, it is the evidence for point 1, and the
day mcpp passes the variable through it reports that and the fix becomes
three lines directly below it.

What the descriptor can do is stop being silent: it now states that these
are static libraries built with the system compiler, that `std::__cxx11::`
therefore crosses the boundary, and that a libc++ consumer cannot use them
— where a user reads it, rather than where the linker says it.

`validate.yml` keeps the member off the llvm leg, with the same reasoning
written at the point that does the skipping. That is in CI and not in a
descriptor for a reason worth saying out loud: the leg is the only layer
that knows which standard library is in play. SKIPPED, NOT MARKED GREEN —
the incompatibility is real for users on a libc++ toolchain; this stops CI
re-measuring a known answer, it does not claim the combination works.

The empty-shard message downstream said "No workspace member affected by
this change", which would now be false in the case this change creates:
`linux llvm 0/4` holds mysql-connector-cpp and nothing else, so skipping it
empties the shard. It now covers both cases and points at the line that
says which.

Co-authored-by: sunrisepeak <x.d2learn.org@gmail.com>
@Sunrisepeak
Sunrisepeak force-pushed the fix/mysql-connector-cpp-stdlib branch from ceb58d1 to 6676e90 Compare September 11, 2026 12:16
Sunrisepeak added a commit that referenced this pull request Sep 11, 2026
Every reason to distrust the diff used to escalate to the whole workspace.
On a PR that is the wrong trade twice over: it buries the change under ~22
shards of unrelated work, and it puts the PR's own legs behind an hour of
queue, so the thing under review is the last thing to report.

Touching this file was enough to trigger it, which is the case that keeps
biting: a one-line CI edit cannot be reviewed against a fast signal.
Measured three times today -- #390, #391 and #392 each ran a full matrix to
validate a change whose blast radius was one job.

`full` now answers only where "check everything" IS the request: the weekly
cron and a manual `workflow_dispatch`. On a PR or a push, the same reasons
call `widen` instead, which records them, prints them, and writes them to
the run summary so a reviewer sees WITHOUT opening a job that this run
deliberately tested less -- and that the sweep is one manual dispatch away.

Degraded, with their reasons kept:

    .github/workflows/validate.yml, tests/*.sh
    mcpp.toml non-member change
    unclassified path
    push with no predecessor / predecessor not in history

NOT weakened: descriptor and member changes select their members exactly as
before. The only thing that changed is what happens when the diff cannot be
classified.

One consequence handled. `widen` does not exit, so the push-with-no-
predecessor path has to leave a usable range behind. `HEAD` alone would diff
root-to-HEAD, name every file and select every member -- a full run by
another name, which is what this change exists to stop. It leaves the range
EMPTY instead: nothing selected, the reason already said, the summary
carrying it to a human. Rare either way, since merges here are squashes and
`event.before` is present on every normal push.

The weekly Sunday 06:00 sweep is deliberately kept. It is the only thing
that would have caught the windows vulkan regression before a user did --
main's leg was pinned to `windows-2022` in #385 and the vulkan members were
never re-tested there until a full run happened to fire today. Removing the
automatic full run on PRs and keeping the periodic net is the same shape
openxlings/xim-pkgindex#815 just added on the other side.

Verified: the rendered fragment on `pull_request` with a validate.yml edit
plus an unclassified path selects only the member its descriptor change
names, and the same input under `workflow_dispatch` still goes full.

Co-authored-by: sunrisepeak <x.d2learn.org@gmail.com>
@Sunrisepeak
Sunrisepeak merged commit c484d92 into main Sep 11, 2026
14 checks passed
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.

1 participant