build: per-file automatic dependencies (.deps), retire the Depend/sed machinery
Replace the monolithic per-directory `Depend` file -- generated by a separate,
serial `make depend` pass (one `gcc -MM` over all sources) and post-processed by
sed -- with automake-style per-file dependency fragments produced as a side
effect of each compile.
rules.mak's %.o rule now adds, when the compiler supports it,
-MMD -MP -MF .deps/<stem>.d
so every object records the (non-system) headers it used. Those fragments are
`-include`d best-effort: absent on a first build, present and correct after.
Benefits:
* self-maintaining -- no explicit depend step; deps refresh on every compile;
* parallel -- generated during the (already parallel) compile, no barrier;
* -MMD already drops system headers (what the sed did) and -MP tolerates a
removed/renamed header, so the sed post-processing is gone;
* fixes out-of-tree incremental header tracking: with an absolute srcdir the
old sed stripped the now-absolute *local* header paths too, silently losing
them; the .d files keep them.
configure probes `-MMD -MP` (AUTODEP_FLAGS; empty and best-effort-skipped if the
compiler cannot). clean/distclean remove .deps (rm -r); .gitignore replaces the
obsolete */Depend with .deps/. `make depend` is kept as a no-op for callers that
still invoke it (e.g. the WASM build script).
Verified out-of-tree (--disable-ccache): 324 .d files, 0 Depend files, a header
touch recompiles its dependents, no-op rebuild is idle, clean clears .deps. (The
top-level depend phase still runs here as a no-op; removed next.)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c27ef5fab1
commit
1bc8537b5d
|
|
@ -70,8 +70,8 @@ doc/latexfiles/Makefile
|
||||||
*.o
|
*.o
|
||||||
*.a
|
*.a
|
||||||
*.so
|
*.so
|
||||||
*/Depend
|
# Per-file dependency fragments (in-tree they land in each source module dir;
|
||||||
*/Depend*.tmp
|
# out-of-tree they are under the build dir). Replaces the old */Depend files.
|
||||||
.deps/
|
.deps/
|
||||||
database/database.h
|
database/database.h
|
||||||
# autoconf config header, generated by ./configure (in-tree location; out-of-tree
|
# autoconf config header, generated by ./configure (in-tree location; out-of-tree
|
||||||
|
|
|
||||||
45
rules.mak
45
rules.mak
|
|
@ -2,31 +2,23 @@
|
||||||
|
|
||||||
module: lib${MODULE}.o
|
module: lib${MODULE}.o
|
||||||
|
|
||||||
depend: ${DEPEND_FILE}
|
# Dependencies are now generated automatically as a side effect of each compile
|
||||||
|
# (see the %.o rule below); "make depend" is a no-op kept only so scripts/habits
|
||||||
# New Depend file generating line (Tim Edwards, 1/25/06). This gets around
|
# that still invoke it do not error.
|
||||||
# problems with gcc. The purpose of "make depend" is to generate a list of
|
.PHONY: depend
|
||||||
# all local dependencies, but gcc insists that anything that is in, for
|
depend:
|
||||||
# example, the /usr/X11R6 path should also be included. The sed scripts
|
|
||||||
# (respectively) do: 1) remove comment lines generated by gcc, 2) remove
|
|
||||||
# any header (.h) files with an absolute path (beginning with "/"), and
|
|
||||||
# 3) remove isolated backslash-returns just to clean things up a bit.
|
|
||||||
|
|
||||||
# The $$PPID allows this to be run on the same dir in parallel without
|
|
||||||
# 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} $(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}
|
|
||||||
|
|
||||||
# Original Depend file generating line:
|
|
||||||
# ${CC} ${CFLAGS} ${CPPFLAGS} ${DFLAGS} ${DEPEND_FLAG} ${SRCS} > ${DEPEND_FILE}
|
|
||||||
|
|
||||||
|
# Compile a source into an object. When the compiler supports it
|
||||||
|
# (AUTODEP_FLAGS = "-MMD -MP"), also write .deps/<stem>.d listing the non-system
|
||||||
|
# headers this object used -- generated as a side effect of the compile, so there
|
||||||
|
# is no separate serial "make depend" pass and it parallelises for free. -MMD
|
||||||
|
# already drops system headers (the job the old sed did), and -MP adds a phony
|
||||||
|
# target per header so a later removed/renamed header does not break the build.
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
@echo --- compiling ${MODULE}/$*.o
|
@echo --- compiling ${MODULE}/$*.o
|
||||||
|
@test -z "${AUTODEP_FLAGS}" || mkdir -p .deps
|
||||||
${RM} $*.o
|
${RM} $*.o
|
||||||
${CC} ${CFLAGS} ${CPPFLAGS} ${DFLAGS} -c $< -o $@
|
${CC} ${CFLAGS} ${CPPFLAGS} ${DFLAGS} ${AUTODEP_FLAGS} $(if ${AUTODEP_FLAGS},-MF .deps/$*.d) -c $< -o $@
|
||||||
|
|
||||||
lib${MODULE}.o: ${OBJS}
|
lib${MODULE}.o: ${OBJS}
|
||||||
@echo --- linking lib${MODULE}.o
|
@echo --- linking lib${MODULE}.o
|
||||||
|
|
@ -53,12 +45,13 @@ ${DESTDIR}${BINDIR}/${MODULE}${EXEEXT}: ${MODULE}${EXEEXT}
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
${RM} ${CLEANS}
|
${RM} ${CLEANS}
|
||||||
|
${RM} -r .deps
|
||||||
|
|
||||||
tags: ${SRCS} ${LIB_SRCS}
|
tags: ${SRCS} ${LIB_SRCS}
|
||||||
ctags $(addprefix $(srcdir)/,${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
|
# Per-file dependency fragments written by the %.o rule above. Best effort: none
|
||||||
# building. If the file is here it's here, if not continue with build optimistically
|
# exist on a first build (everything compiles anyway); on later builds they cause
|
||||||
ifneq (,$(wildcard ${DEPEND_FILE}))
|
# a recompile when a used header changes. `-include` tolerates their absence and
|
||||||
include ${DEPEND_FILE}
|
# the `-MP` phony header targets tolerate a removed/renamed header.
|
||||||
endif
|
-include $(wildcard .deps/*.d)
|
||||||
|
|
|
||||||
|
|
@ -636,7 +636,7 @@ MSED
|
||||||
MCPP
|
MCPP
|
||||||
LD_RUN_PATH
|
LD_RUN_PATH
|
||||||
SHLIB_CFLAGS
|
SHLIB_CFLAGS
|
||||||
DEPEND_FLAG
|
AUTODEP_FLAGS
|
||||||
gr_hprog
|
gr_hprog
|
||||||
gr_hsrcs
|
gr_hsrcs
|
||||||
gr_srcs
|
gr_srcs
|
||||||
|
|
@ -6349,7 +6349,7 @@ extra_defs="$extra_defs -DCAD_DIR=\\\"\${LIBDIR}\\\" -DBIN_DIR=\\\"\${BINDIR}\\\
|
||||||
X_LIBS=
|
X_LIBS=
|
||||||
X_CFLAGS=
|
X_CFLAGS=
|
||||||
INC_SPECS=
|
INC_SPECS=
|
||||||
DEPEND_FLAG=
|
AUTODEP_FLAGS=
|
||||||
SHLIB_CFLAGS=""
|
SHLIB_CFLAGS=""
|
||||||
LD_RUN_PATH=""
|
LD_RUN_PATH=""
|
||||||
WISH_EXE=""
|
WISH_EXE=""
|
||||||
|
|
@ -9435,9 +9435,36 @@ fi
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test "$GCC" = "yes" ; then
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC generates dependencies with -MMD -MP" >&5
|
||||||
DEPEND_FLAG="-MM"
|
$as_echo_n "checking whether $CC generates dependencies with -MMD -MP... " >&6; }
|
||||||
|
magic_save_cflags="$CFLAGS"
|
||||||
|
CFLAGS="$CFLAGS -MMD -MP -MF conftest.autodep.d"
|
||||||
|
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||||
|
/* end confdefs.h. */
|
||||||
|
|
||||||
|
int
|
||||||
|
main ()
|
||||||
|
{
|
||||||
|
|
||||||
|
;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
_ACEOF
|
||||||
|
if ac_fn_c_try_compile "$LINENO"; then :
|
||||||
|
if test -f conftest.autodep.d ; then
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||||
|
$as_echo "yes" >&6; }; AUTODEP_FLAGS="-MMD -MP"
|
||||||
|
else
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no (produced no .d)" >&5
|
||||||
|
$as_echo "no (produced no .d)" >&6; }
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||||
|
$as_echo "no" >&6; }
|
||||||
fi
|
fi
|
||||||
|
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||||
|
rm -f conftest.autodep.d
|
||||||
|
CFLAGS="$magic_save_cflags"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -370,7 +370,7 @@ extra_defs="$extra_defs -DCAD_DIR=\\\"\${LIBDIR}\\\" -DBIN_DIR=\\\"\${BINDIR}\\\
|
||||||
X_LIBS=
|
X_LIBS=
|
||||||
X_CFLAGS=
|
X_CFLAGS=
|
||||||
INC_SPECS=
|
INC_SPECS=
|
||||||
DEPEND_FLAG=
|
AUTODEP_FLAGS=
|
||||||
SHLIB_CFLAGS=""
|
SHLIB_CFLAGS=""
|
||||||
LD_RUN_PATH=""
|
LD_RUN_PATH=""
|
||||||
WISH_EXE=""
|
WISH_EXE=""
|
||||||
|
|
@ -1987,9 +1987,25 @@ if test $usingTcl ; then
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test "$GCC" = "yes" ; then
|
dnl Automatic per-file dependency generation. Compilers that support -MMD -MP
|
||||||
DEPEND_FLAG="-MM"
|
dnl write a .deps/<stem>.d listing the (non-system) headers a source used, as a
|
||||||
fi
|
dnl side effect of compiling it -- replacing the old serial "make depend" pass
|
||||||
|
dnl and its sed post-processing, and parallelising with the compile. Best
|
||||||
|
dnl effort: empty if unsupported, and the build proceeds without incremental
|
||||||
|
dnl header tracking. Probed (not assumed from $GCC) so clang and others are
|
||||||
|
dnl covered only when they actually produce the file.
|
||||||
|
AC_MSG_CHECKING([whether $CC generates dependencies with -MMD -MP])
|
||||||
|
magic_save_cflags="$CFLAGS"
|
||||||
|
CFLAGS="$CFLAGS -MMD -MP -MF conftest.autodep.d"
|
||||||
|
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [])],
|
||||||
|
[if test -f conftest.autodep.d ; then
|
||||||
|
AC_MSG_RESULT([yes]); AUTODEP_FLAGS="-MMD -MP"
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT([no (produced no .d)])
|
||||||
|
fi],
|
||||||
|
[AC_MSG_RESULT([no])])
|
||||||
|
rm -f conftest.autodep.d
|
||||||
|
CFLAGS="$magic_save_cflags"
|
||||||
|
|
||||||
|
|
||||||
dnl Substitute all variables
|
dnl Substitute all variables
|
||||||
|
|
@ -2032,7 +2048,7 @@ AC_SUBST(CFLAGS)
|
||||||
AC_SUBST(CPPFLAGS)
|
AC_SUBST(CPPFLAGS)
|
||||||
AC_SUBST(CXX)
|
AC_SUBST(CXX)
|
||||||
AC_SUBST(CXXFLAGS)
|
AC_SUBST(CXXFLAGS)
|
||||||
AC_SUBST(DEPEND_FLAG)
|
AC_SUBST(AUTODEP_FLAGS)
|
||||||
AC_SUBST(SHLIB_CFLAGS)
|
AC_SUBST(SHLIB_CFLAGS)
|
||||||
AC_SUBST(LDFLAGS)
|
AC_SUBST(LDFLAGS)
|
||||||
AC_SUBST(LD_RUN_PATH)
|
AC_SUBST(LD_RUN_PATH)
|
||||||
|
|
|
||||||
|
|
@ -200,8 +200,10 @@ LDFLAGS = @LDFLAGS@
|
||||||
READLINE_DEFS = @rl_defs@
|
READLINE_DEFS = @rl_defs@
|
||||||
READLINE_LIBS = @rl_libs@
|
READLINE_LIBS = @rl_libs@
|
||||||
|
|
||||||
DEPEND_FILE = Depend
|
# Per-file dependency flags ("-MMD -MP" when the compiler supports it, else
|
||||||
DEPEND_FLAG = @DEPEND_FLAG@
|
# empty); used by the %.o rule in rules.mak to write .deps/<stem>.d as a compile
|
||||||
|
# side effect. Replaces the old serial "make depend" / Depend-file machinery.
|
||||||
|
AUTODEP_FLAGS = @AUTODEP_FLAGS@
|
||||||
EXEEXT = @EXEEXT@
|
EXEEXT = @EXEEXT@
|
||||||
|
|
||||||
GR_CFLAGS = @X_CFLAGS@ @gr_cflags@
|
GR_CFLAGS = @X_CFLAGS@ @gr_cflags@
|
||||||
|
|
@ -214,12 +216,11 @@ GR_HELPER_PROG = @gr_hprog@
|
||||||
OA = @OA@
|
OA = @OA@
|
||||||
OA_LIBS = @OA_LIBS@
|
OA_LIBS = @OA_LIBS@
|
||||||
|
|
||||||
DEPSRCS = ${SRCS}
|
|
||||||
C_OBJS = ${SRCS:.c=.o}
|
C_OBJS = ${SRCS:.c=.o}
|
||||||
CXX_OBJS = ${CXXSRCS:.cpp=.o}
|
CXX_OBJS = ${CXXSRCS:.cpp=.o}
|
||||||
OBJS = ${CXX_OBJS} ${C_OBJS}
|
OBJS = ${CXX_OBJS} ${C_OBJS}
|
||||||
LIB_OBJS = ${LIB_SRCS:.c=.o}
|
LIB_OBJS = ${LIB_SRCS:.c=.o}
|
||||||
CLEANS = Depend ${OBJS} ${LIB_OBJS} lib${MODULE}.a lib${MODULE}.o ${MODULE}
|
CLEANS = ${OBJS} ${LIB_OBJS} lib${MODULE}.a lib${MODULE}.o ${MODULE}
|
||||||
|
|
||||||
# allows Makefile to be selective
|
# allows Makefile to be selective
|
||||||
MAKE_TCL = @MAKE_TCL@
|
MAKE_TCL = @MAKE_TCL@
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue