From 67df47ffb390778dc9dfe9845def6f3c84ccdffd Mon Sep 17 00:00:00 2001 From: "Darryl L. Miles" Date: Wed, 22 Jul 2026 12:42:35 +0000 Subject: [PATCH] build: top Makefile.in + build-dir orchestration (out-of-tree) Make a plain `make` in a build directory build every module into the build tree. The top Makefile becomes a configure-generated Makefile.in, and each recursion drives a build subdirectory (created on demand) using the module Makefile from the source tree. Makefile -> Makefile.in (config.status generates Makefile in the build top via AC_CONFIG_FILES([Makefile:Makefile.in])): * Add MAGICSRC = @abs_top_srcdir@; read VERSION and re-run configure from ${MAGICSRC}. * Every descent `(cd $$dir && ${MAKE} )` and `${MAKE} -C $(dir $@) ` becomes: mkdir -p && ${MAKE} -C \ -f ${MAGICSRC}//Makefile so the build subdir need not pre-exist and the source Makefile is used. Applied to modules/libs/depend pattern rules and the tcllibrary/mains/techs/install/clean loops. * database/database.h: generate from ${MAGICSRC}/.../database.h.in into the build tree (mkdir -p database), via the generated build-tree ${MAGICDIR}/scripts/makedbh. * install-dirs/install-tcl-dirs use ${SCRIPTS}/mkdirs (now source-tree); clean skips absent build subdirs; distclean/dist/tags updated for the split source/build layout. scripts/defs.mak.in: * SCRIPTS now points at the source tree (${MAGICSRC}/scripts) for the static helpers (mkdirs, printmans, ...); the one generated helper, makedbh, is referenced directly at ${MAGICDIR}/scripts (build tree). * Guard VPATH so it is set only inside module subdirectories, never at the build top -- a top-level VPATH into the source tree could let a stale source database/database.h shadow the build-tree copy. scripts/configure.in: AC_CONFIG_FILES([Makefile:Makefile.in]); regenerated scripts/configure. Verified out-of-tree: `../configure && make modules && make libs` builds all 33 module libraries (lib*.o and lib*.a) plus the generated database/database.h into the build tree, with no errors and the source tree left clean. A full `make` (link the magic program, build techs) still needs the later outlier fixes (magic/, scmos/, ...). Co-Authored-By: Claude Opus 4.8 (1M context) --- Makefile => Makefile.in | 56 ++++++++++++++++++++++++----------------- scripts/configure | 3 +++ scripts/configure.in | 1 + scripts/defs.mak.in | 9 ++++++- 4 files changed, 45 insertions(+), 24 deletions(-) rename Makefile => Makefile.in (64%) diff --git a/Makefile b/Makefile.in similarity index 64% rename from Makefile rename to Makefile.in index 7cdd05c2..353d0df2 100644 --- a/Makefile +++ b/Makefile.in @@ -3,6 +3,11 @@ # MAGICDIR = . +# Absolute path to the source tree (config.status substitutes @abs_top_srcdir@). +# For an in-tree build this is the same directory as the build top. Every +# recursion below drives a build subdirectory (created on demand) using the +# module Makefile from the source tree: -C -f ${MAGICSRC}//Makefile. +MAGICSRC = @abs_top_srcdir@ PROGRAMS = magic TECHS = scmos LIBRARIES = database utils extflat @@ -11,7 +16,7 @@ MODULES = bplane cmwind commands database dbwind debug drc extflat \ utils windows wiring # This was `cat VERSION` -VERSION := $(shell cat ${MAGICDIR}/VERSION) +VERSION := $(shell cat ${MAGICSRC}/VERSION) MAKEFLAGS = INSTALL_CAD_DIRS = windows doc ${TECHS} @@ -33,21 +38,23 @@ defs.mak: @exit 1 config: - ${MAGICDIR}/configure + ${MAGICSRC}/configure tcllibrary: database/database.h modules @echo --- making Tcl shared libraries for dir in ${PROGRAMS}; do \ - (cd $$dir && ${MAKE} tcl-main) || exit 1; done + mkdir -p $$dir && ${MAKE} -C $$dir -f ${MAGICSRC}/$$dir/Makefile tcl-main || exit 1; done mains: database/database.h modules libs @echo --- making main programs for dir in ${PROGRAMS}; do \ - (cd $$dir && ${MAKE} main) || exit 1; done + mkdir -p $$dir && ${MAKE} -C $$dir -f ${MAGICSRC}/$$dir/Makefile main || exit 1; done -database/database.h: ${MAGICDIR}/database/database.h.in +# makedbh is the one generated helper script; it lives in the *build* tree. +database/database.h: ${MAGICSRC}/database/database.h.in @echo --- making header file database/database.h - ${SCRIPTS}/makedbh ${MAGICDIR}/database/database.h.in database/database.h + @mkdir -p database + ${MAGICDIR}/scripts/makedbh ${MAGICSRC}/database/database.h.in database/database.h # tiles xyz => tiles/libtiles.o xyz/libxyz.o MODULES_SUBDIR := $(shell for i in ${MODULES}; do echo "$${i}/lib$${i}.o"; done) @@ -56,13 +63,13 @@ LIBS_SUBDIR := $(shell for i in ${MODULES}; do echo "$${i}/lib$${i}.a"; done) .PHONY: FORCE ${MODULES_SUBDIR}: FORCE - @${MAKE} -C $(dir $@) module + @d=$(dir $@); mkdir -p $$d && ${MAKE} -C $$d -f ${MAGICSRC}/$${d}Makefile module .PHONY: modules modules: database/database.h depend ${MODULES_SUBDIR} ${LIBS_SUBDIR}: FORCE - @${MAKE} -C $(dir $@) lib + @d=$(dir $@); mkdir -p $$d && ${MAKE} -C $$d -f ${MAGICSRC}/$${d}Makefile lib # Force the tiles/utils modules to exist first for libdatabase.a .PHONY: libs @@ -85,7 +92,7 @@ SUBDIRS_DEPEND = $(addsuffix /Depend, ${SUBDIRS_FILTERED}) ${SUBDIRS_DEPEND}: database/database.h @echo --- making dependencies - ${MAKE} -C $(dir $@) depend + @d=$(dir $@); mkdir -p $$d && ${MAKE} -C $$d -f ${MAGICSRC}/$${d}Makefile depend .PHONY: depend depend: defs.mak ${SUBDIRS_DEPEND} @@ -94,7 +101,7 @@ depend: defs.mak ${SUBDIRS_DEPEND} techs: depend @echo --- making techs for dir in ${TECHS}; do \ - (cd $$dir && ${MAKE} all) || exit 1; done + mkdir -p $$dir && ${MAKE} -C $$dir -f ${MAGICSRC}/$$dir/Makefile all || exit 1; done install: $(INSTALL_TARGET) @@ -105,17 +112,17 @@ install-magic: install-real: install-dirs for dir in ${INSTALL_CAD_DIRS}; do \ - (cd $$dir && ${MAKE} install); done + mkdir -p $$dir && ${MAKE} -C $$dir -f ${MAGICSRC}/$$dir/Makefile install; done for dir in ${PROGRAMS}; do \ - (cd $$dir && ${MAKE} install); done + mkdir -p $$dir && ${MAKE} -C $$dir -f ${MAGICSRC}/$$dir/Makefile install; done install-tcl-dirs: - ${MAGICDIR}/scripts/mkdirs $(DESTDIR)${INSTALL_BINDIR} \ + ${SCRIPTS}/mkdirs $(DESTDIR)${INSTALL_BINDIR} \ $(DESTDIR)${INSTALL_MANDIR} $(DESTDIR)${INSTALL_SYSDIR} \ $(DESTDIR)${INSTALL_TCLDIR} $(DESTDIR)${INSTALL_TCLDIR}/bitmaps install-dirs: - ${MAGICDIR}/scripts/mkdirs $(DESTDIR)${INSTALL_BINDIR} \ + ${SCRIPTS}/mkdirs $(DESTDIR)${INSTALL_BINDIR} \ $(DESTDIR)${INSTALL_MANDIR} $(DESTDIR)${INSTALL_SYSDIR} \ $(DESTDIR)${INSTALL_SCMDIR} @@ -126,19 +133,22 @@ install-tcl: install-tcl-real: install-tcl-dirs for dir in ${INSTALL_CAD_DIRS} ${PROGRAMS}; do \ - (cd $$dir && ${MAKE} install-tcl); done + mkdir -p $$dir && ${MAKE} -C $$dir -f ${MAGICSRC}/$$dir/Makefile install-tcl; done clean: for dir in ${SUBDIRS_FILTERED} ${TECHS} ${BUNDLED_MODULES}; do \ - (cd $$dir && ${MAKE} clean); done + test -d $$dir && ${MAKE} -C $$dir -f ${MAGICSRC}/$$dir/Makefile clean || true; done ${RM} *.tmp */*.tmp *.sav */*.sav *.log TAGS tags distclean: touch defs.mak @${MAKE} clean - ${RM} defs.mak old.defs.mak ${MAGICDIR}/scripts/defs.mak - ${RM} ${MAGICDIR}/scripts/default.conf - ${RM} ${MAGICDIR}/scripts/config.log ${MAGICDIR}/scripts/config.status + # NB: do NOT remove rules.mak here. In-tree (build == source) it is the + # tracked source file, not a generated one; out-of-tree the build dir is + # disposable, so leaving its generated copy is harmless. + ${RM} defs.mak old.defs.mak + ${RM} scripts/makedbh scripts/default.conf + ${RM} config.log config.status ${RM} database/database.h ${RM} scripts/magic.spec magic-${VERSION} magic-${VERSION}.tgz ${RM} *.log @@ -146,7 +156,7 @@ distclean: dist: ${RM} scripts/magic.spec magic-${VERSION} magic-${VERSION}.tgz ${SED} -e /@VERSION@/s%@VERSION@%${VERSION}% \ - scripts/magic.spec.in > scripts/magic.spec + ${MAGICSRC}/scripts/magic.spec.in > scripts/magic.spec ${LN} -nsf . magic-${VERSION} tar zchvf magic-${VERSION}.tgz --exclude CVS \ --exclude magic-${VERSION}/magic-${VERSION} \ @@ -155,15 +165,15 @@ dist: clean-mains: for dir in ${PROGRAMS}; do \ - (cd $$dir && ${RM} $$dir); done + ${RM} $$dir/$$dir; done tags: ${RM} tags - find . ${MODULES} ${PROGRAMS} -name "*.[ch]" -maxdepth 1 | xargs ctags -o tags + cd ${MAGICSRC} && find . ${MODULES} ${PROGRAMS} -name "*.[ch]" -maxdepth 1 | xargs ctags -o $(CURDIR)/tags TAGS: ${RM} TAGS - find . ${MODULES} ${PROGRAMS} -name "*.[ch]" -maxdepth 1 | xargs etags -o TAGS + cd ${MAGICSRC} && find . ${MODULES} ${PROGRAMS} -name "*.[ch]" -maxdepth 1 | xargs etags -o $(CURDIR)/TAGS setup-git: git config --local include.path ../.gitconfig diff --git a/scripts/configure b/scripts/configure index 08d8731b..942c1124 100755 --- a/scripts/configure +++ b/scripts/configure @@ -9296,6 +9296,8 @@ MAKE_CAIRO=$usingCairo MAKE_READLINE=$use_bundled_readline +ac_config_files="$ac_config_files Makefile:Makefile.in" + ac_config_files="$ac_config_files defs.mak:scripts/defs.mak.in" ac_config_files="$ac_config_files scripts/makedbh:scripts/makedbh.in" @@ -10009,6 +10011,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 for ac_config_target in $ac_config_targets do case $ac_config_target in + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile:Makefile.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" ;; diff --git a/scripts/configure.in b/scripts/configure.in index 9cc46c81..f6cc9e51 100644 --- a/scripts/configure.in +++ b/scripts/configure.in @@ -1980,6 +1980,7 @@ dnl Name the .in templates explicitly (relative to srcdir) so config.status can dnl find them when run from a separate build directory. Outputs land in the 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([Makefile:Makefile.in]) 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 diff --git a/scripts/defs.mak.in b/scripts/defs.mak.in index 2ca9cc5d..2388d12e 100755 --- a/scripts/defs.mak.in +++ b/scripts/defs.mak.in @@ -26,7 +26,12 @@ BUILD_TOP := $(abspath $(MAGICDIR)) # this cannot mis-fire if BUILD_TOP happens to recur later in the path. MODULE_SUBPATH := $(patsubst $(BUILD_TOP)%,%,$(CURDIR)) srcdir := $(MAGICSRC)$(MODULE_SUBPATH) +# Only set VPATH inside a module (sub)directory, never at the build top: a +# top-level VPATH into the source tree could let a stale source-tree +# database/database.h shadow the copy we must (re)generate in the build tree. +ifneq ($(MODULE_SUBPATH),) VPATH := $(srcdir) +endif # -------------------------------------------------------------------------- prefix = @prefix@ @@ -35,7 +40,9 @@ bindir = @bindir@ libdir = @libdir@ mandir = @mandir@ -SCRIPTS = ${MAGICDIR}/scripts +# Source-tree helper scripts (mkdirs, printmans, preproc.py, ...). The one +# generated script, makedbh, lives in the *build* tree at ${MAGICDIR}/scripts. +SCRIPTS = ${MAGICSRC}/scripts INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@