Makefile (8890B)
1 # boot2 — P1 portable pseudo-ISA + M1pp. 2 # 3 # Make declares all build dependencies and ensures every input + tool 4 # exists before any script runs. Scripts in scripts/ are pure 5 # transformations: they assume their inputs are present, do one thing, 6 # write outputs. Any script that runs inside podman starts with `boot`; 7 # the rest run on the host. 8 # 9 # Bootstrap inputs are vendored in vendor/seed/<arch>/. The only image 10 # used is per-arch boot2-busybox:<arch>, built from 11 # scripts/Containerfile.busybox. 12 # 13 # Common entrypoints: 14 # make all (m1pp + pokem for ARCH) 15 # make m1pp build the m1pp expander for ARCH 16 # make pokem build pokem for ARCH 17 # make hello build hello via the bootstrap chain 18 # make scheme1 build the scheme1 interpreter for ARCH 19 # make run run hello in the container 20 # make test every suite, every arch 21 # make test SUITE=m1pp m1pp suite, every arch 22 # make test SUITE=p1 ARCH=amd64 p1 suite, one arch 23 # make test SUITE=scheme1 scheme1 .scm fixtures, every arch 24 # make image build the per-arch container image 25 # make tools bootstrap M0/hex2-0/catm for ARCH 26 # make tables regen pre-pruned P1/P1-<arch>.M1 tables 27 # make tools-native build host-native M1/hex2/m1pp (opt-in) 28 # make clean rm -rf build/ 29 30 ARCH ?= aarch64 31 32 ALL_ARCHES := aarch64 amd64 riscv64 33 34 PLATFORM_aarch64 := linux/arm64 35 PLATFORM_amd64 := linux/amd64 36 PLATFORM_riscv64 := linux/riscv64 37 38 ifeq ($(filter $(ARCH),$(ALL_ARCHES)),) 39 $(error ARCH '$(ARCH)' not supported — use one of $(ALL_ARCHES)) 40 endif 41 42 OUT_DIR := build/$(ARCH) 43 TOOLS_DIR := $(OUT_DIR)/tools 44 IMAGE_STAMP := $(OUT_DIR)/.image 45 46 # All container invocations go through this. Just env/args + one named 47 # script in scripts/; never inline shell. Every script reads ARCH from 48 # the env and derives all its fixed paths (P1 table, ELF header, tools 49 # dir, etc.) from that — only per-call args (source, output) are passed 50 # positionally. 51 # 52 # --tmpfs /tmp: backstop for the stage0 tools' per-byte fputc/fgetc. Without 53 # it /tmp falls through to the container overlay (still backed by virtiofs 54 # on Apple Silicon), and a 1MB M0 input pays a virtiofs round-trip per 55 # byte. Real RAM tmpfs collapses that to local memory access. 56 PODMAN = podman run --rm --pull=never --platform $(PLATFORM_$(1)) \ 57 --tmpfs /tmp:size=512M \ 58 -e ARCH=$(1) \ 59 -v $(CURDIR):/work -w /work boot2-busybox:$(1) 60 61 # --- Targets -------------------------------------------------------------- 62 63 .PHONY: all m1pp pokem hello scheme1 run test image tools tables \ 64 tools-native clean help 65 66 all: m1pp pokem 67 68 help: 69 @sed -n '/^# Common entrypoints:/,/^$$/p' Makefile | sed 's/^# *//' 70 71 clean: 72 rm -rf build/ 73 74 # --- Per-arch container image --------------------------------------------- 75 76 IMAGE_STAMPS := $(foreach a,$(ALL_ARCHES),build/$(a)/.image) 77 78 image: $(IMAGE_STAMP) 79 80 $(IMAGE_STAMPS): build/%/.image: scripts/Containerfile.busybox 81 mkdir -p $(@D) 82 podman build --platform $(PLATFORM_$*) -t boot2-busybox:$* \ 83 -f scripts/Containerfile.busybox scripts/ 84 @touch $@ 85 86 # --- Bootstrap toolchain (per arch) --------------------------------------- 87 # 88 # Stage 1: vendored hex0-seed -> M0/hex2-0/catm in the container. 89 90 TOOLS_M0 := $(foreach a,$(ALL_ARCHES),build/$(a)/tools/M0) 91 92 tools: $(TOOLS_DIR)/M0 93 94 $(TOOLS_M0): build/%/tools/M0: scripts/boot1.sh build/%/.image \ 95 vendor/seed/%/hex0-seed vendor/seed/%/hex0.hex0 \ 96 vendor/seed/%/hex1.hex0 vendor/seed/%/hex2.hex1 \ 97 vendor/seed/%/catm.hex2 vendor/seed/%/M0.hex2 \ 98 vendor/seed/%/ELF.hex2 99 $(call PODMAN,$*) sh scripts/boot1.sh 100 101 # --- Pre-pruned P1 backend tables ----------------------------------------- 102 # 103 # Generated once from P1/gen/p1_gen.py and pruned to just the DEFINEs 104 # referenced by M1pp/pokem/.M1 fixtures. Result is checked in to 105 # P1/P1-<arch>.M1; routine builds skip the prune step. Re-run `make 106 # tables` after editing P1/gen/*.py or any of the prune-source files 107 # below, then commit the updated P1/*.M1. 108 109 P1_PRUNE_SRCS := M1pp/M1pp.P1 pokem/pokem.P1 $(wildcard tests/M1pp/*.M1) 110 111 tables: $(foreach a,$(ALL_ARCHES),P1/P1-$(a).M1) 112 113 build/p1/aarch64.M1 build/p1/amd64.M1 build/p1/riscv64.M1 &: \ 114 $(wildcard P1/gen/*.py) 115 mkdir -p build/p1 116 python3 P1/gen/p1_gen.py --arch aarch64 build/p1 117 python3 P1/gen/p1_gen.py --arch amd64 build/p1 118 python3 P1/gen/p1_gen.py --arch riscv64 build/p1 119 120 P1/P1-%.M1: build/p1/%.M1 scripts/prune-p1-table.sh $(P1_PRUNE_SRCS) 121 sh scripts/prune-p1-table.sh $< $@ $(P1_PRUNE_SRCS) 122 123 # --- Programs (per arch) -------------------------------------------------- 124 125 M1PP_BINS := $(foreach a,$(ALL_ARCHES),build/$(a)/m1pp) 126 POKEM_BINS := $(foreach a,$(ALL_ARCHES),build/$(a)/pokem) 127 HELLO_SRC := tests/M1pp/00-hello.M1 128 HELLO_BINS := $(foreach a,$(ALL_ARCHES),build/$(a)/hello) 129 SCHEME1_SRC := scheme1/scheme1.P1pp 130 SCHEME1_BINS := $(foreach a,$(ALL_ARCHES),build/$(a)/scheme1) 131 132 m1pp: $(OUT_DIR)/m1pp 133 pokem: $(OUT_DIR)/pokem 134 hello: $(OUT_DIR)/hello 135 scheme1: $(OUT_DIR)/scheme1 136 137 # Per-arch deps for .P1/.M1 builds (raw M1, no macro expansion). 138 P1_BUILD_DEPS = scripts/lint.sh scripts/boot-build-p1.sh \ 139 build/%/.image build/%/tools/M0 \ 140 vendor/seed/%/ELF.hex2 P1/P1-%.M1 141 142 # Per-arch deps for .P1pp builds (m1pp expansion + libp1pp). 143 P1PP_BUILD_DEPS = scripts/boot-build-p1pp.sh \ 144 build/%/.image build/%/tools/M0 build/%/m1pp \ 145 vendor/seed/%/ELF.hex2 \ 146 P1/P1-%.M1pp P1/P1.M1pp P1/P1pp.P1pp 147 148 $(M1PP_BINS): build/%/m1pp: M1pp/M1pp.P1 $(P1_BUILD_DEPS) 149 ARCH=$* sh scripts/lint.sh M1pp/M1pp.P1 150 $(call PODMAN,$*) sh scripts/boot-build-p1.sh M1pp/M1pp.P1 $@ 151 152 $(POKEM_BINS): build/%/pokem: pokem/pokem.P1 $(P1_BUILD_DEPS) 153 ARCH=$* sh scripts/lint.sh pokem/pokem.P1 154 $(call PODMAN,$*) sh scripts/boot-build-p1.sh pokem/pokem.P1 $@ 155 156 $(HELLO_BINS): build/%/hello: $(HELLO_SRC) $(P1_BUILD_DEPS) 157 ARCH=$* sh scripts/lint.sh $(HELLO_SRC) 158 $(call PODMAN,$*) sh scripts/boot-build-p1.sh $(HELLO_SRC) $@ 159 160 $(SCHEME1_BINS): build/%/scheme1: $(SCHEME1_SRC) $(P1PP_BUILD_DEPS) 161 $(call PODMAN,$*) sh scripts/boot-build-p1pp.sh $(SCHEME1_SRC) $@ 162 163 run: $(OUT_DIR)/hello $(IMAGE_STAMP) 164 $(call PODMAN,$(ARCH)) ./$(OUT_DIR)/hello 165 166 # --- Native tools (opt-in dev-loop helpers) ------------------------------- 167 168 NATIVE_TOOLS := build/native-tools/M1 build/native-tools/hex2 build/native-tools/m1pp 169 170 tools-native: $(NATIVE_TOOLS) 171 172 build/native-tools/M1: scripts/build-native-tools.sh 173 sh scripts/build-native-tools.sh M1 174 175 build/native-tools/hex2: scripts/build-native-tools.sh 176 sh scripts/build-native-tools.sh hex2 177 178 build/native-tools/m1pp: scripts/build-native-tools.sh M1pp/M1pp.c 179 sh scripts/build-native-tools.sh m1pp 180 181 # --- Tests ---------------------------------------------------------------- 182 # 183 # `make test` runs every suite. SUITE selects one; ARCH restricts to one 184 # arch. Make ensures every dependency (images, tools, tables, m1pp 185 # expanders) exists before scripts/run-tests.sh is invoked. The runner 186 # itself only loops fixtures, builds per-fixture binaries via the boot-* 187 # scripts, runs them in the container, and diffs. 188 189 SUITE ?= 190 191 ifeq ($(origin ARCH),file) 192 ARCH_FILTER := 193 TEST_ARCHES := $(ALL_ARCHES) 194 else 195 ARCH_FILTER := $(ARCH) 196 TEST_ARCHES := $(ARCH) 197 endif 198 199 # m1pp suite per-arch deps: image, tools, table, expander. 200 TEST_M1PP_DEPS := $(foreach a,$(TEST_ARCHES), \ 201 build/$(a)/.image build/$(a)/tools/M0 P1/P1-$(a).M1 build/$(a)/m1pp) 202 203 # p1 suite per-arch deps: image, tools, expander. 204 TEST_P1_DEPS := $(foreach a,$(TEST_ARCHES), \ 205 build/$(a)/.image build/$(a)/tools/M0 build/$(a)/m1pp) 206 207 # scheme1 suite per-arch deps: image, tools, expander, scheme1 binary. 208 # (run-tests.sh runs the pre-built binary against each .scm fixture; it 209 # does not rebuild the interpreter per fixture.) 210 TEST_SCHEME1_DEPS := $(foreach a,$(TEST_ARCHES), \ 211 build/$(a)/.image build/$(a)/tools/M0 build/$(a)/m1pp build/$(a)/scheme1) 212 213 test: 214 ifeq ($(SUITE),) 215 @$(MAKE) --no-print-directory test SUITE=m1pp 216 @$(MAKE) --no-print-directory test SUITE=p1 217 @$(MAKE) --no-print-directory test SUITE=scheme1 218 else ifeq ($(SUITE),m1pp) 219 @$(MAKE) --no-print-directory $(TEST_M1PP_DEPS) 220 sh scripts/run-tests.sh --suite=m1pp $(if $(ARCH_FILTER),--arch=$(ARCH_FILTER)) 221 else ifeq ($(SUITE),p1) 222 @$(MAKE) --no-print-directory $(TEST_P1_DEPS) 223 sh scripts/run-tests.sh --suite=p1 $(if $(ARCH_FILTER),--arch=$(ARCH_FILTER)) 224 else ifeq ($(SUITE),scheme1) 225 @$(MAKE) --no-print-directory $(TEST_SCHEME1_DEPS) 226 sh scripts/run-tests.sh --suite=scheme1 $(if $(ARCH_FILTER),--arch=$(ARCH_FILTER)) 227 else 228 @echo "unknown SUITE='$(SUITE)' (expected m1pp | p1 | scheme1)" >&2; exit 2 229 endif