Files
RedBear-OS/local/recipes/dev/rust-native/recipe.toml
T
vasilito 75a33e0430 fix(rust-native): build host bootstrap stages against a pure host LLVM
rust-native failed with ~200 errors inside the HOST's own glibc and
libstdc++ headers while compiling rustc_llvm's llvm-wrapper/*.cpp for
x86_64-unknown-linux-gnu.

rustc_llvm's build script passes `llvm-config --includedir` straight to
the host c++. The redoxer toolchain's include/ is a MIXED directory,
holding relibc's TARGET headers (stdlib.h, features.h, fenv.h, ...)
beside the llvm/ and clang/ ones, so relibc's features.h shadowed
glibc's, __GLIBC_PREREQ was never defined, and every host header testing
it failed:

    /usr/include/c++/16/x86_64-pc-linux-gnu/bits/os_defines.h:44:19:
    error: missing binary operator before token '('

Reproducible in three lines with no rustc involved:

    printf '#include <cstdlib>\nint main(){}' > t.cpp
    c++ -std=c++17 -I${HOME}/.redoxer/x86_64-unknown-redox/toolchain/include -c t.cpp

This is the same leak recorded as gcc-native's stopping point in
local/docs/NATIVE-TOOLCHAIN-WORKSTREAM.md -- one root cause, both
recipes -- though in the opposite direction to what that note assumed:
target headers reaching a host compile, not the reverse.

Fixed with host:llvm-native (+ .dev/.runtime). Host deps stage into
COOKBOOK_TOOLCHAIN, a tree SEPARATE from the target sysroot, so the
GNU/Linux libLLVM.so.21.1 cannot collide with the Redox one llvm21
stages -- the collision this recipe's llvm21 comment already records.
Its include tree holds only llvm/, llvm-c/, clang/, clang-c/, lld/. An
unset COOKBOOK_TOOLCHAIN is now a hard error rather than a silent
fallback to the polluted path.

Second defect, exposed by the first fix: DYNAMIC_INIT exports
CXXFLAGS=-fno-hardened for the GCC 16 cross compiler, and the unset list
dropped CC/CXX/LDFLAGS but not CFLAGS/CXXFLAGS/CPPFLAGS. cc-rs falls
back to the generic CXXFLAGS when the target-specific one is empty and
handed it to the host c++, which now resolves through
COOKBOOK_TOOLCHAIN/bin to llvm-native's clang++:

    rustc_llvm@0.0.0: c++: error: unknown argument: '-fno-hardened'

A pre-existing leak: the cross recipes/dev/rust carries the same unset
list and never hit it only because nothing puts a clang on its PATH.
llvm-native's own recipe already unsets these three for this reason.

Target-side compilation is unaffected: config.toml pins cc/cxx/ar/linker
for the Redox triple, and the target RUSTFLAGS are captured into
CARGO_TARGET_<ARCH>_UNKNOWN_REDOX_RUSTFLAGS before the unset.

Also carries earlier uncommitted working-tree changes to this recipe
that the build depends on: the explicit relibc dependency, the
llvm-native -> llvm21 switch for the Redox-hosted rustc, and the
COOKBOOK_HOST_SYSROOT assignment, plus deny-warnings = false in
config.toml.

Verified: rustc, cargo, rustdoc, rustfmt, clippy-driver and
librustc_driver-*.so stage as Redox binaries -- ELF interpreter
/lib/ld64.so.1, OS/ABI System V, NEEDED libc.so.6 from relibc.
2026-08-05 15:41:10 +03:00

153 lines
8.3 KiB
TOML

