boot2

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

Makefile (12733B)


      1 # tests/Makefile — test infrastructure (suites + their build deps).
      2 #
      3 # Two ways in:
      4 #   1. `include tests/Makefile` from the top-level Makefile (REPO_ROOT
      5 #      already set). All test/build rules are emitted; the top-level's
      6 #      `test`, `image`, etc. targets resolve here.
      7 #   2. `make -C tests <target>` standalone. We detect the missing
      8 #      REPO_ROOT and re-exec the top-level Makefile, forwarding goals.
      9 #
     10 # Suites:
     11 #   test SUITE=<name>             one suite (defaults to all)
     12 #   test                          aggregate (m1pp, p1, scheme1, cc-util,
     13 #                                 cc-lex, cc-pp, cc-cg, cc, cc-libc)
     14 #   test SUITE=tcc-cc ARCH=...    self-built tcc through cc fixtures
     15 #   test SUITE=tcc-libc ARCH=...  self-built tcc through cc-libc fixtures
     16 #
     17 # Tests pin DRIVER=podman: every binary tests reach for is the
     18 # bootN-built podman variant. The seed-driver chain is exercised by
     19 # the bootstrap top-level, not the test runner.
     20 
     21 ifndef REPO_ROOT
     22 # ── Standalone invocation: delegate to top-level. ────────────────────────
     23 # `make -C tests <goals>` lands here. Forward to ../Makefile.
     24 .PHONY: __forward $(MAKECMDGOALS)
     25 __forward:
     26 	@$(MAKE) -C .. $(if $(MAKECMDGOALS),$(MAKECMDGOALS),test)
     27 $(MAKECMDGOALS): __forward ;
     28 .DEFAULT_GOAL := __forward
     29 else
     30 # ── Included from top-level: emit rules. ─────────────────────────────────
     31 
     32 # Tests always run against the podman driver's bootN outputs. The seed
     33 # driver builds an equivalent chain but boots through QEMU; that path is
     34 # validated by the top-level bootstrap, not by the test suite.
     35 TEST_DRIVER := podman
     36 
     37 # bootN/<file> path helpers — keep call sites readable.
     38 boot0 = build/$(1)/$(TEST_DRIVER)/boot0
     39 boot1 = build/$(1)/$(TEST_DRIVER)/boot1
     40 boot2 = build/$(1)/$(TEST_DRIVER)/boot2
     41 boot3 = build/$(1)/$(TEST_DRIVER)/boot3
     42 boot4 = build/$(1)/$(TEST_DRIVER)/boot4
     43 boot5 = build/$(1)/$(TEST_DRIVER)/boot5
     44 
     45 # ── tests-only container images (boot2-busybox-test, boot2-alpine-gcc) ──
     46 
     47 IMAGE_STAMP  := build/$(ARCH)/.image
     48 IMAGE_STAMPS := $(foreach a,$(ALL_ARCHES),build/$(a)/.image)
     49 
     50 PODMAN_PLATFORM_ARGS_aarch64 := --platform linux/arm64
     51 PODMAN_PLATFORM_ARGS_amd64   := --platform linux/amd64
     52 PODMAN_PLATFORM_ARGS_riscv64 := --platform linux/riscv64
     53 PODMAN_NATIVE_ARCH = $(shell podman info --format '{{.Host.Arch}}' | sed -e 's/^aarch64$$/arm64/' -e 's/^x86_64$$/amd64/')
     54 PODMAN_PLATFORM_ARGS_riscv32 = --platform linux/$(PODMAN_NATIVE_ARCH)
     55 
     56 .PHONY: image
     57 image: $(IMAGE_STAMP)
     58 
     59 $(IMAGE_STAMPS): build/%/.image: tests/containers/Containerfile.busybox-test
     60 	mkdir -p $(@D)
     61 	podman build $(PODMAN_PLATFORM_ARGS_$*) -t boot2-busybox-test:$* \
     62 	    -f tests/containers/Containerfile.busybox-test tests/containers/
     63 	@touch $@
     64 
     65 ALPINE_GCC_IMAGES := $(foreach a,$(TCC_ARCHES),build/$(a)/.image-alpine-gcc)
     66 
     67 $(ALPINE_GCC_IMAGES): build/%/.image-alpine-gcc: tests/containers/Containerfile.alpine-gcc
     68 	mkdir -p $(@D)
     69 	podman build $(PODMAN_PLATFORM_ARGS_$*) \
     70 	    -t boot2-alpine-gcc:$* \
     71 	    -f tests/containers/Containerfile.alpine-gcc tests/containers/
     72 	@touch $@
     73 
     74 PODMAN = podman run --rm --pull=never $(PODMAN_PLATFORM_ARGS_$(1)) \
     75     --tmpfs /tmp:size=512M \
     76     -e ARCH=$(1) \
     77     -v $(CURDIR):/work -w /work boot2-busybox-test:$(1)
     78 
     79 ALPINE_GCC = podman run --rm --pull=never $(PODMAN_PLATFORM_ARGS_$(1)) \
     80     --tmpfs /tmp:size=128M \
     81     -e ARCH=$(1) \
     82     -v $(CURDIR):/work -w /work boot2-alpine-gcc:$(1)
     83 
     84 # ── P1 backend tables (committed under P1/P1-<arch>.M1) ──────────────────
     85 
     86 P1_PRUNE_SRCS := M1pp/M1pp.P1 hex2pp/hex2pp.P1 $(wildcard tests/P1/*.P1)
     87 
     88 .PHONY: tables
     89 tables: $(foreach a,$(ALL_ARCHES),P1/P1-$(a).M1)
     90 
     91 build/%/P1/P1.M1: $(wildcard P1/gen/*.py)
     92 	mkdir -p $(@D)
     93 	python3 P1/gen/p1_gen.py --arch $* --out $@
     94 
     95 .SECONDARY: $(foreach a,$(ALL_ARCHES),build/$(a)/P1/P1.M1)
     96 
     97 P1/P1-%.M1: build/%/P1/P1.M1 bootprep/prune-p1-table.sh $(P1_PRUNE_SRCS)
     98 	sh bootprep/prune-p1-table.sh $< $@ $(P1_PRUNE_SRCS)
     99 
    100 # ── tcc-gcc: same flatten, stock gcc (sanity check) ──────────────────────
    101 
    102 TCC_PKG_INCLUDE = build/$(ARCH)/src/src/tcc/$(TCC_PKG)/include
    103 TCC_PKG_LIBDIR  = build/$(ARCH)/src/src/tcc/$(TCC_PKG)/lib
    104 
    105 TCC_GCC_BIN     := build/$(ARCH)/tcc/gcc/tcc-gcc
    106 TCC_GCC_IMAGE   := build/$(ARCH)/.image-alpine-gcc
    107 TCC_GCC_HARNESS := tcc/gcc/$(ARCH)/start.S tcc/gcc/$(ARCH)/sys_stubs.c
    108 TCC_GCC_TCC_FLAT  := build/$(ARCH)/src/src/tcc/tcc.flat.c
    109 TCC_GCC_LIBC_FLAT := build/$(ARCH)/src/src/libc/libc.flat.c
    110 
    111 $(TCC_GCC_BIN): $(TCC_GCC_TCC_FLAT) $(TCC_GCC_LIBC_FLAT) \
    112         $(TCC_GCC_HARNESS) tcc/scripts/build-tcc-gcc.sh $(TCC_GCC_IMAGE) \
    113         build/$(ARCH)/src/.stamp
    114 	mkdir -p $(@D)
    115 	podman run --rm --pull=never --platform $(PLATFORM_$(ARCH)) \
    116 	    -e ARCH=$(ARCH) \
    117 	    -v $(CURDIR):/work -w /work boot2-alpine-gcc:$(ARCH) \
    118 	    sh tcc/scripts/build-tcc-gcc.sh $@ $(TCC_GCC_TCC_FLAT) $(TCC_GCC_LIBC_FLAT)
    119 
    120 # ── tcc-cc / tcc-libc test stubs (per-arch start.S / sys_stubs.S) ────────
    121 #
    122 # Tests pull every other tcc-flow binary out of bootN now (tcc0 from
    123 # boot3, tcc1/tcc2 from boot4, libc.a/libtcc1.a from boot4/boot5). The
    124 # tcc-cc and tcc-libc trees keep a few small per-arch stubs that the
    125 # bootN chain doesn't expose as standalone .o files.
    126 
    127 HOST_CC ?= cc
    128 
    129 TCC_HARNESS_ARCHES := aarch64 amd64 riscv64
    130 
    131 HOST_CC_TARGET_aarch64 := aarch64-linux-gnu
    132 HOST_CC_TARGET_amd64   := x86_64-linux-gnu
    133 HOST_CC_TARGET = $(HOST_CC_TARGET_$(ARCH))
    134 
    135 # Assembler used to compile per-arch .S stubs into .o:
    136 #   aarch64 — boot3/tcc0 inside the busybox container (it speaks AArch64
    137 #             asm thanks to the phase-1 arm64 patches).
    138 #   riscv64 — alpine-gcc (boot3/tcc0 lacks RISC-V inline asm support).
    139 #   amd64   — host clang/cc with a Linux target triple.
    140 ifeq ($(ARCH),aarch64)
    141 TCC_ASM_DEPS := $(call boot3,$(ARCH))/tcc0 build/$(ARCH)/.image
    142 TCC_ASM       = $(call PODMAN,$(ARCH)) $(call boot3,$(ARCH))/tcc0 -nostdlib -c -o $(1) $(2)
    143 else ifeq ($(ARCH),riscv64)
    144 TCC_ASM_DEPS := build/$(ARCH)/.image-alpine-gcc
    145 TCC_ASM       = $(call ALPINE_GCC,$(ARCH)) cc -c -o $(1) -x assembler $(2)
    146 else
    147 TCC_ASM_DEPS :=
    148 TCC_ASM       = $(HOST_CC) -target $(HOST_CC_TARGET) -c -o $(1) -x assembler $(2)
    149 endif
    150 
    151 TCC_CC_START := build/$(ARCH)/tcc/cc/start.o
    152 
    153 ifeq ($(ARCH),amd64)
    154 # x86_64 va_arg intrinsics (__va_start / __va_arg). On other arches tcc
    155 # lowers va_arg without out-of-line helpers.
    156 TCC_CC_VA_LIST := build/$(ARCH)/tcc/cc/va_list.o
    157 else
    158 TCC_CC_VA_LIST :=
    159 endif
    160 
    161 TCC_LIBC_START     := build/$(ARCH)/tcc/libc/start.o
    162 TCC_LIBC_SYS_STUBS := build/$(ARCH)/tcc/libc/sys_stubs.o
    163 
    164 $(TCC_CC_START): tcc/cc/$(ARCH)/start.S $(TCC_ASM_DEPS)
    165 	mkdir -p $(@D)
    166 	$(call TCC_ASM,$@,$<)
    167 
    168 build/amd64/tcc/cc/va_list.o: \
    169         build/amd64/src/src/tcc/$(TCC_PKG)/lib/va_list.c \
    170         $(call boot3,amd64)/tcc0 build/amd64/.image \
    171         build/amd64/src/.stamp
    172 	mkdir -p $(@D)
    173 	$(call PODMAN,amd64) \
    174 	    $(call boot3,amd64)/tcc0 \
    175 	    -nostdlib -I build/amd64/src/src/tcc/$(TCC_PKG)/include \
    176 	    -D TCC_TARGET_X86_64=1 \
    177 	    -c -o $@ build/amd64/src/src/tcc/$(TCC_PKG)/lib/va_list.c
    178 
    179 $(TCC_LIBC_START): tcc/libc/$(ARCH)/start.S $(TCC_ASM_DEPS)
    180 	mkdir -p $(@D)
    181 	$(call TCC_ASM,$@,$<)
    182 
    183 $(TCC_LIBC_SYS_STUBS): tcc/libc/$(ARCH)/sys_stubs.S $(TCC_ASM_DEPS)
    184 	mkdir -p $(@D)
    185 	$(call TCC_ASM,$@,$<)
    186 
    187 # ── Suite dispatch (proxies to tests/run.sh) ─────────────────────────────
    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 # Suites that consume boot3+ artifacts stay on implemented TCC targets.
    200 # The Scheme-hosted compiler itself is architecture-neutral and is tested on
    201 # every P1 backend, including RV32.
    202 TEST_TCC_ARCHES := $(filter $(TCC_ARCHES),$(TEST_ARCHES))
    203 
    204 # Per-suite build dependency sets. Every entry resolves to a bootN
    205 # artifact (or, for `start.o` / `sys_stubs.o` / `va_list.o`, a small
    206 # per-arch .S stub built next to bootN binaries).
    207 
    208 TEST_M1PP_DEPS := $(foreach a,$(TEST_ARCHES), \
    209     build/$(a)/.image $(call boot1,$(a))/M1pp $(call boot1,$(a))/hex2pp \
    210     vendor/seed/$(a)/ELF.hex2)
    211 
    212 TEST_P1_DEPS := $(foreach a,$(TEST_ARCHES), \
    213     build/$(a)/.image $(call boot0,$(a))/M0 $(call boot0,$(a))/hex2 \
    214     P1/P1-$(a).M1 \
    215     $(call boot1,$(a))/M1pp $(call boot1,$(a))/hex2pp \
    216     vendor/seed/$(a)/ELF.hex2)
    217 
    218 TEST_SCHEME1_DEPS := $(foreach a,$(TEST_ARCHES), \
    219     build/$(a)/.image \
    220     $(call boot1,$(a))/M1pp $(call boot1,$(a))/hex2pp \
    221     $(call boot2,$(a))/scheme1 $(call boot2,$(a))/catm)
    222 
    223 TEST_CC_UNIT_DEPS := $(foreach a,$(TEST_ARCHES), \
    224     build/$(a)/.image \
    225     $(call boot1,$(a))/M1pp $(call boot1,$(a))/hex2pp \
    226     $(call boot2,$(a))/scheme1 $(call boot2,$(a))/catm)
    227 
    228 TEST_CC_DEPS := $(TEST_CC_UNIT_DEPS) build/cc.scm
    229 
    230 TEST_CC_LIBC_DEPS := $(TEST_CC_DEPS) \
    231     $(foreach a,$(TEST_TCC_ARCHES),$(call boot3,$(a))/libc.P1pp) \
    232     P1/entry-libc.P1pp P1/elf-end.P1pp
    233 
    234 TEST_TCC_CC_DEPS := build/$(ARCH)/.image \
    235     $(call boot4,$(ARCH))/tcc1 $(call boot4,$(ARCH))/tcc2 \
    236     $(call boot4,$(ARCH))/libtcc1.a \
    237     $(TCC_CC_START) $(TCC_CC_VA_LIST) \
    238     build/$(ARCH)/src/.stamp
    239 
    240 TEST_TCC_LIBC_DEPS := build/$(ARCH)/.image \
    241     $(call boot4,$(ARCH))/tcc1 $(call boot4,$(ARCH))/tcc2 \
    242     $(call boot4,$(ARCH))/libtcc1.a \
    243     $(call boot5,$(ARCH))/libc.a \
    244     $(TCC_LIBC_START) $(TCC_LIBC_SYS_STUBS) \
    245     $(TCC_CC_VA_LIST) \
    246     build/$(ARCH)/src/.stamp
    247 
    248 .PHONY: test
    249 test:
    250 ifeq ($(SUITE),)
    251 	@$(MAKE) --no-print-directory test SUITE=m1pp
    252 	@$(MAKE) --no-print-directory test SUITE=p1
    253 	@$(MAKE) --no-print-directory test SUITE=scheme1
    254 	@$(MAKE) --no-print-directory test SUITE=cc-util
    255 	@$(MAKE) --no-print-directory test SUITE=cc-lex
    256 	@$(MAKE) --no-print-directory test SUITE=cc-pp
    257 	@$(MAKE) --no-print-directory test SUITE=cc-cg
    258 	@$(MAKE) --no-print-directory test SUITE=cc
    259 ifneq ($(strip $(TEST_TCC_ARCHES)),)
    260 	@$(MAKE) --no-print-directory test SUITE=cc-libc
    261 endif
    262 else ifeq ($(SUITE),m1pp)
    263 	@$(MAKE) --no-print-directory $(TEST_M1PP_DEPS)
    264 	sh tests/run.sh --suite=m1pp $(if $(ARCH_FILTER),--arch=$(ARCH_FILTER)) $(NAMES)
    265 else ifeq ($(SUITE),p1)
    266 	@$(MAKE) --no-print-directory $(TEST_P1_DEPS)
    267 	sh tests/run.sh --suite=p1 $(if $(ARCH_FILTER),--arch=$(ARCH_FILTER)) $(NAMES)
    268 else ifeq ($(SUITE),scheme1)
    269 	@$(MAKE) --no-print-directory $(TEST_SCHEME1_DEPS)
    270 	sh tests/run.sh --suite=scheme1 $(if $(ARCH_FILTER),--arch=$(ARCH_FILTER)) $(NAMES)
    271 else ifeq ($(filter $(SUITE),cc-util cc-lex cc-pp cc-cg),$(SUITE))
    272 	@$(MAKE) --no-print-directory $(TEST_CC_UNIT_DEPS)
    273 	sh tests/run.sh --suite=$(SUITE) $(if $(ARCH_FILTER),--arch=$(ARCH_FILTER)) $(NAMES)
    274 else ifeq ($(SUITE),cc)
    275 	@$(MAKE) --no-print-directory $(TEST_CC_DEPS)
    276 	sh tests/run.sh --suite=cc $(if $(ARCH_FILTER),--arch=$(ARCH_FILTER)) $(NAMES)
    277 else ifeq ($(SUITE),cc-libc)
    278 	@if [ -z "$(TEST_TCC_ARCHES)" ]; then \
    279 	    echo "cc-libc is unavailable for ARCH=$(ARCH): it consumes the intentionally unimplemented RV32 TCC/libc stage" >&2; exit 2; \
    280 	fi
    281 	@$(MAKE) --no-print-directory $(TEST_CC_LIBC_DEPS)
    282 	sh tests/run.sh --suite=cc-libc $(if $(ARCH_FILTER),--arch=$(ARCH_FILTER)) $(NAMES)
    283 else ifeq ($(SUITE),cc-ext)
    284 	@if [ -z "$(TEST_TCC_ARCHES)" ]; then \
    285 	    echo "cc-ext is unavailable for ARCH=$(ARCH): some fixtures consume the intentionally unimplemented RV32 TCC/libc stage" >&2; exit 2; \
    286 	fi
    287 	@$(MAKE) --no-print-directory $(TEST_CC_LIBC_DEPS)
    288 	sh tests/run.sh --suite=cc-ext $(if $(ARCH_FILTER),--arch=$(ARCH_FILTER)) $(NAMES)
    289 else ifeq ($(SUITE),tcc-cc)
    290 	@if [ -z "$(filter $(ARCH),$(TCC_HARNESS_ARCHES))" ]; then \
    291 	    echo "tcc-cc supports ARCH in {$(TCC_HARNESS_ARCHES)} only (got '$(ARCH)')" >&2; exit 2; \
    292 	fi
    293 	@$(MAKE) --no-print-directory ARCH=$(ARCH) $(TEST_TCC_CC_DEPS)
    294 	@s2=0; s3=0; \
    295 	    sh tests/run.sh --suite=tcc-cc --arch=$(ARCH) --stage=2 $(NAMES) || s2=$$?; \
    296 	    sh tests/run.sh --suite=tcc-cc --arch=$(ARCH) --stage=3 $(NAMES) || s3=$$?; \
    297 	    [ $$s2 -eq 0 ] && [ $$s3 -eq 0 ]
    298 else ifeq ($(SUITE),tcc-libc)
    299 	@if [ -z "$(filter $(ARCH),$(TCC_HARNESS_ARCHES))" ]; then \
    300 	    echo "tcc-libc supports ARCH in {$(TCC_HARNESS_ARCHES)} only (got '$(ARCH)')" >&2; exit 2; \
    301 	fi
    302 	@$(MAKE) --no-print-directory ARCH=$(ARCH) $(TEST_TCC_LIBC_DEPS)
    303 	@s2=0; s3=0; \
    304 	    sh tests/run.sh --suite=tcc-libc --arch=$(ARCH) --stage=2 $(NAMES) || s2=$$?; \
    305 	    sh tests/run.sh --suite=tcc-libc --arch=$(ARCH) --stage=3 $(NAMES) || s3=$$?; \
    306 	    [ $$s2 -eq 0 ] && [ $$s3 -eq 0 ]
    307 else
    308 	@echo "unknown SUITE='$(SUITE)' (m1pp | p1 | scheme1 | cc-util | cc-lex | cc-pp | cc-cg | cc | cc-libc | cc-ext | tcc-cc | tcc-libc)" >&2; exit 2
    309 endif
    310 
    311 endif # REPO_ROOT