kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

commit 0d2d302c47e1bb326de5dc23136b33bd37de160d
parent df8ad4cefccdc4ceab566808818f8ec5894e3545
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Wed,  3 Jun 2026 07:45:30 -0700

build: split Makefile into mk/ includes; fold rt build into Makefile

The top-level Makefile read as ~660 lines with the build spine buried in the
middle of source-selection and flag-derivation noise. Extract the non-core
pieces into focused mk/ includes so the Makefile reads top-to-bottom as
setup -> sources -> spine -> extras:

  mk/flags.mk        compiler/linker flag derivation + .build-config stamp
  mk/lib_srcs.mk     libkit source selection -> LIB_OBJS / LIB_DEPS
  mk/driver_srcs.mk  driver source selection -> DRIVER_OBJS / DRIVER_DEPS
  mk/rt.mk           runtime variant/source selection -> RT_OBJS_<variant>
  mk/bootstrap.mk    three-stage self-build verification
  mk/dist.mk         release tarball staging
  mk/maint.mk        format / compile-commands / bench-opt / clean

rt/Makefile is removed: its variant table + per-variant source/flag derivation
move to mk/rt.mk (selection), and its build rules fold into the top-level
Makefile alongside the lib/driver/vendor rules (selection vs rules, same split
as the rest of the build).

Other cleanups in the same pass:
- collapse the repetitive per-arch source-gate trios into an arch-feature-off
  macro, and the driver per-tool / shared-lib gates into tool-cmd / need-any
- group the compile rules by source tree (src/ -> lang/ -> vendor/ -> driver/)
- drop the `ld -r` relocatable step; libkit.a is now a plain ar of LIB_OBJS,
  which also retires the now-unused LD toolchain var and bootstrap LD= plumbing
- drop clean-rt (build/rt is under BUILD_DIR, already removed by `make clean`)

Resolved source lists and flags are byte-identical to before; lib/bin/rt build
clean and test-driver + test-smoke-rv64 pass.

