# version 1.4
.SUFFIXES:
-.EXPORT_ALL_VARIABLES:
.DELETE_ON_ERROR:
-# allow overrides
-KMOD_SOURCE_DIR ?= cc
+#--------------------------------------------------------------------------------
+# defaults for environment variables (override from outer make/env as needed)
+
+# Kernel build tree, which is part of the Linux system, use running kernel if unset
+KMOD_BUILD_DIR ?=
-# allow cross-compile override via KDIR; else default to running kernel
-KDIR ?=
-BUILD_DIR ?= $(if $(KDIR),$(KDIR),/lib/modules/$(shell uname -r)/build)
+# Authored source directory (single dir)
+KMOD_SOURCE_DIR ?= cc
-# default, then canonicalize to absolute regardless of source
-OUTPUT_DIR ?= scratchpad/kmod
-OUTPUT_DIR := $(abspath $(OUTPUT_DIR))
+# Extra compiler flags passed to Kbuild (e.g., -I $(KMOD_SOURCE_DIR))
+# RT uses unified header/source files
+KMOD_CCFLAGS ?=
-# authored basenames (without suffix)
-BASE_LIST := $(patsubst %.kmod.c,%,$(notdir $(wildcard $(KMOD_SOURCE_DIR)/*.kmod.c)))
+# Staging/output directory for Kbuild
+KMOD_OUTPUT_DIR ?= scratchpad/kmod
-# optional library sources (without suffix) to include inside modules
-# set KMOD_INCLUDE_LIB=0 to disable
+# Include *.lib.c into modules (1=yes, 0=no)
KMOD_INCLUDE_LIB ?= 1
+
+
+
+
+#--------------------------------------------------------------------------------
+# derived variables (computed from the above)
+
+# Canonicalize output dir
+kmod_output_dir := $(abspath $(KMOD_OUTPUT_DIR))
+
+# Select kernel build dir (cross or running kernel)
+kmod_build_dir := $(if $(KMOD_BUILD_DIR),$(KMOD_BUILD_DIR),/lib/modules/$(shell uname -r)/build)
+
+# Authored basenames (without suffix)
+base_list := $(patsubst %.kmod.c,%,$(notdir $(wildcard $(KMOD_SOURCE_DIR)/*.kmod.c)))
+
+# Optional library sources (without suffix) to include inside modules
ifeq ($(KMOD_INCLUDE_LIB),1)
-LIB_BASE := $(patsubst %.lib.c,%,$(notdir $(wildcard $(KMOD_SOURCE_DIR)/*.lib.c)))
+lib_base := $(patsubst %.lib.c,%,$(notdir $(wildcard $(KMOD_SOURCE_DIR)/*.lib.c)))
else
-LIB_BASE :=
+lib_base :=
endif
-# staged sources (kept namespaced to prevent .o collisions)
-ALL_KMOD_C := $(addsuffix .kmod.c,$(addprefix $(OUTPUT_DIR)/,$(BASE_LIST)))
-ALL_LIB_C := $(addsuffix .lib.c,$(addprefix $(OUTPUT_DIR)/,$(LIB_BASE)))
+# Staged sources (kept namespaced to prevent .o collisions)
+all_kmod_c := $(addsuffix .kmod.c,$(addprefix $(kmod_output_dir)/,$(base_list)))
+all_lib_c := $(addsuffix .lib.c,$(addprefix $(kmod_output_dir)/,$(lib_base)))
+
+
+
+#--------------------------------------------------------------------------------
+# targets
.PHONY: usage
usage:
.PHONY: information
information:
@echo "KMOD_SOURCE_DIR: " $(KMOD_SOURCE_DIR)
- @echo "BUILD_DIR: " $(BUILD_DIR)
- @echo "OUTPUT_DIR: " $(OUTPUT_DIR)
- @echo "BASE_LIST: " $(BASE_LIST)
- @echo "LIB_BASE: " $(LIB_BASE)
- @echo "ALL_KMOD_C: " $(ALL_KMOD_C)
- @echo "ALL_LIB_C: " $(ALL_LIB_C)
+ @echo "kmod_build_dir: " $(kmod_build_dir)
+ @echo "KMOD_OUTPUT_DIR: " $(KMOD_OUTPUT_DIR)
+ @echo "kmod_output_dir: " $(kmod_output_dir)
+ @echo "base_list: " $(base_list)
+ @echo "lib_base: " $(lib_base)
+ @echo "all_kmod_c: " $(all_kmod_c)
+ @echo "all_lib_c: " $(all_lib_c)
@echo "KMOD_INCLUDE_LIB=" $(KMOD_INCLUDE_LIB)
-ifndef BASE_LIST
-$(warning No *.kmod.c found under $(KMOD_SOURCE_DIR); nothing to build)
+
+ifeq ($(strip $(base_list)),)
+ $(warning No *.kmod.c found under $(KMOD_SOURCE_DIR); nothing to build)
endif
# --- Parallel-safe preparation as real targets ---
# ensure the staging dir exists (order-only prereq)
-$(OUTPUT_DIR):
- @mkdir -p "$(OUTPUT_DIR)"
+$(kmod_output_dir):
+ @mkdir -p "$(kmod_output_dir)"
# generate the Kbuild control Makefile
-# generate the Kbuild control Makefile
-$(OUTPUT_DIR)/Makefile: | $(OUTPUT_DIR)
+$(kmod_output_dir)/Makefile: | $(kmod_output_dir)
@{ \
printf "ccflags-y += %s\n" "$(KMOD_CCFLAGS)"; \
- printf "obj-m := %s\n" "$(foreach m,$(BASE_LIST),$(m).o)"; \
- for m in $(BASE_LIST); do \
+ printf "obj-m := %s\n" "$(foreach m,$(base_list),$(m).o)"; \
+ for m in $(base_list); do \
printf "%s-objs := %s.kmod.o" "$$m" "$$m"; \
- for lb in $(LIB_BASE); do printf " %s.lib.o" "$$lb"; done; \
+ for lb in $(lib_base); do printf " %s.lib.o" "$$lb"; done; \
printf "\n"; \
done; \
} > "$@"
# stage kmod sources (one rule per file; parallelizable)
-$(OUTPUT_DIR)/%.kmod.c: $(KMOD_SOURCE_DIR)/%.kmod.c | $(OUTPUT_DIR)
+$(kmod_output_dir)/%.kmod.c: $(KMOD_SOURCE_DIR)/%.kmod.c | $(kmod_output_dir)
@echo "--- Stage: $@ ---"
@ln -sf "$<" "$@" 2>/dev/null || { rm -f "$@"; cp "$<" "$@"; }
# stage library sources (optional; also parallelizable)
-$(OUTPUT_DIR)/%.lib.c: $(KMOD_SOURCE_DIR)/%.lib.c | $(OUTPUT_DIR)
+$(kmod_output_dir)/%.lib.c: $(KMOD_SOURCE_DIR)/%.lib.c | $(kmod_output_dir)
@echo "--- Stage: $@ ---"
@ln -sf "$<" "$@" 2>/dev/null || { rm -f "$@"; cp "$<" "$@"; }
# rebuild inputs for 'modules'
.PHONY: modules
-modules: $(OUTPUT_DIR)/Makefile $(ALL_KMOD_C) $(ALL_LIB_C)
- @echo "--- Invoking Kbuild for Modules: $(BASE_LIST) ---"
- $(MAKE) -C "$(BUILD_DIR)" M="$(OUTPUT_DIR)" modules
+modules: $(kmod_output_dir)/Makefile $(all_kmod_c) $(all_lib_c)
+ @echo "--- Invoking Kbuild for Modules: $(base_list) ---"
+ $(MAKE) -C "$(kmod_build_dir)" M="$(kmod_output_dir)" modules
# top-level convenience target
.PHONY: kmod
# quality-of-life: allow 'make scratchpad/kmod/foo.ko' after batch build
-$(OUTPUT_DIR)/%.ko: modules
+$(kmod_output_dir)/%.ko: modules
@true
.PHONY: clean
clean:
- @if [ -d "$(OUTPUT_DIR)" ]; then \
- echo "--- Cleaning Kbuild Artifacts in $(OUTPUT_DIR) ---"; \
- $(MAKE) -C "$(BUILD_DIR)" M="$(OUTPUT_DIR)" clean; \
+ @if [ -d "$(kmod_output_dir)" ]; then \
+ echo "--- Cleaning Kbuild Artifacts in $(kmod_output_dir) ---"; \
+ $(MAKE) -C "$(kmod_build_dir)" M="$(kmod_output_dir)" clean; \
# belt & suspenders: nuke common leftovers regardless of Kbuild's behavior
- rm -f "$(OUTPUT_DIR)"/*.o \
- "$(OUTPUT_DIR)"/*.ko \
- "$(OUTPUT_DIR)"/*.mod \
- "$(OUTPUT_DIR)"/*.mod.c \
- "$(OUTPUT_DIR)"/modules.order \
- "$(OUTPUT_DIR)"/Module.symvers \
- "$(OUTPUT_DIR)"/.*.cmd 2>/dev/null || true; \
- rm -rf "$(OUTPUT_DIR)"/.tmp_versions 2>/dev/null || true; \
+ rm -f "$(kmod_output_dir)"/*.o \
+ "$(kmod_output_dir)"/*.ko \
+ "$(kmod_output_dir)"/*.mod \
+ "$(kmod_output_dir)"/*.mod.c \
+ "$(kmod_output_dir)"/modules.order \
+ "$(kmod_output_dir)"/Module.symvers \
+ "$(kmod_output_dir)"/.*.cmd 2>/dev/null || true; \
+ rm -rf "$(kmod_output_dir)"/.tmp_versions 2>/dev/null || true; \
# remove staged sources we created (symlinks or copies)
- find "$(OUTPUT_DIR)" -maxdepth 1 -type l -name '*.kmod.c' -delete 2>/dev/null || true; \
- find "$(OUTPUT_DIR)" -maxdepth 1 -type l -name '*.lib.c' -delete 2>/dev/null || true; \
- find "$(OUTPUT_DIR)" -maxdepth 1 -type f -name '*.kmod.c' -delete 2>/dev/null || true; \
- find "$(OUTPUT_DIR)" -maxdepth 1 -type f -name '*.lib.c' -delete 2>/dev/null || true; \
+ find "$(kmod_output_dir)" -maxdepth 1 -type l -name '*.kmod.c' -delete 2>/dev/null || true; \
+ find "$(kmod_output_dir)" -maxdepth 1 -type l -name '*.lib.c' -delete 2>/dev/null || true; \
+ find "$(kmod_output_dir)" -maxdepth 1 -type f -name '*.kmod.c' -delete 2>/dev/null || true; \
+ find "$(kmod_output_dir)" -maxdepth 1 -type f -name '*.lib.c' -delete 2>/dev/null || true; \
fi
# files have two suffixes by convention, e.g.: X.lib.c or Y.CLI.c
.SUFFIXES:
-.EXPORT_ALL_VARIABLES:
.DELETE_ON_ERROR:
#--------------------------------------------------------------------------------
MACHINE_DIR ?= scratchpad
LN_FLAGS ?=
-ifeq ($(strip $(C)),)
- $(error target_lib_CLI.mk: no C compiler specified)
-endif
-
#--------------------------------------------------------------------------------
# derived variables
# source discovery (single dir)
-C_SOURCE_LIB := $(wildcard $(C_SOURCE_DIR)/*.lib.c)
-C_SOURCE_EXEC := $(wildcard $(C_SOURCE_DIR)/*.CLI.c)
+c_source_lib := $(wildcard $(C_SOURCE_DIR)/*.lib.c)
+c_source_exec := $(wildcard $(C_SOURCE_DIR)/*.CLI.c)
# remove suffix to get base name
-C_BASE_LIB := $(sort $(patsubst %.lib.c,%, $(notdir $(C_SOURCE_LIB))))
-C_BASE_EXEC := $(sort $(patsubst %.CLI.c,%, $(notdir $(C_SOURCE_EXEC))))
+c_base_lib := $(sort $(patsubst %.lib.c,%, $(notdir $(c_source_lib))))
+c_base_exec := $(sort $(patsubst %.CLI.c,%, $(notdir $(c_source_exec))))
# two sets of object files, one for the lib, and one for the CLI programs
-OBJECT_LIB := $(patsubst %, scratchpad/%.lib.o, $(C_BASE_LIB))
-OBJECT_EXEC := $(patsubst %, scratchpad/%.CLI.o, $(C_BASE_EXEC))
+object_lib := $(patsubst %, scratchpad/%.lib.o, $(c_base_lib))
+object_exec := $(patsubst %, scratchpad/%.CLI.o, $(c_base_exec))
-# executables are made from EXEC sources
-EXEC := $(patsubst %, $(MACHINE_DIR)/%, $(C_BASE_EXEC))
+# executables are made from exec_ sources
+exec_ := $(patsubst %, $(MACHINE_DIR)/%, $(c_base_exec))
#--------------------------------------------------------------------------------
# pull in dependencies
--include $(OBJECT_LIB:.o=.d) $(OBJECT_EXEC:.o=.d)
+-include $(object_lib:.o=.d) $(object_exec:.o=.d)
#--------------------------------------------------------------------------------
information:
@printf "· → Unicode middle dot — visible: [%b]\n" "·"
@echo "C_SOURCE_DIR: " $(C_SOURCE_DIR)
- @echo "C_SOURCE_LIB: " $(C_SOURCE_LIB)
- @echo "C_SOURCE_EXEC: " $(C_SOURCE_EXEC)
- @echo "C_BASE_LIB: " $(C_BASE_LIB)
- @echo "C_BASE_EXEC: " $(C_BASE_EXEC)
- @echo "OBJECT_LIB: " $(OBJECT_LIB)
- @echo "OBJECT_EXEC: " $(OBJECT_EXEC)
- @echo "EXEC: " $(EXEC)
+ @echo "c_source_lib: " $(c_source_lib)
+ @echo "c_source_exec: " $(c_source_exec)
+ @echo "c_base_lib: " $(c_base_lib)
+ @echo "c_base_exec: " $(c_base_exec)
+ @echo "object_lib: " $(object_lib)
+ @echo "object_exec: " $(object_exec)
+ @echo "exec_: " $(exec_)
.PHONY: library
library: $(LIBRARY_FILE)
-$(LIBRARY_FILE): $(OBJECT_LIB)
- @if [ -s "$@" ] || [ -n "$(OBJECT_LIB)" ]; then \
+$(LIBRARY_FILE): $(object_lib)
+ @if [ -s "$@" ] || [ -n "$(object_lib)" ]; then \
echo "ar rcs $@ $^"; \
ar rcs $@ $^; \
else \
fi
#.PHONY: CLI
-#CLI: $(LIBRARY_FILE) $(EXEC)
+#CLI: $(LIBRARY_FILE) $(exec_)
.PHONY: CLI
-CLI: library $(EXEC)
+CLI: library $(exec_)
# generally better to use the project local clean scripts, but this will make it so that the make targets can be run again
.PHONY: clean
clean:
rm -f $(LIBRARY_FILE)
- for obj in $(OBJECT_LIB) $(OBJECT_EXEC); do rm -f $$obj $${obj%.o}.d || true; done
- for i in $(EXEC); do [ -e $$i ] && rm $$i || true; done
+ for obj in $(object_lib) $(object_exec); do rm -f $$obj $${obj%.o}.d || true; done
+ for i in $(exec_); do [ -e $$i ] && rm $$i || true; done
# recipes