boot2

Playing with the boostrap
git clone https://git.ryansepassi.com/git/boot2.git
Log | Files | Refs | README

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