fd11aa716c
redbear-ci / check (push) Has been cancelled
Unblocks plasma-workspace/plasma-desktop, which required 14 packages that had
no in-tree recipe. Sources are reproducible from each recipe's tar= + blake3;
the vendored source/ trees are deliberately not committed here (212M).
New recipes:
KF6 6.28.0 kf6-kholidays, kf6-krunner, kf6-kstatusnotifieritem,
kf6-kunitconversion
Plasma 6.7.2 knighttime, layer-shell-qt, libkscreen, libksysguard,
plasma-activities-stats, plasma5support, kscreenlocker
Qt 6.11.1 qtpositioning, qtspeech, qttools
libksysguard carries P0-redox-process-backend.patch: processes_local_p.cpp
dispatches on platform macros and had no __redox__ arm, so ProcessesLocal was
entirely undefined. Adds a real backend reading /scheme/proc/ps (pid, ppid,
real+effective ids, thread count, state) and /scheme/sys/mem, with kill() for
signals. Upstream's generic fallback is a pure stub and was not used. Absent
facilities (no setpriority/sched_setscheduler/ioprio on a microkernel) report
NotSupported rather than pretending.
Restored, no longer disabled:
- night colour: kcms/nighttime + kwin's nightlight plugin, now that
KNightTime/Qt6Positioning/KF6Holidays exist
- KIO FileWidgets (file dialog, places model), wrongly swept in with the
unportable kiod/kssld/kioworkers subdirs
- kf6-ktexteditor text-to-speech: removes a disguised stub that rewrote
speechEngine() to return nullptr and mangled call sites into invalid C++
- kwin KWIN_BUILD_SCREENLOCKER=ON (needs kscreenlocker; see below)
Toolchain and recipe fixes:
- redox-toolchain.cmake: append -lgcc. __extendhfsf2/__extendbfsf2 are
global in libgcc.a but hidden in libgcc_s.so (the Redox libgcc version map
stops at GCC_7.0.0 and never emits the GCC_12/13 nodes upstream exports),
and GCC omits -lgcc for -shared, so no C++23 shared library using
std::format<_Float16|bfloat16_t> could link.
- qtmultimedia: rewrite /usr/src/.../meta_types paths and stage metatypes,
so consumers using qt_internal_add_qml_module can configure.
- qtspeech: qtmultimedia is mandatory, not optional -- upstream return()s
with only a NOTICE without it, yielding a green build over an empty
package. Asserts its own output so that cannot recur.
- narrow Linux-only guards with AND NOT REDOX where the toolchain sets
CMAKE_SYSTEM_NAME=Linux purely to get UNIX=TRUE (kio LibMount,
libksysguard NL/Sensors, plasma-workspace NetworkManagerQt).
- drop REQUIRED components that are declared but referenced nowhere
(Location, QCoro6, Qt6 Test) -- verified by exhaustive grep.
- DESTDIR installs where KDE emits absolute KDE_INSTALL_FULL_* paths that
--prefix cannot re-root, which otherwise write into the build host.
Auth stack:
- pam-redbear: add PAM_MODULE_UNKNOWN (28), missing from both the header and
lib.rs; realign 30/31 to Linux-PAM's PAM_CONV_AGAIN/PAM_INCOMPLETE, which
previously held Red Bear-only names on standard values, so anything built
against stock PAM headers mis-decoded them.
- redbear-authd: support yescrypt ($y$ -- the default shadow format on
current Debian/Ubuntu/Fedora, previously an unexplained login failure),
bcrypt and md5-crypt. Plaintext shadow entries now require the
/etc/redbear/allow-plaintext-passwords sentinel and warn on every use,
instead of being compared silently. 19/19 host tests pass.
Build-system hardening:
- verify-tracked-sources.sh, wired into preflight: fails on deletion of any
tracked vendored source, and on modifications with no baseline entry.
local/sources/ had a dirty gate and version checks; local/recipes/*/source/
had none, which allowed an rm -rf to delete 7958 tracked files and a
pristine re-extract to silently overwrite committed fixes (kwin's
std::expected/vulkan-hpp and X11 gating, kio's Q_OS_REDOX resolver guards).
- validate-source-trees.py: resolve recipe.toml through the overlay symlink;
it reported false MISSING for symlinked recipes.
- test-sddm-virgl-qemu.sh: the null-proxy check used report(), which PASSES
on regex match -- so the known Qt6 Wayland null+8 fault would report PASS
when present. Added report_absent().
kscreenlocker builds only its cmake-level Wayland-only changes so far; the
C++ X11 removal (61 call sites) is not yet applied, so kwin's screenlocker
flag is blocked on it.
331 lines
15 KiB
Bash
Executable File
331 lines
15 KiB
Bash
Executable File
#!/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"
|
|
|
|
# Defensive: detect and repair broken recipe.toml symlinks.
|
|
# These are tracked files — broken symlinks mean corruption from unknown source.
|
|
# Check both local/recipes/ (regular files) and recipes/ (tracked symlinks).
|
|
broken_recipes=$(find local/recipes recipes -name "recipe.toml" -xtype l 2>/dev/null | wc -l)
|
|
if [ "$broken_recipes" -gt 0 ]; then
|
|
echo ">>> WARNING: $broken_recipes broken recipe.toml symlinks detected — auto-repairing from git..." >&2
|
|
find local/recipes recipes -name "recipe.toml" -xtype l -exec git checkout -q -- {} \; 2>/dev/null
|
|
remaining=$(find local/recipes recipes -name "recipe.toml" -xtype l 2>/dev/null | wc -l)
|
|
if [ "$remaining" -gt 0 ] && [ -x "$SCRIPT_DIR/guard-recipes.sh" ]; then
|
|
# `git checkout` only restores TRACKED links. Untracked/generated links
|
|
# (custom local/recipes symlinks that were never committed) must be
|
|
# regenerated by the durability guard, which recomputes correct relative
|
|
# targets from local/recipes/.
|
|
echo ">>> $remaining link(s) not restorable from git — regenerating via guard-recipes.sh --fix..." >&2
|
|
"$SCRIPT_DIR/guard-recipes.sh" --fix >/dev/null 2>&1 || true
|
|
remaining=$(find local/recipes recipes -name "recipe.toml" -xtype l 2>/dev/null | wc -l)
|
|
fi
|
|
if [ "$remaining" -gt 0 ]; then
|
|
echo ">>> ERROR: $remaining recipe.toml files could not be restored. Build may fail." >&2
|
|
else
|
|
echo ">>> Repaired: all recipe.toml symlinks restored."
|
|
fi
|
|
fi
|
|
|
|
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
|
|
|
|
# Tracked vendored source integrity.
|
|
#
|
|
# local/sources/ (the submodule forks) is protected by two existing gates: the
|
|
# dirty-source gate in build-redbear.sh and verify-fork-versions.sh. The
|
|
# vendored recipe trees under local/recipes/*/source/ carry equally durable
|
|
# committed work and had NO equivalent gate, which allowed two real incidents:
|
|
# an `rm -rf <recipe>/source` deleting thousands of tracked files, and a
|
|
# pristine tarball re-extract silently overwriting committed Red Bear fixes
|
|
# (kwin's std::expected/vulkan-hpp + X11 gating, kio's Q_OS_REDOX resolver
|
|
# guards) with no error raised. This closes that asymmetry.
|
|
if [ -x "$SCRIPT_DIR/verify-tracked-sources.sh" ] && [ "${REDBEAR_SKIP_TRACKED_SOURCE_CHECK:-0}" != "1" ]; then
|
|
if ! "$SCRIPT_DIR/verify-tracked-sources.sh"; then
|
|
echo "" >&2
|
|
echo ">>> ERROR: tracked vendored source trees are damaged (see above)." >&2
|
|
echo " Set REDBEAR_SKIP_TRACKED_SOURCE_CHECK=1 to bypass (DANGEROUS: you are" >&2
|
|
echo " choosing to build from, and potentially commit, a corrupted source tree)." >&2
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# Enforce the "no fake version label" rule (local/AGENTS.md):
|
|
# every Cat 2 fork's `<X.Y.Z>-rb<B.B.B>` version must match the source
|
|
# content from upstream `<X.Y.Z>` + Red Bear patches, and the `-rb<B.B.B>`
|
|
# suffix must match the current Red Bear OS git branch.
|
|
if [ -x "$SCRIPT_DIR/verify-fork-versions.sh" ]; then
|
|
if ! "$SCRIPT_DIR/verify-fork-versions.sh" >/tmp/fork-verify.out 2>&1; then
|
|
if [ "${REDBEAR_SKIP_FORK_VERIFY:-0}" != "1" ]; then
|
|
cat /tmp/fork-verify.out >&2
|
|
echo "ERROR: fork version verification failed." >&2
|
|
echo " Set REDBEAR_SKIP_FORK_VERIFY=1 to bypass (DANGEROUS, only for emergency)." >&2
|
|
exit 1
|
|
fi
|
|
echo ">>> Preflight note: fork version verification bypassed via REDBEAR_SKIP_FORK_VERIFY=1." >&2
|
|
else
|
|
echo ">>> Preflight: fork versions verified against upstream."
|
|
fi
|
|
fi
|
|
|
|
if [ -x "$SCRIPT_DIR/check-fork-drift.sh" ] && [ "${REDBEAR_SKIP_DRIFT_CHECK:-0}" != "1" ]; then
|
|
if ! "$SCRIPT_DIR/check-fork-drift.sh" --no-fetch --threshold=50 >/tmp/fork-drift.out 2>&1; then
|
|
echo ">>> WARNING: Upstream drift detected in local forks:" >&2
|
|
grep -E 'DRIFT' /tmp/fork-drift.out >&2 || cat /tmp/fork-drift.out >&2
|
|
echo ">>> Run ./local/scripts/check-fork-drift.sh for full report." >&2
|
|
echo ">>> Run ./local/scripts/upgrade-forks.sh to upgrade." >&2
|
|
echo ">>> Set REDBEAR_SKIP_DRIFT_CHECK=1 to suppress this warning." >&2
|
|
else
|
|
echo ">>> Preflight: fork drift check passed."
|
|
fi
|
|
fi
|
|
|
|
if [ -x "$SCRIPT_DIR/verify-fork-functions.sh" ] && [ "${REDBEAR_SKIP_FUNCTION_CHECK:-0}" != "1" ]; then
|
|
if ! "$SCRIPT_DIR/verify-fork-functions.sh" --no-fetch --quiet >/tmp/fork-functions.out 2>&1; then
|
|
cat /tmp/fork-functions.out >&2
|
|
echo ">>> ERROR: Fork function verification failed — upstream functions are missing." >&2
|
|
echo ">>> This indicates a bad merge/cherry-pick dropped upstream code silently." >&2
|
|
echo ">>> Fix: ./local/scripts/upgrade-forks.sh --no-fetch --force-reapply <fork>" >&2
|
|
if [ "${REDBEAR_SKIP_FORK_VERIFY:-0}" != "1" ]; then
|
|
exit 1
|
|
fi
|
|
echo ">>> WARNING: Bypassed via REDBEAR_SKIP_FORK_VERIFY=1." >&2
|
|
else
|
|
echo ">>> Preflight: fork function verification passed."
|
|
fi
|
|
fi
|
|
|
|
# Phase 1.0C: external tar-recipe version consistency.
|
|
# The local/sources/ forks are guarded above; this guards the OTHER fork family:
|
|
# tar recipes that vendor their upstream source/ in git while also declaring a
|
|
# [source] tar=/blake3. A version bump that rewrites recipe metadata but never
|
|
# propagates into the vendored source/ (or a stale cached source.tar) makes the
|
|
# build silently compile the wrong version (the Qt 6.11.0/6.11.1 and KDE
|
|
# 6.10.0/6.28.0 divergences). Fix: ./local/scripts/sync-recipe-source.sh <recipe>
|
|
if [ -x "$SCRIPT_DIR/verify-external-source-versions.sh" ] && [ "${REDBEAR_SKIP_EXTERNAL_SOURCE_CHECK:-0}" != "1" ]; then
|
|
if ! "$SCRIPT_DIR/verify-external-source-versions.sh" --quiet >/tmp/ext-source.out 2>&1; then
|
|
cat /tmp/ext-source.out >&2
|
|
echo ">>> ERROR: external tar-recipe source version divergence (recipe vs vendored source/)." >&2
|
|
echo ">>> Fix: ./local/scripts/sync-recipe-source.sh --commit <recipe> (propagates the bump)" >&2
|
|
if [ "${REDBEAR_SKIP_FORK_VERIFY:-0}" != "1" ]; then
|
|
exit 1
|
|
fi
|
|
echo ">>> WARNING: Bypassed via REDBEAR_SKIP_FORK_VERIFY=1." >&2
|
|
else
|
|
echo ">>> Preflight: external tar-recipe source versions consistent."
|
|
fi
|
|
fi
|
|
|
|
# Phase 1.0D: static patch-sanity. Validates that every active recipe .patch has
|
|
# internally-consistent hunk line counts, catching the "malformed patch at line N"
|
|
# class at preflight instead of hours into a cook (hit 3x this cycle:
|
|
# qtwaylandscanner/sddm/xwayland). Fix: ./local/scripts/verify-patch-sanity.py --fix
|
|
if [ -x "$SCRIPT_DIR/verify-patch-sanity.py" ] || [ -f "$SCRIPT_DIR/verify-patch-sanity.py" ]; then
|
|
if ! python3 "$SCRIPT_DIR/verify-patch-sanity.py" --quiet >/tmp/patch-sanity.out 2>&1; then
|
|
cat /tmp/patch-sanity.out >&2
|
|
echo ">>> ERROR: malformed recipe patch(es). Fix: ./local/scripts/verify-patch-sanity.py --fix" >&2
|
|
if [ "${REDBEAR_SKIP_FORK_VERIFY:-0}" != "1" ]; then exit 1; fi
|
|
echo ">>> WARNING: Bypassed via REDBEAR_SKIP_FORK_VERIFY=1." >&2
|
|
else
|
|
echo ">>> Preflight: recipe patches are well-formed."
|
|
fi
|
|
fi
|
|
|
|
# Phase 1.0B: enforce patch-presence invariant. Every patch in
|
|
# local/patches/<comp>/ MUST have its content reflected as commits in
|
|
# local/sources/<comp>/'s working tree, or the next fork reset will
|
|
# silently lose that work. See local/docs/legacy-obsolete-2026-07-25/PATCH-PRESERVATION-AUDIT-2026-07-12.md.
|
|
# Default is warn-only; --strict was decided against because current state
|
|
# is mid-recovery and we don't want to block every operator build.
|
|
if [ -x "$SCRIPT_DIR/verify-patch-content.sh" ] && [ "${REDBEAR_SKIP_PATCH_CONTENT_CHECK:-0}" != "1" ]; then
|
|
if ! "$SCRIPT_DIR/verify-patch-content.sh" >/tmp/patch-content.out 2>&1; then
|
|
cat /tmp/patch-content.out >&2
|
|
echo ">>> WARNING: Orphaned patches detected (Phase 1.0B). Build proceeding but Red Bear" >&2
|
|
echo ">>> work in orphaned patches is NOT in the fork. See audit doc for recovery." >&2
|
|
echo ">>> Set REDBEAR_SKIP_PATCH_CONTENT_CHECK=1 to suppress this warning." >&2
|
|
echo ">>> Run ./local/scripts/verify-patch-content.sh --strict for exit-1 enforcement." >&2
|
|
fi
|
|
fi
|
|
|
|
# Phase 4.2: collision detection — config [[files]] vs recipe installs.
|
|
# The original AGENTS.md "Collision Implications" claim that runtime
|
|
# collision detection exists was Phase 0 audit-disproven. This implements
|
|
# the GENERAL variant (config-vs-package) at pre-flight time so the
|
|
# silent-collision class of bug surfaces before install_packages().
|
|
if [ -x "$SCRIPT_DIR/verify-collision-detection.py" ] && [ "${REDBEAR_SKIP_COLLISION_CHECK:-0}" != "1" ]; then
|
|
if ! python3 "$SCRIPT_DIR/verify-collision-detection.py" >/tmp/collision.out 2>&1; then
|
|
cat /tmp/collision.out >&2
|
|
echo ">>> ERROR: Package-vs-config collision detected. Refusing to proceed." >&2
|
|
echo ">>> Set REDBEAR_SKIP_COLLISION_CHECK=1 to bypass (DANGEROUS)." >&2
|
|
else
|
|
echo ">>> Preflight: collision detection passed (config [[files]] vs recipe installs)."
|
|
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, {})
|
|
|
|
known_package_paths = {
|
|
name for name in lookup
|
|
if not name.startswith("host:")
|
|
}
|
|
|
|
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)
|
|
build = recipe.get("build", {})
|
|
script = build.get("script", "") if isinstance(build, dict) else ""
|
|
if script:
|
|
for dep in known_package_paths:
|
|
bad = f"/tmp/{dep}/"
|
|
if bad in script:
|
|
msg = (
|
|
f"recipe {recipe_toml.relative_to(project_root)} references {bad} "
|
|
f"in its build script. The cookbook does not stage host dev-dependencies "
|
|
f"under /tmp/<name>; use ${{COOKBOOK_TOOLCHAIN}} (the cross recipe's "
|
|
f"toolchain directory populated from dev-dependencies) instead."
|
|
)
|
|
(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"
|