diff --git a/.gitignore b/.gitignore index be7c8824c7..5dfa004cda 100644 --- a/.gitignore +++ b/.gitignore @@ -88,3 +88,10 @@ Packages/*.pkgar # from build-redbear.sh — never commit them. The toolchain is rebuilt by # `make prefix` after fork (relibc/kernel/base) changes. /prefix/**/*.tar.gz + +# GCC 16 cross-toolchain build artifacts (reproducible via +# local/scripts/build-gcc16-cross.sh from local/recipes/dev/gcc16/source.tar) +/build/gcc16-build/ +/build/gcc16-install/ +/build/gcc13-backup/ +/build/host-tools/ diff --git a/local/patches/gcc-redox-port/README.md b/local/patches/gcc-redox-port/README.md index 91e188155e..ae8faa6012 100644 --- a/local/patches/gcc-redox-port/README.md +++ b/local/patches/gcc-redox-port/README.md @@ -97,19 +97,84 @@ offline-first build model and matches how other external recipes vendor sources `gitlab.redox-os.org/redox-os/gcc` carries **no** upstream release tags, so the pristine base must come from ftp.gnu.org or gcc-mirror, not from the Redox fork. -## Next steps (in order) +## Two things the extraction missed -1. Vendor `gcc-16.1.0.tar.xz`, record its blake3, create - `local/recipes/dev/gcc16/recipe.toml` (model on `recipes/dev/gcc13`). -2. Apply `files/` + the arms in `registration-hunks.txt`; regenerate `configure` - from `crossconfig.m4` with autoconf. -3. Parameterize the hardcoded `13.2.0` in `mk/prefix.mk` (at minimum the - `lib/gcc/$(GNU_TARGET)/13.2.0/include/limits.h` path). -4. Build the cross compiler; stage into `prefix/`. Expect relibc header - fallout (see risks above) before anything else compiles. -5. Full C++ tree rebuild for the libstdc++ ABI change — Qt6, all KF6, Plasma, - Mesa C++. Budget this as the dominant cost, not the port itself. -6. Only then retry `kwin`, whose 16 `std::ranges::to` files are the reason for - the whole exercise. +The "13 files" count above was derived by grepping the `redox-13.2.0` fork for +"redox". Two requirements do not show up that way and both are fatal if skipped. -**Not started.** Steps 1–6 are unvalidated; nothing below step 0 has been run. +### 1. `gcc/config/redox.opt.urls` (new in GCC 16) + +GCC 16 requires a `.opt.urls` companion for every `.opt` file; `s-options` +fails with *"No rule to make target ... redox.opt.urls"*. GCC 13 had no such +rule. The file is now carried in `files/` and matches what +`gcc/regenerate-opt-urls.py` produces: `rdynamic` gets the standard +`gcc/Link-Options.html#index-rdynamic` suffix, and `pthread` is skipped with the +duplicate-URL comment — identical to the six other upstream `.opt.urls` that +declare the same two options. + +### 2. libtool has no `redox` host — `apply-libtool-redox.py` + +Upstream Redox's GCC fork does not carry redox arms in GCC's bundled +`libtool.m4` either. Their toolchain gets shared libraries because +`recipes/dev/libtool` is a **Redox-patched GNU libtool (2.5.4-redox-9510)** +whose `libtoolize` overwrites the tree's `libtool.m4` during `autoreconf -fvi`. +That route is not usable here: GCC 16 bundles 2.2.7-era macros plus its own +`ltgcc.m4`, and gcc13's recipe only regenerates when an `autoreconf2.69` +happens to be on `PATH`. + +Without the arms, `_LT_SYS_DYNAMIC_LINKER` leaves `dynamic_linker=no` for +redox, so configure reports *"libtool supports shared libraries... no"* and +libstdc++ builds **static only**. That is fatal: `libQt6Core.so` and every KF6 +library carry `DT_NEEDED libstdc++.so.6` (`readelf -d`), so the desktop stack +cannot link against a static-only toolchain. `apply-libtool-redox.py` registers +the four arms that matter, copied verbatim from the Redox libtool macros in +`prefix//gcc-install/share/aclocal/libtool.m4`. + +## Applying to a new GCC (validated sequence) + +```bash +tar xf source.tar -C local/recipes/dev/gcc16/source --strip-components=1 +python3 local/patches/gcc-redox-port/apply-redox-port.py local/recipes/dev/gcc16/source +python3 local/patches/gcc-redox-port/apply-libtool-redox.py local/recipes/dev/gcc16/source +# configure is GENERATED -- regenerate with autoconf 2.69 (GCC pins that exact +# version via config/override.m4; the host's 2.73 is rejected). +(cd local/recipes/dev/gcc16/source/libstdc++-v3 && autoconf) +./local/scripts/build-gcc16-cross.sh # cross compiler + libgcc + libstdc++ +./local/scripts/install-gcc16-toolchain.sh # into prefix + ~/.redoxer (reversible) +``` + +Both appliers are idempotent and report an unmatched anchor rather than +silently producing a half-ported tree. + +## Status — GCC 16.1.0 ported and installed + +| Step | State | +|---|---| +| `gcc-16.1.0.tar.xz` vendored (`local/recipes/dev/gcc16/source.tar`) | done | +| Redox target port applied (10 edits + 6 files) | done | +| `libstdc++-v3/configure` regenerated with autoconf 2.69 | done — purely additive, 3240 lines, no drift | +| Cross compiler built | done — `x86_64-unknown-redox-gcc (GCC) 16.1.0` | +| libgcc + shared libstdc++ | done — `libstdc++.so.6.0.35`, SONAME `libstdc++.so.6`, `NEEDED libc.so.6 libgcc_s.so.1` (identical to the 13.2.0 library it replaces) | +| **`std::ranges::to`** | **works** — `__cpp_lib_ranges_to_container` defined; GCC 13 fails the same test with *"'to' is not a member of 'std::ranges'"* | +| Installed into prefix + `~/.redoxer` | done, reversible via `install-gcc16-toolchain.sh --restore` | + +ABI note: `libstdc++.so.6.0.35` exports up to `GLIBCXX_3.4.35` where 13.2.0 +reached `3.4.32`, and keeps SONAME `libstdc++.so.6` — a backward-compatible +superset, so already-linked binaries still resolve. Recompilation is still +required to *use* the new headers. + +### Still open + +- `mk/prefix.mk` hardcodes `13.2.0` (line 354, the `limits.h` removal) and + `GCC_TARGET=recipes/dev/gcc13/...` (line 10). Neither is on the path this + port takes, but both must be parameterized before the toolchain can be + rebuilt through `make prefix`. +- `local/recipes/dev/gcc16/recipe.toml` does not exist. The cross compiler is + currently produced by `local/scripts/build-gcc16-cross.sh` instead, because + the cookbook's from-source toolchain path is dead: `mk/prefix.mk:315` copies + `$(GCC_TARGET)/stage.cxx/`, and nothing in `src/` produces a `stage.cxx`. +- Full C++ tree rebuild against the new toolchain — the dominant cost, and the + reason the whole exercise exists (`kwin`'s 16 `std::ranges::to` files). +- `riscv64*-*-redox*` is recorded in `registration-points.txt` for + `libgcc/config.host` but is not in the applier's block. Irrelevant for + amd64-only Red Bear; noted so the gap is not mistaken for completeness. diff --git a/local/patches/gcc-redox-port/apply-libtool-redox.py b/local/patches/gcc-redox-port/apply-libtool-redox.py new file mode 100755 index 0000000000..dc1698ead1 --- /dev/null +++ b/local/patches/gcc-redox-port/apply-libtool-redox.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python3 +"""Register the Redox host OS in GCC's bundled libtool.m4. + +Usage: apply-libtool-redox.py [--check] + +Why this is separate from apply-redox-port.py +--------------------------------------------- +The original port extraction (README.md, registration-points.txt) measured +the Redox port by grepping redox-os/gcc for "redox" and found 13 files. It +missed libtool: upstream Redox does not carry redox arms in GCC's bundled +libtool.m4 either. Their toolchain gets shared-library support because +recipes/dev/libtool is a Redox-patched GNU libtool (2.5.4-redox-9510) whose +libtoolize overwrites the tree's libtool.m4 during `autoreconf -fvi`. + +That path is not usable for GCC 16: GCC bundles libtool 2.2.7-era macros +plus its own ltgcc.m4 overrides, and gcc13's recipe only regenerates when +an autoreconf2.69 happens to be on PATH. Splicing 2.5.4 wholesale into a +2.2.7 tree risks a macro-version mismatch across the whole GCC build. + +Without these arms libtool's _LT_SYS_DYNAMIC_LINKER leaves dynamic_linker=no +for redox, so "libtool supports shared libraries... no" and libstdc++ builds +static-only. That is fatal here: libQt6Core.so and every KF6 library carry +DT_NEEDED libstdc++.so.6, so the desktop stack cannot link without a shared +libstdc++ matching the compiler's headers. + +The arm contents below are copied verbatim from the Redox libtool 2.5.4 +macros already present in this repo at + prefix//gcc-install/share/aclocal/libtool.m4 +so the behaviour matches the toolchain they replace. They are plain shell +case arms and are version-agnostic; only the ANCHORS are GCC-version +sensitive, and a missing anchor is reported rather than silently skipped. +""" + +import sys +from pathlib import Path + +MAX_CMD_LEN = """ redox*) + # Under Redox, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + +""" + +DYNAMIC_LINKER = """redox*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + dynamic_linker='relibc ld64.so' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +""" + +DEPLIBS = """redox*) + lt_cv_deplibs_check_method=pass_all + ;; + +""" + +# C++ tag: no special PIC handling needed, -fPIC comes from the generic path. +PIC_CXX = """ redox*) +\t;; +""" + +PIC_C = """ redox*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + +""" + +ARCHIVE_C = """ redox*) +\t_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' +\t_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + ;; + +""" + +LD_SHLIBS_CXX = """ redox*) + _LT_TAGVAR(ld_shlibs, $1)=yes +\t;; + +""" + +# (anchor, block, description) +EDITS = [ + (" gnu*)\n # Under GNU Hurd, this test is not required because there is", + MAX_CMD_LEN, "max_cmd_len"), + ("newsos6)\n version_type=linux", + DYNAMIC_LINKER, "dynamic_linker (enables shared libs)"), + ("newos6*)\n lt_cv_deplibs_check_method=", + DEPLIBS, "deplibs_check_method"), + (" netbsd*)\n if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then\n\t _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects", + LD_SHLIBS_CXX, "ld_shlibs (C++ tag)"), +] + + +def probe_present(text: str, block: str) -> bool: + """A block counts as present when its longest redox-bearing line already + exists as a complete line. Same rule as apply-redox-port.py: a plain + longest-line probe matches generic libtool boilerplate.""" + redox_lines = [l.strip() for l in block.strip().splitlines() + if "redox" in l.lower()] + if not redox_lines: + return False + probe = max(redox_lines, key=len) + return any(l.strip() == probe for l in text.splitlines()) + + +def main() -> int: + if len(sys.argv) < 2: + print(__doc__) + return 2 + root = Path(sys.argv[1]).resolve() + check = "--check" in sys.argv + p = root / "libtool.m4" + if not p.is_file(): + print(f"ERROR: {p} not found", file=sys.stderr) + return 2 + + text = p.read_text(encoding="utf-8", errors="replace") + rc = 0 + pending = [] + + for anchor, block, desc in EDITS: + if probe_present(text, block): + print(f"skip {desc} (already present)") + continue + idx = text.find(anchor) + if idx == -1: + print(f"ANCHOR-FAIL {desc} :: anchor not found -- re-derive for " + f"this GCC version", file=sys.stderr) + rc = 1 + continue + if text.count(anchor) != 1: + print(f"AMBIGUOUS {desc} :: anchor occurs {text.count(anchor)}x", + file=sys.stderr) + rc = 1 + continue + print(f"{'would-apply' if check else 'applied '} {desc}") + pending.append((idx, block)) + + if not check and pending: + # Apply back-to-front so earlier offsets stay valid. + for idx, block in sorted(pending, key=lambda t: -t[0]): + text = text[:idx] + block + text[idx:] + p.write_text(text, encoding="utf-8") + + if rc: + print("libtool.m4 is NOT fully registered for redox.", file=sys.stderr) + else: + print("\nNEXT: regenerate libstdc++-v3/configure with autoconf 2.69.") + return rc + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/local/patches/gcc-redox-port/apply-redox-port.py b/local/patches/gcc-redox-port/apply-redox-port.py index 7572643d04..c2d046f11c 100755 --- a/local/patches/gcc-redox-port/apply-redox-port.py +++ b/local/patches/gcc-redox-port/apply-redox-port.py @@ -174,12 +174,29 @@ def apply_edit(root: Path, rel: str, anchor: str, block: str, check: bool) -> st # the generic block starts "*-redox*)", which occurs inside the already # inserted "aarch64-*-redox* | riscv64*-*-redox*)" and made the second # crossconfig.m4 block silently skip. - # Probe on the block's LONGEST line, matched whole. The first line is not - # distinctive enough: CONFIG_GCC_TARGETS starts "aarch64-*-redox*)", which - # also appears (indented) inside CONFIG_GCC_OS, so a first-line probe made - # the tm_file arms silently skip. - probe = max((l.strip() for l in block.strip().splitlines()), key=len) - if probe and any(l.strip() == probe for l in text.splitlines()): + # Probe on the block's longest REDOX-BEARING line, matched whole. Both + # halves of that rule are load-bearing: + # - "redox-bearing": a plain longest-line probe picks generic upstream + # boilerplate. On GCC 16.1.0 that made three blocks silently skip + # against a pristine tree -- LIBGCC_TARGETS probed + # 'tmake_file="${tmake_file} ${cpu_type}/t-lse t-slibgcc-libgcc"' + # (3 upstream hits) and both crossconfig.m4 blocks probed + # "SECTION_FLAGS='-ffunction-sections -fdata-sections'" (7 hits) and + # "AC_CHECK_FUNCS(aligned_alloc posix_memalign memalign + # _aligned_malloc)" (4 hits), yielding a half-ported tree with no + # libgcc target arms and no libstdc++ redox support. + # - "whole line": CROSSCONFIG_GENERIC's marker is "*-redox*)", a + # substring of the already-inserted + # "aarch64-*-redox* | riscv64*-*-redox*)". + # Longest (not first) still matters: CONFIG_GCC_TARGETS starts + # "aarch64-*-redox*)", which also appears indented inside CONFIG_GCC_OS. + redox_lines = [l.strip() for l in block.strip().splitlines() + if "redox" in l.lower()] + if not redox_lines: + return (f"NO-PROBE {rel} :: block has no redox-bearing line; " + "cannot test idempotency safely") + probe = max(redox_lines, key=len) + if any(l.strip() == probe for l in text.splitlines()): return f"skip {rel} (block already present)" idx = text.find(anchor) if idx == -1: @@ -250,7 +267,7 @@ def main() -> int: for rel, anchor, block, _ in EDITS: msg = apply_edit(root, rel, anchor, block, check) print(msg) - if "ANCHOR-FAIL" in msg or "MISSING" in msg: + if any(k in msg for k in ("ANCHOR-FAIL", "MISSING", "NO-PROBE")): rc = 1 print() diff --git a/local/patches/gcc-redox-port/files/gcc/config/redox.opt.urls b/local/patches/gcc-redox-port/files/gcc/config/redox.opt.urls new file mode 100644 index 0000000000..a7f8f27399 --- /dev/null +++ b/local/patches/gcc-redox-port/files/gcc/config/redox.opt.urls @@ -0,0 +1,8 @@ +; Autogenerated by regenerate-opt-urls.py from gcc/config/redox.opt and generated HTML + +; skipping UrlSuffix for 'pthread' due to multiple URLs: +; duplicate: 'gcc/Link-Options.html#index-pthread-1' +; duplicate: 'gcc/Preprocessor-Options.html#index-pthread' + +rdynamic +UrlSuffix(gcc/Link-Options.html#index-rdynamic) diff --git a/local/scripts/build-gcc16-cross.sh b/local/scripts/build-gcc16-cross.sh new file mode 100755 index 0000000000..c431bc94b2 --- /dev/null +++ b/local/scripts/build-gcc16-cross.sh @@ -0,0 +1,96 @@ +#!/usr/bin/env bash +# Build the GCC 16 cross-compiler (x86_64-linux -> x86_64-unknown-redox). +# +# Why this exists +# --------------- +# mk/prefix.mk has two toolchain paths: +# PREFIX_BINARY=1 (the default, mk/config.mk:13) downloads a prebuilt +# GCC 13.2.0 from static.redox-os.org. +# PREFIX_BINARY=0 cooks host:gcc13 through the cookbook. +# The second path is dead in this fork: it copies +# "$(GCC_TARGET)/stage.cxx/usr/" (mk/prefix.mk:315) and nothing in src/ +# ever produces a stage.cxx directory, so it cannot have run. Repairing +# the cookbook's from-source path is a separate piece of work and is not +# required to obtain a newer GCC. +# +# This script therefore builds the cross compiler directly against the +# artifacts the prefix already provides: binutils 2.43.1 and the relibc +# sysroot (libc.a, crt*.o, headers). Configure flags mirror the cross arm +# of recipes/dev/gcc13/recipe.toml so the resulting compiler is +# configured like the one it replaces. +# +# The GCC 16 source must already carry the Redox target port: +# python3 local/patches/gcc-redox-port/apply-redox-port.py \ +# local/recipes/dev/gcc16/source +# (then regenerate libstdc++-v3/configure with autoconf 2.69) +# See local/patches/gcc-redox-port/README.md. +set -euo pipefail + +ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd) +TARGET=x86_64-unknown-redox +PREFIX_DIR="$ROOT/prefix/$TARGET" +SYSROOT="$PREFIX_DIR/sysroot/$TARGET" +SRC="$ROOT/local/recipes/dev/gcc16/source" +BUILD="$ROOT/build/gcc16-build" +INSTALL="$ROOT/build/gcc16-install" +JOBS="${JOBS:-$(nproc)}" + +for req in "$SRC/gcc/BASE-VER" "$SYSROOT/lib/libc.a" "$PREFIX_DIR/gcc-install/bin/$TARGET-as"; do + [ -e "$req" ] || { echo "FATAL: missing prerequisite: $req" >&2; exit 1; } +done + +# The port must be present, or we would silently build a compiler with no +# Redox target and only discover it at the end of a ~40 minute build. +grep -q 'redox' "$SRC/gcc/config.gcc" || { + echo "FATAL: $SRC is not Redox-ported (gcc/config.gcc has no redox arm)." >&2 + echo " Run local/patches/gcc-redox-port/apply-redox-port.py first." >&2 + exit 1 +} +grep -q 'redox' "$SRC/libstdc++-v3/configure" || { + echo "FATAL: libstdc++-v3/configure has no redox arm -- it was not" >&2 + echo " regenerated from the patched crossconfig.m4 (autoconf 2.69)." >&2 + exit 1 +} + +echo "GCC version : $(cat "$SRC/gcc/BASE-VER")" +echo "target : $TARGET" +echo "sysroot : $SYSROOT" +echo "install : $INSTALL" +echo "jobs : $JOBS" + +export PATH="$PREFIX_DIR/gcc-install/bin:$PATH" +# Redox has no SystemTap probes, but the configure probe can see the host's +# sys/sdt.h and then libgcc fails including a header the target lacks. +# Same reasoning as recipes/dev/gcc13/recipe.toml. +export gcc_cv_sys_sdt_h=no + +rm -rf "$BUILD" "$INSTALL" +mkdir -p "$BUILD" "$INSTALL" +cd "$BUILD" + +"$SRC/configure" \ + --build=x86_64-pc-linux-gnu \ + --host=x86_64-pc-linux-gnu \ + --target="$TARGET" \ + --prefix="$INSTALL" \ + --with-sysroot="$SYSROOT" \ + --with-native-system-header-dir="/include" \ + --with-linker-hash-style=gnu \ + --enable-languages=c,c++,lto \ + --enable-initfini-array \ + --enable-threads=posix \ + --enable-libstdcxx-threads \ + --enable-frame-pointer \ + --disable-nls \ + --disable-multilib \ + --disable-bootstrap \ + --with-bugurl="https://gitea.redbearos.org/vasilito/RedBear-OS/-/issues" + +"${MAKE:-make}" -j "$JOBS" all-gcc +"${MAKE:-make}" -j "$JOBS" all-target-libgcc +"${MAKE:-make}" -j "$JOBS" all-target-libstdc++-v3 +"${MAKE:-make}" install-gcc install-target-libgcc install-target-libstdc++-v3 + +echo +echo "BUILD OK" +"$INSTALL/bin/$TARGET-gcc" --version | head -1 diff --git a/local/scripts/install-gcc16-toolchain.sh b/local/scripts/install-gcc16-toolchain.sh new file mode 100755 index 0000000000..a696bb6c9d --- /dev/null +++ b/local/scripts/install-gcc16-toolchain.sh @@ -0,0 +1,121 @@ +#!/usr/bin/env bash +# Install the GCC 16 cross compiler over the GCC 13.2.0 one, in every +# location the build actually reads a compiler from. +# +# There are three such locations, and all three must agree or the build +# picks up a mixed toolchain: +# +# 1. prefix//gcc-install/ - the GCC half of the prefix +# 2. prefix//sysroot/ - the merged prefix (gcc+rust+clang) +# 3. ~/.redoxer//toolchain/ - HIGHEST PRIORITY. src/cook/script.rs +# prepends this to PATH last, so it wins over both prefix paths for +# every recipe. Missing this one silently leaves recipes on GCC 13. +# +# Reversible: the GCC 13 components are moved aside to a timestamped +# backup dir rather than deleted, and --restore puts them back. +# +# Run local/scripts/build-gcc16-cross.sh first. +set -euo pipefail + +ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd) +TARGET=x86_64-unknown-redox +NEWGCC=16.1.0 +OLDGCC=13.2.0 +SRC="$ROOT/build/gcc16-install" +PREFIX_GCC="$ROOT/prefix/$TARGET/gcc-install" +PREFIX_SYSROOT="$ROOT/prefix/$TARGET/sysroot" +REDOXER="$HOME/.redoxer/$TARGET/toolchain" +BACKUP="$ROOT/build/gcc13-backup" + +# GCC's does `using ::strtold` before relibc's cbindgen trailer has +# declared it, so the C++ wrapper must pull in explicitly. mk/prefix.mk +# does this with a sed, but that sed is NOT idempotent -- the current GCC 13 +# toolchain has the comment block appended 17 times from repeated `make prefix` +# runs. The guard below makes it apply exactly once. +patch_cstdlib() { + local f="$1" + [ -f "$f" ] || return 0 + grep -q "Red Bear: relibc declares strtold" "$f" && return 0 + sed -i '/^#include_next $/a\\n// Red Bear: relibc declares strtold via cbindgen trailer.\n// The explicit include ensures ::strtold is visible when the\n// C++ wrapper processes its using-directives below.\n#include ' "$f" + echo " patched strtold: $f" +} + +# Move GCC's own components out of a tree without disturbing the rust/clang/ +# relibc files that share it. +evict_old() { + local dst="$1" tag="$2" + local bk="$BACKUP/$tag" + mkdir -p "$bk" + for p in "bin/$TARGET-gcc-$OLDGCC" \ + "lib/gcc/$TARGET/$OLDGCC" \ + "libexec/gcc/$TARGET/$OLDGCC" \ + "$TARGET/include/c++/$OLDGCC"; do + if [ -e "$dst/$p" ]; then + mkdir -p "$bk/$(dirname "$p")" + mv "$dst/$p" "$bk/$p" + fi + done + for so in "$dst/$TARGET/lib/"libstdc++.so.6.0.* ; do + [ -e "$so" ] || continue + mkdir -p "$bk/$TARGET/lib" + mv "$so" "$bk/$TARGET/lib/" + done +} + +install_into() { + local dst="$1" tag="$2" + [ -d "$dst" ] || { echo " skip $tag (not present)"; return 0; } + echo " -> $tag: $dst" + evict_old "$dst" "$tag" + # Driver, cc1/cc1plus, target headers and libs. + cp -a "$SRC/bin/." "$dst/bin/" + mkdir -p "$dst/lib/gcc/$TARGET" "$dst/libexec/gcc/$TARGET" + cp -a "$SRC/lib/gcc/$TARGET/$NEWGCC" "$dst/lib/gcc/$TARGET/" + cp -a "$SRC/libexec/gcc/$TARGET/$NEWGCC" "$dst/libexec/gcc/$TARGET/" + mkdir -p "$dst/$TARGET/include/c++" + cp -a "$SRC/$TARGET/include/c++/$NEWGCC" "$dst/$TARGET/include/c++/" + cp -a "$SRC/$TARGET/lib/." "$dst/$TARGET/lib/" + for c in "$dst/$TARGET/include/c++/$NEWGCC/cstdlib"; do patch_cstdlib "$c"; done +} + +if [ "${1:-}" = "--restore" ]; then + [ -d "$BACKUP" ] || { echo "no backup at $BACKUP" >&2; exit 1; } + for tag in gcc-install sysroot redoxer; do + case $tag in + gcc-install) dst="$PREFIX_GCC" ;; + sysroot) dst="$PREFIX_SYSROOT" ;; + redoxer) dst="$REDOXER" ;; + esac + [ -d "$BACKUP/$tag" ] || continue + echo "restoring $tag" + cp -a "$BACKUP/$tag/." "$dst/" + done + echo "GCC $OLDGCC restored. Re-run without --restore to go back to $NEWGCC." + exit 0 +fi + +[ -x "$SRC/bin/$TARGET-gcc" ] || { + echo "FATAL: $SRC not built. Run local/scripts/build-gcc16-cross.sh" >&2; exit 1; } +[ -e "$SRC/$TARGET/lib/libstdc++.so.6" ] || { + echo "FATAL: $SRC has no shared libstdc++. The desktop stack links" >&2 + echo " libstdc++.so.6 (readelf -d libQt6Core.so), so a static-only" >&2 + echo " toolchain cannot build it." >&2; exit 1; } + +echo "Installing GCC $NEWGCC (backup of $OLDGCC -> $BACKUP)" +rm -rf "$BACKUP" +install_into "$PREFIX_GCC" gcc-install +install_into "$PREFIX_SYSROOT" sysroot +install_into "$REDOXER" redoxer + +echo +echo "Verifying the compiler each recipe will actually invoke:" +PATH="$REDOXER/bin:$PREFIX_SYSROOT/bin:$PATH" "$TARGET-gcc" --version | head -1 +PATH="$REDOXER/bin:$PREFIX_SYSROOT/bin:$PATH" "$TARGET-g++" -std=c++23 -x c++ -c - -o /dev/null <<'EOF' +#include +#ifndef __cpp_lib_ranges_to_container +#error ranges::to missing +#endif +int main(){} +EOF +echo "C++23 ranges::to: OK" +echo "Revert with: $0 --restore"