From b522f31d87afad711600b47b15d8b5c621c91593 Mon Sep 17 00:00:00 2001 From: "Darryl L. Miles" Date: Wed, 22 Jul 2026 12:33:37 +0000 Subject: [PATCH] build: VPATH-enable shared make machinery (out-of-tree) With the autoconf layer relocatable, teach the shared make files to read sources from the source tree and write objects into the build tree. The ~26 "standard" and "near-standard" module Makefiles now build out-of-tree with no per-module edits. scripts/defs.mak.in: * Add MAGICSRC = @abs_top_srcdir@ (absolute source top) and derive each module's srcdir/VPATH from CURDIR relative to the build top: BUILD_TOP := $(abspath $(MAGICDIR)) MODULE_SUBPATH := $(subst $(BUILD_TOP),,$(CURDIR)) srcdir := $(MAGICSRC)$(MODULE_SUBPATH) VPATH := $(srcdir) (MAGICDIR keeps meaning the *build* top; in-tree the trees coincide.) * CPPFLAGS: add -I${MAGICSRC} (source top, for "/.h") and -I${srcdir} (same-dir headers), keeping -I${MAGICDIR} for the generated database/database.h in the build top. * MAGIC_VERSION/REVISION read ${MAGICSRC}/VERSION; MAGIC_COMMIT uses `git -C ${MAGICSRC}` so it works from a build dir outside the work-tree. rules.mak: * Compile rule: `-c $*.c` -> `-c $< -o $@` so the source is found via VPATH in srcdir and the object is written to the build cwd. * Depend and tags rules: prefix sources with $(srcdir)/ (they are passed to the compiler/ctags directly, which do not honor VPATH). scripts/configure.in: AC_CONFIG_FILES([rules.mak:rules.mak]) copies the VPATH-aware rules.mak into the build top, so a single ${MAGICDIR} resolves both `include`s in every subdir Makefile. Regenerated configure. Known limitation (v1): the Depend post-processing sed strips absolute-path headers, so with an absolute srcdir most header deps are dropped; out-of-tree incremental header-change rebuilds are weaker. Depend is already "optimistic/optional"; relativizing is a follow-up. Verified out-of-tree: `tiles` and `drc` (the latter #includes the generated database/database.h) build to completion; all objects land in the build tree; the source tree stays clean. Co-Authored-By: Claude Opus 4.8 (1M context) --- rules.mak | 6 +++--- scripts/configure | 3 +++ scripts/configure.in | 4 ++++ scripts/defs.mak.in | 32 ++++++++++++++++++++++++++++---- 4 files changed, 38 insertions(+), 7 deletions(-) diff --git a/rules.mak b/rules.mak index 633a81c1..66f719d1 100644 --- a/rules.mak +++ b/rules.mak @@ -16,7 +16,7 @@ depend: ${DEPEND_FILE} # corrupting the output, the final MV is transactional. If that is needed # it indicates a missing dependency somewhere in a upstream/parent Makefile. ${DEPEND_FILE}: ${DEPSRCS} - ${CC} ${CFLAGS} ${CPPFLAGS} ${DFLAGS} ${DEPEND_FLAG} ${DEPSRCS} > ${DEPEND_FILE}$$PPID.tmp + ${CC} ${CFLAGS} ${CPPFLAGS} ${DFLAGS} ${DEPEND_FLAG} $(addprefix $(srcdir)/,${DEPSRCS}) > ${DEPEND_FILE}$$PPID.tmp ${SED} -e "/#/D" -e "/ \//s/ \/.*\.h//" -e "/ \\\/D" -i ${DEPEND_FILE}$$PPID.tmp ${MV} -f ${DEPEND_FILE}$$PPID.tmp ${DEPEND_FILE} @@ -26,7 +26,7 @@ ${DEPEND_FILE}: ${DEPSRCS} %.o: %.c @echo --- compiling ${MODULE}/$*.o ${RM} $*.o - ${CC} ${CFLAGS} ${CPPFLAGS} ${DFLAGS} -c $*.c + ${CC} ${CFLAGS} ${CPPFLAGS} ${DFLAGS} -c $< -o $@ lib${MODULE}.o: ${OBJS} @echo --- linking lib${MODULE}.o @@ -55,7 +55,7 @@ clean: ${RM} ${CLEANS} tags: ${SRCS} ${LIB_SRCS} - ctags ${SRCS} ${LIB_SRCS} + ctags $(addprefix $(srcdir)/,${SRCS} ${LIB_SRCS}) # Depends are a somewhat optional part of the build process that are only useful when incremental # building. If the file is here it's here, if not continue with build optimistically diff --git a/scripts/configure b/scripts/configure index ffb0643e..08d8731b 100755 --- a/scripts/configure +++ b/scripts/configure @@ -9300,6 +9300,8 @@ ac_config_files="$ac_config_files defs.mak:scripts/defs.mak.in" ac_config_files="$ac_config_files scripts/makedbh:scripts/makedbh.in" +ac_config_files="$ac_config_files rules.mak:rules.mak" + cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure @@ -10009,6 +10011,7 @@ do case $ac_config_target in "defs.mak") CONFIG_FILES="$CONFIG_FILES defs.mak:scripts/defs.mak.in" ;; "scripts/makedbh") CONFIG_FILES="$CONFIG_FILES scripts/makedbh:scripts/makedbh.in" ;; + "rules.mak") CONFIG_FILES="$CONFIG_FILES rules.mak:rules.mak" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac diff --git a/scripts/configure.in b/scripts/configure.in index 43f76843..9cc46c81 100644 --- a/scripts/configure.in +++ b/scripts/configure.in @@ -1982,6 +1982,10 @@ dnl build directory (config.status' CWD): defs.mak at the build top, makedbh dnl under build/scripts/ (matching ${SCRIPTS}/makedbh = ${MAGICDIR}/scripts). AC_CONFIG_FILES([defs.mak:scripts/defs.mak.in]) AC_CONFIG_FILES([scripts/makedbh:scripts/makedbh.in], [chmod +x scripts/makedbh]) +dnl Copy rules.mak into the build top (it has no @...@ substitutions; this just +dnl places it next to the generated defs.mak so a single ${MAGICDIR} resolves +dnl both `include`s in every subdir Makefile out-of-tree). +AC_CONFIG_FILES([rules.mak:rules.mak]) AC_OUTPUT dnl diff --git a/scripts/defs.mak.in b/scripts/defs.mak.in index 26209659..2ca9cc5d 100755 --- a/scripts/defs.mak.in +++ b/scripts/defs.mak.in @@ -8,6 +8,27 @@ SHELL = @SHELL@ +# --- out-of-tree (VPATH) support ------------------------------------------ +# MAGICDIR is set by each subdir Makefile to the relative path back to the +# *build* top (that is where the generated defs.mak / rules.mak live, and where +# the generated database/database.h is written). MAGICSRC is the absolute path +# to the *source* top. For an in-tree build the two trees coincide. +MAGICSRC = @abs_top_srcdir@ + +# Derive this module's source directory (and VPATH) from where make is running +# (CURDIR, a build directory) relative to the build top (abspath of MAGICDIR): +# build top = $(abspath $(MAGICDIR)) +# subpath = "/tiles", or "" at the top +# srcdir = $(MAGICSRC)$(subpath) +BUILD_TOP := $(abspath $(MAGICDIR)) +# Anchored prefix strip (patsubst matches the whole word, so BUILD_TOP must be a +# leading prefix): "" at the build top, "/tiles" in a subdir. Unlike $(subst …) +# this cannot mis-fire if BUILD_TOP happens to recur later in the path. +MODULE_SUBPATH := $(patsubst $(BUILD_TOP)%,%,$(CURDIR)) +srcdir := $(MAGICSRC)$(MODULE_SUBPATH) +VPATH := $(srcdir) +# -------------------------------------------------------------------------- + prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ @@ -79,9 +100,9 @@ LIB_SPECS_GRNULL = @LIB_SPECS_GRNULL@ WISH_EXE = @WISH_EXE@ TCL_LIB_DIR = @TCL_LIB_DIR@ -MAGIC_VERSION ?= $(shell cat ${MAGICDIR}/VERSION | cut -d. -f1-2) -MAGIC_REVISION ?= $(shell cat ${MAGICDIR}/VERSION | cut -d. -f3) -MAGIC_COMMIT ?= $(shell git rev-parse HEAD) +MAGIC_VERSION ?= $(shell cat ${MAGICSRC}/VERSION | cut -d. -f1-2) +MAGIC_REVISION ?= $(shell cat ${MAGICSRC}/VERSION | cut -d. -f3) +MAGIC_COMMIT ?= $(shell git -C ${MAGICSRC} rev-parse HEAD) MAGIC_BUILDDATE ?= $(shell date | tr -d '\r\n') # This allow inheritence of the values from toplevel Makefile @@ -111,7 +132,10 @@ CXX = @CXX@ ### Status: NOT-STABILITY-AFFECTING (if your binary links you are good to continue) #FEATURE_FLAGS += -DSUPPORT_REMOVE_MALLOC_LEGACY -CPPFLAGS = -I${MAGICDIR} @CPPFLAGS@ +# -I${MAGICDIR}: build top, for the generated database/database.h +# -I${MAGICSRC}: source top, for "/
.h" includes +# -I${srcdir}: this module's source dir, for same-directory headers +CPPFLAGS = -I${MAGICDIR} -I${MAGICSRC} -I${srcdir} @CPPFLAGS@ CXXFLAGS = @CXXFLAGS@ DFLAGS_MAGICVERSION = -DMAGIC_VERSION=\"${MAGIC_VERSION}\" -DMAGIC_REVISION=\"${MAGIC_REVISION}\" -DMAGIC_COMMIT=\"${MAGIC_COMMIT}\" "-DMAGIC_BUILDDATE=\"${MAGIC_BUILDDATE}\"" DFLAGS = @extra_defs@ @stub_defs@ @DEFS@ ${DFLAGS_MAGICVERSION} -DGCORE=\"@GCORE@\"