.
authorThomas Walker Lynch <eknp9n@reasoningtechnology.com>
Wed, 22 Oct 2025 08:15:47 +0000 (08:15 +0000)
committerThomas Walker Lynch <eknp9n@reasoningtechnology.com>
Wed, 22 Oct 2025 08:15:47 +0000 (08:15 +0000)
developer/make/environment_RT_1.mk
developer/make/target_kmod.mk
developer/make/target_library_cli.mk

index 84eb5db..af850d4 100644 (file)
@@ -1,21 +1,30 @@
 # makefile environment variable defaults.
-#  cc is the name of the C compiler, a file called <name>.c is C source code.
+# cc is the name of the C compiler, a file called <name>.c is C source code.
+# RT uses header integrated C source files, i.e. the source and the header are the same file
 
 SHELL=/bin/bash
 
-#ECHO= echo -e
-#ECHO= echo
+# environment_RT_1.mk
+
 ECHO := printf "%b\n"
 
+C_SOURCE_DIR     := cc
+KMOD_SOURCE_DIR  := cc
+
+C                := gcc
+CFLAGS           := -std=gnu11 -Wall -Wextra -Wpedantic -finput-charset=UTF-8
+CFLAGS           += -MMD -MP
+CFLAGS           += -I $(C_SOURCE_DIR)
+
+KMOD_CCFLAGS    := -I $(KMOD_SOURCE_DIR)
+
+LIBNAME         := $(PROJECT)
+LIBNAME         := $(subst -,_,$(LIBNAME))
+
+LIBDIR          := scratchpad
+LIBFILE         := $(LIBDIR)/lib$(LIBNAME).a
+
+LINKFLAGS       := -L$(LIBDIR) -L/lib64 -L/lib
 
-# sources found in these subdirectories:
-SRCDIR_LIST=cc
-LIBDIR     := scratchpad
-LIBFILE    := $(LIBDIR)/lib.a
-LINKFLAGS  := -L$(LIBDIR) -L/lib64 -L/lib
-EXECDIR    := scratchpad
+EXECDIR         := scratchpad
 
-C=gcc
-CFLAGS=-std=gnu11 -Wall -Wextra -Wpedantic -finput-charset=UTF-8
-CFLAGS += -MMD -MP
-LINKFLAGS=-L$(LIBDIR) -L/lib64 -L/lib
index d24269d..6fc30e3 100644 (file)
@@ -4,19 +4,27 @@
 
 .SUFFIXES:
 .EXPORT_ALL_VARIABLES:
+.DELETE_ON_ERROR:
 
-SOURCE_DIR  := cc
-BUILD_DIR   := /lib/modules/$(shell uname -r)/build
-OUTPUT_DIR  := $(abspath scratchpad/kmod)   # dedicated kmod staging/build dir
+# allow overrides
+KMOD_SOURCE_DIR ?= cc
+
+# allow cross-compile override via KDIR; else default to running kernel
+KDIR        ?=
+BUILD_DIR   ?= $(if $(KDIR),$(KDIR),/lib/modules/$(shell uname -r)/build)
+
+# default, then canonicalize to absolute regardless of source
+OUTPUT_DIR  ?= scratchpad/kmod
+OUTPUT_DIR  := $(abspath $(OUTPUT_DIR))
 
 # authored basenames (without suffix)
