feat: add build preflight and sysroot helpers
This commit is contained in:
@@ -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"
|
||||||
@@ -3,14 +3,26 @@ set -euo pipefail
|
|||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||||
|
source "$SCRIPT_DIR/lib/relibc-surface.sh"
|
||||||
|
|
||||||
# Source .config for release mode settings (REDBEAR_RELEASE, etc.)
|
# Source .config for release mode settings (REDBEAR_RELEASE, etc.)
|
||||||
if [ -f "$PROJECT_ROOT/.config" ]; then
|
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)
|
key=$(echo "$key" | xargs)
|
||||||
value=$(echo "$value" | xargs)
|
value=$(echo "$value" | xargs)
|
||||||
[ -z "$key" ] && continue
|
[ -z "$key" ] && continue
|
||||||
[[ "$key" =~ ^# ]] && continue
|
|
||||||
# Only set if not already set in environment
|
# Only set if not already set in environment
|
||||||
[ -n "${!key:-}" ] || export "$key=$value"
|
[ -n "${!key:-}" ] || export "$key=$value"
|
||||||
done < "$PROJECT_ROOT/.config"
|
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"
|
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
|
if [ "$APPLY_PATCHES" = "1" ] && [ -z "${REDBEAR_RELEASE:-}" ]; then
|
||||||
echo ">>> Applying local patches..."
|
echo ">>> Applying local patches..."
|
||||||
|
|
||||||
@@ -199,7 +186,7 @@ if [ ! -f "target/release/repo" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$CONFIG" = "redbear-full" ]; then
|
if [ "$CONFIG" = "redbear-full" ]; then
|
||||||
ensure_relibc_desktop_surface
|
redbear_ensure_relibc_desktop_surface
|
||||||
fi
|
fi
|
||||||
|
|
||||||
FW_AMD_DIR="$PROJECT_ROOT/local/firmware/amdgpu"
|
FW_AMD_DIR="$PROJECT_ROOT/local/firmware/amdgpu"
|
||||||
@@ -218,36 +205,17 @@ fi
|
|||||||
echo ">>> Building Red Bear OS with config: $CONFIG"
|
echo ">>> Building Red Bear OS with config: $CONFIG"
|
||||||
echo ">>> This may take 30-60 minutes on first build..."
|
echo ">>> This may take 30-60 minutes on first build..."
|
||||||
|
|
||||||
# In release mode, verify archives exist before building
|
|
||||||
if [ -n "${REDBEAR_RELEASE:-}" ]; then
|
if [ -n "${REDBEAR_RELEASE:-}" ]; then
|
||||||
echo ">>> Release mode: $REDBEAR_RELEASE"
|
bash "$PROJECT_ROOT/local/scripts/build-release-mode.sh" --release="$REDBEAR_RELEASE" --config="$CONFIG" --extra-package=relibc
|
||||||
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
|
|
||||||
fi
|
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
|
if [ "${REDBEAR_ALLOW_UPSTREAM:-0}" = "1" ]; then
|
||||||
echo ">>> WARNING: Upstream fetch ENABLED (REDBEAR_ALLOW_UPSTREAM=1)"
|
echo ">>> WARNING: Upstream fetch ENABLED (REDBEAR_ALLOW_UPSTREAM=1)"
|
||||||
REPO_OFFLINE=0 COOKBOOK_OFFLINE=false CI=1 make all "CONFIG_NAME=$CONFIG" "JOBS=$JOBS"
|
REPO_OFFLINE=0 COOKBOOK_OFFLINE=false CI=1 make all "CONFIG_NAME=$CONFIG" "JOBS=$JOBS"
|
||||||
elif [ -n "${REDBEAR_RELEASE:-}" ]; then
|
elif [ -n "${REDBEAR_RELEASE:-}" ]; then
|
||||||
echo ">>> Release mode: building from immutable archives (offline)"
|
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"
|
REPO_OFFLINE=1 COOKBOOK_OFFLINE=true CI=1 make all "CONFIG_NAME=$CONFIG" "JOBS=$JOBS"
|
||||||
elif [ "$ALLOW_UPSTREAM" -eq 1 ]; then
|
elif [ "$ALLOW_UPSTREAM" -eq 1 ]; then
|
||||||
echo ">>> Upstream recipe refresh enabled"
|
echo ">>> Upstream recipe refresh enabled"
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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())
|
||||||
@@ -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())
|
||||||
@@ -23,67 +23,32 @@ dependencies = [
|
|||||||
script = """
|
script = """
|
||||||
DYNAMIC_INIT
|
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_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_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_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_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_BUILD_LIB="${COOKBOOK_ROOT}/recipes/core/relibc/target/${TARGET}/build/target/${TARGET}/release"
|
||||||
|
|
||||||
RELIBC_STAGE_INCLUDE="$RELIBC_STAGE_INCLUDE_STAGE"
|
RELIBC_STAGE_INCLUDE="$(redbear_choose_relibc_stage_include)"
|
||||||
if [ ! -d "$RELIBC_STAGE_INCLUDE" ] && [ -d "$RELIBC_STAGE_INCLUDE_TMP" ]; then
|
RELIBC_STAGE_LIB="$(redbear_choose_relibc_stage_lib)"
|
||||||
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
|
|
||||||
if [ -d "${RELIBC_STAGE_INCLUDE}" ]; then
|
if [ -d "${RELIBC_STAGE_INCLUDE}" ]; then
|
||||||
mkdir -p "${COOKBOOK_SYSROOT}/include"
|
redbear_copy_relibc_surface_into_sysroot "${COOKBOOK_SYSROOT}"
|
||||||
cp -a "${RELIBC_STAGE_INCLUDE}/." "${COOKBOOK_SYSROOT}/include/"
|
|
||||||
if [ -f "${COOKBOOK_SYSROOT}/include/elf.h" ]; then
|
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 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"
|
sed -i 's/typedef int64_t Elf64_Sword;/typedef int32_t Elf64_Sword;/' "${COOKBOOK_SYSROOT}/include/elf.h"
|
||||||
fi
|
fi
|
||||||
export CPPFLAGS="${CPPFLAGS} -I${RELIBC_STAGE_INCLUDE}"
|
export CPPFLAGS="${CPPFLAGS:-} -I${RELIBC_STAGE_INCLUDE}"
|
||||||
export CFLAGS="${CFLAGS} -I${RELIBC_STAGE_INCLUDE}"
|
export CFLAGS="${CFLAGS:-} -I${RELIBC_STAGE_INCLUDE}"
|
||||||
export CXXFLAGS="${CXXFLAGS} -I${RELIBC_STAGE_INCLUDE}"
|
export CXXFLAGS="${CXXFLAGS:-} -I${RELIBC_STAGE_INCLUDE}"
|
||||||
|
|
||||||
# The Redox GCC toolchain currently prefers its own bundled target elf.h
|
# The Redox GCC toolchain currently prefers its own bundled target elf.h
|
||||||
# under .../x86_64-unknown-redox/include/ over the recipe sysroot copy.
|
# under .../x86_64-unknown-redox/include/ over the recipe sysroot copy.
|
||||||
# Sync the freshly built relibc header into that toolchain include root so
|
# Sync the freshly built relibc header into that toolchain include root so
|
||||||
# Qt's ELF plugin parser sees the corrected ELF64 typedef layout.
|
# 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_INCLUDE="${TOOLCHAIN_ROOT}/x86_64-unknown-redox/include"
|
||||||
TOOLCHAIN_TARGET_USR_INCLUDE="${TOOLCHAIN_ROOT}/x86_64-unknown-redox/usr/include"
|
TOOLCHAIN_TARGET_USR_INCLUDE="${TOOLCHAIN_ROOT}/x86_64-unknown-redox/usr/include"
|
||||||
for header in elf.h semaphore.h unistd.h; do
|
for header in elf.h semaphore.h unistd.h; do
|
||||||
@@ -112,8 +77,6 @@ if [ -d "${RELIBC_STAGE_INCLUDE}" ]; then
|
|||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
if [ -d "${RELIBC_STAGE_LIB}" ]; then
|
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}"
|
export LDFLAGS="-L${RELIBC_STAGE_LIB} -Wl,-rpath-link,${RELIBC_STAGE_LIB} ${LDFLAGS}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -166,12 +129,6 @@ if [ ! -f "${COOKBOOK_SYSROOT}/include/netinet/in6_pktinfo_compat.h" ]; then
|
|||||||
#ifndef IPV6_PKTINFO
|
#ifndef IPV6_PKTINFO
|
||||||
#define IPV6_PKTINFO 50
|
#define IPV6_PKTINFO 50
|
||||||
#endif
|
#endif
|
||||||
#ifndef in6_pktinfo
|
|
||||||
struct in6_pktinfo {
|
|
||||||
struct in6_addr ipi6_addr;
|
|
||||||
unsigned int ipi6_ifindex;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
PKTINFO_EOF
|
PKTINFO_EOF
|
||||||
fi
|
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,
|
# 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).
|
# transaction ID validation, RCODE/TC handling, typed error mapping).
|
||||||
# QtNetwork was previously disabled. Now re-enabled for full KDE desktop path.
|
# 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"
|
"${COOKBOOK_SOURCE}/src/CMakeLists.txt"
|
||||||
# Also re-enable TUIO touch plugin which depends on QtNetwork
|
# 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"
|
"${COOKBOOK_SOURCE}/src/plugins/generic/CMakeLists.txt"
|
||||||
python - <<'PY'
|
python - <<'PY'
|
||||||
import os
|
import os
|
||||||
|
|||||||
Reference in New Issue
Block a user