Files
LithosAnanake/Makefile
T
rajamesandClaude Opus 5.5 79db0e8d88 build: v4 is the default build -- every kernel boots v4; acceptance is v4 on three ISAs and the 32-bit build
Captain Bob, 2026-10-14: "v4 is the default build", "no, qemu to v4
too ... we are effectively trying to retire v3", "the 32 bit build needs
to go into the acceptance test too", "i don't care about v3".

- STARFORTH_V4 defaults on (Kconfig default y) and V4_DEFAULT=1
  everywhere: every kernel carries v4 and v3 and boots v4; system=v3 boots
  v3; STARFORTH_V4=0 builds v3 alone.  Board images write system=v4.
- Acceptance (CLAUDE.md): the three ISAs as built (v4, POST passed,
  V4_SYSTEM dict_hash equal) and make -C v4 test-32.  v3 is not part of
  it.

Acceptance run: amd64, aarch64, riscv64 -- PARITY:V4_POST 538/538,
dict_hash=0xe5a57f3eb72ff94a on all three, no unknown word; test-32: 30
suites, 0 failures.  The SER5 image under OVMF boots v4 as built, v3 after
the one-word edit.  README, BRINGUP, FABRIC-3 XLIII, the register updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 17:21:13 -04:00

222 lines
10 KiB
Makefile

