commit 5716bb7b4a506bdee79e1670ba42fe9f6b8fd763
parent 99709d87da2bf980f84076321e793e5908c060b6
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Mon, 1 Jun 2026 09:36:54 -0700
make: cut Makefile-load overhead from ~507 to ~25 child processes
Two parse-time fixes that make every `make` invocation (any target) pay a
fraction of what it did before — ~2.45s down to ~0.20s of pure parse work:
- mk/config.mk: parse all CFREE_*_ENABLED flags from include/cfree/config.h
in a single awk pass + foreach/eval, instead of one `awk` per flag (38 -> 1
process). The header stays the single source of truth.
- Makefile: give the `$(shell find ...)` source-list variables `:=` (simple)
flavor instead of `=` (recursive). As recursive vars they were re-expanded
~20x apiece through the LIB_SRCS aggregation chain, re-spawning `find` each
time (462 finds per parse). With `:=` each find runs exactly once (21 total).
Computed LIB_SRCS / LIB_OBJS / DRIVER_SRCS / LANG_OBJS and all flag values are
byte-identical before and after, so the build output is unchanged.
Diffstat:
| M | Makefile | | | 44 | ++++++++++++++++++++++++-------------------- |
| M | mk/config.mk | | | 58 | ++++++++-------------------------------------------------- |
2 files changed, 32 insertions(+), 70 deletions(-)
diff --git a/Makefile b/Makefile
@@ -109,11 +109,15 @@ LIB_SRCS_NONARCH = $(LIB_SRCS_ABI_CORE) \
$(LIB_SRCS_CORE) \
$(LIB_SRCS_OBJ_CORE)
-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)
+# 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 ($(CFREE_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))
@@ -145,10 +149,10 @@ ifneq ($(CFREE_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)
+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 ($(CFREE_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))
@@ -164,21 +168,21 @@ 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_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
-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) \
+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)
+LIB_SRCS_LINK := $(shell find src/link -name '*.c' 2>/dev/null)
ifneq ($(CFREE_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_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
@@ -272,9 +276,9 @@ endif
# Per-frontend source sets. Each is gated by its CFREE_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_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 =
diff --git a/mk/config.mk b/mk/config.mk
@@ -2,53 +2,11 @@
# Makefile drops the same sources that #if drops from the compile.
#
# Single source of truth is the header; this file just parses it.
-CFG_HDR := include/cfree/config.h
-cfg_flag = $(shell awk '/^\#define $(1)[ \t]/{print $$3; exit}' $(CFG_HDR))
-
-CFREE_ARCH_AA64_ENABLED := $(call cfg_flag,CFREE_ARCH_AA64_ENABLED)
-CFREE_ARCH_X64_ENABLED := $(call cfg_flag,CFREE_ARCH_X64_ENABLED)
-CFREE_ARCH_RV64_ENABLED := $(call cfg_flag,CFREE_ARCH_RV64_ENABLED)
-CFREE_ARCH_WASM_ENABLED := $(call cfg_flag,CFREE_ARCH_WASM_ENABLED)
-CFREE_ARCH_C_TARGET_ENABLED := $(call cfg_flag,CFREE_ARCH_C_TARGET_ENABLED)
-
-CFREE_OBJ_ELF_ENABLED := $(call cfg_flag,CFREE_OBJ_ELF_ENABLED)
-CFREE_OBJ_MACHO_ENABLED := $(call cfg_flag,CFREE_OBJ_MACHO_ENABLED)
-CFREE_OBJ_COFF_ENABLED := $(call cfg_flag,CFREE_OBJ_COFF_ENABLED)
-CFREE_OBJ_WASM_ENABLED := $(call cfg_flag,CFREE_OBJ_WASM_ENABLED)
-
-CFREE_LANG_ASM_ENABLED := $(call cfg_flag,CFREE_LANG_ASM_ENABLED)
-CFREE_LANG_CPP_ENABLED := $(call cfg_flag,CFREE_LANG_CPP_ENABLED)
-CFREE_LANG_C_ENABLED := $(call cfg_flag,CFREE_LANG_C_ENABLED)
-CFREE_LANG_TOY_ENABLED := $(call cfg_flag,CFREE_LANG_TOY_ENABLED)
-CFREE_LANG_WASM_ENABLED := $(call cfg_flag,CFREE_LANG_WASM_ENABLED)
-
-CFREE_OPT_ENABLED := $(call cfg_flag,CFREE_OPT_ENABLED)
-
-CFREE_AR_ENABLED := $(call cfg_flag,CFREE_AR_ENABLED)
-CFREE_DISASM_ENABLED := $(call cfg_flag,CFREE_DISASM_ENABLED)
-CFREE_DWARF_ENABLED := $(call cfg_flag,CFREE_DWARF_ENABLED)
-CFREE_LINK_ENABLED := $(call cfg_flag,CFREE_LINK_ENABLED)
-CFREE_JIT_ENABLED := $(call cfg_flag,CFREE_JIT_ENABLED)
-CFREE_DBG_ENABLED := $(call cfg_flag,CFREE_DBG_ENABLED)
-CFREE_EMU_ENABLED := $(call cfg_flag,CFREE_EMU_ENABLED)
-CFREE_INTERP_ENABLED := $(call cfg_flag,CFREE_INTERP_ENABLED)
-
-CFREE_TOOL_CC_ENABLED := $(call cfg_flag,CFREE_TOOL_CC_ENABLED)
-CFREE_TOOL_CHECK_ENABLED := $(call cfg_flag,CFREE_TOOL_CHECK_ENABLED)
-CFREE_TOOL_CPP_ENABLED := $(call cfg_flag,CFREE_TOOL_CPP_ENABLED)
-CFREE_TOOL_AS_ENABLED := $(call cfg_flag,CFREE_TOOL_AS_ENABLED)
-CFREE_TOOL_LD_ENABLED := $(call cfg_flag,CFREE_TOOL_LD_ENABLED)
-CFREE_TOOL_AR_ENABLED := $(call cfg_flag,CFREE_TOOL_AR_ENABLED)
-CFREE_TOOL_RANLIB_ENABLED := $(call cfg_flag,CFREE_TOOL_RANLIB_ENABLED)
-CFREE_TOOL_STRIP_ENABLED := $(call cfg_flag,CFREE_TOOL_STRIP_ENABLED)
-CFREE_TOOL_OBJCOPY_ENABLED := $(call cfg_flag,CFREE_TOOL_OBJCOPY_ENABLED)
-CFREE_TOOL_OBJDUMP_ENABLED := $(call cfg_flag,CFREE_TOOL_OBJDUMP_ENABLED)
-CFREE_TOOL_DBG_ENABLED := $(call cfg_flag,CFREE_TOOL_DBG_ENABLED)
-CFREE_TOOL_RUN_ENABLED := $(call cfg_flag,CFREE_TOOL_RUN_ENABLED)
-CFREE_TOOL_EMU_ENABLED := $(call cfg_flag,CFREE_TOOL_EMU_ENABLED)
-CFREE_TOOL_NM_ENABLED := $(call cfg_flag,CFREE_TOOL_NM_ENABLED)
-CFREE_TOOL_SIZE_ENABLED := $(call cfg_flag,CFREE_TOOL_SIZE_ENABLED)
-CFREE_TOOL_ADDR2LINE_ENABLED := $(call cfg_flag,CFREE_TOOL_ADDR2LINE_ENABLED)
-CFREE_TOOL_STRINGS_ENABLED := $(call cfg_flag,CFREE_TOOL_STRINGS_ENABLED)
-CFREE_TOOL_CAS_ENABLED := $(call cfg_flag,CFREE_TOOL_CAS_ENABLED)
-CFREE_TOOL_PKG_ENABLED := $(call cfg_flag,CFREE_TOOL_PKG_ENABLED)
+#
+# Parse every `CFREE_*_ENABLED` flag from the header in a single awk pass — one
+# process for the whole file rather than one `awk` per flag — then define each
+# as an identically named make variable. An absent flag stays unset/empty,
+# exactly as the old per-flag lookups behaved.
+CFG_HDR := include/cfree/config.h
+CFG_DEFS := $(shell awk '/^\#define CFREE_[A-Z0-9_]+_ENABLED[ \t]/{print $$2"="$$3}' $(CFG_HDR))
+$(foreach kv,$(CFG_DEFS),$(eval $(kv)))