-BASE_LIST   := $(patsubst %.kmod.c,%,$(notdir $(wildcard $(SOURCE_DIR)/*.kmod.c)))
+BASE_LIST   := $(patsubst %.kmod.c,%,$(notdir $(wildcard $(KMOD_SOURCE_DIR)/*.kmod.c)))
 
 # optional library sources (without suffix) to include inside modules
 # set KMOD_INCLUDE_LIB=0 to disable
 KMOD_INCLUDE_LIB ?= 1
 ifeq ($(KMOD_INCLUDE_LIB),1)
-LIB_BASE   := $(patsubst %.lib.c,%,$(notdir $(wildcard $(SOURCE_DIR)/*.lib.c)))
+LIB_BASE   := $(patsubst %.lib.c,%,$(notdir $(wildcard $(KMOD_SOURCE_DIR)/*.lib.c)))
 else
 LIB_BASE   :=
 endif
@@ -35,7 +43,7 @@ version:
 
 .PHONY: information
 information:
-       @echo "SOURCE_DIR:   " $(SOURCE_DIR)
+       @echo "KMOD_SOURCE_DIR:   " $(KMOD_SOURCE_DIR)
        @echo "BUILD_DIR:    " $(BUILD_DIR)
        @echo "OUTPUT_DIR:   " $(OUTPUT_DIR)
        @echo "BASE_LIST:    " $(BASE_LIST)
@@ -45,16 +53,17 @@ information:
        @echo "KMOD_INCLUDE_LIB=" $(KMOD_INCLUDE_LIB)
 
 ifndef BASE_LIST
-$(warning No *.kmod.c found under $(SOURCE_DIR); nothing to build)
+$(warning No *.kmod.c found under $(KMOD_SOURCE_DIR); nothing to build)
 endif
 
-.PHONY: kmod
-kmod: _prepare modules
+# --- Parallel-safe preparation as real targets ---
 
-.PHONY: _prepare
-_prepare:
+# ensure the staging dir exists (order-only prereq)
+$(OUTPUT_DIR):
        @mkdir -p "$(OUTPUT_DIR)"
-       # fresh Kbuild control file — one obj per module; each module also links lib objs (if any)
+
+# generate the Kbuild control Makefile
+$(OUTPUT_DIR)/Makefile: | $(OUTPUT_DIR)
        @{ \
          printf "obj-m := %s\n" "$(foreach m,$(BASE_LIST),$(m).o)"; \
          for m in $(BASE_LIST); do \
@@ -62,23 +71,29 @@ _prepare:
            for lb in $(LIB_BASE); do printf " %s.lib.o" "$$lb"; done; \
            printf "\n"; \
          done; \
-       } > "$(OUTPUT_DIR)/Makefile"
-       # stage kmod sources (read-only authored dir, write only to OUTPUT_DIR)
-       @for b in $(BASE_LIST); do \
-         src="$(SOURCE_DIR)/$$b.kmod.c"; dst="$(OUTPUT_DIR)/$$b.kmod.c"; \
-         echo "--- Stage: $$dst ---"; ln -sf "$$src" "$$dst" 2>/dev/null || cp "$$src" "$$dst"; \
-       done
-       # stage library sources (optional)
-       @for b in $(LIB_BASE); do \
-         src="$(SOURCE_DIR)/$$b.lib.c"; dst="$(OUTPUT_DIR)/$$b.lib.c"; \
-         echo "--- Stage: $$dst ---"; ln -sf "$$src" "$$dst" 2>/dev/null || cp "$$src" "$$dst"; \
-       done
+       } > "$@"
+
+# stage kmod sources (one rule per file; parallelizable)
+$(OUTPUT_DIR)/%.kmod.c: $(KMOD_SOURCE_DIR)/%.kmod.c | $(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)
+       @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
 
+# top-level convenience target
+.PHONY: kmod
+kmod: modules
+
+
 # quality-of-life: allow 'make scratchpad/kmod/foo.ko' after batch build
 $(OUTPUT_DIR)/%.ko: modules
        @true
@@ -88,8 +103,18 @@ clean:
        @if [ -d "$(OUTPUT_DIR)" ]; then \
          echo "--- Cleaning Kbuild Artifacts in $(OUTPUT_DIR) ---"; \
          $(MAKE) -C "$(BUILD_DIR)" M="$(OUTPUT_DIR)" clean; \
-         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; \
+         # 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; \
+         # 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; \
        fi
index dd17117..5ef8770 100644 (file)
@@ -3,6 +3,7 @@
 
 .SUFFIXES:
 .EXPORT_ALL_VARIABLES:
+.DELETE_ON_ERROR:
 
 #--------------------------------------------------------------------------------
 # files have two suffixes by convention, e.g.: X.lib.c or Y.cli.c 
@@ -12,35 +13,35 @@ ifeq ($(strip $(C)),)
   $(error target_lib_cli.mk: no C compiler specified)
 endif
 
-# keep only the source directories that are in the file system
-SRCDIR_LIST := $(wildcard $(SRCDIR_LIST))
+# single source directory
+C_SOURCE_DIR ?= cc
+C_SOURCE_DIR_OK := $(wildcard $(C_SOURCE_DIR))
 
-ifeq ($(strip $(SRCDIR_LIST)),)
-  $(warning target_lib_cli.mk: empty SRCDIR_LIST)
+ifeq ($(strip $(C_SOURCE_DIR_OK)),)
+  $(warning target_lib_cli.mk: C_SOURCE_DIR '$(C_SOURCE_DIR)' not found or empty)
 endif
 
-# duplicate source file names in different directories will cause
-# problems with this makefile
+# RT uses header integrated C source files
+CFLAGS ?= -I $(C_SOURCE_DIR)
 
-C_SOURCE_LIB := $(foreach dir, $(SRCDIR_LIST), $(wildcard $(dir)/*.lib.c))
-C_SOURCE_EXEC := $(foreach dir, $(SRCDIR_LIST), $(wildcard $(dir)/*.cli.c))
+# source discovery (single dir)
+C_SOURCE_LIB  := $(wildcard $(C_SOURCE_DIR)/*.lib.c)
+C_SOURCE_EXEC := $(wildcard $(C_SOURCE_DIR)/*.cli.c)
 
-#remove the 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))))
+# 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))))
 
-# two sets of object files, one for the lib, and one for the command line interface progs
-OBJECT_LIB= $(patsubst %, scratchpad/%.lib.o, $(C_BASE_LIB))
-OBJECT_EXEC= $(patsubst %, scratchpad/%.cli.o, $(C_BASE_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))
 
 -include $(OBJECT_LIB:.o=.d) $(OBJECT_EXEC:.o=.d)
 
 # executables are made from EXEC sources
-EXEC= $(patsubst %, $(EXECDIR)/%, $(C_BASE_EXEC))
+EXEC := $(patsubst %, $(EXECDIR)/%, $(C_BASE_EXEC))
 
-# the new C programming style gated sections in source instead of header filesheader
-INCFLAG_List := $(foreach dir, $(SRCDIR_LIST), -I $(dir))
-CFLAGS += $(INCFLAG_List)
 
 #--------------------------------------------------------------------------------
 # targets
@@ -62,7 +63,7 @@ version:
 .PHONY: information
 information:
        @printf "· → Unicode middle dot — visible: [%b]\n" "·"
-       @echo "SRCDIR_LIST: " $(SRCDIR_LIST)
+       @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)
@@ -72,43 +73,16 @@ information:
        @echo "EXEC: " $(EXEC)
        @echo "INCFLAG_List: " $(INCFLAG_List)
 
-#.PHONY: library
-#library: $(LIBFILE) 
-
-NEED_LIB := $(strip $(OBJECT_LIB))
-LIB_ARG  := $(if $(NEED_LIB),$(LIBFILE),)   # expands to lib path only when needed
-
 .PHONY: library
-library: $(if $(NEED_LIB),$(LIBFILE),.remove_lib_if_exists)
-
-.PHONY: .remove_lib_if_exists
-.remove_lib_if_exists:
-       @rm -f $(LIBFILE)
-
-ifneq ($(NEED_LIB),)
-$(LIBFILE): $(OBJECT_LIB)
-       @echo "ar rcs $@ $^"
-       ar rcs $@ $^
-endif
-
-ifeq ($(NEED_LIB),)
-$(LIBFILE):
-       @rm -f $(LIBFILE)
-endif
-
+library: $(LIBFILE)
 
-#$(LIBFILE): $(OBJECT_LIB) $(DEPFILE)
 $(LIBFILE): $(OBJECT_LIB)
-       ar rcs $(LIBFILE) $(OBJECT_LIB)
-
-
-#.PHONY: cli
-#cli: $(LIBFILE) $(DEPFILE)
-#cli: $(LIBFILE)
-#      make sub_cli
-
-#.PHONY: sub_cli
-#sub_cli: $(EXEC)
+       @if [ -s "$@" ] || [ -n "$(OBJECT_LIB)" ]; then \
+               echo "ar rcs $@ $^"; \
+               ar rcs $@ $^; \
+       else \
+               rm -f "$@"; \
+       fi   
 
 #.PHONY: cli
 #cli: $(LIBFILE) $(EXEC)
@@ -117,7 +91,6 @@ $(LIBFILE): $(OBJECT_LIB)
 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
@@ -128,13 +101,9 @@ clean:
 
 
 # recipes
-vpath %.c $(SRCDIR_LIST)
-scratchpad/%.o: %.c
+scratchpad/%.o: $(C_SOURCE_DIR)/%.c
        $(C) $(CFLAGS) -o $@ -c $<
 
-#$(EXECDIR)/%: scratchpad/%.cli.o $(LIBFILE)
-#      $(C) -o $@ $< $(LIBFILE) $(LINKFLAGS)
-
 $(EXECDIR)/%: scratchpad/%.cli.o
        $(C) -o $@ $< $(LIB_ARG) $(LINKFLAGS)