gcc: applier that ports Redox onto pristine GCC, validated on 16.1.0
redbear-ci / check (push) Has been cancelled

Applies the extracted port to an unpacked GCC tree: copies the 5
Redox-owned files, then inserts each redox arm at an anchored point.
Validated against a real gcc-16.1.0 tree (blake3
5f001609f662143ce9285cd740bd0acfeeaf7f13731b46fd1d9ebe620c5c340d).

Findings from that validation:

- GCC 16 already recognises redox in config.sub upstream, one fewer file
  to patch than in 13.2.0.
- Two anchors moved since 13.2.0 and were re-derived: solaris folded into
  the linux arm in crossconfig.m4, and the mingw32 targets were
  consolidated in mkfixinc.sh.
- libgcc's riscv64 arm had been truncated during the original capture;
  restored.

Two idempotency bugs found by comparing redox-line counts against the
13.2.0 reference rather than trusting "it ran clean":

- a substring probe matched the generic block's case label inside the
  already-inserted aarch64/riscv64 label, silently skipping the second
  crossconfig.m4 block;
- a first-line probe matched the aarch64 label inside CONFIG_GCC_OS,
  silently skipping config.gcc's tm_file target arms, which would have
  produced a tree that configures but never pulls in redox.h.

Now probes on the block's longest line, matched whole. config.gcc reaches
16/16 redox lines, matching the 13.2.0 reference exactly.

Verified for x86_64-unknown-redox: config.gcc tm_file arm incl. redox.h,
config.host xm_file, libgcc arm, crossconfig generic arm, mkfixinc arm,
gcc/config/redox.h, and the _GLIBCXX_USE_WEAK_REF define.

Re-running is a no-op. NOT YET BUILT: no compiler has been produced, and
gcc/configure plus libstdc++-v3/configure still need regenerating from
crossconfig.m4 with autoconf.
This commit is contained in:
2026-08-03 11:41:40 +03:00
parent 1bceaa7b47
commit 89d7eb1736
+266
View File
@@ -0,0 +1,266 @@
#!/usr/bin/env python3
"""Apply the Redox target port to a pristine GCC source tree.
Usage: apply-redox-port.py <gcc-source-root> [--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())