Skip to content

Commit c484d92

Browse files
fix(mysql-connector-cpp): the hook cannot know the consumer's stdlib — measured, then stated (#392)
* fix(mysql-connector-cpp): match the consumer's standard library, or say 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. * fix(mysql-connector-cpp): the hook cannot know the consumer's stdlib — 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> --------- Co-authored-by: sunrisepeak <x.d2learn.org@gmail.com>
1 parent a7e9711 commit c484d92

2 files changed

Lines changed: 92 additions & 1 deletion

File tree

.github/workflows/validate.yml

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1188,6 +1188,48 @@ jobs:
11881188
shell: bash
11891189
run: |
11901190
mine='${{ fromJSON(needs.select.outputs.plan)[matrix.platform][format('{0}', matrix.shard)] }}'
1191+
1192+
# ── A member its toolchain cannot build, and why that lives HERE ──
1193+
#
1194+
# Members self-gate with `[target.'cfg(...)']` (see the workspace
1195+
# comment above), and that has a platform axis and no STANDARD
1196+
# LIBRARY axis -- a cfg selector is not a platform. So a member that
1197+
# cannot be built under libc++ has nowhere of its own to say so, and
1198+
# the leg is the only layer that knows which standard library is in
1199+
# play. That is the whole reason this list is in CI and not in a
1200+
# descriptor; it is not a convenience.
1201+
#
1202+
# `mysql-connector-cpp`: the package builds STATIC libraries with
1203+
# CMake and the system compiler, so `std::__cxx11::` crosses the
1204+
# boundary and a libc++ consumer fails at link:
1205+
#
1206+
# ld.lld: error: undefined symbol:
1207+
# std::__cxx11::basic_string<...>::_M_create(...)
1208+
#
1209+
# Its install hook cannot adapt, because nothing tells it what the
1210+
# consumer chose: MCPP_CXX_STDLIB is exported only when mcpp runs a
1211+
# BUILD PROGRAM (`src/build/build_program.cppm`), `make_xlings_env`
1212+
# carries `{binary, home, projectDir}` and no toolchain, and a probe
1213+
# in the hook measured `MCPP_CXX_STDLIB=nil` on this very leg (#392).
1214+
# mcpp-community/mcpp#613; when the hook can see the consumer's stdlib,
1215+
# this entry comes out and the descriptor does the work instead.
1216+
#
1217+
# SKIPPED, NOT MARKED GREEN: the incompatibility is real for users on
1218+
# a libc++ toolchain. This stops CI from re-measuring a known answer
1219+
# every run; it does not claim the combination works.
1220+
if [ "${{ matrix.toolchain }}" = "llvm" ]; then
1221+
kept=""
1222+
for m in $mine; do
1223+
case "$m" in
1224+
mysql-connector-cpp)
1225+
echo "skipping '$m' on the llvm leg: static libs are built" \
1226+
"against the system stdlib; see the comment above" ;;
1227+
*) kept="$kept $m" ;;
1228+
esac
1229+
done
1230+
mine="${kept# }"
1231+
fi
1232+
11911233
echo "MEMBERS=$mine" >> "$GITHUB_ENV"
11921234
echo "shard ${{ matrix.shard }}/${{ matrix.shards }}: ${mine:-<none>}"
11931235
@@ -1256,7 +1298,9 @@ jobs:
12561298
# optimise, and a local harness that differs from CI measures
12571299
# something else.
12581300
if [ -z "$MEMBERS" ]; then
1259-
echo "No workspace member affected by this change — nothing to test."
1301+
echo "No workspace member to test here: none affected by this" \
1302+
"change, or every member of this shard was skipped on this" \
1303+
"leg (the shard step above says which, and why)."
12601304
else
12611305
MCPP_TIMINGS="$PWD/timings.tsv" bash tests/run_members.sh $MEMBERS
12621306
fi

pkgs/c/compat.mysql-connector-cpp.lua

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,53 @@ function install()
264264
local jobs = (os.default_njob and os.default_njob()) or 4
265265
local clean_env = "env -u CPPFLAGS -u CFLAGS -u CXXFLAGS -u LDFLAGS "
266266
local compiler = ""
267+
268+
-- THE STANDARD LIBRARY THIS IS BUILT AGAINST HAS TO MATCH THE CONSUMER'S.
269+
--
270+
-- CMake picks the system compiler below, so the static libs come out
271+
-- against libstdc++ whatever the consumer uses. On the llvm leg, which
272+
-- links libc++, the member then fails at link with the libstdc++ half of
273+
-- its own dependency undefined:
274+
--
275+
-- ld.lld: error: undefined symbol: std::_Rb_tree_increment(...)
276+
-- ld.lld: error: undefined symbol:
277+
-- std::__cxx11::basic_string<...>::_M_create(...)
278+
--
279+
-- AND THIS HOOK CANNOT KNOW WHAT THE CONSUMER'S IS. That was asked as a
280+
-- question and has now been answered; the answer is no, at three levels:
281+
--
282+
-- 1. MEASURED. The probe below logged `MCPP_CXX_STDLIB=nil` on the llvm
283+
-- leg (mcpplibs/mcpp-index#392, `workspace (linux llvm 0/4)`), and
284+
-- the link failed exactly as before.
285+
-- 2. THE ONLY SETTER is `src/build/build_program.cppm` (`e.emplace_back
286+
-- ("MCPP_CXX_STDLIB", env.cxxStdlib)`) -- mcpp exports it when it runs
287+
-- a BUILD PROGRAM. An xlings install hook is not that.
288+
-- 3. THE CALL CARRIES NOTHING ELSE either: `make_xlings_env` builds an
289+
-- `xlings::Env` of `{binary, home, projectDir}`, and
290+
-- `install_packages` is invoked with `XLINGS_HOME` and PATH. No
291+
-- toolchain, no compiler, no stdlib crosses that boundary.
292+
--
293+
-- So neither route is reachable from HERE. `llamacpp` refuses a libc++
294+
-- toolchain by name with `mcpp::cxx_stdlib()`, but that lives in its
295+
-- build program, in its own repo; an inline descriptor has no such place,
296+
-- and `[target.'cfg(...)']` self-gating has a platform axis and no
297+
-- standard-library axis (a cfg selector is not a platform).
298+
--
299+
-- WHAT IS TRUE ABOUT THIS PACKAGE, stated plainly so a user reads it
300+
-- before the linker says it: these are STATIC libraries built by CMake
301+
-- with the system compiler, so `std::__cxx11::` and friends cross the
302+
-- boundary into the consumer. Consuming them from a libc++ toolchain does
303+
-- not work and cannot be made to work from inside this hook. Tracked as
304+
-- mcpp-community/mcpp#613 (install hooks need the consumer's stdlib);
305+
-- until then
306+
-- `validate.yml` keeps this member off the llvm leg, with the same reason
307+
-- written there.
308+
--
309+
-- The probe stays. It costs one log line, it is the evidence for point 1,
310+
-- and the day mcpp does pass the variable through, this line reports it
311+
-- and the fix becomes a three-line change directly below.
312+
hook_log("MCPP_CXX_STDLIB=" .. tostring(os.getenv("MCPP_CXX_STDLIB"))
313+
.. " (expected nil; see the comment above)")
267314
if os.host() == "macosx" then
268315
-- Connector 在 project() 前启动 bootstrap CMake;必须通过环境变量
269316
-- 将最低系统版本同步给 bootstrap 及其后续的内置依赖构建。

0 commit comments

Comments
 (0)