[source]
same_as = "../../../../recipes/dev/rust"
[build]
template = "custom"
dependencies = [
# relibc is explicit. Clearing the stale sysroot showed it had only ever
# arrived transitively: with it gone the sysroot had no libc headers at all
# and every C++ compile failed with
# error: 'abort' has not been declared in '::'
# error: 'abs' has not been declared in '::' (and ~40 more from <cstdlib>)
# Exactly the failure local/docs/NATIVE-TOOLCHAIN-WORKSTREAM.md records for
# gcc-native as finding #8 ('fenv_t' has not been declared), same cause.
"relibc",
"zlib",
"curl",
"openssl3",
# llvm21, NOT llvm-native. This recipe's config.toml sets both `host` and
# `target` to the Redox triple, so the rustc it produces runs on Redox and
# must link a REDOX libLLVM. llvm-native is a deliberate PURE HOST build
# (see its recipe header) -- depending on it staged a GNU/Linux
# libLLVM.so.21.1 into the target sysroot, and bootstrap then linked
# librustc_driver-*.so against it:
# .../sysroot/lib/libLLVM-21.so: undefined reference to `abort@GLIBC_2.2.5'
# (213 such references, every one a glibc symbol Redox does not have)
# llvm21 is the cross build and produces a Redox ELF; recipes/dev/rust --
# the equivalent cross recipe that works -- depends on exactly this.
"llvm21",
"llvm21.runtime",
# rustc_llvm compiles llvm-wrapper/*.cpp, which #include
# "llvm/Config/llvm-config.h". Those headers are staged by the .dev
# package, so without it the build fails with
# LLVMWrapper.h:6:10: fatal error: llvm/Config/llvm-config.h:
# No such file or directory
"llvm21.dev",
# host:llvm-native supplies the HOST llvm-config for the host-triple
# sections of config.toml. It must be a `host:` package, not a plain one:
# host deps stage into COOKBOOK_TOOLCHAIN (target/<t>/toolchain/), a tree
# SEPARATE from the target sysroot, so the GNU/Linux libLLVM.so.21.1 can
# never collide with the Redox one llvm21 stages -- which is exactly the
# breakage the llvm21 comment above records. Main goes in `dependencies`
# because the cook-tree (src/cook/tree.rs) only follows `dependencies` when
# resolving what to COOK; cooking it produces all three subpackage pkgars.
"host:llvm-native",
]
# Staged (not cooked) into COOKBOOK_TOOLCHAIN: .dev carries usr/include/llvm**
# plus the cmake exports, .runtime carries usr/bin/llvm-config and libLLVM*.so.
# Merged in one tree, llvm-config (which is relocatable -- it derives its prefix
# from its own location) then reports an includedir holding ONLY llvm/, llvm-c/,
# clang/, clang-c/, lld/. That is the whole point: see the script below.
dev-dependencies = [
"host:llvm-native.dev",
"host:llvm-native.runtime",
]
script = """
DYNAMIC_INIT
ARCH="${TARGET%%-*}"
export CARGO_TARGET_${ARCH^^}_UNKNOWN_REDOX_RUSTFLAGS="${RUSTFLAGS}"
cat "${COOKBOOK_ROOT}/bin/${TARGET}-llvm-config" > "${COOKBOOK_SYSROOT}/bin/llvm-config"
# The llvm-config just staged is the cross wrapper (bin/${TARGET}-llvm-config), a python
# script that reads COOKBOOK_HOST_SYSROOT, COOKBOOK_SYSROOT and TARGET from the
# ENVIRONMENT and exits 1 if any is missing. The cookbook passes COOKBOOK_SYSROOT
# and TARGET down, but COOKBOOK_HOST_SYSROOT is only a shell variable here -- so
# when rustc's bootstrap spawns `llvm-config --version` during the install step
# the wrapper sees nothing and the whole build dies at the very last phase:
# Error: COOKBOOK_HOST_SYSROOT or COOKBOOK_SYSROOT or TARGET not set
# Command `".../sysroot/bin/llvm-config" "--version"` failed with exit code 1
# The cookbook does NOT set COOKBOOK_HOST_SYSROOT -- nothing in src/ assigns it,
# and recipes that need it define it themselves (see local/recipes/libs/mesa,
# which sets exactly this path). It was empty here, which silently broke two
# lines that already used it: LD_LIBRARY_PATH resolved to a bare "/lib:", and
# the COOKBOOK_TOOLCHAIN substitution below wrote an empty toolchain path into
# config.toml. Exporting an unset variable fixed neither -- it has to be set.
export COOKBOOK_HOST_SYSROOT="${COOKBOOK_HOST_SYSROOT:-${HOME}/.redoxer/${TARGET}/toolchain}"
export COOKBOOK_SYSROOT TARGET
# The host-triple llvm-config must NOT be the redoxer toolchain's.
#
# ${HOME}/.redoxer/${TARGET}/toolchain/include is a MIXED directory: it holds
# relibc's TARGET headers (stdlib.h, features.h, fenv.h, ...) alongside the
# llvm/ and clang/ ones. rustc_llvm's build script passes
# `llvm-config --includedir` straight to the HOST c++ compiling
# llvm-wrapper/*.cpp, so relibc's features.h shadows glibc's, __GLIBC_PREREQ is
# never defined, and every host libstdc++/glibc header that tests it explodes:
# /usr/include/c++/16/x86_64-pc-linux-gnu/bits/os_defines.h:44:19:
# error: missing binary operator before token '('
# 44 | #if __GLIBC_PREREQ(2,15) && defined(_GNU_SOURCE)
# followed by ~200 more from /usr/include/stdlib.h, locale_classes.h,
# shared_ptr_base.h ('abort'/'calloc'/'__c_locale' has not been declared).
# Reproducible in three lines, with no rustc involved:
# printf '#include <cstdlib>\\nint main(){}' > t.cpp
# c++ -std=c++17 -I${HOME}/.redoxer/${TARGET}/toolchain/include -c t.cpp
# This is the SAME host/target header leak recorded as gcc-native's stopping
# point in local/docs/NATIVE-TOOLCHAIN-WORKSTREAM.md -- one root cause, both
# recipes.
#
# host:llvm-native is the fix: a pure HOST LLVM whose include tree contains
# ONLY llvm/, llvm-c/, clang/, clang-c/, lld/. The cookbook stages host deps
# into COOKBOOK_TOOLCHAIN, which is a different tree from COOKBOOK_SYSROOT, so
# the Redox llvm21 the target needs and the host LLVM the stage1 compiler needs
# coexist instead of overwriting each other.
if [ -z "${COOKBOOK_TOOLCHAIN}" ]; then
echo "rust-native: COOKBOOK_TOOLCHAIN is unset -- the host:llvm-native" >&2
echo "dependencies did not stage. Refusing to fall back to the redoxer" >&2
echo "toolchain: its include/ leaks relibc headers into host compiles." >&2
exit 1
fi
COOKBOOK_HOST_LLVM="${COOKBOOK_TOOLCHAIN}"
# Must come AFTER the assignments above: this previously expanded to a bare
# "/lib:" because the variable was empty at this point in the script.
# The host LLVM lib dir comes FIRST -- stage1 (host -> host) links against the
# host libLLVM.so.21.1, and must not pick up the redoxer toolchain's copy.
export LD_LIBRARY_PATH="${COOKBOOK_HOST_LLVM}/lib:${COOKBOOK_HOST_SYSROOT}/lib:${LD_LIBRARY_PATH}"
cat ${COOKBOOK_RECIPE}/config.toml > config.toml
sed -i "s|COOKBOOK_SYSROOT|${COOKBOOK_SYSROOT}|g" config.toml
sed -i "s|COOKBOOK_TOOLCHAIN|${COOKBOOK_HOST_LLVM}|g" config.toml
sed -i "s|COOKBOOK_TARGET|${TARGET}|g" config.toml
sed -i "s|COOKBOOK_GNU_TARGET|${GNU_TARGET}|g" config.toml
# CFLAGS/CXXFLAGS/CPPFLAGS join this list: they are the CROSS flags DYNAMIC_INIT
# exported for the Redox target, and they poisoned the stage1 (host -> host)
# build. DYNAMIC_INIT sets CXXFLAGS=-fno-hardened for the GCC 16 cross compiler;
# cc-rs falls back to the generic CXXFLAGS when the target-specific
# CXXFLAGS_x86_64_unknown_linux_gnu is empty, and hands it to the host c++ --
# which resolves through COOKBOOK_TOOLCHAIN/bin to llvm-native's clang++, and
# clang has no such flag:
# rustc_llvm@0.0.0: c++: error: unknown argument: '-fno-hardened'
# The cross recipes/dev/rust never hit this only because nothing puts a clang on
# its PATH, so its host c++ stays GCC, which accepts the flag. local/recipes/dev/
# llvm-native already unsets exactly these three for exactly this reason
# ("Drop every cross-compile flag DYNAMIC_INIT exported").
# Target-side compilation is unaffected: config.toml pins cc/cxx/ar/linker for
# the Redox triple explicitly, and the target RUSTFLAGS were captured into
# CARGO_TARGET_<ARCH>_UNKNOWN_REDOX_RUSTFLAGS at the top of this script, before
# this unset.
unset AR AS CC CXX LD LDFLAGS CFLAGS CXXFLAGS CPPFLAGS NM OBJCOPY OBJDUMP RANLIB READELF RUSTFLAGS CARGO_ENCODED_RUSTFLAGS STRIP
python3 "${COOKBOOK_SOURCE}/x.py" install \
--config config.toml \
--jobs ${COOKBOOK_MAKE_JOBS}
mkdir -p "${COOKBOOK_STAGE}"/usr
rsync -av --delete "${COOKBOOK_BUILD}"/install/* "${COOKBOOK_STAGE}"/usr/
rm -rf "${COOKBOOK_STAGE}"/usr/lib/rustlib/*.log
"""
[package]
description = "Native Rust toolchain for Red Bear OS (rustc + cargo running on redox)"
dependencies = ["llvm21.runtime"]