feat: add build preflight and sysroot helpers

This commit is contained in:
2026-05-02 22:09:36 +01:00
parent a15d79209c
commit a7be5be48a
7 changed files with 483 additions and 105 deletions
+156
View File
@@ -0,0 +1,156 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
CONFIG="redbear-full"
RELEASE="${REDBEAR_RELEASE:-}"
STRICT_DURABILITY="${REDBEAR_STRICT_DURABILITY:-0}"
STRICT_METADATA="${REDBEAR_STRICT_METADATA:-0}"
EXTRA_PACKAGES=()
usage() {
cat <<EOF
Usage: $(basename "$0") [--config=<name>] [--release=<ver>] [--strict-durability] [--strict-metadata] [--extra-package=<pkg> ...]
EOF
}
while [ $# -gt 0 ]; do
case "$1" in
--config=*) CONFIG="${1#*=}" ;;
--release=*) RELEASE="${1#*=}" ;;
--strict-durability) STRICT_DURABILITY=1 ;;
--strict-metadata) STRICT_METADATA=1 ;;
--extra-package=*) EXTRA_PACKAGES+=("${1#*=}") ;;
-h|--help) usage; exit 0 ;;
*) echo "Unknown: $1" >&2; usage >&2; exit 1 ;;
esac
shift
done
cd "$PROJECT_ROOT"
echo ">>> Build preflight: $CONFIG"
if [ -x "$SCRIPT_DIR/verify-overlay-integrity.sh" ]; then
if ! "$SCRIPT_DIR/verify-overlay-integrity.sh" --quiet; then
echo ">>> Preflight note: overlay integrity script reported legacy issues; continuing with build-focused checks."
fi
fi
if [ -n "$RELEASE" ]; then
bash "$SCRIPT_DIR/build-release-mode.sh" --release="$RELEASE" --config="$CONFIG" "${EXTRA_PACKAGES[@]/#/--extra-package=}"
fi
python3 "$SCRIPT_DIR/validate-source-trees.py" "$CONFIG" "${EXTRA_PACKAGES[@]/#/--extra-package=}"
python3 - "$PROJECT_ROOT" "$CONFIG" "$STRICT_METADATA" "${EXTRA_PACKAGES[@]}" <<'PY'
import sys
import tomllib
from pathlib import Path
project_root = Path(sys.argv[1])
config_name = sys.argv[2]
strict_metadata = sys.argv[3] == "1"
extra_packages = sys.argv[4:]
def build_lookup():
lookup = {}
for root in (project_root / "recipes", project_root / "local/recipes"):
for recipe_toml in root.rglob("recipe.toml"):
if not recipe_toml.exists():
continue
parts = recipe_toml.parts
if "source" in parts or "target" in parts:
continue
package_name = recipe_toml.parent.name
lookup.setdefault(package_name, recipe_toml)
return lookup
def resolve_config(config_path, visited=None):
if visited is None:
visited = set()
config_path = config_path.resolve()
if config_path in visited:
return {}
visited.add(config_path)
config = tomllib.loads(config_path.read_text())
packages = dict(config.get("packages", {}))
for include in config.get("include", []):
include_path = config_path.parent / include
if include_path.exists():
included = resolve_config(include_path, visited)
for name, value in packages.items():
included[name] = value
packages = included
return packages
lookup = build_lookup()
config_path = project_root / "config" / f"{config_name}.toml"
requested = resolve_config(config_path)
for pkg in extra_packages:
requested.setdefault(pkg, {})
errors = []
warnings = []
for package_name, package_conf in sorted(requested.items()):
if str(package_conf) == "ignore" or package_name in {"libgcc", "libstdcxx"}:
continue
recipe_toml = lookup.get(package_name)
if recipe_toml is None:
continue
recipe = tomllib.loads(recipe_toml.read_text())
source = recipe.get("source", {})
rel = recipe_toml.relative_to(project_root).as_posix()
is_wip_or_local = rel.startswith("recipes/wip/") or rel.startswith("local/recipes/")
if isinstance(source, dict) and "tar" in source and "blake3" not in source:
msg = f"missing blake3 for tar recipe: {recipe_toml.relative_to(project_root)}"
(errors if strict_metadata and not is_wip_or_local else warnings).append(msg)
for patch in source.get("patches", []):
patch_path = (recipe_toml.parent / patch).resolve()
if not patch_path.exists():
msg = f"missing patch file: {patch} for {recipe_toml.relative_to(project_root)}"
(errors if strict_metadata else warnings).append(msg)
for warning in warnings:
print(f"WARN: {warning}", file=sys.stderr)
if errors:
for error in errors:
print(f"ERROR: {error}", file=sys.stderr)
raise SystemExit(1)
PY
if [ -x "$SCRIPT_DIR/classify-patch-state.py" ]; then
python3 "$SCRIPT_DIR/classify-patch-state.py"
fi
if [ -x "$SCRIPT_DIR/verify-durable-source-edits.py" ]; then
args=()
if [ "$STRICT_DURABILITY" = "1" ]; then
args+=(--strict)
fi
python3 "$SCRIPT_DIR/verify-durable-source-edits.py" "${args[@]}"
fi
if [ "$CONFIG" = "redbear-full" ]; then
relibc_include="$(PROJECT_ROOT="$PROJECT_ROOT" bash -c 'source "$0"; redbear_relibc_stage_include_dir' "$SCRIPT_DIR/lib/relibc-surface.sh")"
relibc_lib_dir="$(PROJECT_ROOT="$PROJECT_ROOT" bash -c 'source "$0"; redbear_relibc_stage_lib_dir' "$SCRIPT_DIR/lib/relibc-surface.sh")"
if [ -d "$relibc_include" ] && [ -f "$relibc_lib_dir/libc.so" ]; then
for hdr in sys/signalfd.h sys/timerfd.h sys/eventfd.h threads.h; do
if [ ! -f "$relibc_include/$hdr" ]; then
echo ">>> Preflight note: relibc staged surface missing $hdr; top-level build should refresh/sync it before compilation."
fi
done
if ! grep -q 'strtold' "$relibc_include/stdlib.h" 2>/dev/null; then
echo ">>> Preflight note: relibc staged stdlib.h missing strtold declaration; top-level build should refresh/sync it before compilation."
fi
if ! readelf -Ws "$relibc_lib_dir/libc.so" | grep -q '_Z7strtoldPKcPPc'; then
echo ">>> Preflight note: relibc staged libc.so missing C++ strtold compatibility export; top-level build should refresh/sync it before compilation."
fi
else
echo ">>> Preflight note: relibc staged surface not present yet; build will refresh it if needed."
fi
fi
echo ">>> Build preflight passed"
+18 -50
View File
@@ -3,14 +3,26 @@ set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
source "$SCRIPT_DIR/lib/relibc-surface.sh"
# Source .config for release mode settings (REDBEAR_RELEASE, etc.)
if [ -f "$PROJECT_ROOT/.config" ]; then
while IFS='?=' read -r key value; do
while IFS= read -r line; do
line="${line%%#*}"
line=$(echo "$line" | xargs)
[ -z "$line" ] && continue
if [[ "$line" == *"?="* ]]; then
key="${line%%\?=*}"
value="${line#*\?=}"
elif [[ "$line" == *"="* ]]; then
key="${line%%=*}"
value="${line#*=}"
else
continue
fi
key=$(echo "$key" | xargs)
value=$(echo "$value" | xargs)
[ -z "$key" ] && continue
[[ "$key" =~ ^# ]] && continue
# Only set if not already set in environment
[ -n "${!key:-}" ] || export "$key=$value"
done < "$PROJECT_ROOT/.config"
@@ -111,31 +123,6 @@ stash_nested_repo_if_dirty() {
stash_nested_repo_if_dirty "$PROJECT_ROOT/recipes/core/relibc/source" "relibc"
ensure_relibc_desktop_surface() {
local relibc_target="$PROJECT_ROOT/recipes/core/relibc/target/x86_64-unknown-redox"
local relibc_stage_include="$relibc_target/stage/usr/include"
local relibc_stage_lib="$relibc_target/stage/usr/lib/libc.so"
if [ ! -f "$relibc_stage_include/sys/signalfd.h" ] || \
[ ! -f "$relibc_stage_include/sys/timerfd.h" ] || \
[ ! -f "$relibc_stage_include/sys/eventfd.h" ] || \
[ ! -f "$relibc_stage_lib" ] || \
! readelf -Ws "$relibc_stage_lib" | grep -q '_Z7strtoldPKcPPc'; then
echo ">>> Refreshing relibc staged surface for full desktop target..."
rm -rf \
"$relibc_target/build" \
"$relibc_target/stage" \
"$relibc_target/stage.tmp" \
"$relibc_target/sysroot"
rm -f \
"$relibc_target/auto_deps.toml" \
"$relibc_target/stage.pkgar" \
"$relibc_target/stage.toml"
REPO_OFFLINE=1 COOKBOOK_OFFLINE=true CI=1 ./target/release/repo cook relibc
echo ""
fi
}
if [ "$APPLY_PATCHES" = "1" ] && [ -z "${REDBEAR_RELEASE:-}" ]; then
echo ">>> Applying local patches..."
@@ -199,7 +186,7 @@ if [ ! -f "target/release/repo" ]; then
fi
if [ "$CONFIG" = "redbear-full" ]; then
ensure_relibc_desktop_surface
redbear_ensure_relibc_desktop_surface
fi
FW_AMD_DIR="$PROJECT_ROOT/local/firmware/amdgpu"
@@ -218,36 +205,17 @@ fi
echo ">>> Building Red Bear OS with config: $CONFIG"
echo ">>> This may take 30-60 minutes on first build..."
# In release mode, verify archives exist before building
if [ -n "${REDBEAR_RELEASE:-}" ]; then
echo ">>> Release mode: $REDBEAR_RELEASE"
if [ -f "./local/scripts/verify-sources-archived.sh" ]; then
bash "./local/scripts/verify-sources-archived.sh" --release="$REDBEAR_RELEASE" || {
echo "ERROR: Release archive verification failed. Run: provision-release.sh"
exit 1
}
fi
bash "$PROJECT_ROOT/local/scripts/build-release-mode.sh" --release="$REDBEAR_RELEASE" --config="$CONFIG" --extra-package=relibc
fi
bash "$PROJECT_ROOT/local/scripts/build-preflight.sh" --config="$CONFIG" ${REDBEAR_RELEASE:+--release="$REDBEAR_RELEASE"} --extra-package=relibc
if [ "${REDBEAR_ALLOW_UPSTREAM:-0}" = "1" ]; then
echo ">>> WARNING: Upstream fetch ENABLED (REDBEAR_ALLOW_UPSTREAM=1)"
REPO_OFFLINE=0 COOKBOOK_OFFLINE=false CI=1 make all "CONFIG_NAME=$CONFIG" "JOBS=$JOBS"
elif [ -n "${REDBEAR_RELEASE:-}" ]; then
echo ">>> Release mode: building from immutable archives (offline)"
# Validate source trees before building
if [ -f "$PROJECT_ROOT/local/scripts/validate-source-trees.sh" ]; then
echo ">>> Validating source trees..."
bash "$PROJECT_ROOT/local/scripts/validate-source-trees.sh" "$CONFIG" || {
echo "WARNING: Some source trees are missing."
echo "Attempting build with REPO_BINARY=1 fallback for missing packages..."
REPO_OFFLINE=1 COOKBOOK_OFFLINE=true CI=1 REPO_BINARY=1 make all "CONFIG_NAME=$CONFIG" "JOBS=$JOBS" || {
echo "ERROR: Build failed even with binary fallback."
echo "Run: ./local/scripts/restore-sources.sh --release=$REDBEAR_RELEASE"
exit 1
}
exit 0
}
fi
REPO_OFFLINE=1 COOKBOOK_OFFLINE=true CI=1 make all "CONFIG_NAME=$CONFIG" "JOBS=$JOBS"
elif [ "$ALLOW_UPSTREAM" -eq 1 ]; then
echo ">>> Upstream recipe refresh enabled"
+45
View File
@@ -0,0 +1,45 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
RELEASE=""
CONFIG="redbear-full"
EXTRA_PACKAGES=()
usage() {
cat <<EOF
Usage: $(basename "$0") --release=<ver> [--config=<name>] [--extra-package=<pkg> ...]
EOF
}
while [ $# -gt 0 ]; do
case "$1" in
--release=*) RELEASE="${1#*=}" ;;
--config=*) CONFIG="${1#*=}" ;;
--extra-package=*) EXTRA_PACKAGES+=("${1#*=}") ;;
-h|--help) usage; exit 0 ;;
*) echo "Unknown: $1" >&2; usage >&2; exit 1 ;;
esac
shift
done
if [ -z "$RELEASE" ]; then
echo "ERROR: --release is required" >&2
exit 1
fi
cd "$PROJECT_ROOT"
echo ">>> Release mode: $RELEASE"
bash "$SCRIPT_DIR/verify-sources-archived.sh" --release="$RELEASE"
if [ -f "$SCRIPT_DIR/ensure-release-sources.sh" ]; then
echo ">>> Ensuring release source trees for $CONFIG..."
args=("$SCRIPT_DIR/ensure-release-sources.sh" "--release=$RELEASE" "--config=$CONFIG")
for package_name in "${EXTRA_PACKAGES[@]}"; do
args+=("--extra-package=$package_name")
done
bash "${args[@]}"
fi
+57
View File
@@ -0,0 +1,57 @@
#!/usr/bin/env python3
import argparse
import subprocess
import sys
from pathlib import Path
PROJECT_ROOT = Path(__file__).resolve().parents[2]
PATCH_TARGETS = {
"kernel": PROJECT_ROOT / "recipes/core/kernel/source",
"base": PROJECT_ROOT / "recipes/core/base/source",
"relibc": PROJECT_ROOT / "recipes/core/relibc/source",
"bootloader": PROJECT_ROOT / "recipes/core/bootloader/source",
"installer": PROJECT_ROOT / "recipes/core/installer/source",
}
def run_patch(target: Path, patch_file: Path, reverse: bool) -> bool:
cmd = ["patch", "--dry-run", "-p1", "-d", str(target)]
if reverse:
cmd.insert(1, "-R")
with patch_file.open("rb") as handle:
proc = subprocess.run(cmd, stdin=handle, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
return proc.returncode == 0
def classify_patch(target: Path, patch_file: Path) -> str:
if not target.exists():
return "missing_target"
if run_patch(target, patch_file, reverse=False):
return "applies_cleanly"
if run_patch(target, patch_file, reverse=True):
return "already_applied"
return "drifted_or_obsolete"
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--strict", action="store_true")
args = parser.parse_args()
had_problem = False
for label, target in PATCH_TARGETS.items():
patch_dir = PROJECT_ROOT / "local/patches" / label
if not patch_dir.is_dir():
continue
for patch_file in sorted(patch_dir.glob("*.patch")):
status = classify_patch(target, patch_file)
print(f"{label}\t{patch_file.name}\t{status}")
if status in {"missing_target", "drifted_or_obsolete"}:
had_problem = True
return 1 if args.strict and had_problem else 0
if __name__ == "__main__":
sys.exit(main())
+143
View File
@@ -0,0 +1,143 @@
#!/usr/bin/env bash
redbear_project_root() {
if [ -n "${PROJECT_ROOT:-}" ]; then
printf '%s\n' "${PROJECT_ROOT}"
return 0
fi
if [ -n "${COOKBOOK_ROOT:-}" ]; then
printf '%s\n' "${COOKBOOK_ROOT}"
return 0
fi
return 1
}
redbear_choose_toolchain_root() {
if [ -n "${COOKBOOK_HOST_SYSROOT:-}" ] && [ -d "${COOKBOOK_HOST_SYSROOT}" ]; then
printf '%s\n' "${COOKBOOK_HOST_SYSROOT}"
return 0
fi
if [ -d "${HOME}/.redoxer/x86_64-unknown-redox/toolchain" ]; then
printf '%s\n' "${HOME}/.redoxer/x86_64-unknown-redox/toolchain"
return 0
fi
printf '%s\n' "$(redbear_project_root)/prefix/x86_64-unknown-redox/sysroot"
}
redbear_relibc_target_dir() {
printf '%s\n' "$(redbear_project_root)/recipes/core/relibc/target/x86_64-unknown-redox"
}
redbear_relibc_stage_include_dir() {
local relibc_target
relibc_target="$(redbear_relibc_target_dir)"
printf '%s\n' "${relibc_target}/stage/usr/include"
}
redbear_relibc_stage_lib_dir() {
local relibc_target
relibc_target="$(redbear_relibc_target_dir)"
printf '%s\n' "${relibc_target}/stage/usr/lib"
}
redbear_choose_relibc_stage_include() {
local relibc_target stage_include tmp_include
relibc_target="$(redbear_relibc_target_dir)"
stage_include="${relibc_target}/stage/usr/include"
tmp_include="${relibc_target}/stage.tmp/usr/include"
if [ -d "$stage_include" ]; then
printf '%s\n' "$stage_include"
elif [ -d "$tmp_include" ]; then
printf '%s\n' "$tmp_include"
fi
}
redbear_choose_relibc_stage_lib() {
local relibc_target stage_lib tmp_lib build_lib candidate
relibc_target="$(redbear_relibc_target_dir)"
stage_lib="${relibc_target}/stage/usr/lib"
tmp_lib="${relibc_target}/stage.tmp/usr/lib"
build_lib="${relibc_target}/build/target/x86_64-unknown-redox/release"
for candidate in "$stage_lib" "$tmp_lib" "$build_lib"; do
if [ -f "$candidate/libc.so" ] && readelf -Ws "$candidate/libc.so" | grep -q '_Z7strtoldPKcPPc'; then
printf '%s\n' "$candidate"
return 0
fi
done
for candidate in "$stage_lib" "$build_lib" "$tmp_lib"; do
if [ -d "$candidate" ]; then
printf '%s\n' "$candidate"
return 0
fi
done
}
redbear_copy_relibc_surface_into_sysroot() {
local destination_sysroot="$1"
local include_dir lib_dir
include_dir="$(redbear_choose_relibc_stage_include)"
lib_dir="$(redbear_choose_relibc_stage_lib)"
if [ -n "$include_dir" ] && [ -d "$include_dir" ]; then
mkdir -p "${destination_sysroot}/include"
cp -a "${include_dir}/." "${destination_sysroot}/include/"
fi
if [ -n "$lib_dir" ] && [ -d "$lib_dir" ]; then
mkdir -p "${destination_sysroot}/lib"
cp -a "${lib_dir}/." "${destination_sysroot}/lib/"
fi
}
redbear_relibc_surface_ready() {
local relibc_target relibc_stage_include relibc_stage_lib
relibc_target="$(redbear_relibc_target_dir)"
relibc_stage_include="${relibc_target}/stage/usr/include"
relibc_stage_lib="${relibc_target}/stage/usr/lib/libc.so"
[ -f "${relibc_stage_include}/sys/signalfd.h" ] || return 1
[ -f "${relibc_stage_include}/sys/timerfd.h" ] || return 1
[ -f "${relibc_stage_include}/sys/eventfd.h" ] || return 1
[ -f "${relibc_stage_include}/threads.h" ] || return 1
[ -f "${relibc_stage_lib}" ] || return 1
readelf -Ws "${relibc_stage_lib}" | grep -q '_Z7strtoldPKcPPc' || return 1
return 0
}
redbear_sync_relibc_surface_to_toolchain() {
local relibc_target relibc_stage_include relibc_stage_lib toolchain_sysroot
relibc_target="$(redbear_relibc_target_dir)"
relibc_stage_include="${relibc_target}/stage/usr/include"
relibc_stage_lib="${relibc_target}/stage/usr/lib"
toolchain_sysroot="$(redbear_choose_toolchain_root)"
mkdir -p \
"${toolchain_sysroot}/include" \
"${toolchain_sysroot}/x86_64-unknown-redox/include" \
"${toolchain_sysroot}/x86_64-unknown-redox/lib"
cp -a "${relibc_stage_include}/." "${toolchain_sysroot}/include/"
cp -a "${relibc_stage_include}/." "${toolchain_sysroot}/x86_64-unknown-redox/include/"
cp -a "${relibc_stage_lib}/." "${toolchain_sysroot}/x86_64-unknown-redox/lib/"
}
redbear_ensure_relibc_desktop_surface() {
local relibc_target
relibc_target="$(redbear_relibc_target_dir)"
if ! redbear_relibc_surface_ready; then
echo ">>> Refreshing relibc staged surface for full desktop target..."
rm -rf \
"${relibc_target}/build" \
"${relibc_target}/stage" \
"${relibc_target}/stage.tmp" \
"${relibc_target}/sysroot"
rm -f \
"${relibc_target}/auto_deps.toml" \
"${relibc_target}/stage.pkgar" \
"${relibc_target}/stage.toml"
REPO_OFFLINE=1 COOKBOOK_OFFLINE=true CI=1 ./target/release/repo cook relibc
echo ""
fi
redbear_sync_relibc_surface_to_toolchain
}
@@ -0,0 +1,52 @@
#!/usr/bin/env python3
import argparse
import subprocess
import sys
from pathlib import Path
PROJECT_ROOT = Path(__file__).resolve().parents[2]
UPSTREAM_OWNED = {
"kernel": PROJECT_ROOT / "recipes/core/kernel/source",
"base": PROJECT_ROOT / "recipes/core/base/source",
"relibc": PROJECT_ROOT / "recipes/core/relibc/source",
"bootloader": PROJECT_ROOT / "recipes/core/bootloader/source",
"installer": PROJECT_ROOT / "recipes/core/installer/source",
}
def git_has_changes(repo: Path) -> tuple[bool, list[str]]:
if not (repo / ".git").exists():
return False, []
proc = subprocess.run(
["git", "status", "--short"],
cwd=repo,
check=False,
capture_output=True,
text=True,
)
lines = [line.rstrip() for line in proc.stdout.splitlines() if line.strip()]
return bool(lines), lines
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--strict", action="store_true")
args = parser.parse_args()
dirty = False
for label, repo in UPSTREAM_OWNED.items():
has_changes, lines = git_has_changes(repo)
if not has_changes:
continue
dirty = True
print(f"{label}\tDIRTY\t{repo.relative_to(PROJECT_ROOT)}")
for line in lines[:20]:
print(f" {line}")
if len(lines) > 20:
print(f" ... {len(lines) - 20} more")
return 1 if args.strict and dirty else 0
if __name__ == "__main__":
sys.exit(main())
+12 -55
View File
@@ -23,67 +23,32 @@ dependencies = [
script = """
DYNAMIC_INIT
PROJECT_ROOT="${COOKBOOK_ROOT}"
source "${COOKBOOK_ROOT}/local/scripts/lib/relibc-surface.sh"
RELIBC_STAGE_INCLUDE_STAGE="${COOKBOOK_ROOT}/recipes/core/relibc/target/${TARGET}/stage/usr/include"
RELIBC_STAGE_INCLUDE_TMP="${COOKBOOK_ROOT}/recipes/core/relibc/target/${TARGET}/stage.tmp/usr/include"
RELIBC_STAGE_LIB_STAGE="${COOKBOOK_ROOT}/recipes/core/relibc/target/${TARGET}/stage/usr/lib"
RELIBC_STAGE_LIB_TMP="${COOKBOOK_ROOT}/recipes/core/relibc/target/${TARGET}/stage.tmp/usr/lib"
RELIBC_BUILD_LIB="${COOKBOOK_ROOT}/recipes/core/relibc/target/${TARGET}/build/target/${TARGET}/release"
RELIBC_STAGE_INCLUDE="$RELIBC_STAGE_INCLUDE_STAGE"
if [ ! -d "$RELIBC_STAGE_INCLUDE" ] && [ -d "$RELIBC_STAGE_INCLUDE_TMP" ]; then
RELIBC_STAGE_INCLUDE="$RELIBC_STAGE_INCLUDE_TMP"
fi
choose_relibc_lib_stage() {
local candidate="$1"
if [ -f "$candidate/libc.so" ] && readelf -Ws "$candidate/libc.so" | grep -q '_Z7strtoldPKcPPc'; then
printf '%s\n' "$candidate"
return 0
fi
return 1
}
choose_toolchain_root() {
if [ -n "${COOKBOOK_HOST_SYSROOT:-}" ] && [ -d "${COOKBOOK_HOST_SYSROOT}" ]; then
printf '%s\n' "${COOKBOOK_HOST_SYSROOT}"
return 0
fi
if [ -d "${HOME}/.redoxer/x86_64-unknown-redox/toolchain" ]; then
printf '%s\n' "${HOME}/.redoxer/x86_64-unknown-redox/toolchain"
return 0
fi
printf '%s\n' "${COOKBOOK_ROOT}/prefix/x86_64-unknown-redox/sysroot"
}
if RELIBC_STAGE_LIB="$(choose_relibc_lib_stage "$RELIBC_STAGE_LIB_STAGE")"; then
:
elif RELIBC_STAGE_LIB="$(choose_relibc_lib_stage "$RELIBC_STAGE_LIB_TMP")"; then
:
elif RELIBC_STAGE_LIB="$(choose_relibc_lib_stage "$RELIBC_BUILD_LIB")"; then
:
elif [ -d "$RELIBC_STAGE_LIB_STAGE" ]; then
RELIBC_STAGE_LIB="$RELIBC_STAGE_LIB_STAGE"
elif [ -d "$RELIBC_BUILD_LIB" ]; then
RELIBC_STAGE_LIB="$RELIBC_BUILD_LIB"
else
RELIBC_STAGE_LIB="$RELIBC_STAGE_LIB_TMP"
fi
RELIBC_STAGE_INCLUDE="$(redbear_choose_relibc_stage_include)"
RELIBC_STAGE_LIB="$(redbear_choose_relibc_stage_lib)"
if [ -d "${RELIBC_STAGE_INCLUDE}" ]; then
mkdir -p "${COOKBOOK_SYSROOT}/include"
cp -a "${RELIBC_STAGE_INCLUDE}/." "${COOKBOOK_SYSROOT}/include/"
redbear_copy_relibc_surface_into_sysroot "${COOKBOOK_SYSROOT}"
if [ -f "${COOKBOOK_SYSROOT}/include/elf.h" ]; then
sed -i 's/typedef uint64_t Elf64_Word;/typedef uint32_t Elf64_Word;/' "${COOKBOOK_SYSROOT}/include/elf.h"
sed -i 's/typedef int64_t Elf64_Sword;/typedef int32_t Elf64_Sword;/' "${COOKBOOK_SYSROOT}/include/elf.h"
fi
export CPPFLAGS="${CPPFLAGS} -I${RELIBC_STAGE_INCLUDE}"
export CFLAGS="${CFLAGS} -I${RELIBC_STAGE_INCLUDE}"
export CXXFLAGS="${CXXFLAGS} -I${RELIBC_STAGE_INCLUDE}"
export CPPFLAGS="${CPPFLAGS:-} -I${RELIBC_STAGE_INCLUDE}"
export CFLAGS="${CFLAGS:-} -I${RELIBC_STAGE_INCLUDE}"
export CXXFLAGS="${CXXFLAGS:-} -I${RELIBC_STAGE_INCLUDE}"
# The Redox GCC toolchain currently prefers its own bundled target elf.h
# under .../x86_64-unknown-redox/include/ over the recipe sysroot copy.
# Sync the freshly built relibc header into that toolchain include root so
# Qt's ELF plugin parser sees the corrected ELF64 typedef layout.
TOOLCHAIN_ROOT="$(choose_toolchain_root)"
TOOLCHAIN_ROOT="$(redbear_choose_toolchain_root)"
TOOLCHAIN_TARGET_INCLUDE="${TOOLCHAIN_ROOT}/x86_64-unknown-redox/include"
TOOLCHAIN_TARGET_USR_INCLUDE="${TOOLCHAIN_ROOT}/x86_64-unknown-redox/usr/include"
for header in elf.h semaphore.h unistd.h; do
@@ -112,8 +77,6 @@ if [ -d "${RELIBC_STAGE_INCLUDE}" ]; then
done
fi
if [ -d "${RELIBC_STAGE_LIB}" ]; then
mkdir -p "${COOKBOOK_SYSROOT}/lib"
cp -a "${RELIBC_STAGE_LIB}/." "${COOKBOOK_SYSROOT}/lib/"
export LDFLAGS="-L${RELIBC_STAGE_LIB} -Wl,-rpath-link,${RELIBC_STAGE_LIB} ${LDFLAGS}"
fi
@@ -166,12 +129,6 @@ if [ ! -f "${COOKBOOK_SYSROOT}/include/netinet/in6_pktinfo_compat.h" ]; then
#ifndef IPV6_PKTINFO
#define IPV6_PKTINFO 50
#endif
#ifndef in6_pktinfo
struct in6_pktinfo {
struct in6_addr ipi6_addr;
unsigned int ipi6_ifindex;
};
#endif
#endif
PKTINFO_EOF
fi
@@ -319,10 +276,10 @@ mv "${COOKBOOK_SOURCE}/src/corelib/CMakeLists.txt.tmp" "${COOKBOOK_SOURCE}/src/c
# Enable QtNetwork — relibc DNS resolver hardened (2026-04-29: use-after-free fix, FD leak fix,
# transaction ID validation, RCODE/TC handling, typed error mapping).
# QtNetwork was previously disabled. Now re-enabled for full KDE desktop path.
sed -i 's/^# add_subdirectory(network)/ add_subdirectory(network)/' \
sed -i 's/^\\s*# add_subdirectory(network).*/ add_subdirectory(network)/' \
"${COOKBOOK_SOURCE}/src/CMakeLists.txt"
# Also re-enable TUIO touch plugin which depends on QtNetwork
sed -i 's/^# add_subdirectory(tuiotouch)/ add_subdirectory(tuiotouch)/' \
sed -i 's/^\\s*# add_subdirectory(tuiotouch).*/ add_subdirectory(tuiotouch)/' \
"${COOKBOOK_SOURCE}/src/plugins/generic/CMakeLists.txt"
python - <<'PY'
import os