diff --git a/local/patches/gcc-redox-port/apply-redox-port.py b/local/patches/gcc-redox-port/apply-redox-port.py new file mode 100755 index 0000000000..7572643d04 --- /dev/null +++ b/local/patches/gcc-redox-port/apply-redox-port.py @@ -0,0 +1,266 @@ +#!/usr/bin/env python3 +"""Apply the Redox target port to a pristine GCC source tree. + +Usage: apply-redox-port.py [--check] + +Extracted from redox-os/gcc branch redox-13.2.0 (see README.md). The port is +13 files: 5 Redox-owned (copied verbatim from files/) and 8 existing GCC files +that need a `*-*-redox*` arm registered. + +Every edit is anchored on stable upstream text and is IDEMPOTENT: a file that +already mentions redox in the relevant place is left alone. Anchors were chosen +to be the kind of plumbing that changes slowly between GCC releases; if one +stops matching after a version bump, the script reports it rather than silently +producing a half-ported tree. + +NOTE: gcc/configure and libstdc++-v3/configure also reference redox in the +13.2.0 fork, but they are GENERATED. Do not patch them here -- regenerate from +crossconfig.m4 with autoconf after running this script. +""" + +import shutil +import sys +from pathlib import Path + +HERE = Path(__file__).resolve().parent +FILES = HERE / "files" + +# --- blocks to insert, keyed by file ----------------------------------------- + +CONFIG_GCC_OS = """*-*-redox*) + gas=yes + gnu_ld=yes + default_use_cxa_atexit=yes + gcc_cv_initfini_array=yes + tmake_file="${tmake_file} t-slibgcc" + extra_options="${extra_options} redox.opt" + case ${enable_threads} in + yes) + thread_file='posix' + ;; + esac + case ${target} in + i[34567]86-*-redox* | x86_64-*-redox*) + xm_file=i386/xm-redox.h + ;; + aarch64-*-redox*) + xm_file=aarch64/xm-redox.h + ;; + riscv64*-*-redox*) + xm_file=riscv/xm-redox.h + ;; + esac + ;; +""" + +CONFIG_GCC_TARGETS = """aarch64-*-redox*) +\ttm_file="${tm_file} elfos.h aarch64/aarch64-elf.h aarch64/aarch64-elf-raw.h redox.h newlib-stdint.h" +\t;; +i[34567]86-*-redox*) +\ttm_file="${tm_file} i386/unix.h i386/att.h elfos.h i386/i386elf.h redox.h newlib-stdint.h" +\t;; +riscv64*-*-redox*) +\ttm_file="${tm_file} elfos.h riscv/elf.h redox.h newlib-stdint.h" +\t;; +x86_64-*-redox*) +\ttm_file="${tm_file} i386/unix.h i386/att.h elfos.h i386/i386elf.h i386/x86-64.h redox.h newlib-stdint.h" +\t;; +""" + +CONFIG_HOST = """ i[34567]86-*-redox* | x86_64-*-redox*) + host_xm_file=i386/xm-redox.h + ;; + aarch64-*-redox*) + host_xm_file=aarch64/xm-redox.h + ;; + riscv64*-*-redox*) + host_xm_file=riscv/xm-redox.h + ;; +""" + +CONFIG_BUILD = """ i[34567]86-*-redox* | x86_64-*-redox* ) + build_xm_file=i386/xm-redox.h + ;; + aarch64-*-redox*) + build_xm_file=aarch64/xm-redox.h + ;; + riscv64*-*-redox*) + build_xm_file=riscv/xm-redox.h + ;; +""" + +LIBGCC_OS = """*-*-redox*) + extra_parts="$extra_parts crtbegin.o crtbeginS.o crtend.o crtendS.o" + tmake_file="$tmake_file t-crtstuff-pic t-libgcc-pic" + tmake_file="$tmake_file t-slibgcc t-slibgcc-gld t-slibgcc-elf-ver" + ;; +""" + +LIBGCC_TARGETS = """i[34567]86-*-redox*) +\ttmake_file="$tmake_file i386/t-crtstuff" +\t;; +x86_64-*-redox*) +\ttmake_file="$tmake_file i386/t-crtstuff" +\t;; +aarch64-*-redox*) +\textra_parts="$extra_parts crtfastmath.o" +\ttmake_file="${tmake_file} ${cpu_type}/t-aarch64" +\ttmake_file="${tmake_file} ${cpu_type}/t-lse t-slibgcc-libgcc" +\ttmake_file="${tmake_file} ${cpu_type}/t-softfp t-softfp t-crtfm" +\tmd_unwind_header=aarch64/aarch64-unwind.h +\t;; +""" + +CROSSCONFIG_AARCH64 = """ aarch64-*-redox* | riscv64*-*-redox*) + SECTION_FLAGS='-ffunction-sections -fdata-sections' + AC_SUBST(SECTION_FLAGS) + AC_DEFINE(HAVE_ALIGNED_ALLOC) + ;; + +""" + +CROSSCONFIG_GENERIC = """ *-redox*) + GLIBCXX_CHECK_COMPILER_FEATURES + GLIBCXX_CHECK_LINKER_FEATURES + GLIBCXX_CHECK_MATH_SUPPORT + GLIBCXX_CHECK_STDLIB_SUPPORT + AC_CHECK_FUNCS(aligned_alloc posix_memalign memalign _aligned_malloc) + ;; +""" + +MKFIXINC = """ aarch64-*-redox* | \\ + i?86-*-redox* | \\ + riscv64*-*-redox* | \\ + x86_64-*-redox* | \\ +""" + +OS_DEFINES = """ +// Causes issues on Redox +#define _GLIBCXX_USE_WEAK_REF 0 +""" + +# (relative path, anchor text, block, insert_before) +EDITS = [ + ("gcc/config.gcc", "*-*-netbsd*)", CONFIG_GCC_OS, True), + ("gcc/config.gcc", "i[34567]86-pc-msdosdjgpp*)", CONFIG_GCC_TARGETS, True), + ("gcc/config.host", "esac", CONFIG_HOST, True), + ("gcc/config.build", "esac", CONFIG_BUILD, True), + ("libgcc/config.host", "*-*-rtems*)", LIBGCC_OS, True), + ("libgcc/config.host", "i[34567]86-*-elf*)", LIBGCC_TARGETS, True), + ("libstdc++-v3/crossconfig.m4", " *-hpux*)", CROSSCONFIG_AARCH64, True), + # GCC 16 moved *-solaris* into the *-linux* arm and consolidated the + # mingw32 targets, so these two anchors differ from 13.2.0. + ("libstdc++-v3/crossconfig.m4", " *-mingw32*)", CROSSCONFIG_GENERIC, True), + ("fixincludes/mkfixinc.sh", " *-mingw32* | \\", MKFIXINC, True), +] + + +def already_ported(path: Path, marker: str = "redox") -> bool: + try: + return marker in path.read_text(encoding="utf-8", errors="replace").lower() + except OSError: + return False + + +def apply_edit(root: Path, rel: str, anchor: str, block: str, check: bool) -> str: + p = root / rel + if not p.is_file(): + return f"MISSING {rel}" + text = p.read_text(encoding="utf-8", errors="replace") + # Idempotency must be per-EDIT, not per-file: crossconfig.m4 and + # config.gcc each take TWO separate blocks, so a whole-file "does it + # mention redox" test would silently skip the second one. + # Match the probe as a COMPLETE line. A substring test is wrong here: + # 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()): + return f"skip {rel} (block already present)" + idx = text.find(anchor) + if idx == -1: + return f"ANCHOR-FAIL {rel} :: {anchor!r} not found -- re-derive for this GCC version" + if check: + return f"would-apply {rel} at offset {idx}" + p.write_text(text[:idx] + block + text[idx:], encoding="utf-8") + return f"applied {rel}" + + +def main() -> int: + if len(sys.argv) < 2: + print(__doc__) + return 2 + root = Path(sys.argv[1]).resolve() + check = "--check" in sys.argv + if not (root / "gcc" / "config.gcc").is_file(): + print(f"ERROR: {root} does not look like a GCC source tree", file=sys.stderr) + return 2 + + rc = 0 + + # 1. Redox-owned files (pure copies -- always safe). + for src in sorted(FILES.rglob("*")): + if not src.is_file(): + continue + rel = src.relative_to(FILES) + dst = root / rel + if check: + print(f"would-copy {rel}") + continue + dst.parent.mkdir(parents=True, exist_ok=True) + shutil.copy2(src, dst) + print(f"copied {rel}") + + # 2. config.sub: add redox to the recognised OS list. + cs = root / "config.sub" + if cs.is_file(): + t = cs.read_text(encoding="utf-8", errors="replace") + if "redox" in t: + print("skip config.sub (already references redox)") + elif "| fuchsia* " in t: + if not check: + cs.write_text(t.replace("| fuchsia* ", "| fuchsia* | redox* ", 1), + encoding="utf-8") + print(("would-apply " if check else "applied ") + "config.sub") + else: + print("ANCHOR-FAIL config.sub :: '| fuchsia* ' not found") + rc = 1 + + # 3. os_defines.h: append before the trailing #endif. + od = root / "libstdc++-v3/config/os/generic/os_defines.h" + if od.is_file(): + t = od.read_text(encoding="utf-8", errors="replace") + if "Redox" in t: + print("skip os_defines.h (already references Redox)") + else: + i = t.rfind("#endif") + if i == -1: + print("ANCHOR-FAIL os_defines.h :: no trailing #endif") + rc = 1 + else: + if not check: + od.write_text(t[:i] + OS_DEFINES + "\n" + t[i:], encoding="utf-8") + print(("would-apply " if check else "applied ") + "os_defines.h") + + # 4. Anchored insertions. + 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: + rc = 1 + + print() + print("NEXT: regenerate configure from crossconfig.m4 with autoconf " + "(gcc/configure and libstdc++-v3/configure are GENERATED).") + if rc: + print("One or more anchors failed -- the tree is NOT fully ported.", + file=sys.stderr) + return rc + + +if __name__ == "__main__": + sys.exit(main())