# ============================================================================== # 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// -- 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= that board's boot image + its book # make [all] TARGET= hosted v3 build with that profile # # make boot_image TARGET= only the board's boot image # make boot_images every board that has a kernel port # make docs [TARGET=] the book; a board adds its appendix # # make clean all of build/ except build/cache/ # make clean TARGET= the board's image + book and its ISA's kernel objects # make clean TARGET= build// for every arch # make clean-docs build/docs/ # # make kernel ARCH= [GOAL=g] kernel/Makefile goal (default: all) # make boards list boards and whether they can be built # make 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 # ------------------------------------------------------------------------------ # 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 @$(SUBMAKE) -f kernel/Makefile \ BOARD=$(BOARD_DIR) ARCH=$(call board_arch,$(TARGET)) TARGET=kernel boot_image 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";) # ------------------------------------------------------------------------------ # 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 $@