Diffstat:
MMakefile | 684++++++++++++-------------------------------------------------------------------
Amk/bootstrap.mk | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amk/dist.mk | 21+++++++++++++++++++++
Amk/driver_srcs.mk | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amk/flags.mk | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amk/lib_srcs.mk | 259+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amk/maint.mk | 36++++++++++++++++++++++++++++++++++++
Amk/rt.mk | 246+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Drt/Makefile | 284-------------------------------------------------------------------------------
9 files changed, 878 insertions(+), 864 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,6 +1,5 @@ CC = clang AR = ar -LD = ld RELEASE ?= 0 ifeq ($(RELEASE),1) BUILD_DIR ?= build/release @@ -8,509 +7,74 @@ else BUILD_DIR ?= build endif -# Host detection, driver/env source selection, host SDK -isysroot wiring. -# Everything that branches on HOST_OS / HOST_ARCH lives in env.mk; the rest -# of this Makefile only reads the variables it produces. -include mk/env.mk - .DEFAULT_GOAL := all -ifeq ($(RELEASE),1) -HOST_OPTFLAGS ?= -O2 -HOST_MODE_CPPFLAGS = -DNDEBUG -HOST_MODE_CFLAGS = -ffunction-sections -fdata-sections -ifeq ($(HOST_OS),darwin) -HOST_MODE_LDFLAGS = -Wl,-dead_strip -Wl,-S -else -HOST_MODE_LDFLAGS = -Wl,--gc-sections -Wl,-S -endif -else -HOST_OPTFLAGS ?= -O0 -HOST_MODE_CPPFLAGS = -HOST_MODE_CFLAGS = -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls \ - -fsanitize=address,undefined \ - -fno-sanitize-recover=address,undefined \ - -fsanitize-address-use-after-scope -HOST_MODE_LDFLAGS = -fsanitize=address,undefined -ASAN_OPTIONS ?= halt_on_error=1:abort_on_error=1 -UBSAN_OPTIONS ?= halt_on_error=1:print_stacktrace=1 -export ASAN_OPTIONS UBSAN_OPTIONS -endif - -# HOST_SYSROOT_{C,LD}FLAGS come from env.mk: a `-isysroot <path>` pair on -# Darwin, empty elsewhere. Stage/bootstrap recipes can clear these when -# kit itself is the compiler. - -CFLAGS_COMMON = $(HOST_OPTFLAGS) $(HOST_MODE_CPPFLAGS) $(HOST_MODE_CFLAGS) \ - -std=c11 -Wpedantic -Wall -Wextra -Werror -HOST_CFLAGS = $(CFLAGS_COMMON) $(HOST_SYSROOT_CFLAGS) -HOST_LDFLAGS = $(HOST_SYSROOT_LDFLAGS) $(HOST_MODE_LDFLAGS) - -DEPFLAGS = -MMD -MP - -BUILD_CONFIG = $(BUILD_DIR)/.build-config - -.PHONY: FORCE -FORCE: - -$(BUILD_CONFIG): FORCE - @mkdir -p $(dir $@) - @{ \ - printf '%s\n' 'RELEASE=$(RELEASE)'; \ - printf '%s\n' 'HOST_OPTFLAGS=$(HOST_OPTFLAGS)'; \ - printf '%s\n' 'HOST_MODE_CPPFLAGS=$(HOST_MODE_CPPFLAGS)'; \ - printf '%s\n' 'HOST_MODE_CFLAGS=$(HOST_MODE_CFLAGS)'; \ - printf '%s\n' 'HOST_MODE_LDFLAGS=$(HOST_MODE_LDFLAGS)'; \ - } > $@.tmp - @if ! cmp -s $@.tmp $@; then mv $@.tmp $@; else rm -f $@.tmp; fi - -# Freestanding objects must not see host SDK/libc headers. Homebrew clang can -# also inject a configured sysroot before command-line flags; use -# --no-default-config when the selected compiler supports it, but omit it for -# bootstrap stages where $(CC) is kit cc. -FREESTANDING_CONFIG_CFLAGS = $(shell $(CC) --no-default-config -x c -E /dev/null >/dev/null 2>&1 && printf '%s' --no-default-config) -FREESTANDING_CFLAGS = $(CFLAGS_COMMON) $(FREESTANDING_CONFIG_CFLAGS) -ffreestanding -nostdinc -Irt/include - -# libkit: written in C11 freestanding; sees both src/ (internal) and -# include/ (its own public surface). -LIB_VISIBILITY_CFLAGS = -fvisibility=hidden -LIB_CFLAGS = $(FREESTANDING_CFLAGS) $(LIB_VISIBILITY_CFLAGS) -Iinclude -Isrc -Ivendor - -# Driver: mostly freestanding CLI binary. Sees only the public include/ tree — -# that's what makes the driver the first consumer of libkit. -Ilang lets `cc` -# reach the C frontend's public header ("c/c.h") for the JIT REPL; it -# deliberately does NOT get -Isrc, so internal headers ("core/...", "link/...") -# are unreachable from the driver. -# -# driver/env/ holds all hosted OS/libc adapter code and is compiled with -# DRIVER_ENV_CFLAGS. The per-OS feature-test macros and the exact source -# list (DRIVER_ENV_OS_CFLAGS / DRIVER_ENV_SRCS) come from mk/env.mk. -DRIVER_CFLAGS = $(FREESTANDING_CFLAGS) -Iinclude -Ilang -Idriver -Idriver/lib -DRIVER_ENV_CFLAGS = $(HOST_CFLAGS) -Iinclude -Ilang -Idriver -Idriver/lib -TEST_HOST_CFLAGS = $(HOST_CFLAGS) -Iinclude -Ilang - +# Build setup, in dependency order. Each include owns one concern and only +# reads the variables produced by the ones before it: +# env.mk host detection, driver/env source selection, SDK sysroot +# config.mk KIT_*_ENABLED component flags (mirrored from config.h) +# flags.mk compiler/linker flag derivation + the .build-config stamp +# lib_srcs.mk libkit source selection -> LIB_OBJS / LIB_DEPS +# driver_srcs.mk driver source selection -> DRIVER_OBJS / DRIVER_DEPS +# rt.mk runtime variant/source selection -> RT_OBJS_<variant> +include mk/env.mk include mk/config.mk +include mk/flags.mk +include mk/lib_srcs.mk +include mk/driver_srcs.mk +include mk/rt.mk -# Core lib sources. Optional subsystems, backend directories, object format -# directories, and ABI implementations are added below from their own groups. -LIB_SRCS_ABI_CORE = src/abi/abi.c src/abi/registry.c -LIB_SRCS_API_CORE = $(filter-out src/api/archive.c src/api/disasm.c \ - src/api/link.c src/api/cas.c src/api/package.c \ - src/api/compress.c src/api/stubs.c,$(wildcard src/api/*.c)) -LIB_SRCS_ARCH_CORE = $(filter-out src/arch/%_stubs.c,$(wildcard src/arch/*.c)) -LIB_SRCS_ASM_CORE = $(wildcard src/asm/*.c) -LIB_SRCS_CG_CORE = $(wildcard src/cg/*.c) -LIB_SRCS_CORE = $(wildcard src/core/*.c) -LIB_SRCS_OBJ_CORE = $(filter-out src/obj/%_stubs.c,$(wildcard src/obj/*.c)) -LIB_SRCS_NONARCH = $(LIB_SRCS_ABI_CORE) \ - $(LIB_SRCS_API_CORE) \ - $(LIB_SRCS_ARCH_CORE) \ - $(LIB_SRCS_ASM_CORE) \ - $(LIB_SRCS_CG_CORE) \ - $(LIB_SRCS_CORE) \ - $(LIB_SRCS_OBJ_CORE) - -# These source lists use `:=` (not `=`) so each `find` runs exactly once at -# parse time. With recursive `=`, every reference below (LIB_SRCS is rebuilt -# and re-expanded many times) would re-spawn the `find`, turning ~20 finds into -# hundreds on every `make` invocation. -LIB_SRCS_ARCH_AA64 := $(shell find src/arch/aa64 -name '*.c' 2>/dev/null) -LIB_SRCS_ARCH_X64 := $(shell find src/arch/x64 -name '*.c' 2>/dev/null) -LIB_SRCS_ARCH_RV64 := $(shell find src/arch/rv64 -name '*.c' 2>/dev/null) -LIB_SRCS_ARCH_WASM := $(shell find src/arch/wasm -name '*.c' 2>/dev/null) -LIB_SRCS_ARCH_C_TARGET := $(shell find src/arch/c_target -name '*.c' 2>/dev/null) -ifneq ($(KIT_OPT_ENABLED),1) -LIB_SRCS_ARCH_AA64 := $(filter-out %/opt_coord.c,$(LIB_SRCS_ARCH_AA64)) -LIB_SRCS_ARCH_X64 := $(filter-out %/opt_coord.c,$(LIB_SRCS_ARCH_X64)) -LIB_SRCS_ARCH_RV64 := $(filter-out %/opt_coord.c,$(LIB_SRCS_ARCH_RV64)) -endif -ifneq ($(KIT_DISASM_ENABLED),1) -LIB_SRCS_ARCH_AA64 := $(filter-out %/disasm.c,$(LIB_SRCS_ARCH_AA64)) -LIB_SRCS_ARCH_X64 := $(filter-out %/disasm.c,$(LIB_SRCS_ARCH_X64)) -LIB_SRCS_ARCH_RV64 := $(filter-out %/disasm.c,$(LIB_SRCS_ARCH_RV64)) -LIB_SRCS_NONARCH += src/arch/disasm_stubs.c -endif -ifneq ($(KIT_LINK_ENABLED),1) -LIB_SRCS_ARCH_AA64 := $(filter-out %/link.c,$(LIB_SRCS_ARCH_AA64)) -LIB_SRCS_ARCH_X64 := $(filter-out %/link.c,$(LIB_SRCS_ARCH_X64)) -LIB_SRCS_ARCH_RV64 := $(filter-out %/link.c,$(LIB_SRCS_ARCH_RV64)) -LIB_SRCS_NONARCH += src/arch/link_stubs.c -endif -ifneq ($(KIT_DBG_ENABLED),1) -LIB_SRCS_ARCH_AA64 := $(filter-out %/dbg.c,$(LIB_SRCS_ARCH_AA64)) -LIB_SRCS_ARCH_X64 := $(filter-out %/dbg.c,$(LIB_SRCS_ARCH_X64)) -LIB_SRCS_ARCH_RV64 := $(filter-out %/dbg.c,$(LIB_SRCS_ARCH_RV64)) -LIB_SRCS_NONARCH += src/arch/dbg_stubs.c -endif -ifneq ($(KIT_EMU_ENABLED),1) -LIB_SRCS_ARCH_RV64 := $(filter-out %/emu.c,$(LIB_SRCS_ARCH_RV64)) -LIB_SRCS_NONARCH += src/arch/emu_stubs.c -endif -ifneq ($(KIT_INTERP_ENABLED),1) -LIB_SRCS_NONARCH += src/interp/interp_stubs.c -endif - -LIB_SRCS_OBJ_ELF := $(shell find src/obj/elf -name '*.c' 2>/dev/null) -LIB_SRCS_OBJ_MACHO := $(shell find src/obj/macho -name '*.c' 2>/dev/null) -LIB_SRCS_OBJ_COFF := $(shell find src/obj/coff -name '*.c' 2>/dev/null) -LIB_SRCS_OBJ_WASM := $(shell find src/obj/wasm -name '*.c' 2>/dev/null) -ifneq ($(KIT_LINK_ENABLED),1) -LIB_SRCS_OBJ_ELF := $(filter-out %/link.c %/link_dyn.c,$(LIB_SRCS_OBJ_ELF)) -LIB_SRCS_OBJ_MACHO := $(filter-out %/link.c,$(LIB_SRCS_OBJ_MACHO)) -LIB_SRCS_OBJ_COFF := $(filter-out %/link.c,$(LIB_SRCS_OBJ_COFF)) -LIB_SRCS_NONARCH += src/obj/link_stubs.c -endif -ifneq ($(KIT_EMU_ENABLED),1) -LIB_SRCS_OBJ_ELF := $(filter-out %/emu_load.c,$(LIB_SRCS_OBJ_ELF)) -LIB_SRCS_NONARCH += src/obj/emu_stubs.c -endif -ifneq ($(KIT_AR_ENABLED),1) -LIB_SRCS_OBJ_COFF := $(filter-out %/archive.c,$(LIB_SRCS_OBJ_COFF)) -LIB_SRCS_NONARCH += src/obj/archive_stubs.c -endif - -LIB_SRCS_OPT := $(filter-out src/opt/pass_o2.c,$(shell find src/opt -name '*.c' 2>/dev/null)) -LIB_SRCS_INTERP := $(filter-out %/interp_stubs.c,$(shell find src/interp -name '*.c' 2>/dev/null)) -LIB_SRCS_WASM_CORE := $(shell find src/wasm -name '*.c' 2>/dev/null) -LIB_SRCS_API_AR = src/api/archive.c -LIB_SRCS_API_DISASM = src/api/disasm.c -LIB_SRCS_API_LINK = src/api/link.c -# Distribution subsystem (content store + signed packages). The cas layer -# needs blake2b (-> monocypher); the pkg layer adds the crypto/container shims -# and the second monocypher TU. The compression codecs (deflate + lz4 block) -# are shared by pkg and the standalone compress API, so they live in their own -# CODEC group pulled in once if either is enabled. The lz4 frame layer -# (LIB_SRCS_DIST_COMPRESS) is needed only by the compress API. All vendored .c -# (lz4.c, lz4frame.c's xxhash/lz4hc/lz4frame) are #included by their src/dist -# shim (amalgamation), so they are NOT compiled standalone. -LIB_SRCS_API_CAS = src/api/cas.c -LIB_SRCS_API_PKG = src/api/package.c -LIB_SRCS_API_COMPRESS = src/api/compress.c -LIB_SRCS_DIST_CAS = src/dist/dist.c src/dist/blake2b.c src/dist/blob.c \ - src/dist/tree.c src/dist/cas.c -LIB_SRCS_VENDOR_CAS = vendor/monocypher/monocypher.c -LIB_SRCS_DIST_CODEC = src/dist/deflate.c src/dist/lz4.c -LIB_SRCS_DIST_COMPRESS = src/dist/lz4frame.c -LIB_SRCS_DIST_PKG = src/dist/b64.c src/dist/ed25519.c src/dist/minisig.c \ - src/dist/tar.c src/dist/kpkg.c src/dist/manifest.c \ - src/dist/trust.c -LIB_SRCS_VENDOR_PKG = vendor/monocypher/monocypher-ed25519.c -LIB_SRCS_DEBUG := $(shell find src/debug -name '*.c' 2>/dev/null) -LIB_SRCS_DBG := $(shell find src/dbg -name '*.c' 2>/dev/null) -LIB_SRCS_EMU := $(shell find src/emu -name '*.c' 2>/dev/null) \ - $(shell find src/os -name '*.c' 2>/dev/null) -LIB_SRCS_LINK := $(shell find src/link -name '*.c' 2>/dev/null) -ifneq ($(KIT_JIT_ENABLED),1) -LIB_SRCS_LINK := $(filter-out %/link_jit.c,$(LIB_SRCS_LINK)) -endif -LIB_SRCS_JIT_ASM := $(shell find src/jit -name '*.S' 2>/dev/null) - -LIB_SRC_ABI_AAPCS64 = src/abi/abi_aapcs64.c -LIB_SRC_ABI_APPLE_ARM64 = src/abi/abi_apple_arm64.c -LIB_SRC_ABI_AAPCS64_WINDOWS = src/abi/abi_aapcs64_windows.c -LIB_SRC_ABI_SYSV_X64 = src/abi/abi_sysv_x64.c -LIB_SRC_ABI_APPLE_X64 = src/abi/abi_apple_x64.c -LIB_SRC_ABI_WIN64_X64 = src/abi/abi_win64_x64.c -LIB_SRC_ABI_RV64 = src/abi/abi_rv64.c - -LIB_SRCS = $(LIB_SRCS_NONARCH) -ifeq ($(KIT_OPT_ENABLED),1) -LIB_SRCS += $(LIB_SRCS_OPT) -endif -ifeq ($(KIT_INTERP_ENABLED),1) -LIB_SRCS += $(LIB_SRCS_INTERP) -endif -ifeq ($(KIT_AR_ENABLED),1) -LIB_SRCS += $(LIB_SRCS_API_AR) -endif -ifeq ($(KIT_DISASM_ENABLED),1) -LIB_SRCS += $(LIB_SRCS_API_DISASM) -endif -ifeq ($(KIT_DWARF_ENABLED),1) -LIB_SRCS += $(LIB_SRCS_DEBUG) -endif -ifeq ($(KIT_LINK_ENABLED),1) -LIB_SRCS += $(LIB_SRCS_API_LINK) $(LIB_SRCS_LINK) -endif -ifeq ($(KIT_DBG_ENABLED),1) -LIB_SRCS += $(LIB_SRCS_DBG) -endif -ifeq ($(KIT_EMU_ENABLED),1) -LIB_SRCS += $(LIB_SRCS_EMU) -endif -ifeq ($(KIT_CAS_ENABLED),1) -LIB_SRCS += $(LIB_SRCS_API_CAS) $(LIB_SRCS_DIST_CAS) $(LIB_SRCS_VENDOR_CAS) -endif -# Shared compression codecs (deflate + lz4 block): pulled in once if either the -# compress API or the pkg layer needs them. -KIT_NEED_CODEC := -ifeq ($(KIT_COMPRESS_ENABLED),1) -LIB_SRCS += $(LIB_SRCS_API_COMPRESS) $(LIB_SRCS_DIST_COMPRESS) -KIT_NEED_CODEC := 1 -endif -ifeq ($(KIT_PKG_ENABLED),1) -LIB_SRCS += $(LIB_SRCS_API_PKG) $(LIB_SRCS_DIST_PKG) $(LIB_SRCS_VENDOR_PKG) -KIT_NEED_CODEC := 1 -endif -ifeq ($(KIT_NEED_CODEC),1) -LIB_SRCS += $(LIB_SRCS_DIST_CODEC) -endif -ifeq ($(KIT_ARCH_AA64_ENABLED),1) -LIB_SRCS += $(LIB_SRCS_ARCH_AA64) -endif -ifeq ($(KIT_ARCH_X64_ENABLED),1) -LIB_SRCS += $(LIB_SRCS_ARCH_X64) -endif -ifeq ($(KIT_ARCH_RV64_ENABLED),1) -LIB_SRCS += $(LIB_SRCS_ARCH_RV64) -endif -ifeq ($(KIT_ARCH_WASM_ENABLED),1) -LIB_SRCS += $(LIB_SRCS_ARCH_WASM) -endif -ifeq ($(KIT_ARCH_C_TARGET_ENABLED),1) -LIB_SRCS += $(LIB_SRCS_ARCH_C_TARGET) -endif -ifneq ($(filter 1,$(KIT_ARCH_WASM_ENABLED) $(KIT_OBJ_WASM_ENABLED) $(KIT_LANG_WASM_ENABLED)),) -LIB_SRCS += $(LIB_SRCS_WASM_CORE) -LIB_SRCS += $(LIB_SRCS_OBJ_WASM) -endif -ifeq ($(KIT_OBJ_ELF_ENABLED),1) -LIB_SRCS += $(LIB_SRCS_OBJ_ELF) -endif -ifeq ($(KIT_OBJ_MACHO_ENABLED),1) -LIB_SRCS += $(LIB_SRCS_OBJ_MACHO) -endif -ifeq ($(KIT_OBJ_COFF_ENABLED),1) -LIB_SRCS += $(LIB_SRCS_OBJ_COFF) -endif -ifneq ($(filter 1,$(KIT_ARCH_AA64_ENABLED) $(KIT_ARCH_C_TARGET_ENABLED)),) -ifneq ($(filter 1,$(KIT_OBJ_ELF_ENABLED) $(KIT_OBJ_MACHO_ENABLED) $(KIT_OBJ_COFF_ENABLED)),) -LIB_SRCS += $(LIB_SRC_ABI_AAPCS64) -endif -ifeq ($(KIT_OBJ_MACHO_ENABLED),1) -LIB_SRCS += $(LIB_SRC_ABI_APPLE_ARM64) -endif -ifeq ($(KIT_OBJ_COFF_ENABLED),1) -LIB_SRCS += $(LIB_SRC_ABI_AAPCS64_WINDOWS) -endif -endif -ifneq ($(filter 1,$(KIT_ARCH_X64_ENABLED) $(KIT_ARCH_C_TARGET_ENABLED)),) -ifneq ($(filter 1,$(KIT_OBJ_ELF_ENABLED) $(KIT_OBJ_MACHO_ENABLED)),) -LIB_SRCS += $(LIB_SRC_ABI_SYSV_X64) -endif -ifeq ($(KIT_OBJ_MACHO_ENABLED),1) -LIB_SRCS += $(LIB_SRC_ABI_APPLE_X64) -endif -ifeq ($(KIT_OBJ_COFF_ENABLED),1) -LIB_SRCS += $(LIB_SRC_ABI_WIN64_X64) -endif -endif -ifneq ($(filter 1,$(KIT_ARCH_RV64_ENABLED) $(KIT_ARCH_C_TARGET_ENABLED)),) -ifeq ($(KIT_OBJ_ELF_ENABLED),1) -LIB_SRCS += $(LIB_SRC_ABI_RV64) -endif -endif +LIB_AR = $(BUILD_DIR)/libkit.a +BIN = $(BUILD_DIR)/kit -# Per-frontend source sets. Each is gated by its KIT_LANG_*_ENABLED flag -# from mk/config.mk so the matching `#if` in src/api/lang_registry.c and -# the build agree on which frontends are compiled in. -LANG_CPP_SRCS := $(shell find lang/cpp -name '*.c' 2>/dev/null) -LANG_C_SRCS := $(shell find lang/c -name '*.c' 2>/dev/null) -LANG_WASM_SRCS := $(shell find lang/wasm -name '*.c' 2>/dev/null) -LANG_TOY_SRCS = $(wildcard lang/toy/*.c) - -LANG_OBJS = -ifeq ($(KIT_LANG_CPP_ENABLED),1) -LANG_OBJS += $(patsubst lang/cpp/%.c,$(BUILD_DIR)/lang/cpp/%.o,$(LANG_CPP_SRCS)) -endif -ifeq ($(KIT_LANG_C_ENABLED),1) -LANG_OBJS += $(patsubst lang/c/%.c,$(BUILD_DIR)/lang/c/%.o,$(LANG_C_SRCS)) -endif -ifeq ($(KIT_LANG_WASM_ENABLED),1) -LANG_OBJS += $(patsubst lang/wasm/%.c,$(BUILD_DIR)/lang/wasm/%.o,$(LANG_WASM_SRCS)) -endif -ifeq ($(KIT_LANG_TOY_ENABLED),1) -LANG_OBJS += $(patsubst lang/toy/%.c,$(BUILD_DIR)/lang/toy/%.o,$(LANG_TOY_SRCS)) -endif +# =========================================================================== +# Main build sequence: objects -> archive -> binary. +# =========================================================================== -LIB_ASMS = -ifeq ($(KIT_JIT_ENABLED),1) -LIB_ASMS += $(LIB_SRCS_JIT_ASM) -endif -LIB_OBJS = $(patsubst src/%.c,$(BUILD_DIR)/lib/%.o,$(filter src/%.c,$(LIB_SRCS))) \ - $(patsubst vendor/%.c,$(BUILD_DIR)/vendor/%.o,$(filter vendor/%.c,$(LIB_SRCS))) \ - $(LANG_OBJS) \ - $(patsubst src/%.S,$(BUILD_DIR)/lib/%.o,$(LIB_ASMS)) -LIB_DEPS = $(LIB_OBJS:.o=.d) -LIB_RELOC_OBJ = $(BUILD_DIR)/libkit.o - -DRIVER_SRCS = driver/main.c driver/lib/target.c $(DRIVER_ENV_SRCS) -DRIVER_TOOL_SRCS = -ifeq ($(KIT_TOOL_CC_ENABLED),1) -DRIVER_TOOL_SRCS += driver/cmd/cc.c -endif -ifeq ($(KIT_TOOL_CHECK_ENABLED),1) -DRIVER_TOOL_SRCS += driver/cmd/cc.c -endif -ifeq ($(KIT_TOOL_COMPILE_ENABLED),1) -DRIVER_TOOL_SRCS += driver/cmd/compile.c -endif -ifeq ($(KIT_TOOL_INSTALL_ENABLED),1) -DRIVER_TOOL_SRCS += driver/cmd/install.c -endif -ifeq ($(KIT_TOOL_CPP_ENABLED),1) -DRIVER_TOOL_SRCS += driver/cmd/cpp.c -endif -ifeq ($(KIT_TOOL_AS_ENABLED),1) -DRIVER_TOOL_SRCS += driver/cmd/as.c -endif -ifeq ($(KIT_TOOL_LD_ENABLED),1) -DRIVER_TOOL_SRCS += driver/cmd/ld.c -endif -ifeq ($(KIT_TOOL_AR_ENABLED),1) -DRIVER_TOOL_SRCS += driver/cmd/ar.c -endif -ifeq ($(KIT_TOOL_RANLIB_ENABLED),1) -DRIVER_TOOL_SRCS += driver/cmd/ranlib.c -endif -ifeq ($(KIT_TOOL_STRIP_ENABLED),1) -DRIVER_TOOL_SRCS += driver/cmd/strip.c -endif -ifeq ($(KIT_TOOL_OBJCOPY_ENABLED),1) -DRIVER_TOOL_SRCS += driver/cmd/objcopy.c -endif -ifeq ($(KIT_TOOL_OBJDUMP_ENABLED),1) -DRIVER_TOOL_SRCS += driver/cmd/objdump.c -endif -ifeq ($(KIT_TOOL_DBG_ENABLED),1) -DRIVER_TOOL_SRCS += driver/cmd/dbg.c -endif -ifeq ($(KIT_TOOL_RUN_ENABLED),1) -DRIVER_TOOL_SRCS += driver/cmd/run.c -endif -ifeq ($(KIT_TOOL_EMU_ENABLED),1) -DRIVER_TOOL_SRCS += driver/cmd/emu.c -endif -ifeq ($(KIT_TOOL_NM_ENABLED),1) -DRIVER_TOOL_SRCS += driver/cmd/nm.c -endif -ifeq ($(KIT_TOOL_SIZE_ENABLED),1) -DRIVER_TOOL_SRCS += driver/cmd/size.c -endif -ifeq ($(KIT_TOOL_ADDR2LINE_ENABLED),1) -DRIVER_TOOL_SRCS += driver/cmd/addr2line.c -endif -ifeq ($(KIT_TOOL_STRINGS_ENABLED),1) -DRIVER_TOOL_SRCS += driver/cmd/strings.c -endif -# The cas/pkg tools link libkit's public cas/package APIs (gated by -# KIT_CAS_ENABLED / KIT_PKG_ENABLED, asserted by config_assert.c); the -# dist implementation and vendored primitives live in the library now. -ifneq ($(filter 1,$(KIT_TOOL_CAS_ENABLED) $(KIT_TOOL_PKG_ENABLED)),) -DRIVER_TOOL_SRCS += driver/lib/dist_host.c -endif -ifeq ($(KIT_TOOL_CAS_ENABLED),1) -DRIVER_TOOL_SRCS += driver/cmd/cas.c -endif -ifeq ($(KIT_TOOL_PKG_ENABLED),1) -DRIVER_TOOL_SRCS += driver/cmd/pkg.c -endif -ifeq ($(KIT_TOOL_XXD_ENABLED),1) -DRIVER_TOOL_SRCS += driver/cmd/xxd.c -endif -ifeq ($(KIT_TOOL_CMP_ENABLED),1) -DRIVER_TOOL_SRCS += driver/cmd/cmp.c -endif -ifeq ($(KIT_TOOL_HASH_ENABLED),1) -DRIVER_TOOL_SRCS += driver/cmd/hash.c -endif -ifeq ($(KIT_TOOL_COMPRESS_ENABLED),1) -DRIVER_TOOL_SRCS += driver/cmd/compress.c -endif -ifeq ($(KIT_TOOL_DISAS_ENABLED),1) -DRIVER_TOOL_SRCS += driver/cmd/disas.c -endif -ifeq ($(KIT_TOOL_MC_ENABLED),1) -DRIVER_TOOL_SRCS += driver/cmd/mc.c -endif -DRIVER_SRCS += $(sort $(DRIVER_TOOL_SRCS)) -ifneq ($(filter 1,$(KIT_TOOL_CC_ENABLED) $(KIT_TOOL_CHECK_ENABLED) $(KIT_TOOL_CPP_ENABLED) $(KIT_TOOL_AS_ENABLED) $(KIT_TOOL_DBG_ENABLED) $(KIT_TOOL_RUN_ENABLED)),) -DRIVER_SRCS += driver/lib/cflags.c -endif -ifneq ($(filter 1,$(KIT_TOOL_CC_ENABLED) $(KIT_TOOL_CHECK_ENABLED) $(KIT_TOOL_LD_ENABLED) $(KIT_TOOL_RUN_ENABLED)),) -DRIVER_SRCS += driver/lib/lib_resolve.c -endif -ifneq ($(filter 1,$(KIT_TOOL_CC_ENABLED) $(KIT_TOOL_CHECK_ENABLED) $(KIT_TOOL_RUN_ENABLED)),) -DRIVER_SRCS += driver/lib/hosted.c -endif -ifneq ($(filter 1,$(KIT_TOOL_CC_ENABLED) $(KIT_TOOL_CHECK_ENABLED) $(KIT_TOOL_LD_ENABLED)),) -DRIVER_SRCS += driver/lib/runtime.c -endif -ifneq ($(filter 1,$(KIT_TOOL_AR_ENABLED) $(KIT_TOOL_RANLIB_ENABLED) $(KIT_TOOL_STRIP_ENABLED) $(KIT_TOOL_DBG_ENABLED) $(KIT_TOOL_RUN_ENABLED)),) -DRIVER_SRCS += driver/lib/inputs.c -endif -ifneq ($(filter 1,$(KIT_TOOL_CC_ENABLED) $(KIT_TOOL_CHECK_ENABLED) $(KIT_TOOL_COMPILE_ENABLED)),) -DRIVER_SRCS += driver/lib/compile_engine.c -endif -DRIVER_SRCS := $(sort $(DRIVER_SRCS)) -DRIVER_OBJS = $(patsubst driver/%.c,$(BUILD_DIR)/driver/%.o,$(DRIVER_SRCS)) -DRIVER_DEPS = $(DRIVER_OBJS:.o=.d) - -LIB_AR = $(BUILD_DIR)/libkit.a -BIN = $(BUILD_DIR)/kit - -DIST_STAGING = build/dist/kit -DIST_TARBALL = build/dist/kit.tar.gz - -.PHONY: \ - all \ - lib \ - bin \ - dist \ - format \ - compile-commands \ - clean \ - bootstrap \ - bootstrap-debug \ - bootstrap-release \ - _do-bootstrap \ - bench-opt +.PHONY: all lib bin all: lib bin +lib: $(LIB_AR) + bin: $(BIN) $(BUILD_DIR)/support/rt $(BUILD_DIR)/support/rt: @mkdir -p $(dir $@) ln -sfn $(abspath rt) $@ -lib: $(LIB_AR) - -# Replace the archive (`ar rcs` only adds/updates), so removing a .c file -# also removes its .o from the archive on the next build. -$(LIB_RELOC_OBJ): $(LIB_OBJS) $(BUILD_CONFIG) - @mkdir -p $(dir $@) - @rm -f $@ - $(LD) -r -o $@ $(LIB_OBJS) - -$(LIB_AR): $(LIB_RELOC_OBJ) +# Rebuild the archive from scratch (rm first): `ar rcs` only adds/updates, so +# recreating it ensures a removed .c file also drops its .o from the archive. +$(LIB_AR): $(LIB_OBJS) $(BUILD_CONFIG) @mkdir -p $(dir $@) @rm -f $@ - $(AR) rcs $@ $(LIB_RELOC_OBJ) + $(AR) rcs $@ $(LIB_OBJS) $(BIN): $(DRIVER_OBJS) $(LIB_AR) $(BUILD_CONFIG) $(CC) $(HOST_LDFLAGS) -o $@ $(DRIVER_OBJS) $(LIB_AR) $(HOST_LDLIBS) +# --------------------------------------------------------------------------- +# Compile rules, grouped by source tree: src/ (libkit) -> lang/ (frontends) -> +# vendor/ -> driver/. Each tree gets its own include scope; see mk/flags.mk for +# the *_CFLAGS definitions and the rationale behind each tree's include set. +# --------------------------------------------------------------------------- + +# --- src/: libkit core (C + asm), freestanding, hidden visibility ----------- $(BUILD_DIR)/lib/%.o: src/%.c Makefile $(BUILD_CONFIG) @mkdir -p $(dir $@) $(CC) $(LIB_CFLAGS) $(DEPFLAGS) -c $< -o $@ +$(BUILD_DIR)/lib/%.o: src/%.S Makefile $(BUILD_CONFIG) + @mkdir -p $(dir $@) + $(CC) $(LIB_CFLAGS) $(DEPFLAGS) -c $< -o $@ + # lang_registry.c is the one libkit source that crosses into lang/*; it # uses -Ilang so the frontend headers can be reached as "c/c.h" etc. $(BUILD_DIR)/lib/api/lang_registry.o: src/api/lang_registry.c Makefile $(BUILD_CONFIG) @mkdir -p $(dir $@) $(CC) $(FREESTANDING_CFLAGS) $(LIB_VISIBILITY_CFLAGS) -Iinclude -Ilang -Isrc $(DEPFLAGS) -c $< -o $@ +# --- lang/: frontends, each with its own include set ------------------------ $(BUILD_DIR)/lang/cpp/%.o: lang/cpp/%.c Makefile $(BUILD_CONFIG) @mkdir -p $(dir $@) $(CC) $(FREESTANDING_CFLAGS) $(LIB_VISIBILITY_CFLAGS) -Iinclude -Ilang/cpp $(DEPFLAGS) -c $< -o $@ @@ -522,20 +86,26 @@ $(BUILD_DIR)/lang/c/%.o: lang/c/%.c Makefile $(BUILD_CONFIG) @mkdir -p $(dir $@) $(CC) $(FREESTANDING_CFLAGS) $(LIB_VISIBILITY_CFLAGS) -Iinclude -Ilang/cpp -Ilang/c $(DEPFLAGS) -c $< -o $@ +# The Wasm frontend is the one lang/* tree that reaches internal headers: it +# includes "wasm/wasm.h" to share src/wasm/ (the module/encode/decode library) +# with the Wasm backend, so it gets -Isrc. lang/c and lang/cpp deliberately do +# not — they see only the public include/ surface. $(BUILD_DIR)/lang/wasm/%.o: lang/wasm/%.c Makefile $(BUILD_CONFIG) @mkdir -p $(dir $@) $(CC) $(FREESTANDING_CFLAGS) $(LIB_VISIBILITY_CFLAGS) -Iinclude -Isrc -Ilang/wasm $(DEPFLAGS) -c $< -o $@ -$(BUILD_DIR)/lib/%.o: src/%.S Makefile $(BUILD_CONFIG) +$(BUILD_DIR)/lang/toy/%.o: lang/toy/%.c Makefile $(BUILD_CONFIG) @mkdir -p $(dir $@) - $(CC) $(LIB_CFLAGS) $(DEPFLAGS) -c $< -o $@ + $(CC) $(FREESTANDING_CFLAGS) $(LIB_VISIBILITY_CFLAGS) -Iinclude -Ilang/toy $(DEPFLAGS) -c $< -o $@ +# --- vendor/: third-party sources compiled into libkit ---------------------- # Vendored third-party sources (monocypher) compiled into libkit. Same # freestanding flags as the rest of the library; symbols stay hidden. $(BUILD_DIR)/vendor/%.o: vendor/%.c Makefile $(BUILD_CONFIG) @mkdir -p $(dir $@) $(CC) $(LIB_CFLAGS) $(DEPFLAGS) -c $< -o $@ +# --- driver/: hosted CLI; env/ is the OS/libc adapter sub-tree -------------- $(BUILD_DIR)/driver/%.o: driver/%.c Makefile $(BUILD_CONFIG) @mkdir -p $(dir $@) $(CC) $(DRIVER_CFLAGS) $(DEPFLAGS) -c $< -o $@ @@ -544,114 +114,68 @@ $(BUILD_DIR)/driver/env/%.o: driver/env/%.c Makefile $(BUILD_CONFIG) @mkdir -p $(dir $@) $(CC) $(DRIVER_ENV_CFLAGS) $(DRIVER_ENV_OS_CFLAGS) $(DEPFLAGS) -c $< -o $@ -$(BUILD_DIR)/lang/toy/%.o: lang/toy/%.c Makefile $(BUILD_CONFIG) - @mkdir -p $(dir $@) - $(CC) $(FREESTANDING_CFLAGS) $(LIB_VISIBILITY_CFLAGS) -Iinclude -Ilang/toy $(DEPFLAGS) -c $< -o $@ +# =========================================================================== +# Runtime (libkit_rt.a): kit compiles and archives its own runtime, one +# variant per target. The variant table and per-variant source/flag lists come +# from mk/rt.mk; this section is the per-variant build rules expanded over it. +# =========================================================================== -include rt/Makefile - -# Bootstrap: build kit with the host compiler as stage 1, then rebuild it -# twice through the normal Makefile using kit's busybox-style cc/ar/ld -# symlinks. Stages 2 and 3 must be bitwise identical. -BOOTSTRAP_DIR = $(BUILD_DIR)/bootstrap -BOOTSTRAP_STAGE1_DIR = $(BOOTSTRAP_DIR)/stage1 -BOOTSTRAP_STAGE2_DIR = $(BOOTSTRAP_DIR)/stage2 -BOOTSTRAP_STAGE3_DIR = $(BOOTSTRAP_DIR)/stage3 -BOOTSTRAP_STAGE1_BIN = $(BOOTSTRAP_STAGE1_DIR)/kit -BOOTSTRAP_STAGE2_BIN = $(BOOTSTRAP_STAGE2_DIR)/kit -BOOTSTRAP_STAGE3_BIN = $(BOOTSTRAP_STAGE3_DIR)/kit -BOOTSTRAP_TOOLS = cc ld ar ranlib as -BOOTSTRAP_HOST_MODE_CFLAGS = -BOOTSTRAP_HOST_MODE_LDFLAGS = -BOOTSTRAP_STAMP = $(BOOTSTRAP_DIR)/.stamp -BOOTSTRAP_RT_LIBS = $(addprefix $(RT_BUILD_DIR)/,$(addsuffix /libkit_rt.a,$(RT_DEFAULT_VARIANTS))) -BOOTSTRAP_MAKEFILES = Makefile mk/config.mk rt/Makefile +RT_CC ?= $(BIN) cc +RT_AR ?= $(BIN) ar +RT_AS ?= $(BIN) as +RT_AS_COMPILE_FLAGS ?= -ifeq ($(RELEASE),1) -$(BOOTSTRAP_STAMP): HOST_OPTFLAGS = -O1 -$(BOOTSTRAP_STAMP): BOOTSTRAP_HOST_MODE_CFLAGS = $(HOST_MODE_CFLAGS) -$(BOOTSTRAP_STAMP): BOOTSTRAP_HOST_MODE_LDFLAGS = -Wl,--gc-sections -Wl,-S -endif +.PHONY: rt rt-all-targets rt-no-native-target $(addprefix rt-,$(RT_VARIANTS)) + +rt: $(if $(RT_DEFAULT_VARIANTS),$(addprefix rt-,$(RT_DEFAULT_VARIANTS)),rt-no-native-target) +rt-all-targets: $(addprefix rt-,$(RT_VARIANTS)) -bootstrap: bootstrap-debug bootstrap-release - -bootstrap-debug: - $(MAKE) RELEASE=0 BUILD_DIR='$(BUILD_DIR)/debug' _do-bootstrap - -bootstrap-release: - $(MAKE) RELEASE=1 BUILD_DIR='$(BUILD_DIR)/release' _do-bootstrap - -_do-bootstrap: $(BOOTSTRAP_STAMP) - -$(BOOTSTRAP_STAMP): $(BIN) $(BOOTSTRAP_RT_LIBS) $(BOOTSTRAP_MAKEFILES) - rm -rf $(BOOTSTRAP_DIR) - @mkdir -p $(BOOTSTRAP_STAGE1_DIR) - cp $(BIN) $(BOOTSTRAP_STAGE1_BIN) - @for tool in $(BOOTSTRAP_TOOLS); do ln -sf kit "$(BOOTSTRAP_STAGE1_DIR)/$$tool"; done - $(MAKE) lib bin \ - BUILD_DIR='$(abspath $(BOOTSTRAP_STAGE2_DIR))' \ - RELEASE='$(RELEASE)' \ - HOST_OPTFLAGS='$(HOST_OPTFLAGS)' \ - HOST_MODE_CFLAGS='$(BOOTSTRAP_HOST_MODE_CFLAGS)' \ - HOST_MODE_LDFLAGS='$(BOOTSTRAP_HOST_MODE_LDFLAGS)' \ - CC='$(abspath $(BOOTSTRAP_STAGE1_DIR))/cc' \ - AR='$(abspath $(BOOTSTRAP_STAGE1_DIR))/ar' \ - LD='$(abspath $(BOOTSTRAP_STAGE1_DIR))/ld' - @for tool in $(BOOTSTRAP_TOOLS); do ln -sf kit "$(BOOTSTRAP_STAGE2_DIR)/$$tool"; done - $(MAKE) lib bin \ - BUILD_DIR='$(abspath $(BOOTSTRAP_STAGE3_DIR))' \ - RELEASE='$(RELEASE)' \ - HOST_OPTFLAGS='$(HOST_OPTFLAGS)' \ - HOST_MODE_CFLAGS='$(BOOTSTRAP_HOST_MODE_CFLAGS)' \ - HOST_MODE_LDFLAGS='$(BOOTSTRAP_HOST_MODE_LDFLAGS)' \ - CC='$(abspath $(BOOTSTRAP_STAGE2_DIR))/cc' \ - AR='$(abspath $(BOOTSTRAP_STAGE2_DIR))/ar' \ - LD='$(abspath $(BOOTSTRAP_STAGE2_DIR))/ld' - cmp $(BOOTSTRAP_STAGE2_BIN) $(BOOTSTRAP_STAGE3_BIN) - shasum -a 256 $(BOOTSTRAP_STAGE2_BIN) $(BOOTSTRAP_STAGE3_BIN) - @touch $@ - -bench-opt: - $(MAKE) RELEASE=1 bin - @KIT='$(abspath build/release/kit)' bash scripts/opt_bench.sh - -dist: - $(MAKE) RELEASE=1 bin - @rm -rf $(DIST_STAGING) - @mkdir -p $(DIST_STAGING)/support/rt $(DIST_STAGING)/lib - cp build/release/kit $(DIST_STAGING)/kit - cp build/release/libkit.a $(DIST_STAGING)/lib/libkit.a - cp -r include $(DIST_STAGING)/include - cp -r rt/include $(DIST_STAGING)/support/rt/include - cp -r rt/lib $(DIST_STAGING)/support/rt/lib - cd build/dist && tar czf kit.tar.gz kit - @echo "dist: $(abspath $(DIST_TARBALL))" - -# Format only the .c/.h files changed in the working tree (staged, unstaged, or -# new/untracked), restricted to the formatted roots and excluding test/pp. When -# nothing has changed, fall back to formatting every source file. -format: - @files=$$( { git diff --name-only --diff-filter=ACMR HEAD -- '*.c' '*.h'; \ - git ls-files --others --exclude-standard -- '*.c' '*.h'; } 2>/dev/null \ - | grep -E '^(src|include|driver|lang|test|rt)/' \ - | grep -vE '^test/pp/' \ - | sort -u ); \ - if [ -n "$$files" ]; then \ - echo "$$files" | xargs clang-format -i --style=google; \ - echo "$$files" | sed 's/^/formatted /'; \ - else \ - echo "no changed sources; formatting all"; \ - find src include driver lang test rt -path test/pp -prune -o \( -name '*.c' -o -name '*.h' \) -print | xargs clang-format -i --style=google; \ - fi - -# Regenerate the clangd compilation database (build/compile_commands.json). -# clangd auto-discovers it under build/; re-run after adding/removing sources -# or after `make clean`. -compile-commands: - python3 scripts/gen_compile_commands.py - -clean: - rm -rf $(BUILD_DIR) +rt-no-native-target: + $(error unsupported native runtime target: HOST_UNAME=$(HOST_UNAME) RT_HOST_MACHINE=$(RT_HOST_MACHINE)) + +define RT_VARIANT_rules +rt-$(1): $$(RT_BUILD_DIR)/$(1)/libkit_rt.a + +# Regular (not order-only) dep on $(BIN): kit compiles and archives its own +# runtime, so a codegen or `ar` change in the compiler must rebuild the rt. +# The archive lists $(RT_OBJS) explicitly rather than $^ so the kit binary +# (now a regular prereq) is not itself archived. +# +# Depend on mk/rt.mk + this Makefile too: the member list (RT_*_SRCS) lives in +# mk/rt.mk and `ar rcs` only adds/updates members. When the list grows, an +# existing archive whose objects happen to be newer would otherwise never +# regenerate and would silently drop the new members (e.g. a missing +# __clear_cache breaking links). With the makefiles as prereqs, any list edit +# re-fires the `rm -f` + full re-archive below so the archive always matches +# RT_OBJS. +$$(RT_BUILD_DIR)/$(1)/libkit_rt.a: $$(RT_OBJS_$(1)) mk/rt.mk Makefile $$(BIN) + @mkdir -p $$(dir $$@) + @rm -f $$@ + $$(RT_AR) rcs $$@ $$(RT_OBJS_$(1)) + +$$(RT_BUILD_DIR)/$(1)/%.s.o: rt/lib/%.s $$(BIN) + @mkdir -p $$(dir $$@) + $$(RT_AS) $$(RT_ASFLAGS_$(1)) $$(RT_AS_COMPILE_FLAGS) $$< -o $$@ + +$$(RT_BUILD_DIR)/$(1)/%.S.o: rt/lib/%.S $$(BIN) + @mkdir -p $$(dir $$@) + $$(RT_AS) $$(RT_ASFLAGS_$(1)) $$(RT_AS_COMPILE_FLAGS) $$< -o $$@ + +$$(RT_BUILD_DIR)/$(1)/%.o: rt/lib/% $$(BIN) + @mkdir -p $$(dir $$@) + $$(RT_CC) $$(RT_CFLAGS_$(1)) -c $$< -o $$@ + +$$(RT_BUILD_DIR)/$(1)/atomic/atomic_freestanding.c.o: rt/lib/atomic/atomic_common.inc +endef + +$(foreach variant,$(RT_VARIANTS),$(eval $(call RT_VARIANT_rules,$(variant)))) + +# =========================================================================== +# Bootstrap, dist, and maintenance targets live in their own includes. +# =========================================================================== +include mk/bootstrap.mk +include mk/dist.mk +include mk/maint.mk -include $(LIB_DEPS) -include $(DRIVER_DEPS) diff --git a/mk/bootstrap.mk b/mk/bootstrap.mk @@ -0,0 +1,67 @@ +# mk/bootstrap.mk +# =========================================================================== +# Three-stage self-build verification. Included after mk/rt.mk because it +# references RT_BUILD_DIR / RT_DEFAULT_VARIANTS. +# +# Build kit with the host compiler as stage 1, then rebuild it twice through +# the normal Makefile using kit's busybox-style cc/ar/ld symlinks. Stages 2 +# and 3 must be bitwise identical. + +.PHONY: bootstrap bootstrap-debug bootstrap-release _do-bootstrap + +BOOTSTRAP_DIR = $(BUILD_DIR)/bootstrap +BOOTSTRAP_STAGE1_DIR = $(BOOTSTRAP_DIR)/stage1 +BOOTSTRAP_STAGE2_DIR = $(BOOTSTRAP_DIR)/stage2 +BOOTSTRAP_STAGE3_DIR = $(BOOTSTRAP_DIR)/stage3 +BOOTSTRAP_STAGE1_BIN = $(BOOTSTRAP_STAGE1_DIR)/kit +BOOTSTRAP_STAGE2_BIN = $(BOOTSTRAP_STAGE2_DIR)/kit +BOOTSTRAP_STAGE3_BIN = $(BOOTSTRAP_STAGE3_DIR)/kit +BOOTSTRAP_TOOLS = cc ld ar ranlib as +BOOTSTRAP_HOST_MODE_CFLAGS = +BOOTSTRAP_HOST_MODE_LDFLAGS = +BOOTSTRAP_STAMP = $(BOOTSTRAP_DIR)/.stamp +BOOTSTRAP_RT_LIBS = $(addprefix $(RT_BUILD_DIR)/,$(addsuffix /libkit_rt.a,$(RT_DEFAULT_VARIANTS))) +BOOTSTRAP_MAKEFILES = Makefile mk/env.mk mk/config.mk mk/flags.mk \ + mk/lib_srcs.mk mk/driver_srcs.mk mk/rt.mk + +ifeq ($(RELEASE),1) +$(BOOTSTRAP_STAMP): HOST_OPTFLAGS = -O1 +$(BOOTSTRAP_STAMP): BOOTSTRAP_HOST_MODE_CFLAGS = $(HOST_MODE_CFLAGS) +$(BOOTSTRAP_STAMP): BOOTSTRAP_HOST_MODE_LDFLAGS = -Wl,--gc-sections -Wl,-S +endif + +bootstrap: bootstrap-debug bootstrap-release + +bootstrap-debug: + $(MAKE) RELEASE=0 BUILD_DIR='$(BUILD_DIR)/debug' _do-bootstrap + +bootstrap-release: + $(MAKE) RELEASE=1 BUILD_DIR='$(BUILD_DIR)/release' _do-bootstrap + +_do-bootstrap: $(BOOTSTRAP_STAMP) + +$(BOOTSTRAP_STAMP): $(BIN) $(BOOTSTRAP_RT_LIBS) $(BOOTSTRAP_MAKEFILES) + rm -rf $(BOOTSTRAP_DIR) + @mkdir -p $(BOOTSTRAP_STAGE1_DIR) + cp $(BIN) $(BOOTSTRAP_STAGE1_BIN) + @for tool in $(BOOTSTRAP_TOOLS); do ln -sf kit "$(BOOTSTRAP_STAGE1_DIR)/$$tool"; done + $(MAKE) lib bin \ + BUILD_DIR='$(abspath $(BOOTSTRAP_STAGE2_DIR))' \ + RELEASE='$(RELEASE)' \ + HOST_OPTFLAGS='$(HOST_OPTFLAGS)' \ + HOST_MODE_CFLAGS='$(BOOTSTRAP_HOST_MODE_CFLAGS)' \ + HOST_MODE_LDFLAGS='$(BOOTSTRAP_HOST_MODE_LDFLAGS)' \ + CC='$(abspath $(BOOTSTRAP_STAGE1_DIR))/cc' \ + AR='$(abspath $(BOOTSTRAP_STAGE1_DIR))/ar' + @for tool in $(BOOTSTRAP_TOOLS); do ln -sf kit "$(BOOTSTRAP_STAGE2_DIR)/$$tool"; done + $(MAKE) lib bin \ + BUILD_DIR='$(abspath $(BOOTSTRAP_STAGE3_DIR))' \ + RELEASE='$(RELEASE)' \ + HOST_OPTFLAGS='$(HOST_OPTFLAGS)' \ + HOST_MODE_CFLAGS='$(BOOTSTRAP_HOST_MODE_CFLAGS)' \ + HOST_MODE_LDFLAGS='$(BOOTSTRAP_HOST_MODE_LDFLAGS)' \ + CC='$(abspath $(BOOTSTRAP_STAGE2_DIR))/cc' \ + AR='$(abspath $(BOOTSTRAP_STAGE2_DIR))/ar' + cmp $(BOOTSTRAP_STAGE2_BIN) $(BOOTSTRAP_STAGE3_BIN) + shasum -a 256 $(BOOTSTRAP_STAGE2_BIN) $(BOOTSTRAP_STAGE3_BIN) + @touch $@ diff --git a/mk/dist.mk b/mk/dist.mk @@ -0,0 +1,21 @@ +# mk/dist.mk +# =========================================================================== +# Release tarball staging: a self-contained kit/ tree (binary, libkit.a, +# public headers, runtime sources) packaged as kit.tar.gz. + +.PHONY: dist + +DIST_STAGING = build/dist/kit +DIST_TARBALL = build/dist/kit.tar.gz + +dist: + $(MAKE) RELEASE=1 bin + @rm -rf $(DIST_STAGING) + @mkdir -p $(DIST_STAGING)/support/rt $(DIST_STAGING)/lib + cp build/release/kit $(DIST_STAGING)/kit + cp build/release/libkit.a $(DIST_STAGING)/lib/libkit.a + cp -r include $(DIST_STAGING)/include + cp -r rt/include $(DIST_STAGING)/support/rt/include + cp -r rt/lib $(DIST_STAGING)/support/rt/lib + cd build/dist && tar czf kit.tar.gz kit + @echo "dist: $(abspath $(DIST_TARBALL))" diff --git a/mk/driver_srcs.mk b/mk/driver_srcs.mk @@ -0,0 +1,63 @@ +# mk/driver_srcs.mk +# =========================================================================== +# Driver source selection -> DRIVER_OBJS / DRIVER_DEPS. +# +# The tool set is gated by the KIT_TOOL_*_ENABLED flags (mk/config.mk), the +# same flags main.c keys its dispatch table on. DRIVER_ENV_SRCS (the hosted +# OS/libc adapter set) comes from mk/env.mk. + +# A subcommand TU: include driver/cmd/$(2).c when KIT_TOOL_$(1)_ENABLED is set. +tool-cmd = $(if $(filter 1,$(KIT_TOOL_$(1)_ENABLED)),driver/cmd/$(2).c) +# A shared driver/lib TU: include $(2) if ANY of the named tools is enabled. +need-any = $(if $(filter 1,$(foreach f,$(1),$(KIT_TOOL_$(f)_ENABLED))),$(2)) + +DRIVER_SRCS = driver/main.c driver/lib/target.c $(DRIVER_ENV_SRCS) + +# One entry per subcommand. cc.c serves both `cc` and `check`; the final +# $(sort) below dedupes it. The cas/pkg tools additionally pull in +# driver/lib/dist_host.c (handled with the shared-lib group below). +DRIVER_TOOL_SRCS = \ + $(call tool-cmd,CC,cc) \ + $(call tool-cmd,CHECK,cc) \ + $(call tool-cmd,COMPILE,compile) \ + $(call tool-cmd,INSTALL,install) \ + $(call tool-cmd,CPP,cpp) \ + $(call tool-cmd,AS,as) \ + $(call tool-cmd,LD,ld) \ + $(call tool-cmd,AR,ar) \ + $(call tool-cmd,RANLIB,ranlib) \ + $(call tool-cmd,STRIP,strip) \ + $(call tool-cmd,OBJCOPY,objcopy) \ + $(call tool-cmd,OBJDUMP,objdump) \ + $(call tool-cmd,DBG,dbg) \ + $(call tool-cmd,RUN,run) \ + $(call tool-cmd,EMU,emu) \ + $(call tool-cmd,NM,nm) \ + $(call tool-cmd,SIZE,size) \ + $(call tool-cmd,ADDR2LINE,addr2line) \ + $(call tool-cmd,STRINGS,strings) \ + $(call tool-cmd,CAS,cas) \ + $(call tool-cmd,PKG,pkg) \ + $(call tool-cmd,XXD,xxd) \ + $(call tool-cmd,CMP,cmp) \ + $(call tool-cmd,HASH,hash) \ + $(call tool-cmd,COMPRESS,compress) \ + $(call tool-cmd,DISAS,disas) \ + $(call tool-cmd,MC,mc) +DRIVER_SRCS += $(sort $(DRIVER_TOOL_SRCS)) + +# Shared driver/lib support, each compiled in when any of its consumer tools +# is enabled. The cas/pkg tools link libkit's public cas/package APIs (gated +# by KIT_CAS_ENABLED / KIT_PKG_ENABLED, asserted by config_assert.c); the dist +# implementation and vendored primitives live in the library now. +DRIVER_SRCS += $(call need-any,CC CHECK CPP AS DBG RUN,driver/lib/cflags.c) +DRIVER_SRCS += $(call need-any,CC CHECK LD RUN,driver/lib/lib_resolve.c) +DRIVER_SRCS += $(call need-any,CC CHECK RUN,driver/lib/hosted.c) +DRIVER_SRCS += $(call need-any,CC CHECK LD,driver/lib/runtime.c) +DRIVER_SRCS += $(call need-any,AR RANLIB STRIP DBG RUN,driver/lib/inputs.c) +DRIVER_SRCS += $(call need-any,CC CHECK COMPILE,driver/lib/compile_engine.c) +DRIVER_SRCS += $(call need-any,CAS PKG,driver/lib/dist_host.c) + +DRIVER_SRCS := $(sort $(DRIVER_SRCS)) +DRIVER_OBJS = $(patsubst driver/%.c,$(BUILD_DIR)/driver/%.o,$(DRIVER_SRCS)) +DRIVER_DEPS = $(DRIVER_OBJS:.o=.d) diff --git a/mk/flags.mk b/mk/flags.mk @@ -0,0 +1,82 @@ +# mk/flags.mk +# =========================================================================== +# Compiler/linker flag derivation and the .build-config stamp. +# +# Consumes HOST_OS and HOST_SYSROOT_{C,LD}FLAGS from mk/env.mk and the +# RELEASE switch from the top-level Makefile; produces the *_CFLAGS / +# *_LDFLAGS the compile rules splice in. Nothing here branches on the host +# beyond the Darwin dead-strip choice. + +ifeq ($(RELEASE),1) +HOST_OPTFLAGS ?= -O2 +HOST_MODE_CPPFLAGS = -DNDEBUG +HOST_MODE_CFLAGS = -ffunction-sections -fdata-sections +ifeq ($(HOST_OS),darwin) +HOST_MODE_LDFLAGS = -Wl,-dead_strip -Wl,-S +else +HOST_MODE_LDFLAGS = -Wl,--gc-sections -Wl,-S +endif +else +HOST_OPTFLAGS ?= -O0 +HOST_MODE_CPPFLAGS = +HOST_MODE_CFLAGS = -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls \ + -fsanitize=address,undefined \ + -fno-sanitize-recover=address,undefined \ + -fsanitize-address-use-after-scope +HOST_MODE_LDFLAGS = -fsanitize=address,undefined +ASAN_OPTIONS ?= halt_on_error=1:abort_on_error=1 +UBSAN_OPTIONS ?= halt_on_error=1:print_stacktrace=1 +export ASAN_OPTIONS UBSAN_OPTIONS +endif + +# HOST_SYSROOT_{C,LD}FLAGS come from env.mk: a `-isysroot <path>` pair on +# Darwin, empty elsewhere. Stage/bootstrap recipes can clear these when +# kit itself is the compiler. + +CFLAGS_COMMON = $(HOST_OPTFLAGS) $(HOST_MODE_CPPFLAGS) $(HOST_MODE_CFLAGS) \ + -std=c11 -Wpedantic -Wall -Wextra -Werror +HOST_CFLAGS = $(CFLAGS_COMMON) $(HOST_SYSROOT_CFLAGS) +HOST_LDFLAGS = $(HOST_SYSROOT_LDFLAGS) $(HOST_MODE_LDFLAGS) + +DEPFLAGS = -MMD -MP + +BUILD_CONFIG = $(BUILD_DIR)/.build-config + +.PHONY: FORCE +FORCE: + +$(BUILD_CONFIG): FORCE + @mkdir -p $(dir $@) + @{ \ + printf '%s\n' 'RELEASE=$(RELEASE)'; \ + printf '%s\n' 'HOST_OPTFLAGS=$(HOST_OPTFLAGS)'; \ + printf '%s\n' 'HOST_MODE_CPPFLAGS=$(HOST_MODE_CPPFLAGS)'; \ + printf '%s\n' 'HOST_MODE_CFLAGS=$(HOST_MODE_CFLAGS)'; \ + printf '%s\n' 'HOST_MODE_LDFLAGS=$(HOST_MODE_LDFLAGS)'; \ + } > $@.tmp + @if ! cmp -s $@.tmp $@; then mv $@.tmp $@; else rm -f $@.tmp; fi + +# Freestanding objects must not see host SDK/libc headers. Homebrew clang can +# also inject a configured sysroot before command-line flags; use +# --no-default-config when the selected compiler supports it, but omit it for +# bootstrap stages where $(CC) is kit cc. +FREESTANDING_CONFIG_CFLAGS = $(shell $(CC) --no-default-config -x c -E /dev/null >/dev/null 2>&1 && printf '%s' --no-default-config) +FREESTANDING_CFLAGS = $(CFLAGS_COMMON) $(FREESTANDING_CONFIG_CFLAGS) -ffreestanding -nostdinc -Irt/include + +# libkit: written in C11 freestanding; sees both src/ (internal) and +# include/ (its own public surface). +LIB_VISIBILITY_CFLAGS = -fvisibility=hidden +LIB_CFLAGS = $(FREESTANDING_CFLAGS) $(LIB_VISIBILITY_CFLAGS) -Iinclude -Isrc -Ivendor + +# Driver: mostly freestanding CLI binary. Sees only the public include/ tree — +# that's what makes the driver the first consumer of libkit. -Ilang lets `cc` +# reach the C frontend's public header ("c/c.h") for the JIT REPL; it +# deliberately does NOT get -Isrc, so internal headers ("core/...", "link/...") +# are unreachable from the driver. +# +# driver/env/ holds all hosted OS/libc adapter code and is compiled with +# DRIVER_ENV_CFLAGS. The per-OS feature-test macros and the exact source +# list (DRIVER_ENV_OS_CFLAGS / DRIVER_ENV_SRCS) come from mk/env.mk. +DRIVER_CFLAGS = $(FREESTANDING_CFLAGS) -Iinclude -Ilang -Idriver -Idriver/lib +DRIVER_ENV_CFLAGS = $(HOST_CFLAGS) -Iinclude -Ilang -Idriver -Idriver/lib +TEST_HOST_CFLAGS = $(HOST_CFLAGS) -Iinclude -Ilang diff --git a/mk/lib_srcs.mk b/mk/lib_srcs.mk @@ -0,0 +1,259 @@ +# mk/lib_srcs.mk +# =========================================================================== +# libkit source selection -> LIB_OBJS / LIB_DEPS. +# +# Consumes the KIT_*_ENABLED flags (mk/config.mk) and BUILD_DIR; mirrors the +# `#if` gates in the corresponding sources so the build drops exactly what the +# compile drops. The matching frontend `#if`s live in src/api/lang_registry.c. + +# When a native feature is disabled, drop its per-arch TU from all three +# native backends and, where one exists, compile a stub in its place. +# $(1) = TU basename (e.g. disasm.c) $(2) = stub source, or empty +define arch-feature-off +LIB_SRCS_ARCH_AA64 := $$(filter-out %/$(1),$$(LIB_SRCS_ARCH_AA64)) +LIB_SRCS_ARCH_X64 := $$(filter-out %/$(1),$$(LIB_SRCS_ARCH_X64)) +LIB_SRCS_ARCH_RV64 := $$(filter-out %/$(1),$$(LIB_SRCS_ARCH_RV64)) +LIB_SRCS_NONARCH += $(2) +endef + +# Core lib sources. Optional subsystems, backend directories, object format +# directories, and ABI implementations are added below from their own groups. +LIB_SRCS_ABI_CORE = src/abi/abi.c src/abi/registry.c +LIB_SRCS_API_CORE = $(filter-out src/api/archive.c src/api/disasm.c \ + src/api/link.c src/api/cas.c src/api/package.c \ + src/api/compress.c src/api/stubs.c,$(wildcard src/api/*.c)) +LIB_SRCS_ARCH_CORE = $(filter-out src/arch/%_stubs.c,$(wildcard src/arch/*.c)) +LIB_SRCS_ASM_CORE = $(wildcard src/asm/*.c) +LIB_SRCS_CG_CORE = $(wildcard src/cg/*.c) +LIB_SRCS_CORE = $(wildcard src/core/*.c) +LIB_SRCS_OBJ_CORE = $(filter-out src/obj/%_stubs.c,$(wildcard src/obj/*.c)) +LIB_SRCS_NONARCH = $(LIB_SRCS_ABI_CORE) \ + $(LIB_SRCS_API_CORE) \ + $(LIB_SRCS_ARCH_CORE) \ + $(LIB_SRCS_ASM_CORE) \ + $(LIB_SRCS_CG_CORE) \ + $(LIB_SRCS_CORE) \ + $(LIB_SRCS_OBJ_CORE) + +# These source lists use `:=` (not `=`) so each `find` runs exactly once at +# parse time. With recursive `=`, every reference below (LIB_SRCS is rebuilt +# and re-expanded many times) would re-spawn the `find`, turning ~20 finds into +# hundreds on every `make` invocation. +LIB_SRCS_ARCH_AA64 := $(shell find src/arch/aa64 -name '*.c' 2>/dev/null) +LIB_SRCS_ARCH_X64 := $(shell find src/arch/x64 -name '*.c' 2>/dev/null) +LIB_SRCS_ARCH_RV64 := $(shell find src/arch/rv64 -name '*.c' 2>/dev/null) +LIB_SRCS_ARCH_WASM := $(shell find src/arch/wasm -name '*.c' 2>/dev/null) +LIB_SRCS_ARCH_C_TARGET := $(shell find src/arch/c_target -name '*.c' 2>/dev/null) +ifneq ($(KIT_OPT_ENABLED),1) +$(eval $(call arch-feature-off,opt_coord.c,)) +endif +ifneq ($(KIT_DISASM_ENABLED),1) +$(eval $(call arch-feature-off,disasm.c,src/arch/disasm_stubs.c)) +endif +ifneq ($(KIT_LINK_ENABLED),1) +$(eval $(call arch-feature-off,link.c,src/arch/link_stubs.c)) +endif +ifneq ($(KIT_DBG_ENABLED),1) +$(eval $(call arch-feature-off,dbg.c,src/arch/dbg_stubs.c)) +endif +ifneq ($(KIT_EMU_ENABLED),1) +LIB_SRCS_ARCH_RV64 := $(filter-out %/emu.c,$(LIB_SRCS_ARCH_RV64)) +LIB_SRCS_NONARCH += src/arch/emu_stubs.c +endif +ifneq ($(KIT_INTERP_ENABLED),1) +LIB_SRCS_NONARCH += src/interp/interp_stubs.c +endif + +LIB_SRCS_OBJ_ELF := $(shell find src/obj/elf -name '*.c' 2>/dev/null) +LIB_SRCS_OBJ_MACHO := $(shell find src/obj/macho -name '*.c' 2>/dev/null) +LIB_SRCS_OBJ_COFF := $(shell find src/obj/coff -name '*.c' 2>/dev/null) +LIB_SRCS_OBJ_WASM := $(shell find src/obj/wasm -name '*.c' 2>/dev/null) +ifneq ($(KIT_LINK_ENABLED),1) +LIB_SRCS_OBJ_ELF := $(filter-out %/link.c %/link_dyn.c,$(LIB_SRCS_OBJ_ELF)) +LIB_SRCS_OBJ_MACHO := $(filter-out %/link.c,$(LIB_SRCS_OBJ_MACHO)) +LIB_SRCS_OBJ_COFF := $(filter-out %/link.c,$(LIB_SRCS_OBJ_COFF)) +LIB_SRCS_NONARCH += src/obj/link_stubs.c +endif +ifneq ($(KIT_EMU_ENABLED),1) +LIB_SRCS_OBJ_ELF := $(filter-out %/emu_load.c,$(LIB_SRCS_OBJ_ELF)) +LIB_SRCS_NONARCH += src/obj/emu_stubs.c +endif +ifneq ($(KIT_AR_ENABLED),1) +LIB_SRCS_OBJ_COFF := $(filter-out %/archive.c,$(LIB_SRCS_OBJ_COFF)) +LIB_SRCS_NONARCH += src/obj/archive_stubs.c +endif + +LIB_SRCS_OPT := $(filter-out src/opt/pass_o2.c,$(shell find src/opt -name '*.c' 2>/dev/null)) +LIB_SRCS_INTERP := $(filter-out %/interp_stubs.c,$(shell find src/interp -name '*.c' 2>/dev/null)) +LIB_SRCS_WASM_CORE := $(shell find src/wasm -name '*.c' 2>/dev/null) +LIB_SRCS_API_AR = src/api/archive.c +LIB_SRCS_API_DISASM = src/api/disasm.c +LIB_SRCS_API_LINK = src/api/link.c +# Distribution subsystem (content store + signed packages). The cas layer +# needs blake2b (-> monocypher); the pkg layer adds the crypto/container shims +# and the second monocypher TU. The compression codecs (deflate + lz4 block) +# are shared by pkg and the standalone compress API, so they live in their own +# CODEC group pulled in once if either is enabled. The lz4 frame layer +# (LIB_SRCS_DIST_COMPRESS) is needed only by the compress API. All vendored .c +# (lz4.c, lz4frame.c's xxhash/lz4hc/lz4frame) are #included by their src/dist +# shim (amalgamation), so they are NOT compiled standalone. +LIB_SRCS_API_CAS = src/api/cas.c +LIB_SRCS_API_PKG = src/api/package.c +LIB_SRCS_API_COMPRESS = src/api/compress.c +LIB_SRCS_DIST_CAS = src/dist/dist.c src/dist/blake2b.c src/dist/blob.c \ + src/dist/tree.c src/dist/cas.c +LIB_SRCS_VENDOR_CAS = vendor/monocypher/monocypher.c +LIB_SRCS_DIST_CODEC = src/dist/deflate.c src/dist/lz4.c +LIB_SRCS_DIST_COMPRESS = src/dist/lz4frame.c +LIB_SRCS_DIST_PKG = src/dist/b64.c src/dist/ed25519.c src/dist/minisig.c \ + src/dist/tar.c src/dist/kpkg.c src/dist/manifest.c \ + src/dist/trust.c +LIB_SRCS_VENDOR_PKG = vendor/monocypher/monocypher-ed25519.c +LIB_SRCS_DEBUG := $(shell find src/debug -name '*.c' 2>/dev/null) +LIB_SRCS_DBG := $(shell find src/dbg -name '*.c' 2>/dev/null) +LIB_SRCS_EMU := $(shell find src/emu -name '*.c' 2>/dev/null) \ + $(shell find src/os -name '*.c' 2>/dev/null) +LIB_SRCS_LINK := $(shell find src/link -name '*.c' 2>/dev/null) +ifneq ($(KIT_JIT_ENABLED),1) +LIB_SRCS_LINK := $(filter-out %/link_jit.c,$(LIB_SRCS_LINK)) +endif +LIB_SRCS_JIT_ASM := $(shell find src/jit -name '*.S' 2>/dev/null) + +LIB_SRC_ABI_AAPCS64 = src/abi/abi_aapcs64.c +LIB_SRC_ABI_APPLE_ARM64 = src/abi/abi_apple_arm64.c +LIB_SRC_ABI_AAPCS64_WINDOWS = src/abi/abi_aapcs64_windows.c +LIB_SRC_ABI_SYSV_X64 = src/abi/abi_sysv_x64.c +LIB_SRC_ABI_APPLE_X64 = src/abi/abi_apple_x64.c +LIB_SRC_ABI_WIN64_X64 = src/abi/abi_win64_x64.c +LIB_SRC_ABI_RV64 = src/abi/abi_rv64.c + +LIB_SRCS = $(LIB_SRCS_NONARCH) +ifeq ($(KIT_OPT_ENABLED),1) +LIB_SRCS += $(LIB_SRCS_OPT) +endif +ifeq ($(KIT_INTERP_ENABLED),1) +LIB_SRCS += $(LIB_SRCS_INTERP) +endif +ifeq ($(KIT_AR_ENABLED),1) +LIB_SRCS += $(LIB_SRCS_API_AR) +endif +ifeq ($(KIT_DISASM_ENABLED),1) +LIB_SRCS += $(LIB_SRCS_API_DISASM) +endif +ifeq ($(KIT_DWARF_ENABLED),1) +LIB_SRCS += $(LIB_SRCS_DEBUG) +endif +ifeq ($(KIT_LINK_ENABLED),1) +LIB_SRCS += $(LIB_SRCS_API_LINK) $(LIB_SRCS_LINK) +endif +ifeq ($(KIT_DBG_ENABLED),1) +LIB_SRCS += $(LIB_SRCS_DBG) +endif +ifeq ($(KIT_EMU_ENABLED),1) +LIB_SRCS += $(LIB_SRCS_EMU) +endif +ifeq ($(KIT_CAS_ENABLED),1) +LIB_SRCS += $(LIB_SRCS_API_CAS) $(LIB_SRCS_DIST_CAS) $(LIB_SRCS_VENDOR_CAS) +endif +# Shared compression codecs (deflate + lz4 block): pulled in once if either the +# compress API or the pkg layer needs them. +KIT_NEED_CODEC := +ifeq ($(KIT_COMPRESS_ENABLED),1) +LIB_SRCS += $(LIB_SRCS_API_COMPRESS) $(LIB_SRCS_DIST_COMPRESS) +KIT_NEED_CODEC := 1 +endif +ifeq ($(KIT_PKG_ENABLED),1) +LIB_SRCS += $(LIB_SRCS_API_PKG) $(LIB_SRCS_DIST_PKG) $(LIB_SRCS_VENDOR_PKG) +KIT_NEED_CODEC := 1 +endif +ifeq ($(KIT_NEED_CODEC),1) +LIB_SRCS += $(LIB_SRCS_DIST_CODEC) +endif +ifeq ($(KIT_ARCH_AA64_ENABLED),1) +LIB_SRCS += $(LIB_SRCS_ARCH_AA64) +endif +ifeq ($(KIT_ARCH_X64_ENABLED),1) +LIB_SRCS += $(LIB_SRCS_ARCH_X64) +endif +ifeq ($(KIT_ARCH_RV64_ENABLED),1) +LIB_SRCS += $(LIB_SRCS_ARCH_RV64) +endif +ifeq ($(KIT_ARCH_WASM_ENABLED),1) +LIB_SRCS += $(LIB_SRCS_ARCH_WASM) +endif +ifeq ($(KIT_ARCH_C_TARGET_ENABLED),1) +LIB_SRCS += $(LIB_SRCS_ARCH_C_TARGET) +endif +ifneq ($(filter 1,$(KIT_ARCH_WASM_ENABLED) $(KIT_OBJ_WASM_ENABLED) $(KIT_LANG_WASM_ENABLED)),) +LIB_SRCS += $(LIB_SRCS_WASM_CORE) +LIB_SRCS += $(LIB_SRCS_OBJ_WASM) +endif +ifeq ($(KIT_OBJ_ELF_ENABLED),1) +LIB_SRCS += $(LIB_SRCS_OBJ_ELF) +endif +ifeq ($(KIT_OBJ_MACHO_ENABLED),1) +LIB_SRCS += $(LIB_SRCS_OBJ_MACHO) +endif +ifeq ($(KIT_OBJ_COFF_ENABLED),1) +LIB_SRCS += $(LIB_SRCS_OBJ_COFF) +endif +ifneq ($(filter 1,$(KIT_ARCH_AA64_ENABLED) $(KIT_ARCH_C_TARGET_ENABLED)),) +ifneq ($(filter 1,$(KIT_OBJ_ELF_ENABLED) $(KIT_OBJ_MACHO_ENABLED) $(KIT_OBJ_COFF_ENABLED)),) +LIB_SRCS += $(LIB_SRC_ABI_AAPCS64) +endif +ifeq ($(KIT_OBJ_MACHO_ENABLED),1) +LIB_SRCS += $(LIB_SRC_ABI_APPLE_ARM64) +endif +ifeq ($(KIT_OBJ_COFF_ENABLED),1) +LIB_SRCS += $(LIB_SRC_ABI_AAPCS64_WINDOWS) +endif +endif +ifneq ($(filter 1,$(KIT_ARCH_X64_ENABLED) $(KIT_ARCH_C_TARGET_ENABLED)),) +ifneq ($(filter 1,$(KIT_OBJ_ELF_ENABLED) $(KIT_OBJ_MACHO_ENABLED)),) +LIB_SRCS += $(LIB_SRC_ABI_SYSV_X64) +endif +ifeq ($(KIT_OBJ_MACHO_ENABLED),1) +LIB_SRCS += $(LIB_SRC_ABI_APPLE_X64) +endif +ifeq ($(KIT_OBJ_COFF_ENABLED),1) +LIB_SRCS += $(LIB_SRC_ABI_WIN64_X64) +endif +endif +ifneq ($(filter 1,$(KIT_ARCH_RV64_ENABLED) $(KIT_ARCH_C_TARGET_ENABLED)),) +ifeq ($(KIT_OBJ_ELF_ENABLED),1) +LIB_SRCS += $(LIB_SRC_ABI_RV64) +endif +endif + +# Per-frontend source sets. Each is gated by its KIT_LANG_*_ENABLED flag +# from mk/config.mk so the matching `#if` in src/api/lang_registry.c and +# the build agree on which frontends are compiled in. +LANG_CPP_SRCS := $(shell find lang/cpp -name '*.c' 2>/dev/null) +LANG_C_SRCS := $(shell find lang/c -name '*.c' 2>/dev/null) +LANG_WASM_SRCS := $(shell find lang/wasm -name '*.c' 2>/dev/null) +LANG_TOY_SRCS = $(wildcard lang/toy/*.c) + +LANG_OBJS = +ifeq ($(KIT_LANG_CPP_ENABLED),1) +LANG_OBJS += $(patsubst lang/cpp/%.c,$(BUILD_DIR)/lang/cpp/%.o,$(LANG_CPP_SRCS)) +endif +ifeq ($(KIT_LANG_C_ENABLED),1) +LANG_OBJS += $(patsubst lang/c/%.c,$(BUILD_DIR)/lang/c/%.o,$(LANG_C_SRCS)) +endif +ifeq ($(KIT_LANG_WASM_ENABLED),1) +LANG_OBJS += $(patsubst lang/wasm/%.c,$(BUILD_DIR)/lang/wasm/%.o,$(LANG_WASM_SRCS)) +endif +ifeq ($(KIT_LANG_TOY_ENABLED),1) +LANG_OBJS += $(patsubst lang/toy/%.c,$(BUILD_DIR)/lang/toy/%.o,$(LANG_TOY_SRCS)) +endif + +LIB_ASMS = +ifeq ($(KIT_JIT_ENABLED),1) +LIB_ASMS += $(LIB_SRCS_JIT_ASM) +endif + +LIB_OBJS = $(patsubst src/%.c,$(BUILD_DIR)/lib/%.o,$(filter src/%.c,$(LIB_SRCS))) \ + $(patsubst vendor/%.c,$(BUILD_DIR)/vendor/%.o,$(filter vendor/%.c,$(LIB_SRCS))) \ + $(LANG_OBJS) \ + $(patsubst src/%.S,$(BUILD_DIR)/lib/%.o,$(LIB_ASMS)) +LIB_DEPS = $(LIB_OBJS:.o=.d) diff --git a/mk/maint.mk b/mk/maint.mk @@ -0,0 +1,36 @@ +# mk/maint.mk +# =========================================================================== +# Developer maintenance targets: source formatting, the clangd compilation +# database, optimizer benchmarking, and clean. + +.PHONY: format compile-commands bench-opt clean + +# Format only the .c/.h files changed in the working tree (staged, unstaged, or +# new/untracked), restricted to the formatted roots and excluding test/pp. When +# nothing has changed, fall back to formatting every source file. +format: + @files=$$( { git diff --name-only --diff-filter=ACMR HEAD -- '*.c' '*.h'; \ + git ls-files --others --exclude-standard -- '*.c' '*.h'; } 2>/dev/null \ + | grep -E '^(src|include|driver|lang|test|rt)/' \ + | grep -vE '^test/pp/' \ + | sort -u ); \ + if [ -n "$$files" ]; then \ + echo "$$files" | xargs clang-format -i --style=google; \ + echo "$$files" | sed 's/^/formatted /'; \ + else \ + echo "no changed sources; formatting all"; \ + find src include driver lang test rt -path test/pp -prune -o \( -name '*.c' -o -name '*.h' \) -print | xargs clang-format -i --style=google; \ + fi + +# Regenerate the clangd compilation database (build/compile_commands.json). +# clangd auto-discovers it under build/; re-run after adding/removing sources +# or after `make clean`. +compile-commands: + python3 scripts/gen_compile_commands.py + +bench-opt: + $(MAKE) RELEASE=1 bin + @KIT='$(abspath build/release/kit)' bash scripts/opt_bench.sh + +clean: + rm -rf $(BUILD_DIR) diff --git a/mk/rt.mk b/mk/rt.mk @@ -0,0 +1,246 @@ +# mk/rt.mk +# =========================================================================== +# Runtime (libkit_rt.a) variant selection and per-variant source/flag +# derivation -> RT_OBJS_<variant> / RT_CFLAGS_<variant> / RT_ASFLAGS_<variant>. +# +# The build rules that consume these live in the top-level Makefile. This file +# is the data: the variant table, the host-native variant detection, the +# feature->source/flag groups, and the template that expands one variant into +# its concrete source/object/flag lists. Paths are root-relative. + +RT_BUILD_DIR ?= $(BUILD_DIR)/rt +RT_COMMON_CFLAGS = -Werror +RT_LIB_INCS = -Irt/lib/include/common -Irt/lib/impl + +RT_VARIANTS = \ + x86_64-linux \ + x86_64-apple-darwin \ + aarch64-linux \ + aarch64-apple-darwin \ + riscv64-linux \ + riscv64-elf \ + riscv64-elf-save-restore \ + aarch64-windows \ + x86_64-pc-windows \ + i386-linux \ + wasm32 \ + riscv32-elf \ + riscv32-elf-save-restore \ + arm-eabi-thumb2 \ + arm-eabi-thumb1 + +RT_HOST_MACHINE ?= $(shell uname -m 2>/dev/null || printf unknown) +RT_NATIVE_VARIANT = +ifeq ($(HOST_UNAME),Darwin) +ifneq ($(filter arm64 aarch64,$(RT_HOST_MACHINE)),) +RT_NATIVE_VARIANT = aarch64-apple-darwin +else ifneq ($(filter x86_64 amd64,$(RT_HOST_MACHINE)),) +RT_NATIVE_VARIANT = x86_64-apple-darwin +endif +else ifeq ($(HOST_UNAME),Linux) +ifneq ($(filter x86_64 amd64,$(RT_HOST_MACHINE)),) +RT_NATIVE_VARIANT = x86_64-linux +else ifneq ($(filter arm64 aarch64,$(RT_HOST_MACHINE)),) +RT_NATIVE_VARIANT = aarch64-linux +else ifneq ($(filter riscv64,$(RT_HOST_MACHINE)),) +RT_NATIVE_VARIANT = riscv64-linux +else ifneq ($(filter i386 i486 i586 i686,$(RT_HOST_MACHINE)),) +RT_NATIVE_VARIANT = i386-linux +endif +else ifneq ($(filter MINGW% MSYS% CYGWIN%,$(HOST_UNAME)),) +ifneq ($(filter x86_64 amd64,$(RT_HOST_MACHINE)),) +RT_NATIVE_VARIANT = x86_64-pc-windows +else ifneq ($(filter arm64 aarch64,$(RT_HOST_MACHINE)),) +RT_NATIVE_VARIANT = aarch64-windows +endif +endif + +RT_DEFAULT_VARIANTS ?= $(RT_NATIVE_VARIANT) + +# ---------- variant feature flags -------------------------------------------- +# TARGET - clang target triple +# ABI - lp64 | ilp32 | llp64 +# INT128 - 0 | 1 +# CORO - x86_64 | x86_64_win | i386 | aarch64 | +# arm32 | arm32_thumb1 | riscv32 | riscv64 | empty +# LDBL128 - 1 enables binary128 long double support +# SAVE_RESTORE - 1 enables RISC-V save-restore routines +# AEABI - thumb2 | thumb1 | empty +# ARCH_FLAGS - extra target-specific flags + +RT_x86_64-linux_TARGET = x86_64-linux-gnu +RT_x86_64-linux_ABI = lp64 +RT_x86_64-linux_INT128 = 1 +RT_x86_64-linux_CORO = x86_64 + +RT_x86_64-apple-darwin_TARGET = x86_64-apple-darwin +RT_x86_64-apple-darwin_ABI = lp64 +RT_x86_64-apple-darwin_INT128 = 1 +RT_x86_64-apple-darwin_CORO = x86_64 + +RT_aarch64-linux_TARGET = aarch64-linux-gnu +RT_aarch64-linux_ABI = lp64 +RT_aarch64-linux_INT128 = 1 +RT_aarch64-linux_CORO = aarch64 +RT_aarch64-linux_LDBL128 = 1 +RT_EXTRA_SRCS_aarch64-linux = rt/lib/coro/aarch64_elf.s + +RT_aarch64-apple-darwin_TARGET = aarch64-apple-darwin +RT_aarch64-apple-darwin_ABI = lp64 +RT_aarch64-apple-darwin_INT128 = 1 +RT_aarch64-apple-darwin_CORO = aarch64 +RT_EXTRA_SRCS_aarch64-apple-darwin = rt/lib/coro/aarch64_macho.s + +RT_aarch64-windows_TARGET = aarch64-w64-windows-gnu +RT_aarch64-windows_ABI = llp64 +RT_aarch64-windows_INT128 = 1 +RT_aarch64-windows_CORO = aarch64 +RT_aarch64-windows_HOSTED = 1 + +RT_riscv64-linux_TARGET = riscv64-linux-gnu +RT_riscv64-linux_ABI = lp64 +RT_riscv64-linux_INT128 = 1 +RT_riscv64-linux_CORO = riscv64 +# RISC-V `long double` is IEEE-754 binary128 per the psABI; ship the quad +# soft-float / __int128 runtime (fp_tf, fp_ti). +RT_riscv64-linux_LDBL128 = 1 +RT_riscv64-linux_ARCH_FLAGS = -mabi=lp64d -march=rv64imafd + +RT_riscv64-elf_TARGET = riscv64-unknown-elf +RT_riscv64-elf_ABI = lp64 +RT_riscv64-elf_INT128 = 1 +RT_riscv64-elf_CORO = riscv64 +RT_riscv64-elf_LDBL128 = 1 +RT_riscv64-elf_ARCH_FLAGS = -mabi=lp64 -march=rv64imafd + +RT_riscv64-elf-save-restore_TARGET = riscv64-unknown-elf +RT_riscv64-elf-save-restore_ABI = lp64 +RT_riscv64-elf-save-restore_INT128 = 1 +RT_riscv64-elf-save-restore_CORO = riscv64 +RT_riscv64-elf-save-restore_SAVE_RESTORE = 1 +RT_riscv64-elf-save-restore_LDBL128 = 1 +RT_riscv64-elf-save-restore_ARCH_FLAGS = -mabi=lp64 -march=rv64imafd + +RT_x86_64-pc-windows_TARGET = x86_64-pc-windows-msvc +RT_x86_64-pc-windows_ABI = llp64 +RT_x86_64-pc-windows_INT128 = 1 +RT_x86_64-pc-windows_CORO = x86_64_win +RT_x86_64-pc-windows_HOSTED = 1 + +RT_i386-linux_TARGET = i386-linux-gnu +RT_i386-linux_ABI = ilp32 +RT_i386-linux_INT128 = 0 +RT_i386-linux_CORO = i386 + +RT_wasm32_TARGET = wasm32-unknown-unknown +RT_wasm32_ABI = ilp32 +RT_wasm32_INT128 = 0 + +RT_riscv32-elf_TARGET = riscv32-unknown-elf +RT_riscv32-elf_ABI = ilp32 +RT_riscv32-elf_INT128 = 0 +RT_riscv32-elf_CORO = riscv32 +RT_riscv32-elf_ARCH_FLAGS = -mabi=ilp32 -march=rv32imafd + +RT_riscv32-elf-save-restore_TARGET = riscv32-unknown-elf +RT_riscv32-elf-save-restore_ABI = ilp32 +RT_riscv32-elf-save-restore_INT128 = 0 +RT_riscv32-elf-save-restore_CORO = riscv32 +RT_riscv32-elf-save-restore_SAVE_RESTORE = 1 +RT_riscv32-elf-save-restore_ARCH_FLAGS = -mabi=ilp32 -march=rv32imafd + +RT_arm-eabi-thumb2_TARGET = arm-none-eabi +RT_arm-eabi-thumb2_ABI = ilp32 +RT_arm-eabi-thumb2_INT128 = 0 +RT_arm-eabi-thumb2_CORO = arm32 +RT_arm-eabi-thumb2_AEABI = thumb2 + +RT_arm-eabi-thumb1_TARGET = arm-none-eabi +RT_arm-eabi-thumb1_ABI = ilp32 +RT_arm-eabi-thumb1_INT128 = 0 +RT_arm-eabi-thumb1_CORO = arm32_thumb1 +RT_arm-eabi-thumb1_AEABI = thumb1 + +# ---------- feature -> source/flag groups ------------------------------------ +RT_BASE_SRCS = \ + rt/lib/assert/assert.c \ + rt/lib/int/int.c \ + rt/lib/int/si_div.c \ + rt/lib/fp/fp.c \ + rt/lib/mem/mem.c \ + rt/lib/string/string.c \ + rt/lib/stdlib/stdlib.c \ + rt/lib/stdlib/qsort.c \ + rt/lib/stdio/printf.c \ + rt/lib/atomic/atomic_freestanding.c \ + rt/lib/cache/clear_cache.c \ + rt/lib/kit/ifunc_init.c + +RT_COMPILER_SRCS = \ + rt/lib/int/int.c \ + rt/lib/int/si_div.c \ + rt/lib/fp/fp.c \ + rt/lib/atomic/atomic_freestanding.c \ + rt/lib/cache/clear_cache.c \ + rt/lib/kit/ifunc_init.c + +RT_ABI_SRCS_lp64 = rt/lib/int64/int64.c +RT_ABI_SRCS_llp64 = rt/lib/int64/int64.c +RT_ABI_SRCS_ilp32 = rt/lib/int32/int32.c + +RT_ABI_INC_lp64 = -Irt/lib/include/lp64_le +RT_ABI_INC_llp64 = -Irt/lib/include/llp64_le +RT_ABI_INC_ilp32 = -Irt/lib/include/ilp32_le + +RT_CORO_SRCS_x86_64 = rt/lib/coro/x86_64.c rt/lib/coro/coro.c +RT_CORO_SRCS_x86_64_win = rt/lib/coro/x86_64_win.c rt/lib/coro/coro.c +RT_CORO_SRCS_i386 = rt/lib/coro/i386.c rt/lib/coro/coro.c +RT_CORO_SRCS_aarch64 = rt/lib/coro/aarch64.c rt/lib/coro/coro.c +RT_CORO_SRCS_arm32 = rt/lib/coro/arm32.c rt/lib/coro/coro.c +RT_CORO_SRCS_arm32_thumb1 = rt/lib/coro/arm32_thumb1.c rt/lib/coro/coro.c +RT_CORO_SRCS_riscv32 = rt/lib/coro/riscv32.c rt/lib/coro/coro.c +RT_CORO_SRCS_riscv64 = rt/lib/coro/riscv64.c rt/lib/coro/coro.c + +RT_LDBL128_SRCS = rt/lib/fp_tf/fp_tf.c rt/lib/fp_ti/fp_ti.c +RT_LDBL128_FLAGS = -Irt/lib/include/lp64_le_ldbl128 -DKITRT_LDBL128=1 + +RT_SAVE_RESTORE_SRCS_lp64 = rt/lib/riscv/rv64.S +RT_SAVE_RESTORE_SRCS_ilp32 = rt/lib/riscv/rv32.S +RT_SAVE_RESTORE_FLAGS = -msave-restore + +RT_AEABI_SRCS_thumb2 = rt/lib/arm/aeabi_thumb2.S rt/lib/arm/aeabi.c +RT_AEABI_SRCS_thumb1 = rt/lib/arm/aeabi_thumb1.S rt/lib/arm/aeabi.c +RT_AEABI_FLAGS_thumb2 = -march=armv7-a -mthumb -mfloat-abi=soft +RT_AEABI_FLAGS_thumb1 = -march=armv6-m -mthumb -mfloat-abi=soft + +# ---------- per-variant derivation ------------------------------------------- +# Expand one variant into its concrete source/object/flag lists. `:=` makes +# each list concrete at eval time so the rule template in the top-level +# Makefile can reference RT_OBJS_<variant> directly. +define RT_VARIANT_srcs +RT_SRCS_$(1) := \ + $$(if $$(RT_$(1)_HOSTED),$$(RT_COMPILER_SRCS),$$(RT_BASE_SRCS)) \ + $$(RT_ABI_SRCS_$$(RT_$(1)_ABI)) \ + $$(RT_CORO_SRCS_$$(RT_$(1)_CORO)) \ + $$(if $$(RT_$(1)_LDBL128),$$(RT_LDBL128_SRCS)) \ + $$(if $$(RT_$(1)_SAVE_RESTORE),$$(RT_SAVE_RESTORE_SRCS_$$(RT_$(1)_ABI))) \ + $$(RT_AEABI_SRCS_$$(RT_$(1)_AEABI)) \ + $$(RT_EXTRA_SRCS_$(1)) +RT_CFLAGS_$(1) := \ + $$(RT_COMMON_CFLAGS) $$(RT_LIB_INCS) \ + -target $$(RT_$(1)_TARGET) \ + -DHAS_INT128=$$(RT_$(1)_INT128) \ + $$(RT_ABI_INC_$$(RT_$(1)_ABI)) \ + $$(if $$(RT_$(1)_LDBL128),$$(RT_LDBL128_FLAGS)) \ + $$(if $$(RT_$(1)_CORO),-Irt/include) +RT_ASFLAGS_$(1) := \ + -target $$(RT_$(1)_TARGET) \ + -DHAS_INT128=$$(RT_$(1)_INT128) \ + -D__ASSEMBLER__=1 \ + $$(RT_ABI_INC_$$(RT_$(1)_ABI)) \ + $$(if $$(RT_$(1)_LDBL128),$$(RT_LDBL128_FLAGS)) \ + $$(if $$(RT_$(1)_CORO),-Irt/include) +RT_OBJS_$(1) := $$(patsubst rt/lib/%,$$(RT_BUILD_DIR)/$(1)/%.o,$$(RT_SRCS_$(1))) +endef + +$(foreach variant,$(RT_VARIANTS),$(eval $(call RT_VARIANT_srcs,$(variant)))) diff --git a/rt/Makefile b/rt/Makefile @@ -1,284 +0,0 @@ -# Included by the repository-root Makefile. Paths are root-relative. - -RT_CC ?= $(BIN) cc -RT_AR ?= $(BIN) ar -RT_AS ?= $(BIN) as -RT_AS_COMPILE_FLAGS ?= - -RT_BUILD_DIR ?= $(BUILD_DIR)/rt -RT_COMMON_CFLAGS = -Werror -RT_LIB_INCS = -Irt/lib/include/common -Irt/lib/impl - -RT_VARIANTS = \ - x86_64-linux \ - x86_64-apple-darwin \ - aarch64-linux \ - aarch64-apple-darwin \ - riscv64-linux \ - riscv64-elf \ - riscv64-elf-save-restore \ - aarch64-windows \ - x86_64-pc-windows \ - i386-linux \ - wasm32 \ - riscv32-elf \ - riscv32-elf-save-restore \ - arm-eabi-thumb2 \ - arm-eabi-thumb1 - -RT_HOST_MACHINE ?= $(shell uname -m 2>/dev/null || printf unknown) -RT_NATIVE_VARIANT = -ifeq ($(HOST_UNAME),Darwin) -ifneq ($(filter arm64 aarch64,$(RT_HOST_MACHINE)),) -RT_NATIVE_VARIANT = aarch64-apple-darwin -else ifneq ($(filter x86_64 amd64,$(RT_HOST_MACHINE)),) -RT_NATIVE_VARIANT = x86_64-apple-darwin -endif -else ifeq ($(HOST_UNAME),Linux) -ifneq ($(filter x86_64 amd64,$(RT_HOST_MACHINE)),) -RT_NATIVE_VARIANT = x86_64-linux -else ifneq ($(filter arm64 aarch64,$(RT_HOST_MACHINE)),) -RT_NATIVE_VARIANT = aarch64-linux -else ifneq ($(filter riscv64,$(RT_HOST_MACHINE)),) -RT_NATIVE_VARIANT = riscv64-linux -else ifneq ($(filter i386 i486 i586 i686,$(RT_HOST_MACHINE)),) -RT_NATIVE_VARIANT = i386-linux -endif -else ifneq ($(filter MINGW% MSYS% CYGWIN%,$(HOST_UNAME)),) -ifneq ($(filter x86_64 amd64,$(RT_HOST_MACHINE)),) -RT_NATIVE_VARIANT = x86_64-pc-windows -else ifneq ($(filter arm64 aarch64,$(RT_HOST_MACHINE)),) -RT_NATIVE_VARIANT = aarch64-windows -endif -endif - -RT_DEFAULT_VARIANTS ?= $(RT_NATIVE_VARIANT) - -.PHONY: rt rt-all-targets rt-no-native-target $(addprefix rt-,$(RT_VARIANTS)) clean-rt - -rt: $(if $(RT_DEFAULT_VARIANTS),$(addprefix rt-,$(RT_DEFAULT_VARIANTS)),rt-no-native-target) -rt-all-targets: $(addprefix rt-,$(RT_VARIANTS)) - -rt-no-native-target: - $(error unsupported native runtime target: HOST_UNAME=$(HOST_UNAME) RT_HOST_MACHINE=$(RT_HOST_MACHINE)) - -# ---------- variant feature flags -------------------------------------------- -# TARGET - clang target triple -# ABI - lp64 | ilp32 | llp64 -# INT128 - 0 | 1 -# CORO - x86_64 | x86_64_win | i386 | aarch64 | -# arm32 | arm32_thumb1 | riscv32 | riscv64 | empty -# LDBL128 - 1 enables binary128 long double support -# SAVE_RESTORE - 1 enables RISC-V save-restore routines -# AEABI - thumb2 | thumb1 | empty -# ARCH_FLAGS - extra target-specific flags - -RT_x86_64-linux_TARGET = x86_64-linux-gnu -RT_x86_64-linux_ABI = lp64 -RT_x86_64-linux_INT128 = 1 -RT_x86_64-linux_CORO = x86_64 - -RT_x86_64-apple-darwin_TARGET = x86_64-apple-darwin -RT_x86_64-apple-darwin_ABI = lp64 -RT_x86_64-apple-darwin_INT128 = 1 -RT_x86_64-apple-darwin_CORO = x86_64 - -RT_aarch64-linux_TARGET = aarch64-linux-gnu -RT_aarch64-linux_ABI = lp64 -RT_aarch64-linux_INT128 = 1 -RT_aarch64-linux_CORO = aarch64 -RT_aarch64-linux_LDBL128 = 1 -RT_EXTRA_SRCS_aarch64-linux = rt/lib/coro/aarch64_elf.s - -RT_aarch64-apple-darwin_TARGET = aarch64-apple-darwin -RT_aarch64-apple-darwin_ABI = lp64 -RT_aarch64-apple-darwin_INT128 = 1 -RT_aarch64-apple-darwin_CORO = aarch64 -RT_EXTRA_SRCS_aarch64-apple-darwin = rt/lib/coro/aarch64_macho.s - -RT_aarch64-windows_TARGET = aarch64-w64-windows-gnu -RT_aarch64-windows_ABI = llp64 -RT_aarch64-windows_INT128 = 1 -RT_aarch64-windows_CORO = aarch64 -RT_aarch64-windows_HOSTED = 1 - -RT_riscv64-linux_TARGET = riscv64-linux-gnu -RT_riscv64-linux_ABI = lp64 -RT_riscv64-linux_INT128 = 1 -RT_riscv64-linux_CORO = riscv64 -# RISC-V `long double` is IEEE-754 binary128 per the psABI; ship the quad -# soft-float / __int128 runtime (fp_tf, fp_ti). -RT_riscv64-linux_LDBL128 = 1 -RT_riscv64-linux_ARCH_FLAGS = -mabi=lp64d -march=rv64imafd - -RT_riscv64-elf_TARGET = riscv64-unknown-elf -RT_riscv64-elf_ABI = lp64 -RT_riscv64-elf_INT128 = 1 -RT_riscv64-elf_CORO = riscv64 -RT_riscv64-elf_LDBL128 = 1 -RT_riscv64-elf_ARCH_FLAGS = -mabi=lp64 -march=rv64imafd - -RT_riscv64-elf-save-restore_TARGET = riscv64-unknown-elf -RT_riscv64-elf-save-restore_ABI = lp64 -RT_riscv64-elf-save-restore_INT128 = 1 -RT_riscv64-elf-save-restore_CORO = riscv64 -RT_riscv64-elf-save-restore_SAVE_RESTORE = 1 -RT_riscv64-elf-save-restore_LDBL128 = 1 -RT_riscv64-elf-save-restore_ARCH_FLAGS = -mabi=lp64 -march=rv64imafd - -RT_x86_64-pc-windows_TARGET = x86_64-pc-windows-msvc -RT_x86_64-pc-windows_ABI = llp64 -RT_x86_64-pc-windows_INT128 = 1 -RT_x86_64-pc-windows_CORO = x86_64_win -RT_x86_64-pc-windows_HOSTED = 1 - -RT_i386-linux_TARGET = i386-linux-gnu -RT_i386-linux_ABI = ilp32 -RT_i386-linux_INT128 = 0 -RT_i386-linux_CORO = i386 - -RT_wasm32_TARGET = wasm32-unknown-unknown -RT_wasm32_ABI = ilp32 -RT_wasm32_INT128 = 0 - -RT_riscv32-elf_TARGET = riscv32-unknown-elf -RT_riscv32-elf_ABI = ilp32 -RT_riscv32-elf_INT128 = 0 -RT_riscv32-elf_CORO = riscv32 -RT_riscv32-elf_ARCH_FLAGS = -mabi=ilp32 -march=rv32imafd - -RT_riscv32-elf-save-restore_TARGET = riscv32-unknown-elf -RT_riscv32-elf-save-restore_ABI = ilp32 -RT_riscv32-elf-save-restore_INT128 = 0 -RT_riscv32-elf-save-restore_CORO = riscv32 -RT_riscv32-elf-save-restore_SAVE_RESTORE = 1 -RT_riscv32-elf-save-restore_ARCH_FLAGS = -mabi=ilp32 -march=rv32imafd - -RT_arm-eabi-thumb2_TARGET = arm-none-eabi -RT_arm-eabi-thumb2_ABI = ilp32 -RT_arm-eabi-thumb2_INT128 = 0 -RT_arm-eabi-thumb2_CORO = arm32 -RT_arm-eabi-thumb2_AEABI = thumb2 - -RT_arm-eabi-thumb1_TARGET = arm-none-eabi -RT_arm-eabi-thumb1_ABI = ilp32 -RT_arm-eabi-thumb1_INT128 = 0 -RT_arm-eabi-thumb1_CORO = arm32_thumb1 -RT_arm-eabi-thumb1_AEABI = thumb1 - -# ---------- sources and flags derived from features -------------------------- -RT_BASE_SRCS = \ - rt/lib/assert/assert.c \ - rt/lib/int/int.c \ - rt/lib/int/si_div.c \ - rt/lib/fp/fp.c \ - rt/lib/mem/mem.c \ - rt/lib/string/string.c \ - rt/lib/stdlib/stdlib.c \ - rt/lib/stdlib/qsort.c \ - rt/lib/stdio/printf.c \ - rt/lib/atomic/atomic_freestanding.c \ - rt/lib/cache/clear_cache.c \ - rt/lib/kit/ifunc_init.c - -RT_COMPILER_SRCS = \ - rt/lib/int/int.c \ - rt/lib/int/si_div.c \ - rt/lib/fp/fp.c \ - rt/lib/atomic/atomic_freestanding.c \ - rt/lib/cache/clear_cache.c \ - rt/lib/kit/ifunc_init.c - -RT_ABI_SRCS_lp64 = rt/lib/int64/int64.c -RT_ABI_SRCS_llp64 = rt/lib/int64/int64.c -RT_ABI_SRCS_ilp32 = rt/lib/int32/int32.c - -RT_ABI_INC_lp64 = -Irt/lib/include/lp64_le -RT_ABI_INC_llp64 = -Irt/lib/include/llp64_le -RT_ABI_INC_ilp32 = -Irt/lib/include/ilp32_le - -RT_CORO_SRCS_x86_64 = rt/lib/coro/x86_64.c rt/lib/coro/coro.c -RT_CORO_SRCS_x86_64_win = rt/lib/coro/x86_64_win.c rt/lib/coro/coro.c -RT_CORO_SRCS_i386 = rt/lib/coro/i386.c rt/lib/coro/coro.c -RT_CORO_SRCS_aarch64 = rt/lib/coro/aarch64.c rt/lib/coro/coro.c -RT_CORO_SRCS_arm32 = rt/lib/coro/arm32.c rt/lib/coro/coro.c -RT_CORO_SRCS_arm32_thumb1 = rt/lib/coro/arm32_thumb1.c rt/lib/coro/coro.c -RT_CORO_SRCS_riscv32 = rt/lib/coro/riscv32.c rt/lib/coro/coro.c -RT_CORO_SRCS_riscv64 = rt/lib/coro/riscv64.c rt/lib/coro/coro.c - -RT_LDBL128_SRCS = rt/lib/fp_tf/fp_tf.c rt/lib/fp_ti/fp_ti.c -RT_LDBL128_FLAGS = -Irt/lib/include/lp64_le_ldbl128 -DKITRT_LDBL128=1 - -RT_SAVE_RESTORE_SRCS_lp64 = rt/lib/riscv/rv64.S -RT_SAVE_RESTORE_SRCS_ilp32 = rt/lib/riscv/rv32.S -RT_SAVE_RESTORE_FLAGS = -msave-restore - -RT_AEABI_SRCS_thumb2 = rt/lib/arm/aeabi_thumb2.S rt/lib/arm/aeabi.c -RT_AEABI_SRCS_thumb1 = rt/lib/arm/aeabi_thumb1.S rt/lib/arm/aeabi.c -RT_AEABI_FLAGS_thumb2 = -march=armv7-a -mthumb -mfloat-abi=soft -RT_AEABI_FLAGS_thumb1 = -march=armv6-m -mthumb -mfloat-abi=soft - -define RT_VARIANT_template -RT_SRCS_$(1) := \ - $$(if $$(RT_$(1)_HOSTED),$$(RT_COMPILER_SRCS),$$(RT_BASE_SRCS)) \ - $$(RT_ABI_SRCS_$$(RT_$(1)_ABI)) \ - $$(RT_CORO_SRCS_$$(RT_$(1)_CORO)) \ - $$(if $$(RT_$(1)_LDBL128),$$(RT_LDBL128_SRCS)) \ - $$(if $$(RT_$(1)_SAVE_RESTORE),$$(RT_SAVE_RESTORE_SRCS_$$(RT_$(1)_ABI))) \ - $$(RT_AEABI_SRCS_$$(RT_$(1)_AEABI)) \ - $$(RT_EXTRA_SRCS_$(1)) -RT_CFLAGS_$(1) := \ - $$(RT_COMMON_CFLAGS) $$(RT_LIB_INCS) \ - -target $$(RT_$(1)_TARGET) \ - -DHAS_INT128=$$(RT_$(1)_INT128) \ - $$(RT_ABI_INC_$$(RT_$(1)_ABI)) \ - $$(if $$(RT_$(1)_LDBL128),$$(RT_LDBL128_FLAGS)) \ - $$(if $$(RT_$(1)_CORO),-Irt/include) -RT_ASFLAGS_$(1) := \ - -target $$(RT_$(1)_TARGET) \ - -DHAS_INT128=$$(RT_$(1)_INT128) \ - -D__ASSEMBLER__=1 \ - $$(RT_ABI_INC_$$(RT_$(1)_ABI)) \ - $$(if $$(RT_$(1)_LDBL128),$$(RT_LDBL128_FLAGS)) \ - $$(if $$(RT_$(1)_CORO),-Irt/include) -RT_OBJS_$(1) := $$(patsubst rt/lib/%,$$(RT_BUILD_DIR)/$(1)/%.o,$$(RT_SRCS_$(1))) - -rt-$(1): $$(RT_BUILD_DIR)/$(1)/libkit_rt.a - -# Regular (not order-only) dep on $(BIN): kit compiles and archives its own -# runtime, so a codegen or `ar` change in the compiler must rebuild the rt. -# The archive lists $(RT_OBJS) explicitly rather than $^ so the kit binary -# (now a regular prereq) is not itself archived. -# -# Depend on rt/Makefile too: the member list (RT_*_SRCS) lives here, and -# `ar rcs` only adds/updates members. When the list grows, an existing -# archive whose objects happen to be newer would otherwise never regenerate -# and would silently drop the new members (e.g. a missing __clear_cache -# breaking links). With the makefile as a prereq, any list edit re-fires the -# `rm -f` + full re-archive below so the archive always matches RT_OBJS. -$$(RT_BUILD_DIR)/$(1)/libkit_rt.a: $$(RT_OBJS_$(1)) rt/Makefile $$(BIN) - @mkdir -p $$(dir $$@) - @rm -f $$@ - $$(RT_AR) rcs $$@ $$(RT_OBJS_$(1)) - -$$(RT_BUILD_DIR)/$(1)/%.s.o: rt/lib/%.s $$(BIN) - @mkdir -p $$(dir $$@) - $$(RT_AS) $$(RT_ASFLAGS_$(1)) $$(RT_AS_COMPILE_FLAGS) $$< -o $$@ - -$$(RT_BUILD_DIR)/$(1)/%.S.o: rt/lib/%.S $$(BIN) - @mkdir -p $$(dir $$@) - $$(RT_AS) $$(RT_ASFLAGS_$(1)) $$(RT_AS_COMPILE_FLAGS) $$< -o $$@ - -$$(RT_BUILD_DIR)/$(1)/%.o: rt/lib/% $$(BIN) - @mkdir -p $$(dir $$@) - $$(RT_CC) $$(RT_CFLAGS_$(1)) -c $$< -o $$@ - -$$(RT_BUILD_DIR)/$(1)/atomic/atomic_freestanding.c.o: rt/lib/atomic/atomic_common.inc -endef - -$(foreach variant,$(RT_VARIANTS),$(eval $(call RT_VARIANT_template,$(variant)))) - -clean: clean-rt - -clean-rt: - rm -rf $(RT_BUILD_DIR)