From 0a6f11b719bcd4d15e7b4d36f4b08e2404589e82 Mon Sep 17 00:00:00 2001 From: vasilito Date: Wed, 5 Aug 2026 16:38:17 +0300 Subject: [PATCH] fix(gcc-native): link generators against host libstdc++; build C++23 modules Three defects. gcc-native now cooks and publishes both packages. 1. Generator links failed with `undefined reference to __letf2@GCC_4.3.0` (+ __gttf2 __eqtf2 __getf2 __unordtf2). The Redox libgcc_s.so.1 sits in build/gcc/, and the host g++ resolves its libstdc++'s ld script "GROUP ( libgcc_s.so.1 -lgcc )" against the cwd first, binding the REDOX libgcc, which carries no GCC_4.3.0 soft-float symbols. The recipe already defined _rb_linker_for_build for exactly this and never passed it to make -- dead code. BUILD_LDFLAGS and BUILD_CPPFLAGS do not exist in the TOP-LEVEL Makefile (they are gcc/Makefile variables), so a top-level `make BUILD_LDFLAGS=...` never reaches the gcc sub-make. CXX_FOR_BUILD does: the top level defines it and forwards it to every sub-make, and gcc/Makefile.in:870 sets LINKER_FOR_BUILD = $(CXX_FOR_BUILD). Confirmed with `make -n all-gcc` before changing anything. The in-recipe note claiming LINKER_FOR_BUILD was tried and did not reach is superseded: it reaches from inside build/gcc; the problem was propagation from the top level. Sequencing all-gcc first does NOT remove the cause, contrary to the older comment -- it only holds for a clean build. This failure hit during all-gcc before any target library was rebuilt, because a previous run had already left libgcc_s.so.1 behind. Recipes must rebuild correctly on a dirty target/, so the flag is the fix; sequencing stays as defence in depth. 2. Both C++23 modules were silently dropped. src/c++23/Makefile retries with an EMPTIED std.cc when the compile fails, so the build exited 0 having shipped no std.gcm or std.compat.gcm, with 41 'fenv_t has not been declared' errors in the log. #include_next from the new libstdc++ wrapper resolved to the PREFIX toolchain's installed copy of the same wrapper, guarded by the same _GLIBCXX_FENV_H the new one had already defined -- so its body was skipped, relibc's was never reached, and every `using ::` below failed. relibc is not at fault: the header compiles cleanly in C and C++ on its own. Stock GCC builds target libraries with the in-tree compiler, which carries -nostdinc++. Here CXX is the prefix compiler, so CXX_FOR_TARGET is plain and the installed C++ headers stay on the search path. Fixed with CXXFLAGS_FOR_TARGET, a top-level variable that reaches std.lo through LTCXXCOMPILE, set before configure so the generated Makefiles carry it. Verified: 41 errors -> 0, both "Cannot compile ... module" lines gone, std.gcm and std.compat.gcm produced, std.cc/std.compat.cc 4502/795 lines rather than emptied, libstdc++.modules.json staged. Shipping this as an accepted limitation would have been a STUB AND WORKAROUND POLICY violation regardless of GCC's Makefile being what empties the source. 3. Changing CXX_FOR_BUILD makes autoconf refuse against an existing build dir ("`CXX' has changed since the previous run" in build-*/libcpp), since the top level exports it as CXX into the build-side configure environment. That is autoconf working correctly; documented, with the clean-build requirement. Also records the subdirectories configure declines to build in this Canadian cross (libatomic, libgomp, libsanitizer, libbacktrace among them) as an open capability gap needing an operator decision, rather than leaving it unstated. Carries earlier uncommitted working-tree changes to this recipe that the build depends on (the CPPFLAGS sysroot strip, BUILD_CPPFLAGS restatement, static libstdc++ staging, and the GCC 16 move). --- local/docs/NATIVE-TOOLCHAIN-WORKSTREAM.md | 142 ++++++++++++++- local/recipes/dev/gcc-native/recipe.toml | 210 +++++++++++++++++++++- local/sources/base | 2 +- 3 files changed, 347 insertions(+), 7 deletions(-) diff --git a/local/docs/NATIVE-TOOLCHAIN-WORKSTREAM.md b/local/docs/NATIVE-TOOLCHAIN-WORKSTREAM.md index 60772f9b6c..adf657b9ff 100644 --- a/local/docs/NATIVE-TOOLCHAIN-WORKSTREAM.md +++ b/local/docs/NATIVE-TOOLCHAIN-WORKSTREAM.md @@ -141,10 +141,144 @@ printf '#include \nint main(){}' > t.cpp c++ -std=c++17 -I${HOME}/.redoxer/x86_64-unknown-redox/toolchain/include -c t.cpp ``` -So this is a target→host leak, not a host→target one. See the `rust-native` -finding #5 below for the fix pattern (`host:` packages stage into -`COOKBOOK_TOOLCHAIN`, which is a separate tree from the target sysroot); the -same approach should apply here. +So this is a target→host leak, not a host→target one. + +**This section is now historical: `gcc-native` BUILDS (2026-08-05).** Both +`gcc-native` (gcc, cc1, libgcc.a) and the `gcc-native.gcc-native` C++ +subpackage (g++, c++, cc1plus, libstdc++.a, the 16.1.0 C++ headers) cook and +publish. + +A correction to what this file said a few hours earlier: it predicted the +`host:` package pattern from `rust-native` finding #5 would be what unblocked +this. **It was not.** The leak above was already handled in the recipe by +stripping `-I${COOKBOOK_SYSROOT}/include` out of `CPPFLAGS` and restating +`BUILD_CPPFLAGS` without the trailing `$(CPPFLAGS)`. What remained were two +different defects: + +| # | Defect | Resolution | +|---|---|---| +| 11 | Generator links failed with `undefined reference to __letf2@GCC_4.3.0` (+ `__gttf2`, `__eqtf2`, `__getf2`, `__unordtf2`). The Redox `libgcc_s.so.1` sits in `build/gcc/`, and the host `g++` resolves its libstdc++'s `GROUP ( libgcc_s.so.1 -lgcc )` against the cwd first, binding the REDOX libgcc, which has no `GCC_4.3.0` soft-float symbols | pass `CXX_FOR_BUILD="g++ -static-libstdc++"`. The recipe already defined `_rb_linker_for_build` for this and never passed it to make — dead code | +| 12 | `error: 'CXX' has changed since the previous run` from `build-x86_64-pc-linux-gnu/libcpp` — caused by fixing #11, since the top level exports `CXX=$(CXX_FOR_BUILD)` into the build-side subdirs' configure environment | wipe the build dir once (`COOKBOOK_CLEAN_BUILD=true`). Autoconf behaving correctly, not a defect | + +**Why the flag and not the sequencing.** The recipe builds `all-gcc` as its own +make invocation before the target libraries, on the reasoning that sequencing +"removes the cause instead of papering over it". That only holds for a CLEAN +build. Once any previous run has left the Redox `libgcc_s.so.1` in `build/gcc/`, +the *first* `all-gcc` of the next run links its generators beside that file and +fails again — which is exactly what happened. Recipes must rebuild correctly on +a dirty `target/`, so the flag is the fix; the sequencing is kept as defence in +depth. + +**Why `CXX_FOR_BUILD` is the knob that works.** `BUILD_LDFLAGS` and +`BUILD_CPPFLAGS` are `gcc/Makefile` variables that do not exist in the +TOP-LEVEL Makefile, so a top-level `make BUILD_LDFLAGS=…` never reaches the gcc +sub-make. `CXX_FOR_BUILD` is defined at top level and forwarded to every +sub-make explicitly, and `gcc/Makefile.in:870` sets +`LINKER_FOR_BUILD = $(CXX_FOR_BUILD)`. Confirmed with `make -n all-gcc` from +the top level before changing anything: with `CXX_FOR_BUILD` the command +becomes `g++ -static-libstdc++ …`; the `BUILD_LDFLAGS` form leaves it bare. +This supersedes the older in-recipe note claiming `LINKER_FOR_BUILD` was tried +and did not reach — it does reach, from inside `build/gcc`; the problem was +always propagation from the top level. + +### Finding 13 — both C++23 modules were silently dropped (FIXED) + +The build exited 0 while emitting 41 errors, and shipped no `std.gcm` or +`std.compat.gcm`. `gcc/Makefile` deliberately tolerates the failure: + +``` +if ! …compile std.cc…; then + echo "Cannot compile std module" >&2 + echo "Module initialization function will be missing" >&2 + echo > std.cc.tmp && mv std.cc.tmp std.cc && …compile the now-empty file… +fi +``` + +`std.cc` pulls in all of ``, including ``, and libstdc++'s +own `fenv.h` wrapper fails at `using ::fenv_t;` / `::fexcept_t` / the `fe*` +functions. The module source is then replaced with an empty file and the build +continues, so no `std.gcm` is staged. Ordinary `#include ` is unaffected; +only C++23 named modules are. + +**relibc is not at fault, and this is not a missing implementation.** Compiling + +``` +#include +fenv_t e; fexcept_t f; +int main(){ feclearexcept(0); return 0; } +``` + +with `x86_64-unknown-redox-gcc` succeeds cleanly, in C and in C++. Same +"header-path problem, not a missing implementation" pattern as finding #8. + +**Root cause.** `-H` on a reproduction TU shows where `#include_next` lands: + +``` +.. build/…/libstdc++-v3/include/fenv.h <- new wrapper +... prefix/…/relibc-install/x86_64-unknown-redox/include/c++/16.1.0/fenv.h <- include_next +``` + +It reaches the PREFIX toolchain's already-installed copy of the same libstdc++ +wrapper, not relibc's C ``. Both use the guard `_GLIBCXX_FENV_H`, which +the new wrapper defines *before* its `#include_next`, so the installed copy's +body is skipped entirely, the chain dead-ends, and every `using ::` below fails. + +Ordinary `#include` never had this problem — the in-tree `-I` flags come first. +Only `include_next`, which resumes *after* the current header's directory, +walks out of the build tree. + +A stock GCC build never hits it because target libraries are built with the +in-tree compiler, which carries `-nostdinc++`. Here the recipe exports +`CXX=${GNU_TARGET}-g++`, so the top-level Makefile gets +`CXX_FOR_TARGET=RAW_CXX_FOR_TARGET=x86_64-unknown-redox-c++` — plain, with the +installed C++ header directory still on its search path. Only `src/c++17` and +`src/experimental` pass `-nostdinc++` of their own accord, which is why nothing +else broke. + +**Fix:** `export CXXFLAGS_FOR_TARGET="-g -O2 ${CXXFLAGS} -nostdinc++"` before +configure. Unlike `BUILD_*`, it is a top-level variable — forwarded to every +sub-make and exported as target `CXXFLAGS` — so it reaches `std.lo` through +`LTCXXCOMPILE`. Setting it pre-configure bakes it into the generated target +Makefiles so incremental rebuilds stay consistent. + +**Verified:** 41 errors → 0; both "Cannot compile … module" lines gone; +`std.gcm` and `std.compat.gcm` produced; `std.cc`/`std.compat.cc` are 4502/795 +lines rather than emptied; `libstdc++.modules.json` and +`usr/include/c++/16.1.0/bits/std.cc` staged. + +**Process note.** This was first written up as an accepted limitation rather +than fixed. That is a STUB AND WORKAROUND POLICY violation: it does not matter +that GCC's own Makefile performs the emptying — shipping a toolchain whose +modules were removed to make the build pass is the same thing as stubbing them. +Exit code 0 plus present artifacts is not evidence a build is whole; the log +has to be read for swallowed failures. + +### Open: subdirectories configure declines to build + +Not a stub, but a real capability gap in the shipped compiler, recorded rather +than discovered later. `configure` reports: + +``` +*** This configuration is not supported in the following subdirectories: + target-libgomp target-libatomic target-libitm target-libsanitizer + target-libvtv target-libbacktrace target-libffi target-zlib (+ the + Ada/Go/D/Fortran/ObjC/Modula-2/COBOL/Algol68 trees) +``` + +The language trees are irrelevant here (`--enable-languages=c,c++,lto`). These +are not: + +| Subdirectory | Consequence for the shipped toolchain | +|---|---| +| `target-libatomic` | no `libatomic`; some atomic operations will not link | +| `target-libgomp` | `-fopenmp` unavailable | +| `target-libsanitizer` | no ASan/UBSan | +| `target-libbacktrace` | `std::stacktrace` degraded (libstdc++ still builds `stacktrace.cc`) | + +This is GCC's Canadian-cross limitation for a `--host==--target` build driven +from a Linux build machine, not something the recipe introduced. Needs an +operator decision: accept the reduced toolchain, or restructure the build so +these are supported. ## `rust-native` — four findings, one open diff --git a/local/recipes/dev/gcc-native/recipe.toml b/local/recipes/dev/gcc-native/recipe.toml index 0a58d035ca..5784693145 100644 --- a/local/recipes/dev/gcc-native/recipe.toml +++ b/local/recipes/dev/gcc-native/recipe.toml @@ -58,6 +58,30 @@ DYNAMIC_INIT # Same shape as the cpuid.h shadowing in recipes/dev/gcc13. export CPPFLAGS="-I${COOKBOOK_SOURCE}/include ${CPPFLAGS}" +# Drop the target sysroot from CPPFLAGS entirely. +# +# src/cook/script.rs adds -I${COOKBOOK_SYSROOT}/include to CPPFLAGS for every +# recipe. For GCC that is actively harmful: gcc/Makefile feeds $(CPPFLAGS) to +# the build/ generators too, which run on the BUILD machine and are compiled by +# the host g++ against host glibc and libstdc++. relibc's headers then shadow +# glibc's and the host's own headers stop parsing: +# /usr/include/c++/16/.../bits/os_defines.h:44: +# error: missing binary operator before token '(' +# #if __GLIBC_PREREQ(2,15) && defined(_GNU_SOURCE) +# __GLIBC_PREREQ comes from glibc's ; relibc's shadowing copy has +# no such macro. Overriding BUILD_CPPFLAGS alone is not enough -- $(CPPFLAGS) +# reaches those compiles by more than one route. +# +# Nothing needs it here: target headers come from the cross compiler's own +# --with-sysroot, and gmp/mpfr/mpc are located by explicit --with-* flags below. +# (sed with a '|' delimiter rather than bash ${var//a/b}: the pattern contains +# slashes, and a backslash-escaped slash is an invalid escape sequence inside a +# TOML multi-line basic string. The parser reads this whole script as one +# string, so shell comments are not exempt from either that rule or from +# accidentally closing the quote.) +CPPFLAGS="$(printf '%s' "${CPPFLAGS}" | sed "s|-I${COOKBOOK_SYSROOT}/include||g")" +export CPPFLAGS + export CFLAGS="${CFLAGS//-std=gnu17/}" export CXXFLAGS="${CXXFLAGS//-std=gnu17/}" @@ -70,6 +94,44 @@ export LD="${GNU_TARGET}-ld" export NM="${GNU_TARGET}-nm" export STRIP="${GNU_TARGET}-strip" +# Build the TARGET libraries with -nostdinc++, or libstdc++ is compiled against +# the PREFIX toolchain's already-installed libstdc++ headers. +# +# A stock GCC build never needs this stated: it builds target libraries with the +# in-tree compiler, which carries -nostdinc++ and -B flags of its own. Here CXX +# is the prefix compiler (set above, and this configures --host=--target=redox), +# so the top-level Makefile ends up with +# CXX_FOR_TARGET=x86_64-unknown-redox-c++ +# RAW_CXX_FOR_TARGET=x86_64-unknown-redox-c++ +# -- plain, with the installed C++ header directory still on its search path. +# +# Ordinary #include is unaffected, because the -I flags for the in-tree headers +# come first. #include_next is NOT: it resumes the search AFTER the directory +# holding the current header, which walks straight out of the build tree and +# into prefix/.../include/c++/16.1.0. libstdc++'s own c_compatibility/fenv.h +# does exactly that to reach the C , and lands on the INSTALLED copy of +# itself -- which is guarded by the same _GLIBCXX_FENV_H the new one has already +# defined, so its body is skipped, relibc's fenv.h is never reached, and every +# declaration in the block below it fails: +# .../libstdc++-v3/include/fenv.h:65: error: 'fenv_t' has not been declared in '::' +# (then fexcept_t, feclearexcept, fegetexceptflag, ... 41 errors) +# +# That killed the C++23 `std` module: src/c++23/Makefile's std.lo rule retries +# with an EMPTIED std.cc when the compile fails, so the build went green while +# silently shipping no std.gcm. Suppressing a module to make a build pass is a +# stub by another name (local/AGENTS.md, STUB AND WORKAROUND POLICY) -- the +# header path is the defect and is what gets fixed. +# +# Verified by reproducing the failure in a two-line TU with the same -I chain +# and no -fmodules, then compiling it clean with -nostdinc++ added. +# +# CXXFLAGS_FOR_TARGET is the right knob: unlike BUILD_*, it is a TOP-LEVEL +# variable (forwarded to every sub-make, and exported as CXXFLAGS for target +# directories), so it reaches std.lo through LTCXXCOMPILE. Set before configure +# so the generated target Makefiles carry it and incremental rebuilds stay +# consistent. "-g -O2" reproduces the default configure would have derived. +export CXXFLAGS_FOR_TARGET="-g -O2 ${CXXFLAGS} -nostdinc++" + # Configure for native compilation: host AND target are both redox COOKBOOK_CONFIGURE_FLAGS+=( --host="${GNU_TARGET}" @@ -92,8 +154,129 @@ COOKBOOK_CONFIGURE_FLAGS+=( ) "${COOKBOOK_CONFIGURE}" "${COOKBOOK_CONFIGURE_FLAGS[@]}" -"${COOKBOOK_MAKE}" -j "${COOKBOOK_MAKE_JOBS}" all-gcc all-target-libgcc all-target-libstdc++-v3 -"${COOKBOOK_MAKE}" install-gcc install-target-libgcc install-target-libstdc++-v3 DESTDIR="${COOKBOOK_STAGE}" + +# Keep the TARGET sysroot out of HOST-side compiles. +# +# gcc/Makefile.in:875 defines +# BUILD_CPPFLAGS= -I. -I$(@D) -I$(srcdir) -I$(srcdir)/$(@D) \ +# -I$(srcdir)/../include $(INCINTL) $(CPPINC) $(CPPFLAGS) +# -- it ends in $(CPPFLAGS). The generators in build/ (genversion, genmodes, +# gengtype, ...) run on the BUILD machine and are compiled by the host g++ +# against host glibc and libstdc++ headers, but that trailing $(CPPFLAGS) +# hands them the target's -I${COOKBOOK_SYSROOT}/include as well (the cookbook +# adds it to every recipe, src/cook/script.rs). relibc's headers then shadow +# glibc's, so glibc's own macros are never defined and its headers stop +# parsing: +# /usr/include/sys/single_threaded.h:24: error: '__BEGIN_DECLS' is not a type +# /usr/include/stdlib.h:752: error: expected initializer before '__THROW' +# with relibc's `#define __noreturn [[noreturn]]` colliding on top. +# +# The top-level CPPFLAGS_FOR_BUILD knob does NOT reach this: configure already +# generates it empty in build/Makefile, and gcc/Makefile still appends +# $(CPPFLAGS) regardless. So restate the definition verbatim, minus that one +# trailing variable. Single-quoted: these are make variables, expanded per +# rule by make, not by this shell. +_rb_build_cppflags='-I. -I$(@D) -I$(srcdir) -I$(srcdir)/$(@D) -I$(srcdir)/../include $(INCINTL) $(CPPINC)' + +# Same leak, link side. configure derives BUILD_LDFLAGS from LDFLAGS_FOR_BUILD, +# which defaults to $LDFLAGS -- and the cookbook puts the TARGET sysroot in +# there: "-L${COOKBOOK_SYSROOT}/lib -Wl,-rpath-link,${COOKBOOK_SYSROOT}/lib". +# gcc/Makefile.in:3421 then links the build/ generators with +# $(LINKER_FOR_BUILD) $(BUILD_LINKERFLAGS) $(BUILD_LDFLAGS) +# so the HOST g++ searches Redox libraries first and cannot resolve the host's +# own libgcc_s, leaving its libstdc++.so short of the 128-bit float builtins: +# /usr/lib/gcc/x86_64-pc-linux-gnu/16/libstdc++.so: +# undefined reference to `__letf2@GCC_4.3.0' (also __gttf2, __eqtf2, +# __getf2, __unordtf2 -- all libgcc soft-float TF symbols) +# Emptying BUILD_LDFLAGS is enough here, unlike the CPPFLAGS case: the only +# other variable on that rule is BUILD_LINKERFLAGS, which is BUILD_CXXFLAGS and +# carries no -L. Target-side links are untouched and still resolve through the +# cross compiler's --with-sysroot. +# Link the build/ generators against a STATIC libstdc++. +# +# all-target-libgcc writes the REDOX libgcc_s.so.1 into build/gcc/ -- the very +# directory the host-side generator links run from. The host g++ pulls in its +# own libstdc++.so, whose DT_NEEDED is satisfied through the ld script +# GROUP ( libgcc_s.so.1 -lgcc ) +# and that bare filename resolves against the current directory first, so the +# HOST link binds the REDOX libgcc_s. It carries no GCC_4.3.0-versioned soft +# float symbols, so the host libstdc++ is left unresolved: +# /usr/lib/gcc/x86_64-pc-linux-gnu/16/libstdc++.so: +# undefined reference to `__letf2@GCC_4.3.0' +# (also __gttf2, __eqtf2, __getf2, __unordtf2) +# +# Verified directory-dependent: the identical g++ command passes from the repo +# root and fails from build/gcc. It is also why a FIRST build succeeds and only +# a rebuild fails -- on the first pass target libgcc does not exist yet. +# +# -static-libstdc++ removes the dependency being mis-resolved, and was measured +# to be the variant that links (plain, +libiberty, and +libiberty -lgcc_s all +# fail from that directory; -static-libstdc++ passes). The sysroot -L/-rpath-link +# that LDFLAGS would otherwise contribute is dropped by not forwarding LDFLAGS. +_rb_build_ldflags='-static-libstdc++' +# BUILD_LDFLAGS does not reach these rules AT ALL from a top-level make, and +# the reason is not that the rules ignore it. +# +# gcc/Makefile does use it -- build/genversion links with +# $(LINKER_FOR_BUILD) $(BUILD_LINKERFLAGS) $(BUILD_LDFLAGS) +# and overriding either BUILD_LDFLAGS or LINKER_FOR_BUILD from INSIDE build/gcc +# puts the flag in the emitted command. But BUILD_LDFLAGS and BUILD_CPPFLAGS do +# not exist in the TOP-LEVEL Makefile at all; they are gcc/Makefile variables. +# A top-level `make BUILD_LDFLAGS=...` therefore never lands in the gcc +# sub-make, which is why the generator links kept coming out bare: +# g++ -DIN_GCC -DGENERATOR_FILE build/genversion.o -o build/genversion +# +# CXX_FOR_BUILD is the knob that does reach: the top level defines it (= g++) +# and forwards it to every sub-make explicitly, and gcc/Makefile.in:870 sets +# LINKER_FOR_BUILD = $(CXX_FOR_BUILD) +# so the flag applies uniformly to every build/ generator link. Verified with +# `make -n all-gcc` from the top level: with CXX_FOR_BUILD the command becomes +# g++ -static-libstdc++ -DIN_GCC -DGENERATOR_FILE build/genversion.o -o ... +# while the BUILD_LDFLAGS form leaves it unchanged. +# +# It is passed for compiles as well as links, which is harmless -- g++ accepts +# -static-libstdc++ on a -c command line and it affects nothing there. +# +# NOTE for anyone changing this value: the top level exports it as CXX to the +# build-side subdirectories (Makefile "CXX=$(CXX_FOR_BUILD); export CXX"), so +# it is part of their configure environment. Changing it against an existing +# build/ makes autoconf refuse: +# error: `CXX' has changed since the previous run: +# in `build-x86_64-pc-linux-gnu/libcpp': +# run `make distclean' and/or `rm ./config.cache' and start over +# That is autoconf working correctly, not a defect. Wipe the build directory +# (COOKBOOK_CLEAN_BUILD=true, or make c.gcc-native) when this value changes; +# once configured with it, later incremental rebuilds are consistent. +_rb_cxx_for_build='g++ -static-libstdc++' + +# Build all-gcc FIRST, as its own make invocation, before the target libraries. +# +# all-target-libgcc installs the REDOX libgcc_s.so.1 into build/gcc/ -- the same +# directory the host-side generator links (genchecksum, genversion, ...) run +# from. The host g++ needs its own libstdc++, whose libgcc dependency resolves +# through the ld script "GROUP ( libgcc_s.so.1 -lgcc )", and that bare filename +# is matched against the current directory first -- so the HOST link binds the +# REDOX libgcc_s, which has no GCC_4.3.0-versioned soft-float symbols: +# /usr/lib/gcc/x86_64-pc-linux-gnu/16/libstdc++.so: +# undefined reference to `__letf2@GCC_4.3.0' (+ __gttf2 __eqtf2 +# __getf2 __unordtf2) +# Confirmed cwd-dependent: the identical g++ command passes from the repo root +# and fails from build/gcc. It is also why the FIRST build of this recipe +# succeeds and only rebuilds fail -- initially that file does not exist yet. +# +# Listing the goals in one -j make does not help: make interleaves them, so the +# file can appear before the generators are linked. +# +# Sequencing alone is NOT sufficient, though, and relying on it hid that: it +# only holds for a CLEAN build. Once a previous run has left the Redox +# libgcc_s.so.1 in build/gcc/, the very first all-gcc of the NEXT run links its +# generators next to that file and fails again -- which is exactly what +# happened here, in all-gcc, before any target library was rebuilt. Recipes +# must rebuild correctly on a dirty target/, so the CXX_FOR_BUILD override +# above is the actual fix and the sequencing is kept as defence in depth. +"${COOKBOOK_MAKE}" -j "${COOKBOOK_MAKE_JOBS}" CXX_FOR_BUILD="${_rb_cxx_for_build}" BUILD_CPPFLAGS="${_rb_build_cppflags}" BUILD_LDFLAGS="${_rb_build_ldflags}" all-gcc +"${COOKBOOK_MAKE}" -j "${COOKBOOK_MAKE_JOBS}" CXX_FOR_BUILD="${_rb_cxx_for_build}" BUILD_CPPFLAGS="${_rb_build_cppflags}" BUILD_LDFLAGS="${_rb_build_ldflags}" all-target-libgcc all-target-libstdc++-v3 +"${COOKBOOK_MAKE}" CXX_FOR_BUILD="${_rb_cxx_for_build}" BUILD_CPPFLAGS="${_rb_build_cppflags}" BUILD_LDFLAGS="${_rb_build_ldflags}" install-gcc install-target-libgcc install-target-libstdc++-v3 DESTDIR="${COOKBOOK_STAGE}" # Native GCC doesn't need the target prefix for tool in gcc g++ c++ cpp gcc-ar gcc-nm gcc-ranlib gcov gcov-dump gcov-tool gfortran; do @@ -109,6 +292,29 @@ ln -sf gcc "${COOKBOOK_STAGE}/usr/bin/cc" rm -f "${COOKBOOK_STAGE}"/usr/lib/libgcc_s.so* "${COOKBOOK_STAGE}"/usr/lib/libstdc++.so* rm -f "${COOKBOOK_STAGE}"/usr/lib/*.la +# Stage the static libstdc++. +# +# The comment below has always said "libgcc and libstdc++", but only libgcc was +# ever copied, and the package shipped no usable C++ runtime at all: +# - install-target-libstdc++-v3 installs the SHARED libstdc++.so* (plus +# libstdc++exp.a). libtool does not install a static libstdc++.a, even +# though the build produces one. +# - the `rm -f ... libstdc++.so*` line just above then deletes what it did +# install. +# Net result: usr/lib held libstdc++exp.a and nothing else, so a native g++ +# could compile but never link a C++ program. +# +# Take the static archive straight from the build tree. It lands in usr/lib so +# the `usr/lib/*c++*` glob in [[optional-packages]] routes it into the C++ +# package alongside cc1plus and the headers, rather than the C-only package. +_rb_libstdcxx="${COOKBOOK_BUILD}/${GNU_TARGET}/libstdc++-v3/src/.libs/libstdc++.a" +if [ -f "${_rb_libstdcxx}" ]; then + cp -a "${_rb_libstdcxx}" "${COOKBOOK_STAGE}/usr/lib/" +else + echo "ERROR: static libstdc++.a not found at ${_rb_libstdcxx}" >&2 + exit 1 +fi + # Copy libgcc and libstdc++ into target lib dir mkdir -p "${COOKBOOK_STAGE}/usr/lib/${GNU_TARGET}" # Version-globbed: a hardcoded GCC version here silently stops matching the diff --git a/local/sources/base b/local/sources/base index 70077c518b..3e4e3e4f46 160000 --- a/local/sources/base +++ b/local/sources/base @@ -1 +1 @@ -Subproject commit 70077c518b1bd4b9751d264c226441dac9a46263 +Subproject commit 3e4e3e4f46b8a95ca1a9b6812fe90ddd87f16868