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