# ==============================================================================
# LithosAnanke / StarForth -- top-level Makefile
#
# Thin dispatcher. The real build lives in:
# v3/Makefile -- hosted StarForth v3 (Linux userland VM, POST, DoE)
# kernel/Makefile -- LithosAnanke kernel (UEFI loader, kernel ELF, QEMU)
# boards/<board>/ -- one directory per physical target (board.mk + boot files)
# docs/book/Makefile -- the single LaTeX book (build/docs/*.pdf)
# Every sub-make runs from this directory, so paths are always repo-relative.
#
# TARGET is either a board (SER5 RASPI MILKV ZYNQ7020), a hosted v3 profile
# (standard fast fastest turbo asan ...), or empty:
#
# make [all] every board that has a kernel port, the
# hosted v3 build, and the book
# make [all] TARGET=<board> that board's boot image + its book
# make [all] TARGET=<profile> hosted v3 build with that profile
#
# make boot_image TARGET=<board> only the board's boot image, with its SBOM
# (build/boards/<board>/*.spdx*) and a fresh
# source SBOM -- needs syft
# make boot_images every board that has a kernel port
# make docs [TARGET=<board>] the book; a board adds its appendix
#
# make clean all of build/ except build/cache/
# make clean TARGET=<board> the board's image + book and its ISA's kernel objects
# make clean TARGET=<profile> build/<arch>/<profile> for every arch
# make clean-docs build/docs/
#
# make sbom SPDX SBOM of the source tree (sbom.spdx, sbom.spdx.json)
# make kernel ARCH=<arch> [GOAL=g] kernel/Makefile goal (default: all)
# make boards list boards and whether they can be built
# make <other goal> goes to v3/Makefile (make help-hosted)
# ==============================================================================
# Board name (as typed on the command line) -> boards/ directory.
BOARD_DIR_SER5 := ser5
BOARD_DIR_RASPI := raspi
BOARD_DIR_MILKV := milkv
BOARD_DIR_ZYNQ7020 := zynq7020
BOARDS := SER5 RASPI MILKV ZYNQ7020
empty :=
space := $(empty) $(empty)
board_field = $(if $(BOARD_DIR_$(1)),$(shell sed -n 's/^$(2) *:= *//p' boards/$(BOARD_DIR_$(1))/board.mk))
board_arch = $(call board_field,$(1),BOARD_ARCH)
# A board can be built once its ISA's kernel port exists.
board_ready = $(if $(call board_arch,$(1)),$(wildcard kernel/src/arch/$(call board_arch,$(1))/.))
READY_BOARDS := $(foreach b,$(BOARDS),$(if $(call board_ready,$(b)),$(b)))
UNREADY_BOARDS := $(filter-out $(READY_BOARDS),$(BOARDS))
TARGET := $(strip $(TARGET))
BOARD_DIR := $(if $(TARGET),$(BOARD_DIR_$(TARGET)))
SUBMAKE := $(MAKE) --no-print-directory
.DEFAULT_GOAL := all
.PHONY: all boot_image boot_images docs clean clean-docs kernel boards help help-hosted sbom sbom-board
# ------------------------------------------------------------------------------
# all
# ------------------------------------------------------------------------------
ifeq ($(TARGET),)
all:
@for b in $(READY_BOARDS); do \
$(SUBMAKE) boot_image TARGET=$$b || exit 1; \
done
@$(SUBMAKE) -f v3/Makefile all
@$(SUBMAKE) docs
@echo ""
@echo "Built:"
@for b in $(READY_BOARDS); do \
d=$$(echo $$b | tr A-Z a-z); ls build/boards/$$d/*.img | sed 's/^/ /'; \
done
@echo " build/docs/LithosAnanke.pdf"
@$(foreach b,$(UNREADY_BOARDS),echo "Skipped $(b): needs kernel/src/arch/$(call board_arch,$(b)), which does not exist yet";)
else ifneq ($(BOARD_DIR),)
all:
@$(SUBMAKE) boot_image TARGET=$(TARGET)
@$(SUBMAKE) docs TARGET=$(TARGET)
else
all:
@$(SUBMAKE) -f v3/Makefile all TARGET=$(TARGET)
endif
# ------------------------------------------------------------------------------
# boot images
# ------------------------------------------------------------------------------
boot_image:
@if [ -z "$(BOARD_DIR)" ]; then \
echo "Usage: make boot_image TARGET=<$(subst $(space),|,$(BOARDS))>"; \
[ -z "$(TARGET)" ] || echo "Unknown board TARGET='$(TARGET)'"; \
exit 1; \
fi
@if [ -z "$(call board_ready,$(TARGET))" ]; then \
echo "Error: $(TARGET) needs the $(call board_arch,$(TARGET)) kernel port (kernel/src/arch/$(call board_arch,$(TARGET))), which does not exist yet."; \
echo " $(call board_field,$(TARGET),BOARD_DESC)"; \
exit 1; \
fi
@# Both systems in one image, v4 unless the boot arguments say system=v3
@# (boards/BRINGUP.md A6, ruled 2026-10-14; v4 the default, same day). A clean build every time: the
@# kernel objects are shared with `make qemu`, and make does not see a
@# change of compile flags -- an image could otherwise carry objects built
@# without v4, or without the bring-up console.
@$(SUBMAKE) -f kernel/Makefile ARCH=$(call board_arch,$(TARGET)) TARGET=kernel clean
@$(SUBMAKE) -f kernel/Makefile \
BOARD=$(BOARD_DIR) ARCH=$(call board_arch,$(TARGET)) TARGET=kernel \
STARFORTH_V4=1 V4_DEFAULT=1 boot_image
@# Its SBOM, and the source tree's, are part of the build (2026-10-14).
@$(SUBMAKE) sbom-board TARGET=$(TARGET)
@$(SUBMAKE) sbom
boot_images:
@for b in $(READY_BOARDS); do \
$(SUBMAKE) boot_image TARGET=$$b || exit 1; \
done
@$(foreach b,$(UNREADY_BOARDS),echo "Skipped $(b): needs kernel/src/arch/$(call board_arch,$(b)), which does not exist yet";)
# ------------------------------------------------------------------------------
# SBOMs (SPDX 2.3, by syft; config mk/syft.yaml) -- part of every board build
# ------------------------------------------------------------------------------
# The source SBOM covers what the product is built from: the tracked files of
# the kernel, v3, v4, capsules, boards, build tooling and proofs, each with its
# SHA-256 -- copied to build/sbom/src first, so nothing untracked in the
# working directory is ever swept in. Not logs, documents, experiment data or
# the disk images. A board's SBOM covers
# its image and every file on it, copied off the image, so the SBOM is of what
# is on the medium, not of what was meant to be. Versioned as the kernel
# version and the commit. No syft: the build stops, as for any missing tool.
SYFT ?= syft
SBOM_VERSION = $(shell sed -n 's/^LITHOS_VERSION *?= *//p' kernel/Makefile)+$(shell git describe --always --dirty 2>/dev/null)
# What the product is built from: tracked files only, in these places (never
# untracked or ignored files in the working directory).
SBOM_SOURCES := kernel v3 v4 capsules boards mk tools scripts proof configs \
Makefile Kconfig Kconfig.arch Kconfig.heartbeat Kconfig.kernel \
Kconfig.physics Kconfig.variant LICENSE NOTICE.md
GIT_PLAIN := git -c filter.lfs.process= -c filter.lfs.smudge=cat -c filter.lfs.required=false
define need_syft
@command -v $(SYFT) >/dev/null 2>&1 || { \
echo "Error: syft not found -- the SBOM is part of this build."; \
echo " Install a release from https://github.com/anchore/syft/releases"; \
echo " (verify it against the release's checksums), or SYFT=/path/to/syft."; exit 1; }
endef
sbom:
$(need_syft)
@echo " SBOM source tree -> sbom.spdx, sbom.spdx.json ($(SBOM_VERSION))"
@rm -rf build/sbom/src && mkdir -p build/sbom/src && \
$(GIT_PLAIN) ls-files -z -- $(SBOM_SOURCES) | xargs -0 cp --parents -t build/sbom/src && \
$(SYFT) -q -c mk/syft.yaml dir:build/sbom/src \
--source-name LithosAnanke --source-version "$(SBOM_VERSION)" \
-o spdx-json=sbom.spdx.json -o spdx=sbom.spdx
sbom-board:
$(need_syft)
@if [ -z "$(BOARD_DIR)" ]; then echo "Usage: make sbom-board TARGET=<$(subst $(space),|,$(BOARDS))>"; exit 1; fi
@img=build/boards/$(BOARD_DIR)/$(call board_field,$(TARGET),BOARD_IMAGE); \
if [ ! -f "$$img" ]; then echo "Error: $$img not built (make boot_image TARGET=$(TARGET))"; exit 1; fi; \
rm -rf build/boards/$(BOARD_DIR)/contents && mkdir -p build/boards/$(BOARD_DIR)/contents && \
mcopy -s -n -i "$$img@@1M" '::/*' build/boards/$(BOARD_DIR)/contents/ && \
echo " SBOM $$img -> $${img%.img}.spdx, $${img%.img}.spdx.json" && \
$(SYFT) -q -c mk/syft.yaml dir:build/boards/$(BOARD_DIR) \
--exclude './*.spdx' --exclude './*.spdx.json' \
--source-name "LithosAnanke-$(BOARD_DIR)" --source-version "$(SBOM_VERSION)" \
-o spdx-json=$${img%.img}.spdx.json -o spdx=$${img%.img}.spdx
# ------------------------------------------------------------------------------
# docs
# ------------------------------------------------------------------------------
docs:
@if [ -n "$(TARGET)" ] && [ -z "$(BOARD_DIR)" ]; then \
echo "Error: make docs takes TARGET=<$(subst $(space),|,$(BOARDS))> or no TARGET; '$(TARGET)' is not a board."; \
exit 1; \
fi
@$(SUBMAKE) -f docs/book/Makefile BOARD=$(BOARD_DIR) BOARD_NAME=$(TARGET)
clean-docs:
rm -rf build/docs
# ------------------------------------------------------------------------------
# clean
# ------------------------------------------------------------------------------
ifeq ($(TARGET),)
clean:
@if [ -d build ]; then find build -mindepth 1 -maxdepth 1 ! -name cache -exec rm -rf {} +; fi
rm -f v3/include/version.h
rm -f v3/src/*.gcda v3/src/*.gcno v3/src/word_source/*.gcda v3/src/word_source/*.gcno
@echo "Cleaned build/ (kept build/cache/)"
else ifneq ($(BOARD_DIR),)
clean:
rm -rf build/boards/$(BOARD_DIR) build/$(call board_arch,$(TARGET))/kernel build/docs/$(BOARD_DIR) \
build/docs/LithosAnanke-$(BOARD_DIR).pdf
else
clean:
rm -rf build/*/$(TARGET)
endif
# ------------------------------------------------------------------------------
# misc
# ------------------------------------------------------------------------------
GOAL ?= all
kernel:
@$(SUBMAKE) -f kernel/Makefile TARGET=kernel $(GOAL)
boards:
@$(foreach b,$(BOARDS),printf ' %-9s %-8s %s\n' "$(b)" \
"$(if $(call board_ready,$(b)),ready,no port)" "$(call board_field,$(b),BOARD_DESC)";)
help:
@sed -n '/^# TARGET is/,/^# =====/p' Makefile | sed '$$d; s/^# \{0,1\}//'
help-hosted:
@$(SUBMAKE) -f v3/Makefile help
# Everything else is the hosted v3 build, unchanged. (The empty Makefile
# rule stops the match-anything rule from trying to remake this file.)
Makefile: ;
%:
@$(SUBMAKE) -f v3/Makefile $@