rust-native now builds. Records the three defects found getting there (host/target header leak, the -fno-hardened cross-flag leak, relibc's duplicate _POSIX_THREADS) and closes the previously-open "unreachable 'pub' item" item, which deny-warnings = false already resolved. Corrects the gcc-native diagnosis. It read "the host's libstdc++ headers are being pulled into a target compile"; the direction is the reverse -- relibc's TARGET headers reach a HOST compile through the redoxer toolchain's mixed include/ directory, so __GLIBC_PREREQ is undefined where the host headers expect it. That matters for how gcc-native gets unblocked: the host: package pattern used for rust-native should apply, rather than reworking GCC's cross-build header model. Status flipped DEFERRED -> ACTIVE per the 2026-08-05 operator decision.
12 KiB
Native Toolchain Workstream — gcc-native / rust-native
Status: ACTIVE. Deferred 2026-08-03 ("Treat gcc-native/rust-native as a
separate workstream, explicitly deferred by me, for now."), then RE-ENABLED by
explicit operator decision, 2026-08-05: "Build and add gcc-native and
rust-native to project." Both are = {} in config/redbear-full.toml again.
Scope: local/recipes/dev/gcc-native/, local/recipes/dev/rust-native/.
Not deferred: binutils-native and llvm-native build and remain in
config/redbear-full.toml. llvm-native is required, not optional — it
supplies the host LLVM dev tree that libclc and Mesa's iris/radeonsi CLC path
consume.
Related: local/patches/gcc-redox-port/README.md,
VENDORED-LIBC-FORK.md, FORK-BUMP-PATCHING-POLICY.md,
LOCAL-FORK-SUPREMACY-POLICY.md.
What this workstream is
A toolchain that runs on Redox and targets Redox — gcc, cargo/rustc
executing inside the OS. Distinct from the cross toolchain in prefix/,
which runs on the Linux host and is what actually builds the distribution.
That distinction matters for prioritisation: the cross toolchain is done
(GCC 16.1.0, libstdc++.so.6.0.35, working std::ranges::to) and is what
compiled every other package. Nothing in the desktop path — Mesa/virgl,
Wayland, Qt6, KF6, SDDM — depends on the native toolchain.
Why it is deferred, honestly
Not because it is unimportant, and not for the reason the old config gave.
The previous exclusion said "suppressed: Redox C++/pthread header gaps; not
needed for greeter proof". That was wrong on both counts. llvm-native has no
header gap at all — it cooks clean in isolation, and only failed in parallel
builds because of a cookbook race on shared staging paths (fixed; see
src/bin/repo.rs recipe_dir_lock). A real build-system bug had been
misdiagnosed as a porting gap and used to justify excluding a required package.
Restoring these packages is how the twelve defects below were found at all —
including that redbear-iwlwifi had never compiled since the commit that broke
it.
The deferral is instead a scope judgement: making GCC build itself for Redox is a genuine porting project. Upstream Redox has only ever shipped GCC 8.2.0 and 13.2.0; nobody has done GCC 16 for this target. Every fix so far has revealed the next layer, and the remaining failures are header-model conflicts (GCC's internal headers vs relibc's, host vs target) that want someone working through GCC's cross-build header model as a whole rather than patching incrementally.
gcc-native — moved to GCC 16, twelve findings
The recipe now builds GCC 16.1.0 from local/recipes/dev/gcc16/source
(upstream 16.1.0 + local/patches/gcc-redox-port/), not GCC 13.
Why the move happened
Building GCC 13 with the GCC 16 cross compiler is three major versions of drift and is not a supported configuration. Three fixes landed before it became untenable:
| # | Defect | Resolution |
|---|---|---|
| 1 | char8_t. GCC 16 defaults to C++20, which changed u8"" from const char[] to const char8_t[]; libcody uses them throughout (~100 diagnostics) |
pin the C++ standard |
| 2 | libcody's configure contains #if __cplusplus > 201103 / #error "C++11 is required" — it rejects anything newer than C++11 |
-std=gnu++11, which also fixes #1 (no char8_t before C++20) |
| 3 | bit_AVX512PF / ER / 4VNNIW / 4FMAPS / PREFETCHWT1 undeclared — GCC 15/16 removed these macros for withdrawn ISA extensions, but GCC 13's cpuinfo.h needs them |
put GCC 13's own cpuid.h ahead of the toolchain's include path |
Then GCC 16 ICEd compiling GCC 13's own libstdc++:
libstdc++-v3/libsupc++/eh_call.cc:39:1: internal compiler error:
in gimple_build_eh_must_not_throw
An ICE is where flag-tweaking stops being a legitimate answer. Those three
fixes remain in recipes/dev/gcc13/recipe.toml, where they are correct for
that recipe. Note that the recipe no longer builds anything: as of 2026-08-05
this fork has no GCC 13 path at all — mk/prefix.mk defaults to
GCC_RECIPE?=gcc16 and build-redbear.sh refuses a non-GCC-16 toolchain. See
TOOLCHAIN-GCC16.md.
After the move to GCC 16
| # | Defect | Resolution |
|---|---|---|
| 4 | The same_as symlink source -> recipes/dev/gcc13/source survived the recipe edit, so the "GCC 16" build was still compiling GCC 13 sources |
removed; now -> ../gcc16/source |
| 5 | gcc13 / gcc13.cxx dependencies build the very compiler being replaced |
dropped |
| 6 | unknown type name 'bool' — GCC 16's sources are C23, where bool is a keyword, but the cookbook pins -std=gnu17 tree-wide for the C17-era recipes |
exempt this recipe from the pin |
| 7 | cannot guess version — same_as used to supply it; a path source gives the cookbook nothing to infer from |
explicit [package].version |
| 8 | 'fenv_t' has not been declared in '::' — dropping gcc13 also removed what transitively staged relibc's headers, leaving the sysroot with no libc headers at all |
explicit relibc dependency |
| 9 | _getopt_internal undeclared — libiberty needs GCC's own include/getopt.h, which declares that GNU-internal symbol; relibc's getopt.h was shadowing it |
GCC's include/ ahead of the sysroot |
| 10 | FNM_FILE_NAME / FNM_LEADING_DIR undeclared — GNU extensions genuinely absent from relibc |
implemented in the relibc fork (see below) |
Correction worth preserving
Finding #8 was initially misdiagnosed as "relibc's fenv.h is a 3-line
stub". It is not. relibc's fenv.h correctly delegates to openlibm_fenv.h,
which dispatches on __x86_64__ to openlibm_fenv_amd64.h where fenv_t
(line 48) and fexcept_t (line 50) are both defined — and relibc stages all of
those headers. The header was simply never reaching this recipe's sysroot. A
commit message asserting a relibc fenv gap was wrong and is corrected in the
commit that follows it.
The lesson generalises to most of this list: an "undeclared identifier" against relibc is more often a header-path problem than a missing implementation. Check whether the header reaches the compiler before concluding relibc is incomplete.
Real relibc gap that was fixed
FNM_FILE_NAME and FNM_LEADING_DIR are now implemented in
local/sources/relibc/src/header/fnmatch/mod.rs (pushed on
submodule/relibc). FNM_FILE_NAME is the GNU synonym for FNM_PATHNAME, so
an alias. FNM_LEADING_DIR is real behaviour — the pattern may match a leading
directory, so foo matches foo/bar — implemented by trying the exact match
then each prefix ending before a /. Declaring the flag without honouring it
would have been a stub. Its value (16) is the next free bit in relibc's own
numbering, not glibc's.
Where it stopped
/usr/include/c++/16/x86_64-pc-linux-gnu/bits/os_defines.h:44:
error: missing binary operator before token '('
Root cause identified 2026-08-05 while unblocking rust-native — it is the
same defect, and it is now understood. The initial reading above ("host
libstdc++ headers pulled into a target compile") had the direction backwards.
What actually happens is the reverse: ${HOME}/.redoxer/${TARGET}/toolchain/include
is a MIXED directory holding relibc's target headers (stdlib.h,
features.h, fenv.h, …) beside the llvm/ and clang/ ones. When that
directory reaches a host compile via -I, relibc's features.h shadows
glibc's, __GLIBC_PREREQ is never defined, and every host libstdc++/glibc
header testing it fails. Reproducible in three lines, no rustc or GCC build
involved:
printf '#include <cstdlib>\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.
rust-native — four findings, one open
| # | Defect | Resolution |
|---|---|---|
| 1 | nix 0.30.1 incompatible with libc 0.2.178: declares SaFlags_t = c_ulong while libc has sa_flags/SA_* as c_int (E0308 both directions) |
nix 0.31 fixed it; ctrlc 3.5 requires nix "0.31" |
| 2 | in-tree miri pinned nix = "0.30.1" and held the broken version in the graph |
bumped; carried as local/patches/rust/01-miri-nix-0.31.patch |
| 3 | CLD_EXITED / P_ALL etc. not in crate libc — its Redox bindings never exposed the waitid surface relibc implements, still absent in 0.2.189 |
vendored fork, see VENDORED-LIBC-FORK.md |
| 4 | llvm/Config/llvm-config.h: No such file — llvm-native.dev (which stages the headers) missing from dependencies |
added |
| 5 | ~200 errors in the HOST's own glibc/libstdc++ headers building rustc_llvm for the host triple. rustc_llvm's build script feeds llvm-config --includedir straight to the host c++, and the redoxer toolchain's include/ is the mixed dir described under gcc-native above |
host:llvm-native (+ .dev/.runtime). Host deps stage into COOKBOOK_TOOLCHAIN, a tree SEPARATE from the target sysroot, so the host LLVM and the Redox llvm21 coexist instead of overwriting each other — which is the collision the recipe's llvm21 comment records |
| 6 | c++: error: unknown argument: '-fno-hardened'. DYNAMIC_INIT exports CXXFLAGS=-fno-hardened for the GCC 16 cross compiler; the recipe's unset list dropped CC/CXX/LDFLAGS but not CFLAGS/CXXFLAGS/CPPFLAGS, so it leaked into the host stage1 build, where c++ now resolves through COOKBOOK_TOOLCHAIN/bin to llvm-native's clang++ |
added CFLAGS CXXFLAGS CPPFLAGS to the unset. Pre-existing leak; the cross recipes/dev/rust has the same list and never hit it only because nothing puts a clang on its PATH |
| 7 | '_POSIX_THREADS' redefined [-Werror] building rustc_llvm for the target. relibc defined it twice: unistd.h 202405L (correct — POSIX puts it there) and pthread.h 1, emitted from a pub const in src/header/pthread/mod.rs that had zero users |
deleted the dead constant in the relibc fork (851a505f on submodule/relibc), + prefix rebuild |
Findings 5 and 6 were pre-existing latent defects, not regressions: #5 is
the same root cause as gcc-native's stopping point, and #6 only becomes
reachable once a clang is on PATH. #7 broke any -Werror C++ TU including both
headers, which is every C++ TU — libstdc++'s <iterator> chain reaches
pthread.h via gthr-default.h.
Closed: the five error: unreachable 'pub' item diagnostics are resolved by
deny-warnings = false in config.toml (documented in that file: the vendored
libc fork arrives as a PATH dependency, so cargo's --cap-lints allow for
registry deps does not apply to it).
Re-enabling
Both were re-enabled in config/redbear-full.toml on 2026-08-05; nothing needs
un-ignoring. Build with
./local/scripts/build-redbear.sh --upstream redbear-full.
gcc-native should now resume past its recorded stopping point using the
finding-#5 pattern (a host: package, so the host compile never sees the mixed
redoxer include dir) rather than by patching GCC's header model incrementally.
Diagnose failures in isolation — COOKBOOK_COOK_JOBS=1 ./target/release/repo cook <recipe>. The aggregate build multiplexes output from parallel cooks, and
several wrong turns in this workstream came from attributing one recipe's error
to another in the interleaved log.
Upstream-reportable
Two findings belong upstream rather than in Red Bear indefinitely:
- The
libccrate's Redox module lacks thewaitidsurface (idtype_t,P_*,CLD_*,waitid) that relibc implements. Retirement procedure inVENDORED-LIBC-FORK.md. - relibc's missing GNU
fnmatchextensions — now fixed in the fork, and worth offering upstream. - relibc's duplicate
_POSIX_THREADS(finding #7) — thepthread.hcopy is both misplaced per POSIX and carries an invalid value. Fixed in the fork and worth offering upstream.