From 78e6f47d81b708b8f9c0cb40d818423995f06412 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sat, 12 Sep 2026 03:28:55 +0800 Subject: [PATCH 1/2] fix(mysql-connector-cpp): state the C++ standard library as a layer requirement The install hook cannot see the consumer's standard library: mcpp resolves the toolchain after the dependency graph, so none exists when a dependency installs (mcpp-community/mcpp#613). The descriptor now declares requires = { "mcpp:c++-abi=libstdc++" }, so a libc++ consumer is refused at resolution naming both implementations instead of failing at link. The llvm-leg skip stays with its reason updated. --- .github/workflows/validate.yml | 16 ++++++------ pkgs/c/compat.mysql-connector-cpp.lua | 36 +++++++++++++++------------ 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 04d98127..f0ac948a 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -1206,13 +1206,15 @@ jobs: # ld.lld: error: undefined symbol: # std::__cxx11::basic_string<...>::_M_create(...) # - # Its install hook cannot adapt, because nothing tells it what the - # consumer chose: MCPP_CXX_STDLIB is exported only when mcpp runs a - # BUILD PROGRAM (`src/build/build_program.cppm`), `make_xlings_env` - # carries `{binary, home, projectDir}` and no toolchain, and a probe - # in the hook measured `MCPP_CXX_STDLIB=nil` on this very leg (#392). - # mcpp-community/mcpp#613; when the hook can see the consumer's stdlib, - # this entry comes out and the descriptor does the work instead. + # Its install hook cannot adapt: mcpp resolves the toolchain after the + # dependency graph, so the consumer's standard library does not exist + # yet when the hook runs, and MCPP_CXX_STDLIB is nil (older mcpp) or + # empty (2026.9.12.2 and later) there (#392; mcpp-community/mcpp#613, + # measured by its tests/e2e/648). The descriptor states the + # requirement instead, `requires = { "mcpp:c++-abi=libstdc++" }`, and a + # libc++ consumer is refused at resolution naming both implementations. + # That refusal follows the hook's source build, so the member stays off + # this leg: the leg would spend the build to reach a known refusal. # # SKIPPED, NOT MARKED GREEN: the incompatibility is real for users on # a libc++ toolchain. This stops CI from re-measuring a known answer diff --git a/pkgs/c/compat.mysql-connector-cpp.lua b/pkgs/c/compat.mysql-connector-cpp.lua index 90b598f5..d3fc5e7e 100644 --- a/pkgs/c/compat.mysql-connector-cpp.lua +++ b/pkgs/c/compat.mysql-connector-cpp.lua @@ -46,6 +46,12 @@ package = { sources = { "mcpp_mysql_connector_cpp_anchor.c" }, include_dirs = { "include" }, targets = { ["mysql_connector_cpp"] = { kind = "lib" } }, + -- The static libraries are compiled against libstdc++ (see the comment + -- in install()), so a consumer whose toolchain resolves another C++ + -- standard library is refused at resolution, naming both, instead of + -- failing at link. An mcpp older than the layer grammar reports this + -- key as unknown and proceeds as before. + requires = { "mcpp:c++-abi=libstdc++" }, deps = { ["compat.libmysqlclient"] = "8.4.6", ["compat.openssl"] = "3.5.1", @@ -282,13 +288,12 @@ function install() -- 1. MEASURED. The probe below logged `MCPP_CXX_STDLIB=nil` on the llvm -- leg (mcpplibs/mcpp-index#392, `workspace (linux llvm 0/4)`), and -- the link failed exactly as before. - -- 2. THE ONLY SETTER is `src/build/build_program.cppm` (`e.emplace_back - -- ("MCPP_CXX_STDLIB", env.cxxStdlib)`) -- mcpp exports it when it runs - -- a BUILD PROGRAM. An xlings install hook is not that. - -- 3. THE CALL CARRIES NOTHING ELSE 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 stdlib crosses that boundary. + -- 2. BY CONSTRUCTION, NOT BY OMISSION. mcpp 2026.9.12.2 emits + -- MCPP_CXX_STDLIB to a dependency's install hook, and it is empty + -- there: mcpp resolves the toolchain after the dependency graph, + -- because a package in the graph may supply a target-side layer, so no + -- standard library exists yet when this hook runs + -- (mcpp-community/mcpp#613, measured by its tests/e2e/648). -- -- So neither route is reachable from HERE. `llamacpp` refuses a libc++ -- toolchain by name with `mcpp::cxx_stdlib()`, but that lives in its @@ -300,17 +305,16 @@ function install() -- before the linker says it: these are STATIC libraries built by CMake -- with the system compiler, so `std::__cxx11::` and friends cross the -- boundary into the consumer. Consuming them from a libc++ toolchain does - -- not work and cannot be made to work from inside this hook. Tracked as - -- mcpp-community/mcpp#613 (install hooks need the consumer's stdlib); - -- until then - -- `validate.yml` keeps this member off the llvm leg, with the same reason - -- written there. + -- not work and cannot be made to work from inside this hook. The + -- descriptor states it instead (`requires` in the mcpp table above), and + -- `validate.yml` keeps this member off the llvm leg, because the refusal + -- follows this hook's source build and the leg would spend the build to + -- reach an answer it already knows. -- - -- The probe stays. It costs one log line, it is the evidence for point 1, - -- and the day mcpp does pass the variable through, this line reports it - -- and the fix becomes a three-line change directly below. + -- The probe stays. It costs one log line and is the evidence for points 1 + -- and 2: nil from an mcpp older than 2026.9.12.2, empty from a newer one. hook_log("MCPP_CXX_STDLIB=" .. tostring(os.getenv("MCPP_CXX_STDLIB")) - .. " (expected nil; see the comment above)") + .. " (expected nil or empty; see the comment above)") if os.host() == "macosx" then -- Connector 在 project() 前启动 bootstrap CMake;必须通过环境变量 -- 将最低系统版本同步给 bootstrap 及其后续的内置依赖构建。 From 04503f137cb8abc0a69776955c0ed1afa84fcd64 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sat, 12 Sep 2026 03:40:39 +0800 Subject: [PATCH 2/2] fix(mysql-connector-cpp): the standard library requirement follows each platform's system compiler The macOS default leg refused the member: install() builds with Apple clang there, so the static libraries are libc++ and the default toolchain's libc++ is the matching one. The requirement moves into the per-platform tables: libstdc++ under linux, libc++ under macosx. Measured locally: a linux-scoped requirement is refused under llvm naming both implementations and satisfied by gcc; mcpp xpkg parse --all-os accepts both sections. --- .github/workflows/validate.yml | 7 +++++-- pkgs/c/compat.mysql-connector-cpp.lua | 22 +++++++++++++--------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index f0ac948a..9429419f 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -1211,8 +1211,11 @@ jobs: # yet when the hook runs, and MCPP_CXX_STDLIB is nil (older mcpp) or # empty (2026.9.12.2 and later) there (#392; mcpp-community/mcpp#613, # measured by its tests/e2e/648). The descriptor states the - # requirement instead, `requires = { "mcpp:c++-abi=libstdc++" }`, and a - # libc++ consumer is refused at resolution naming both implementations. + # requirement instead, `requires = { "mcpp:c++-abi=libstdc++" }` in its + # `linux` table, and a libc++ consumer is refused at resolution naming + # both implementations. (On macOS the libraries are built with Apple + # clang, and the `macosx` table requires libc++, which the default + # toolchain there resolves.) # That refusal follows the hook's source build, so the member stays off # this leg: the leg would spend the build to reach a known refusal. # diff --git a/pkgs/c/compat.mysql-connector-cpp.lua b/pkgs/c/compat.mysql-connector-cpp.lua index d3fc5e7e..c9d27843 100644 --- a/pkgs/c/compat.mysql-connector-cpp.lua +++ b/pkgs/c/compat.mysql-connector-cpp.lua @@ -46,24 +46,27 @@ package = { sources = { "mcpp_mysql_connector_cpp_anchor.c" }, include_dirs = { "include" }, targets = { ["mysql_connector_cpp"] = { kind = "lib" } }, - -- The static libraries are compiled against libstdc++ (see the comment - -- in install()), so a consumer whose toolchain resolves another C++ - -- standard library is refused at resolution, naming both, instead of - -- failing at link. An mcpp older than the layer grammar reports this - -- key as unknown and proceeds as before. - requires = { "mcpp:c++-abi=libstdc++" }, deps = { ["compat.libmysqlclient"] = "8.4.6", ["compat.openssl"] = "3.5.1", }, + -- THE STANDARD LIBRARY THE STATIC LIBRARIES WERE COMPILED AGAINST, per + -- platform, because install() uses each platform's system compiler: + -- g++ with libstdc++ on Linux, Apple clang with libc++ on macOS. A + -- consumer whose toolchain resolves the other one is refused at + -- resolution, naming both, instead of failing at link. An mcpp older + -- than the layer grammar reports the key as unknown and proceeds as + -- before. linux = { + requires = { "mcpp:c++-abi=libstdc++" }, ldflags = { "-Llib", "-l:libmysqlcppconnx-static.a", "-l:libmysqlcppconn-static.a", "-lresolv", }, }, macosx = { + requires = { "mcpp:c++-abi=libc++" }, ldflags = { "-Llib", "-lmysqlcppconnx-static", "-lmysqlcppconn-static", "-lresolv", @@ -273,8 +276,8 @@ function install() -- THE STANDARD LIBRARY THIS IS BUILT AGAINST HAS TO MATCH THE CONSUMER'S. -- - -- CMake picks the system compiler below, so the static libs come out - -- against libstdc++ whatever the consumer uses. On the llvm leg, which + -- CMake picks the system compiler below, so on Linux the static libs come + -- out against libstdc++ whatever the consumer uses. On the llvm leg, which -- links libc++, the member then fails at link with the libstdc++ half of -- its own dependency undefined: -- @@ -306,7 +309,8 @@ function install() -- with the system compiler, so `std::__cxx11::` and friends cross the -- boundary into the consumer. Consuming them from a libc++ toolchain does -- not work and cannot be made to work from inside this hook. The - -- descriptor states it instead (`requires` in the mcpp table above), and + -- descriptor states it instead (`requires` in the per-platform tables of + -- the mcpp segment above), and -- `validate.yml` keeps this member off the llvm leg, because the refusal -- follows this hook's source build and the leg would spend the build to -- reach an answer it already knows.