# This file contains the build system commands configuration # and environment variables include mk/config.mk # Build system dependencies include mk/depends.mk # Delete a target's output file if its recipe exits with a non-zero status. # Without this, a partially-written artifact (e.g. a build that died mid-link, # a cookbook crash leaving a corrupt pkgar) survives as "up to date" and Make # skips rebuilding it on the next run — producing silently wrong output. # This is a global setting; it applies to every file target in this Makefile # and every target defined by the mk/*.mk fragments included below. .DELETE_ON_ERROR: # Make's default shell is /bin/sh without -e. Recipes rely on `&&` chaining # for sequence safety, which is correct but fragile when an author forgets a # chain. Forcing -e would be the safer default but would change semantics for # existing recipes that depend on the `|| true` idiom for optional cleanup. # We instead rely on .DELETE_ON_ERROR above + per-recipe `&&` chains + the # cookbook Rust binary's own Result-based error propagation. # # If a future audit confirms no recipe depends on shell-level error tolerance, # adding `.SHELLFLAGS := -euo pipefail -c` here would be the next hardening. all: lint-config $(BUILD)/harddrive.img # Post-build validation gate. Runs init-service checks, file-ownership checks, # and config-vs-package collision detection against the freshly built image. # This is a MANDATORY part of `make all` — a build that produces a broken image # (init services pointing at missing binaries, config overrides that will be # silently overwritten by package staging, file ownership conflicts) is not a # successful build even if the image file exists. # # Escape hatch: REDBEAR_NO_VALIDATE=1 skips the entire validation chain. # Use only when you understand why validation is failing and have a separate # plan to fix it. The collision-detection component has its own finer-grained # escape hatch (REDBEAR_COLLISIONS_WARN=1) that downgrades strict failures to # warnings while still running the rest of the gate. ifneq ($(REDBEAR_NO_VALIDATE),1) all: validate endif # ── 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 @if ls local/cache/rbos-cache-* >/dev/null 2>&1; then \ echo "Red Bear: restoring recipe stage artifacts from snapshot..."; \ bash $(CACHE_RESTORE); \ echo "Red Bear: verifying cache integrity..."; \ bash $(CACHE_RESTORE) --verify || { \ echo "Red Bear: \033[1;31;49mCACHE INTEGRITY CHECK FAILED\033[0m — restored artifacts may be incomplete."; \ echo "The build may produce incorrect results. Inspect local/cache/ and re-run snapshot-cache.sh if needed."; \ exit 1; \ }; \ else \ echo "Red Bear: no cache snapshot found (first build or cache purged) — full build required"; \ fi cache-save: @bash $(CACHE_SAVE) cache-save-essential: @bash $(CACHE_SAVE) --essential cache-verify: @bash $(CACHE_RESTORE) --verify # Phase J / Improvement C: verify that all Cargo [patch] # sections in the local sources' Cargo.toml files resolve # to the expected local fork paths. Run after `make all` # to confirm Phase J end-to-end. Returns non-zero exit on # any unresolved patch. verify-patches: @bash local/scripts/check-cargo-patches.sh # Phase I: also run the file-level patch check verify-file-patches: @bash local/scripts/check-unwired-patches.sh --strict # Verify everything: file-level patches + Cargo [patch] sections verify-all: verify-file-patches verify-patches 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 — run 'make container' first to build the Podman image, or set PODMAN_BUILD=0 in .config for a native build) $(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 ALWAYS refuses # to unfetch local overlay recipes (they are internal Red Bear subprojects # with no upstream). This is unconditional: no env var or flag can override it. # 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 — run 'make container' first to build the Podman image, or set PODMAN_BUILD=0 in .config for a native build) $(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: now a no-op for local/ recipes — local/ sources are # unconditionally immutable. This target remains for compatibility but # behaves identically to distclean. Use rm -rf directly if you really # want to delete local/ sources (NOT recommended — local/ is internal). distclean-nuclear: ifeq ($(PODMAN_BUILD),1) $(info distclean-nuclear is not supported in Podman mode; use native build) else $(warning !! distclean-nuclear is a no-op for local/ recipes; local/ is immutable) $(MAKE) fetch_clean $(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: # 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-patches: @bash local/scripts/validate-patches.sh