9e5794ea7a
Commit 827895d32 added the C-7 KF6 sed migration script v2
and 13 unit tests, but didn't wire the new make target or
Gitea Actions job. This commit adds both so the migration
smoke test runs on every PR.
Makefile:
- New `make test-migration-dry-run` target. Runs
`migrate-kf6-seds-to-patches.sh --dry-run --limit=1`.
Discovers candidates, prints the per-recipe plan, exits 0
on success. Does NOT do any fetches, cooks, or patch
writes. <5s wall-clock. Added to `.PHONY:`.
- Picked up automatically by the existing
`make test-lint-scripts` discovery path (the new test
file is in local/scripts/tests/, so it's already covered
by the existing target — no change there).
Gitea Actions (`.gitea/workflows/build-system.yml`):
- New job `migration-dry-run` (job 5 of 9, depends on
`unit-tests`, runs on every PR + branch push + schedule).
Triggers `make test-migration-dry-run` and treats
exit 0 as success.
- Renumbered subsequent stage headers to 1f (was 1e).
- Updated unit-tests job description: '55 cases' -> '99
cases' (reflects the new 13 migration tests).
Docs:
- BUILD-SYSTEM-IMPROVEMENTS.md: added the new make
target to the Make targets table.
- BUILD-SYSTEM-V6-HARDENING-POSTMORTEM.md: Session 12
entry covers the v2 migration script + 13 tests + CI
integration. Updated test count (86 -> 99 Python),
scope line (11-session -> 12-session), C-7 finding
(now 'migration script v2 ... now runnable; per-recipe
execution + recipe rewrite still manual'), and
durability caveat (10 most recent commits now cover
the migration work + this postmortem itself).
- Added the test_migrate_kf6_seds.py row to the test
coverage table.
Verified:
- `make test-migration-dry-run` discovers 1 candidate
and exits 0 in <1s.
- `make test-lint-scripts` still passes 99/99 tests
in <1s.
- Gitea workflow YAML validates: 9 jobs total
(was 8).
327 lines
11 KiB
Makefile
327 lines
11 KiB
Makefile
# This file contains the build system commands configuration
|
|
# and environment variables
|
|
include mk/config.mk
|
|
|
|
# Build system dependencies
|
|
include mk/depends.mk
|
|
|
|
all: lint-config $(BUILD)/harddrive.img
|
|
|
|
# ── Red Bear OS Build Cache (OBLIGATORY) ─────────────────────────────────
|
|
# Cache sync is a mandatory part of every successful build.
|
|
# The git-tracked cache survives make clean, make distclean, and git clone.
|
|
#
|
|
# Flow:
|
|
# make all → cache-restore (if needed) → build → cache-sync → cache-commit
|
|
#
|
|
# Commands:
|
|
# make cache-sync Sync built → git cache (manual)
|
|
# make cache-commit Sync + git commit (manual)
|
|
# make cache-restore Restore from git cache
|
|
# make cache-status Compare cache vs build state
|
|
|
|
CACHE_SYNC = local/scripts/cache-sync.sh
|
|
CACHE_SAVE = local/scripts/snapshot-cache.sh
|
|
CACHE_RESTORE = local/scripts/restore-cache.sh
|
|
|
|
cache-sync:
|
|
@bash $(CACHE_SYNC)
|
|
|
|
cache-commit:
|
|
@bash $(CACHE_SYNC) --commit
|
|
|
|
cache-restore:
|
|
@echo "Red Bear: restoring from git-tracked cache..."
|
|
@bash $(CACHE_SYNC) --restore
|
|
@bash $(CACHE_RESTORE) 2>/dev/null || true
|
|
|
|
cache-save:
|
|
@bash $(CACHE_SAVE)
|
|
|
|
cache-save-essential:
|
|
@bash $(CACHE_SAVE) --essential
|
|
|
|
cache-verify:
|
|
@bash $(CACHE_RESTORE) --verify
|
|
|
|
cache-list:
|
|
@bash $(CACHE_SAVE) --list
|
|
|
|
cache-status:
|
|
@bash $(CACHE_SYNC) --status
|
|
|
|
# Obligatory cache pipeline — runs before AND after every build
|
|
cache-auto:
|
|
@# ── BEFORE BUILD: restore cache if target is empty ──
|
|
@if [ ! -f $(BUILD)/repo.tag ]; then \
|
|
if ls local/cache/pkgar/*/stage.pkgar >/dev/null 2>&1; then \
|
|
echo "Red Bear: restoring build cache..."; \
|
|
bash $(CACHE_SYNC) --restore; \
|
|
fi; \
|
|
fi
|
|
@# ── AFTER BUILD: sync cache back to git-tracked storage ──
|
|
@if [ -f $(BUILD)/harddrive.img ]; then \
|
|
echo "Red Bear: syncing build cache..."; \
|
|
bash $(CACHE_SYNC); \
|
|
echo "Red Bear: committing cache to git..."; \
|
|
bash $(CACHE_SYNC) --commit 2>/dev/null || echo "Red Bear: cache commit skipped (no changes or not in git repo)"; \
|
|
fi
|
|
|
|
$(BUILD)/harddrive.img: cache-auto
|
|
|
|
live:
|
|
-$(FUMOUNT) $(BUILD)/filesystem/ || true
|
|
-$(FUMOUNT) /tmp/redbear_installer/ || true
|
|
rm -f $(LIVE_ISO) $(LIVE_IMG) $(LIVE_BOOTLOADER) $(LIVE_IPXE)
|
|
$(MAKE) $(LIVE_ISO)
|
|
|
|
popsicle: $(LIVE_ISO)
|
|
popsicle-gtk $(LIVE_ISO)
|
|
|
|
image:
|
|
-$(FUMOUNT) $(BUILD)/filesystem/ || true
|
|
-$(FUMOUNT) /tmp/redbear_installer/ || true
|
|
rm -f $(BUILD)/harddrive.img $(LIVE_ISO) $(LIVE_IMG) $(LIVE_BOOTLOADER) $(LIVE_IPXE)
|
|
$(MAKE) all
|
|
|
|
rebuild:
|
|
-$(FUMOUNT) $(BUILD)/filesystem/ || true
|
|
-$(FUMOUNT) /tmp/redbear_installer/ || true
|
|
rm -rf $(BUILD)/repo.tag $(BUILD)/harddrive.img $(LIVE_ISO) $(LIVE_IMG) $(LIVE_BOOTLOADER) $(LIVE_IPXE)
|
|
$(MAKE) all
|
|
|
|
# To tell that it's not safe
|
|
# to execute the cookbook binary
|
|
NOT_ON_PODMAN?=0
|
|
|
|
clean:
|
|
ifeq ($(PODMAN_BUILD),1)
|
|
ifneq ("$(wildcard $(CONTAINER_TAG))","")
|
|
$(PODMAN_RUN) make $@
|
|
else
|
|
$(info will not run cookbook clean as container is not built)
|
|
$(MAKE) clean PODMAN_BUILD=0 NOT_ON_PODMAN=1 SKIP_CHECK_TOOLS=1
|
|
endif # CONTAINER_TAG
|
|
else
|
|
ifneq ($(NOT_ON_PODMAN),1)
|
|
$(MAKE) repo_clean
|
|
-$(FUMOUNT) $(BUILD)/filesystem/ || true
|
|
-$(FUMOUNT) /tmp/redbear_installer/ || true
|
|
endif # NOT_ON_PODMAN
|
|
rm -rf repo
|
|
rm -rf $(BUILD) $(PREFIX)
|
|
$(MAKE) fstools_clean
|
|
endif # PODMAN_BUILD
|
|
|
|
# distclean: removes build artifacts, toolchain, and upstream source trees.
|
|
# local/ overlay source trees are PROTECTED — the repo binary refuses to
|
|
# unfetch local overlay recipes unless REDBEAR_ALLOW_LOCAL_UNFETCH=1 is set.
|
|
# This is the safe default for Red Bear OS. local/ is NEVER deleted.
|
|
distclean:
|
|
ifneq ($(REDBEAR_RELEASE),)
|
|
$(error distclean is disabled in release mode (REDBEAR_RELEASE=$(REDBEAR_RELEASE)). Sources are immutable. Use: make clean (build artifacts only, safe))
|
|
endif
|
|
ifeq ($(PODMAN_BUILD),1)
|
|
ifneq ("$(wildcard $(CONTAINER_TAG))","")
|
|
$(PODMAN_RUN) make $@
|
|
else
|
|
$(info will not run cookbook unfetch as container is not built)
|
|
$(MAKE) distclean PODMAN_BUILD=0 NOT_ON_PODMAN=1 SKIP_CHECK_TOOLS=1
|
|
endif # CONTAINER_TAG
|
|
else
|
|
ifneq ($(NOT_ON_PODMAN),1)
|
|
$(info ==> distclean: cleaning build artifacts and upstream source trees)
|
|
$(info ==> local/ overlay sources are PROTECTED and will NOT be deleted)
|
|
$(MAKE) fetch_clean
|
|
endif # NOT_ON_PODMAN
|
|
$(MAKE) clean NOT_ON_PODMAN=1
|
|
endif # PODMAN_BUILD
|
|
|
|
# distclean-nuclear: DESTRUCTIVE — also deletes local/ overlay source trees.
|
|
# This is the OLD distclean behavior that can destroy Red Bear work.
|
|
# You must set REDBEAR_ALLOW_LOCAL_UNFETCH=1 for this to actually delete
|
|
# local overlay sources. Without it, the repo binary still protects them.
|
|
# Use ONLY when you are certain you want to discard local overlay source code.
|
|
distclean-nuclear:
|
|
ifeq ($(PODMAN_BUILD),1)
|
|
$(info distclean-nuclear is not supported in Podman mode; use native build)
|
|
else
|
|
$(warning !! distclean-nuclear will attempt to DELETE ALL source trees including local/ overlays)
|
|
$(warning !! This can destroy Red Bear OS work that is not committed to git)
|
|
$(warning !! The repo binary still protects local overlays unless REDBEAR_ALLOW_LOCAL_UNFETCH=1)
|
|
$(MAKE) fetch_clean REDBEAR_ALLOW_LOCAL_UNFETCH=1
|
|
$(MAKE) clean NOT_ON_PODMAN=1
|
|
endif # PODMAN_BUILD
|
|
|
|
pull:
|
|
git pull
|
|
rm -f $(FSTOOLS_TAG)
|
|
|
|
repo: $(BUILD)/repo.tag
|
|
|
|
repo_clean: c.--all
|
|
|
|
fetch_clean: u.--all
|
|
|
|
# Podman build recipes and vars
|
|
include mk/podman.mk
|
|
|
|
# Disk Imaging and Cookbook tools
|
|
include mk/fstools.mk
|
|
|
|
# Cross compiler recipes
|
|
include mk/prefix.mk
|
|
|
|
# Repository maintenance
|
|
include mk/repo.mk
|
|
|
|
# Disk images
|
|
include mk/disk.mk
|
|
|
|
# Emulation recipes
|
|
include mk/qemu.mk
|
|
include mk/virtualbox.mk
|
|
|
|
# CI
|
|
include mk/ci.mk
|
|
|
|
include mk/redbear.mk
|
|
|
|
# Ensure Red Bear OS integration runs before repo cook and disk image creation
|
|
$(BUILD)/harddrive.img: $(REDBEAR_TAG)
|
|
$(LIVE_ISO): $(REDBEAR_TAG)
|
|
$(REPO_TAG): $(REDBEAR_TAG)
|
|
|
|
env: prefix FORCE $(CONTAINER_TAG)
|
|
ifeq ($(PODMAN_BUILD),1)
|
|
$(PODMAN_RUN) make $@
|
|
else
|
|
export PATH="$(PREFIX_PATH):$$PATH" && \
|
|
bash
|
|
endif
|
|
|
|
setenv: FORCE
|
|
@echo export ARCH='$(ARCH)'
|
|
@echo export BOARD='$(BOARD)'
|
|
@echo export CONFIG_NAME='$(CONFIG_NAME)'
|
|
@echo BUILD='$(BUILD)'
|
|
|
|
export RUST_GDB=gdb-multiarch # Necessary when debugging for another architecture than the host
|
|
GDB_KERNEL_FILE=recipes/core/kernel/target/$(TARGET)/build/kernel.sym
|
|
gdb: FORCE
|
|
rust-gdb $(GDB_KERNEL_FILE) --eval-command="target remote :1234"
|
|
|
|
# This target allows debugging a userspace application without requiring gdbserver running inside
|
|
# the VM. Because gdb doesn't know when the userspace application is scheduled by the kernel and as
|
|
# it stops the entire VM rather than just the userspace application that the user wants to debug,
|
|
# connecting to a gdbserver running inside the VM is highly encouraged when possible. This target
|
|
# should only be used when the application to debug runs early during boot before the network stack
|
|
# has started or you need to debug the interaction between the application and the kernel.
|
|
# tl;dr: DO NOT USE THIS TARGET UNLESS YOU HAVE TO
|
|
gdb-userspace: FORCE
|
|
rust-gdb $(GDB_APP_FILE) --eval-command="add-symbol-file $(GDB_KERNEL_FILE)" --eval-command="target remote :1234"
|
|
|
|
# An empty target
|
|
FORCE:
|
|
|
|
.PHONY: lint-patches lint-patches-full lint-kf6-deps lint-cook-failure \
|
|
lint-cook-failure-explain lint-cook-recipe lint-recipe lint-recipe.% \
|
|
lint-recipe.strict lint-recipe.%.strict \
|
|
lint-build-system lint-build-system-full \
|
|
test-lint-scripts test-lint-scripts-quiet \
|
|
test-migration-dry-run \
|
|
repair.% clean-repair.%
|
|
|
|
# Wireshark
|
|
wireshark: FORCE
|
|
wireshark $(BUILD)/network.pcap
|
|
packages-sync: ; @bash local/scripts/sync-packages.sh
|
|
packages-list: ; @ls -la Packages/*.pkgar 2>/dev/null | wc -l && echo "pkgar files in Packages/"
|
|
validate-sources:
|
|
@for d in local/sources/kernel local/sources/relibc local/sources/base local/sources/bootloader local/sources/installer; do \
|
|
if [ -d "$$d/.git" ]; then \
|
|
echo "$$d: $(shell git -C $$d rev-list --count HEAD 2>/dev/null || echo 0) commits, $(shell git -C $$d ls-files 2>/dev/null | wc -l) files"; \
|
|
else \
|
|
echo "$$d: MISSING — run local/scripts/create-forks.sh"; \
|
|
fi; \
|
|
done
|
|
|
|
# v6.0 build-system lint targets. These run the three audit scripts
|
|
# that validate the v6.0 build system: idempotent patches, KF6 dep
|
|
# accuracy, and cook-failure classification. Each target exits non-zero
|
|
# on a real problem so CI can wire them up directly.
|
|
|
|
lint-patches:
|
|
@python3 local/scripts/audit-patch-idempotency.py --no-fetch
|
|
|
|
lint-patches-full:
|
|
@python3 local/scripts/audit-patch-idempotency.py
|
|
|
|
lint-kf6-deps:
|
|
@python3 local/scripts/audit-kf6-deps.py --no-fetch
|
|
|
|
test-lint-scripts:
|
|
@python3 -m unittest discover -s local/scripts/tests -v
|
|
|
|
test-lint-scripts-quiet:
|
|
@python3 -m unittest discover -s local/scripts/tests
|
|
|
|
# Smoke test: run the KF6 sed migration script in --dry-run
|
|
# against the live recipe tree. Catches:
|
|
# - recipe discovery regression (script can't find kf6-*)
|
|
# - path-argument vs name-argument mixup
|
|
# - permission / executable issues
|
|
# Does NOT do any real fetches, cooks, or patch writes.
|
|
test-migration-dry-run:
|
|
@./local/scripts/migrate-kf6-seds-to-patches.sh --dry-run --limit=1
|
|
|
|
lint-cook-failure:
|
|
@python3 local/scripts/classify-cook-failure.py --last || \
|
|
(echo "No /tmp/redbear-cook.log or /tmp/build.log found. Run a cook first."; exit 0)
|
|
|
|
lint-cook-failure-explain:
|
|
@python3 local/scripts/classify-cook-failure.py --explain-rule qfloat16
|
|
|
|
# Per-recipe v6.0-policy lint. Catches R1/R2 violations BEFORE the
|
|
# slow cook starts. Per build-system improvement #5.
|
|
# Usage:
|
|
# make lint-recipe # all recipes in local/recipes/
|
|
# make lint-recipe.kf6-kimageformats # one recipe by bare name
|
|
# make lint-recipe.strict # all recipes, warnings as errors
|
|
# make lint-recipe.kf6-kimageformats.strict # one recipe, strict mode
|
|
lint-recipe:
|
|
@python3 local/scripts/lint-recipe.py --all
|
|
|
|
lint-recipe.%:
|
|
@python3 local/scripts/lint-recipe.py $*
|
|
|
|
lint-recipe.strict:
|
|
@python3 local/scripts/lint-recipe.py --all --strict
|
|
|
|
lint-recipe.%.strict:
|
|
@python3 local/scripts/lint-recipe.py $* --strict
|
|
|
|
lint-build-system: lint-patches lint-kf6-deps lint-cook-recipe
|
|
@echo "Build system lint complete."
|
|
|
|
lint-build-system-full: lint-patches-full lint-kf6-deps lint-cook-recipe
|
|
@echo "Full build system lint complete (with network)."
|
|
cascade.%: FORCE
|
|
@bash local/scripts/rebuild-cascade.sh $(basename $(subst cascade,, $*))
|
|
|
|
# Repair-cook wrapper: equivalent to `repo cook <recipe>` but with
|
|
# a fast-path that skips configure + compile if the existing build/
|
|
# is still valid. Per build-system improvement #2.
|
|
# Usage: make repair.qtbase (incremental, fast if cache fresh)
|
|
# make repair.qtbase CLEAN=1 (force full rebuild)
|
|
repair.%: FORCE
|
|
@if [ "$(CLEAN)" = "1" ]; then \
|
|
./local/scripts/repair-cook.sh $* --clean-build; \
|
|
else \
|
|
./local/scripts/repair-cook.sh $*; \
|
|
fi
|
|
# Use `make clean-repair.X` to force a clean rebuild
|
|
# (alias for the CLEAN=1 form above)
|
|
clean-repair.%: FORCE
|
|
@./local/scripts/repair-cook.sh $* --clean-build
|