kit

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

Makefile (12098B)


      1 CC      = clang
      2 AR      = ar
      3 RELEASE ?= 0
      4 ifeq ($(RELEASE),1)
      5 BUILD_DIR ?= build/release
      6 else
      7 BUILD_DIR ?= build
      8 endif
      9 
     10 .DEFAULT_GOAL := all
     11 
     12 # Parallelize the library/binary/runtime build by default: appending -j to
     13 # MAKEFLAGS at the top level turns plain `make`, `make lib`, `make bin`, etc.
     14 # into parallel builds without the caller passing -j. Two guards keep it
     15 # scoped:
     16 #   - MAKELEVEL 0 only, so a recursive $(MAKE) (bootstrap/dist/rt) inherits the
     17 #     parent jobserver instead of re-forcing -j (which would disable the
     18 #     jobserver and oversubscribe cores).
     19 #   - skip when any requested goal is a test target: the suites are heavy and
     20 #     their output interleaves badly under -j, so `make test-*` stays serial.
     21 # A caller's explicit `-j`/`-jN` still wins; override with `make NCPU=1 ...`.
     22 NCPU ?= $(shell getconf _NPROCESSORS_ONLN 2>/dev/null || echo 4)
     23 ifeq ($(MAKELEVEL),0)
     24 ifeq ($(filter test%,$(MAKECMDGOALS)),)
     25 MAKEFLAGS += -j$(NCPU)
     26 endif
     27 endif
     28 
     29 # Build setup, in dependency order. Each include owns one concern and only
     30 # reads the variables produced by the ones before it:
     31 #   env.mk         host detection, driver/env source selection, SDK sysroot
     32 #   config.mk      KIT_*_ENABLED component flags (mirrored from config.h)
     33 #   flags.mk       compiler/linker flag derivation + the .build-config stamp
     34 #   lib_srcs.mk    libkit source selection -> LIB_OBJS / LIB_DEPS
     35 #   driver_srcs.mk driver source selection -> DRIVER_OBJS / DRIVER_DEPS
     36 #   rt.mk          runtime variant/source selection -> RT_OBJS_<variant>
     37 include mk/env.mk
     38 include mk/config.mk
     39 include mk/flags.mk
     40 include mk/lib_srcs.mk
     41 include mk/driver_srcs.mk
     42 include mk/rt.mk
     43 
     44 LIB_AR = $(BUILD_DIR)/libkit.a
     45 BIN    = $(BUILD_DIR)/kit
     46 KIT_DRIVER_CUSTOM_BIN ?= $(BUILD_DIR)/kit-custom
     47 
     48 # ===========================================================================
     49 # Main build sequence: objects -> archive -> binary.
     50 # ===========================================================================
     51 
     52 .PHONY: all lib bin custom-bin
     53 
     54 all: lib bin rt
     55 
     56 lib: $(LIB_AR)
     57 
     58 bin: $(BIN) $(BUILD_DIR)/support/rt
     59 
     60 custom-bin: $(KIT_DRIVER_CUSTOM_BIN) $(dir $(KIT_DRIVER_CUSTOM_BIN))support/rt
     61 
     62 # A kit binary resolves its runtime support from <bindir>/support/rt (an
     63 # `rt` symlink in a `support` dir beside the executable). This pattern rule
     64 # installs that symlink for ANY directory ending in /support/rt, so an
     65 # alternative build dir — or a snapshot binary copied next to its own
     66 # support/ (see `perf-golden` in mk/maint.mk) — is self-contained and finds
     67 # its runtime from any cwd, no in-checkout requirement.
     68 %/support/rt:
     69 	@mkdir -p $(@D)
     70 	ln -sfn $(abspath rt) $@
     71 
     72 # Rebuild the archive from scratch (rm first): `ar rcs` only adds/updates, so
     73 # recreating it ensures a removed .c file also drops its .o from the archive.
     74 $(LIB_AR): $(LIB_OBJS) $(BUILD_CONFIG)
     75 	@mkdir -p $(dir $@)
     76 	@rm -f $@
     77 	$(AR) rcs $@ $(LIB_OBJS)
     78 
     79 $(BIN): $(DRIVER_OBJS) $(LIB_AR) $(BUILD_CONFIG)
     80 	$(CC) $(HOST_LDFLAGS) -o $@ $(DRIVER_OBJS) $(LIB_AR) $(HOST_LDLIBS)
     81 
     82 CUSTOM_DRIVER_OBJS = $(patsubst $(BUILD_DIR)/driver/%.o,$(BUILD_DIR)/custom-driver/%.o,$(DRIVER_OBJS))
     83 CUSTOM_DRIVER_EXT_CFLAGS = $(if $(KIT_DRIVER_EXT_REGISTER),-DKIT_DRIVER_EXT_REGISTER=$(KIT_DRIVER_EXT_REGISTER))
     84 
     85 $(KIT_DRIVER_CUSTOM_BIN): $(CUSTOM_DRIVER_OBJS) $(LIB_AR) $(KIT_DRIVER_EXT_OBJS) $(BUILD_CONFIG)
     86 	@mkdir -p $(dir $@)
     87 	$(CC) $(HOST_LDFLAGS) -o $@ $(CUSTOM_DRIVER_OBJS) $(KIT_DRIVER_EXT_OBJS) $(LIB_AR) $(HOST_LDLIBS)
     88 
     89 # ---------------------------------------------------------------------------
     90 # Compile rules, grouped by source tree: src/ (libkit) -> lang/ (frontends) ->
     91 # vendor/ -> driver/. Each tree gets its own include scope; see mk/flags.mk for
     92 # the *_CFLAGS definitions and the rationale behind each tree's include set.
     93 #
     94 # The libkit (src/, vendor/, lang/) objects use path-flattened basenames so the
     95 # `ar` member names in libkit.a are unique (see `flatobjs` in mk/lib_srcs.mk);
     96 # the basename no longer matches the source, so these are generated explicit
     97 # rules rather than `%`-pattern rules. The per-group compile flags are attached
     98 # as a target-specific RULE_CFLAGS, not threaded through $(call) — the flag
     99 # strings can contain commas (e.g. -fsanitize=address,undefined). The driver/
    100 # objects are NOT archived (they link directly), so they keep simple patterns.
    101 # ---------------------------------------------------------------------------
    102 
    103 # $(1)=source  $(2)=tree root to strip  $(3)=dest subdir under BUILD_DIR
    104 define libkit_obj_rule
    105 $(call flatobjs,$(1),$(2),$(3)): $(1) Makefile $$(BUILD_CONFIG)
    106 	@mkdir -p $$(@D)
    107 	$$(CC) $$(RULE_CFLAGS) $$(DEPFLAGS) -c $$< -o $$@
    108 endef
    109 
    110 # --- src/: libkit core (C + asm), freestanding, hidden visibility -----------
    111 $(foreach s,$(LIB_SRCS_C_GENERAL) $(LIB_ASMS),$(eval $(call libkit_obj_rule,$(s),src,lib)))
    112 $(call flatobjs,$(LIB_SRCS_C_GENERAL) $(LIB_ASMS),src,lib): RULE_CFLAGS = $(LIB_CFLAGS)
    113 
    114 # lang_registry.c is the one libkit source that crosses into lang/*; it
    115 # uses -Ilang so the frontend headers can be reached as "c/c.h" etc.
    116 ifneq ($(LIB_SRCS_LANGREG),)
    117 $(foreach s,$(LIB_SRCS_LANGREG),$(eval $(call libkit_obj_rule,$(s),src,lib)))
    118 $(call flatobjs,$(LIB_SRCS_LANGREG),src,lib): RULE_CFLAGS = $(FREESTANDING_CFLAGS) $(LIB_VISIBILITY_CFLAGS) -Iinclude -Ilang -Isrc
    119 endif
    120 
    121 # --- lang/: frontends, each with its own include set ------------------------
    122 ifeq ($(KIT_LANG_CPP_ENABLED),1)
    123 $(foreach s,$(LANG_CPP_SRCS),$(eval $(call libkit_obj_rule,$(s),lang,lang)))
    124 $(call flatobjs,$(LANG_CPP_SRCS),lang,lang): RULE_CFLAGS = $(FREESTANDING_CFLAGS) $(LIB_VISIBILITY_CFLAGS) -Iinclude -Ilang/cpp
    125 endif
    126 
    127 # The C frontend includes the lexer and preprocessor headers (pp/pp.h,
    128 # lex/lex.h) which now live under lang/cpp/, and cpp_support.h is the
    129 # shared substrate. So lang/c objects build with -Ilang/cpp -Ilang/c.
    130 ifeq ($(KIT_LANG_C_ENABLED),1)
    131 $(foreach s,$(LANG_C_SRCS),$(eval $(call libkit_obj_rule,$(s),lang,lang)))
    132 $(call flatobjs,$(LANG_C_SRCS),lang,lang): RULE_CFLAGS = $(FREESTANDING_CFLAGS) $(LIB_VISIBILITY_CFLAGS) -Iinclude -Ilang/cpp -Ilang/c
    133 endif
    134 
    135 # The Wasm frontend is the one lang/* tree that reaches internal headers: it
    136 # includes "wasm/wasm.h" to share src/wasm/ (the module/encode/decode library)
    137 # with the Wasm backend, so it gets -Isrc. lang/c and lang/cpp deliberately do
    138 # not — they see only the public include/ surface.
    139 ifeq ($(KIT_LANG_WASM_ENABLED),1)
    140 $(foreach s,$(LANG_WASM_SRCS),$(eval $(call libkit_obj_rule,$(s),lang,lang)))
    141 $(call flatobjs,$(LANG_WASM_SRCS),lang,lang): RULE_CFLAGS = $(FREESTANDING_CFLAGS) $(LIB_VISIBILITY_CFLAGS) -Iinclude -Isrc -Ilang/wasm
    142 endif
    143 
    144 ifeq ($(KIT_LANG_TOY_ENABLED),1)
    145 $(foreach s,$(LANG_TOY_SRCS),$(eval $(call libkit_obj_rule,$(s),lang,lang)))
    146 $(call flatobjs,$(LANG_TOY_SRCS),lang,lang): RULE_CFLAGS = $(FREESTANDING_CFLAGS) $(LIB_VISIBILITY_CFLAGS) -Iinclude -Ilang/toy
    147 endif
    148 
    149 # --- vendor/: third-party sources compiled into libkit ----------------------
    150 # Vendored third-party sources (monocypher) compiled into libkit. Same
    151 # freestanding flags as the rest of the library; symbols stay hidden.
    152 ifneq ($(LIB_SRCS_VENDOR),)
    153 $(foreach s,$(LIB_SRCS_VENDOR),$(eval $(call libkit_obj_rule,$(s),vendor,vendor)))
    154 $(call flatobjs,$(LIB_SRCS_VENDOR),vendor,vendor): RULE_CFLAGS = $(LIB_CFLAGS)
    155 endif
    156 
    157 # --- driver/: hosted CLI; env/ is the OS/libc adapter sub-tree --------------
    158 $(BUILD_DIR)/driver/%.o: driver/%.c Makefile $(BUILD_CONFIG)
    159 	@mkdir -p $(dir $@)
    160 	$(CC) $(DRIVER_CFLAGS) $(DEPFLAGS) -c $< -o $@
    161 
    162 # version.o carries the injected VERSION / build-id / host-triple. It depends on
    163 # the dedicated version sentinel (not BUILD_CONFIG) so only this one TU rebuilds
    164 # when those change. The defines append to DRIVER_CFLAGS for this target only
    165 # (the pattern rule above uses $(DRIVER_CFLAGS) directly). See mk/flags.mk.
    166 $(BUILD_DIR)/driver/version.o $(BUILD_DIR)/custom-driver/version.o: $(VERSION_CONFIG)
    167 $(BUILD_DIR)/driver/version.o $(BUILD_DIR)/custom-driver/version.o: \
    168 	DRIVER_CFLAGS += $(KIT_VERSION_DEFS)
    169 
    170 # Generated update-channel URL + trust-anchor set. Keep it out of the public
    171 # headers and attach its include path only to the one driver translation unit.
    172 $(RELEASE_CONFIG_HEADER): FORCE scripts/gen_release_config.sh $(KIT_RELEASE_PUBKEYS_EFFECTIVE)
    173 	@sh scripts/gen_release_config.sh "$@" "$(KIT_UPDATE_INDEX_URL)" $(KIT_RELEASE_PUBKEYS_EFFECTIVE)
    174 
    175 $(BUILD_DIR)/driver/release_key.o $(BUILD_DIR)/custom-driver/release_key.o: $(RELEASE_CONFIG_HEADER)
    176 $(BUILD_DIR)/driver/release_key.o $(BUILD_DIR)/custom-driver/release_key.o: \
    177 	DRIVER_CFLAGS += -I$(BUILD_DIR)/generated
    178 
    179 $(BUILD_DIR)/driver/env/%.o: driver/env/%.c Makefile $(BUILD_CONFIG)
    180 	@mkdir -p $(dir $@)
    181 	$(CC) $(DRIVER_ENV_CFLAGS) $(DRIVER_ENV_OS_CFLAGS) $(DEPFLAGS) -c $< -o $@
    182 
    183 $(BUILD_DIR)/custom-driver/%.o: driver/%.c Makefile $(BUILD_CONFIG)
    184 	@mkdir -p $(dir $@)
    185 	$(CC) $(DRIVER_CFLAGS) $(CUSTOM_DRIVER_EXT_CFLAGS) $(DEPFLAGS) -c $< -o $@
    186 
    187 $(BUILD_DIR)/custom-driver/env/%.o: driver/env/%.c Makefile $(BUILD_CONFIG)
    188 	@mkdir -p $(dir $@)
    189 	$(CC) $(DRIVER_ENV_CFLAGS) $(DRIVER_ENV_OS_CFLAGS) $(CUSTOM_DRIVER_EXT_CFLAGS) $(DEPFLAGS) -c $< -o $@
    190 
    191 # ===========================================================================
    192 # Runtime (libkit_rt.a): kit compiles and archives its own runtime, one
    193 # variant per target. The variant table and per-variant source/flag lists come
    194 # from mk/rt.mk; this section is the per-variant build rules expanded over it.
    195 # ===========================================================================
    196 
    197 RT_CC ?= $(BIN) cc
    198 RT_AR ?= $(if $(filter 1,$(KIT_TOOL_AR_ENABLED)),$(BIN) ar,$(AR))
    199 RT_AS ?= $(BIN) as
    200 RT_AS_COMPILE_FLAGS ?=
    201 
    202 .PHONY: rt rt-all-targets rt-no-native-target $(addprefix rt-,$(RT_VARIANTS))
    203 
    204 rt: $(if $(RT_DEFAULT_VARIANTS),$(addprefix rt-,$(RT_DEFAULT_VARIANTS)),rt-no-native-target)
    205 rt-all-targets: $(addprefix rt-,$(RT_VARIANTS))
    206 
    207 rt-no-native-target:
    208 	$(error unsupported native runtime target: HOST_UNAME=$(HOST_UNAME) RT_HOST_MACHINE=$(RT_HOST_MACHINE))
    209 
    210 define RT_VARIANT_rules
    211 rt-$(1): $$(RT_BUILD_DIR)/$(1)/libkit_rt.a
    212 
    213 # Regular (not order-only) dep on $(BIN): kit compiles and archives its own
    214 # runtime, so a codegen or `ar` change in the compiler must rebuild the rt.
    215 # The archive lists $(RT_OBJS) explicitly rather than $^ so the kit binary
    216 # (now a regular prereq) is not itself archived.
    217 #
    218 # Depend on mk/rt.mk + this Makefile too: the member list (RT_*_SRCS) lives in
    219 # mk/rt.mk and `ar rcs` only adds/updates members. When the list grows, an
    220 # existing archive whose objects happen to be newer would otherwise never
    221 # regenerate and would silently drop the new members (e.g. a missing
    222 # __clear_cache breaking links). With the makefiles as prereqs, any list edit
    223 # re-fires the `rm -f` + full re-archive below so the archive always matches
    224 # RT_OBJS.
    225 $$(RT_BUILD_DIR)/$(1)/libkit_rt.a: $$(RT_OBJS_$(1)) mk/rt.mk Makefile $$(BIN)
    226 	@mkdir -p $$(dir $$@)
    227 	@rm -f $$@
    228 	$$(RT_AR) rcs $$@ $$(RT_OBJS_$(1))
    229 
    230 $$(RT_BUILD_DIR)/$(1)/%.s.o: rt/lib/%.s $$(BIN)
    231 	@mkdir -p $$(dir $$@)
    232 	$$(RT_AS) $$(RT_ASFLAGS_$(1)) $$(RT_AS_COMPILE_FLAGS) $$< -o $$@
    233 
    234 $$(RT_BUILD_DIR)/$(1)/%.S.o: rt/lib/%.S $$(BIN)
    235 	@mkdir -p $$(dir $$@)
    236 	$$(RT_AS) $$(RT_ASFLAGS_$(1)) $$(RT_AS_COMPILE_FLAGS) $$< -o $$@
    237 
    238 $$(RT_BUILD_DIR)/$(1)/%.o: rt/lib/% $$(BIN)
    239 	@mkdir -p $$(dir $$@)
    240 	$$(RT_CC) $$(RT_CFLAGS_$(1)) -c $$< -o $$@
    241 
    242 $$(RT_BUILD_DIR)/$(1)/atomic/atomic_freestanding.c.o: rt/lib/atomic/atomic_common.inc
    243 endef
    244 
    245 $(foreach variant,$(RT_VARIANTS),$(eval $(call RT_VARIANT_rules,$(variant))))
    246 
    247 # ===========================================================================
    248 # Bootstrap, dist, and maintenance targets live in their own includes.
    249 # ===========================================================================
    250 include mk/bootstrap.mk
    251 include mk/dist.mk
    252 include mk/maint.mk
    253 
    254 -include $(LIB_DEPS)
    255 -include $(DRIVER_DEPS)
    256 
    257 include mk/test.mk
    258 # Optional: the portability test-orchestration targets (test-cross/test-selfhost/
    259 # provision). -include so a tracked-files-only ship (e.g. the freebsd/linux
    260 # self-host bootstrap) that omits an as-yet-uncommitted port.mk still builds kit.
    261 -include mk/port.mk