# ============================================================================== # mk/Kconfig.mk — shared Kconfig bridge for Makefile and Makefile.starkernel # ============================================================================== # # Included by both build systems, after each has finished resolving its own # ARCH. The two Makefiles canonicalize aarch64 differently (hosted Makefile: # aarch64 -> arm64, for ARCH_DIR; kernel Makefile: aarch64 -> aarch64, for # ARCH) -- so rather than this file re-deriving an architecture directory # name of its own, the including Makefile must set KCONFIG_ARCH_DIR to # whatever *it* already builds objects under, immediately before the # `include mk/Kconfig.mk` line. # # Config lives per-architecture under build/$(KCONFIG_ARCH_DIR)/ rather than # a single root .config, because this project's own QEMU acceptance workflow # builds all three kernel architectures back-to-back in one script, in the # same working directory -- a shared root .config would desync from whichever # arch is actually being built the moment any symbol has an arch-conditional # default. build/ is already gitignored and already per-arch. # # Phase 2 status: this bridge is wired but genuinely inert for anyone who # hasn't opted in. Nothing in either Makefile reads a $(CONFIG_FOO) variable # yet -- see the `ifneq ($(wildcard $(KCONFIG_CONFIG_FILE)),)` guard below. # Until a developer runs one of the targets this file defines (menuconfig, # xconfig, config, oldconfig, a *_defconfig), no build/$(ARCH)/.config exists, # the guard is false, and this file contributes nothing to a build -- today's # plain `?=` knobs remain the only thing driving -D flags. Later phases # repoint specific knob families from $(VAR) to $(CONFIG_VAR) one at a time; # this file does not change when they do. ifndef KCONFIG_ARCH_DIR $(error mk/Kconfig.mk: KCONFIG_ARCH_DIR must be set by the including Makefile before `include mk/Kconfig.mk`) endif KCONFIG_TOOLDIR := tools/kconfig KCONFIG_CONF := $(KCONFIG_TOOLDIR)/conf KCONFIG_MCONF := $(KCONFIG_TOOLDIR)/mconf KCONFIG_QCONF := $(KCONFIG_TOOLDIR)/qconf KCONFIG_ROOT := Kconfig KCONFIG_BUILD_DIR := build/$(KCONFIG_ARCH_DIR) KCONFIG_CONFIG_FILE := $(KCONFIG_BUILD_DIR)/.config KCONFIG_AUTOCONF_FILE := $(KCONFIG_BUILD_DIR)/include/config/auto.conf KCONFIG_AUTOHEADER_FILE := $(KCONFIG_BUILD_DIR)/include/generated/autoconf.h KCONFIG_RUSTCCFG_FILE := $(KCONFIG_BUILD_DIR)/include/generated/rustc_cfg # conf/confdata.c honors these four env vars directly (getenv("KCONFIG_CONFIG") # / KCONFIG_AUTOCONFIG / KCONFIG_AUTOHEADER / KCONFIG_RUSTCCFG) -- without all # four set, the split per-symbol files, auto.conf/autoconf.h, and rustc_cfg # fall back to bare include/config, include/generated relative to $(CURDIR), # which pollutes the real source tree. Confirmed by observation while # validating this file -- rustc_cfg is easy to miss since StarForth has no # Rust code; conf.c writes it unconditionally regardless. export KCONFIG_CONFIG := $(KCONFIG_CONFIG_FILE) export KCONFIG_AUTOCONFIG := $(KCONFIG_AUTOCONF_FILE) export KCONFIG_AUTOHEADER := $(KCONFIG_AUTOHEADER_FILE) export KCONFIG_RUSTCCFG := $(KCONFIG_RUSTCCFG_FILE) # Build the vendored host tools on demand. tools/kconfig/Makefile builds each # frontend independently, so `oldconfig`/`config`/`defconfig`/`menuconfig` # never pull in qconf's Qt dependency unless xconfig is actually requested. $(KCONFIG_CONF): $(MAKE) -C $(KCONFIG_TOOLDIR) conf $(KCONFIG_MCONF): $(MAKE) -C $(KCONFIG_TOOLDIR) mconf $(KCONFIG_QCONF): $(MAKE) -C $(KCONFIG_TOOLDIR) qconf .PHONY: menuconfig xconfig config oldconfig savedefconfig menuconfig: $(KCONFIG_MCONF) @mkdir -p $(KCONFIG_BUILD_DIR) $(KCONFIG_MCONF) $(KCONFIG_ROOT) xconfig: $(KCONFIG_QCONF) @mkdir -p $(KCONFIG_BUILD_DIR) $(KCONFIG_QCONF) $(KCONFIG_ROOT) config: $(KCONFIG_CONF) @mkdir -p $(KCONFIG_BUILD_DIR) $(KCONFIG_CONF) $(KCONFIG_ROOT) oldconfig: $(KCONFIG_CONF) @mkdir -p $(KCONFIG_BUILD_DIR) $(KCONFIG_CONF) --oldconfig $(KCONFIG_ROOT) savedefconfig: $(KCONFIG_CONF) $(KCONFIG_CONF) --savedefconfig=defconfig.out $(KCONFIG_ROOT) @echo "Wrote defconfig.out -- review and move into configs/ if it should be kept" # make hosted_standard_defconfig / make kernel_amd64_defconfig / etc. # Filename under configs/ matches the target name exactly, same convention # as the upstream kernel's arch/*/configs/*_defconfig. %_defconfig: $(KCONFIG_CONF) @mkdir -p $(KCONFIG_BUILD_DIR) $(KCONFIG_CONF) --defconfig=configs/$@ $(KCONFIG_ROOT) # Auto-remake bridge: a genuine `include`, not an order-only prerequisite, # so Make's native "remake included makefiles, then restart before # dispatching any -jN jobs" behavior fully serializes "regenerate config" # before "compile anything" -- for free, with no hand-maintained # prerequisite list. Deliberately not the include/version.h-style # order-only pattern (Makefile.starkernel:49-53/656-658), which needed its # own special-cased -j/clean workaround once already. # # Guarded on the config file already existing: until a developer opts in via # one of the targets above, build/$(ARCH)/.config does not exist, this # include is skipped entirely, and the bridge contributes zero behavior # change to a plain `make`/`make clean`. This is what keeps Phase 2 honestly # inert rather than inert-in-name-only. KCONFIG_ACTIVE := ifneq ($(wildcard $(KCONFIG_CONFIG_FILE)),) KCONFIG_ACTIVE := 1 $(KCONFIG_AUTOCONF_FILE): $(KCONFIG_CONFIG_FILE) $(KCONFIG_CONF) @mkdir -p $(KCONFIG_BUILD_DIR) $(KCONFIG_CONF) --syncconfig $(KCONFIG_ROOT) include $(KCONFIG_AUTOCONF_FILE) endif # ============================================================================== # Per-knob bridge macros for repointing a Makefile's own $(VAR) from a bare # historical default to the Kconfig-fed $(CONFIG_VAR), one knob family at a # time (see the phased cutover in the Kconfig migration plan). Both preserve # today's behavior exactly when KCONFIG_ACTIVE is unset (no .config yet) -- # in that branch this is just $(VAR) ?= default, same as before the knob was # ever touched. Command-line/environment overrides of $(VAR) always win # regardless of which branch fires: Make never lets an in-makefile # assignment, `?=` or `:=`, override a value already supplied on the command # line, so `make ROLLING_WINDOW_SIZE=8192` keeps working identically whether # or not a .config is present. # # $(eval $(call kconfig_bool,STRICT_PTR,1)) # -- for Kconfig `bool` symbols; auto.conf writes CONFIG_FOO=y or omits # the line entirely for n, so this maps y -> 1, anything else -> 0 (the # C side has always taken 0/1 integers here, never y/n). # # $(eval $(call kconfig_int,ROLLING_WINDOW_SIZE,4096)) # -- for Kconfig `int` (and, since auto.conf writes `string` defaults # unquoted too, `string`-typed numeric-literal symbols like the SSM_* # thresholds) symbols. $(or ...) covers both "Kconfig inactive" and # "Kconfig active but this symbol's `depends on` was unmet, so it never # appears in auto.conf at all" (e.g. TRANSITION_WINDOW_SIZE when # ENABLE_PIPELINING=n) -- both fall back to the same historical default # rather than emitting an empty -D value. define kconfig_bool ifeq ($(KCONFIG_ACTIVE),1) $1 := $$(if $$(filter y,$$(CONFIG_$1)),1,0) else $1 ?= $2 endif endef define kconfig_int ifeq ($(KCONFIG_ACTIVE),1) $1 := $$(or $$(CONFIG_$1),$2) else $1 ?= $2 endif endef