git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH/RFC 2/2 v3] Makefile: lazily compute header dependencies

From
Jonathan Nieder <jrnieder@gmail.com>
Date
Nov 28, 2009, 09:29 UTC
Message-ID
<20091128092948.GA8515@progeny.tock>
In-Reply-To
<20091127175043.GC3461@progeny.tock>

Use the gcc -MMD -MP -MF options to generate dependencies as a byproduct of building .o files.

This feature has to be optional (I don’t think MSVC, for example, supports anything like this), so unless someone hooks in a rule to check the static header dependencies for correctness, this won’t help much with header dependency maintainance. It is enabled by setting the COMPUTE_HEADER_DEPENDENCIES variable, unset by default.

The scope of the %.o: %.c pattern rule has been restricted to make it easier to tell if a new object file has not been hooked into the dependency generation machinery.

An unrelated fix also snuck in: the %.s: %.c pattern rule to generate an assembler listing did not have correct dependencies. It is meant to be invoked by hand and should always run.

To avoid litering the build directory with even more build products, the generated Makefile fragments are squirreled away into deps/ subdirectories of each directory containing object files. These directories are currently generated as a side-effect of the GIT-CFLAGS rule, to guarantee they will be available whenever the %.o: %.c and %.o: %.S pattern rules are being used. This is really not ideal, especially because it requires hard-coding the list of directories with objects.

gcc learned the -MMD -MP -MF options in version 3.0, so most gcc users should have them by now.

Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
I’ll send the .c.s and dependency fixes separately.
Thoughts? Advice?

Thanks, Jonathan

 .gitignore |    1 +
 Makefile   |   63 ++++++++++++++++++++++++++++++++++++++++++-----------------
 2 files changed, 46 insertions(+), 18 deletions(-)
diff --git a/.gitignore b/.gitignore
index ac02a58..803247f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -170,6 +170,7 @@
 *.exe
 *.[aos]
 *.py[co]
+*.o.d
 *+
 /config.mak
 /autom4te.cache
diff --git a/Makefile b/Makefile
index ed0f461..fb20302 100644
--- a/Makefile
+++ b/Makefile
@@ -216,6 +216,9 @@ all::
 #   DEFAULT_EDITOR='~/bin/vi',
 #   DEFAULT_EDITOR='$GIT_FALLBACK_EDITOR',
 #   DEFAULT_EDITOR='"C:\Program Files\Vim\gvim.exe" --nofork'
+#
+# Define COMPUTE_HEADER_DEPENDENCIES if you want to avoid rebuilding objects
+# when an unrelated header file changes and your compiler supports it.
 
 GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
 	@$(SHELL_PATH) ./GIT-VERSION-GEN
@@ -1559,12 +1562,42 @@ git.o git.spec \
 	$(patsubst %.perl,%,$(SCRIPT_PERL)) \
 	: GIT-VERSION-FILE
 
-%.o: %.c GIT-CFLAGS
-	$(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $<
-%.s: %.c GIT-CFLAGS
+GIT_OBJS := http.o http-walker.o http-push.o \
+	$(LIB_OBJS) $(BUILTIN_OBJS) \
+	$(patsubst git-%$X,%.o,$(PROGRAMS)) git.o
+
+OBJECTS := $(GIT_OBJS) $(XDIFF_OBJS)
+
+ifndef COMPUTE_HEADER_DEPENDENCIES
+$(GIT_OBJS): $(LIB_H)
+
+$(XDIFF_OBJS): xdiff/xinclude.h xdiff/xmacros.h xdiff/xdiff.h xdiff/xtypes.h \
+	xdiff/xutils.h xdiff/xprepare.h xdiff/xdiffi.h xdiff/xemit.h
+
+http.o http-walker.o http-push.o: http.h
+
+builtin-revert.o wt-status.o: wt-status.h
+
+$(patsubst git-%$X,%.o,$(PROGRAMS)) git.o: $(wildcard */*.h)
+else
+dep_files := $(wildcard $(foreach f,$(OBJECTS),$(dir $f)deps/$(notdir $f).d))
+
+ifneq ($(dep_files),)
+include $(dep_files)
+endif
+
+# Take advantage of gcc's dependency generation.
+# See <http://gcc.gnu.org/gcc-3.0/features.html>.
+dep_args = -MF $(dep_file) -MMD -MP
+dep_file = $(dir $@)deps/$(notdir $@).d
+endif
+
+$(OBJECTS): %.o: %.c GIT-CFLAGS
+	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $<
+%.s: %.c GIT-CFLAGS .FORCE-LISTING
 	$(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $<
-%.o: %.S
-	$(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $<
+$(OBJECTS): %.o: %.S GIT-CFLAGS
+	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $<
 
 exec_cmd.o: exec_cmd.c GIT-CFLAGS
 exec_cmd.o: ALL_CFLAGS += \
@@ -1594,10 +1627,6 @@ git-imap-send$X: imap-send.o $(GITLIBS)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
 		$(LIBS) $(OPENSSL_LINK) $(OPENSSL_LIBSSL)
 
-http.o http-walker.o http-push.o: http.h
-
-http.o http-walker.o: $(LIB_H)
-
 git-http-fetch$X: revision.o http.o http-walker.o http-fetch.o $(GITLIBS)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
 		$(LIBS) $(CURL_LIBCURL)
@@ -1609,22 +1638,15 @@ git-remote-curl$X: remote-curl.o http.o http-walker.o $(GITLIBS)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
 		$(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
 
-$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
-$(patsubst git-%$X,%.o,$(PROGRAMS)) git.o: $(LIB_H) $(wildcard */*.h)
-builtin-revert.o wt-status.o: wt-status.h
-
 $(LIB_FILE): $(LIB_OBJS)
 	$(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
 
 XDIFF_OBJS=xdiff/xdiffi.o xdiff/xprepare.o xdiff/xutils.o xdiff/xemit.o \
 	xdiff/xmerge.o xdiff/xpatience.o
-$(XDIFF_OBJS): xdiff/xinclude.h xdiff/xmacros.h xdiff/xdiff.h xdiff/xtypes.h \
-	xdiff/xutils.h xdiff/xprepare.h xdiff/xdiffi.h xdiff/xemit.h
 
 $(XDIFF_LIB): $(XDIFF_OBJS)
 	$(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(XDIFF_OBJS)
 
-
 doc:
 	$(MAKE) -C Documentation all
 
@@ -1657,6 +1679,9 @@ TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\
              $(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)
 
 GIT-CFLAGS: .FORCE-GIT-CFLAGS
+	mkdir -p deps block-sha1/deps ppc/deps compat/deps \
+		compat/regex/deps compat/nedmalloc/deps compat/fnmatch/deps \
+		xdiff/deps
 	@FLAGS='$(TRACK_CFLAGS)'; \
 	    if test x"$$FLAGS" != x"`cat GIT-CFLAGS 2>/dev/null`" ; then \
 		echo 1>&2 "    * new build flags or prefix"; \
@@ -1873,8 +1898,10 @@ distclean: clean
 	$(RM) configure
 
 clean:
-	$(RM) *.o block-sha1/*.o arm/*.o ppc/*.o compat/*.o compat/*/*.o xdiff/*.o \
+	$(RM) *.o block-sha1/*.o ppc/*.o compat/*.o compat/*/*.o xdiff/*.o \
 		$(LIB_FILE) $(XDIFF_LIB)
+	$(RM) -r deps block-sha1/deps ppc/deps compat/deps \
+		compat/*/deps xdiff/deps
 	$(RM) $(ALL_PROGRAMS) $(BUILT_INS) git$X
 	$(RM) $(TEST_PROGRAMS)
 	$(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags cscope*
@@ -1899,7 +1926,7 @@ endif
 .PHONY: all install clean strip
 .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
 .PHONY: .FORCE-GIT-VERSION-FILE TAGS tags cscope .FORCE-GIT-CFLAGS
-.PHONY: .FORCE-GIT-BUILD-OPTIONS
+.PHONY: .FORCE-GIT-BUILD-OPTIONS .FORCE-LISTING
 
 ### Check documentation
 #
-- 
1.6.5.3
Previous: Jonathan NiederNext: Andreas Schwab
Message 14 of 28 in “Makefile: determine the list of header files using a glob”
  1. Makefile: determine the list of header files using a globJohannes Sixt, Nov 27, 2009
  2. Mike HommeyNov 27, 2009
  3. Johannes SixtNov 27, 2009
  4. Mike HommeyNov 27, 2009
  5. Junio C HamanoNov 27, 2009
  6. Mike HommeyDec 30, 2009
  7. Junio C HamanoDec 30, 2009
  8. Johannes SchindelinNov 27, 2009
  9. 0/2 Lazily generate header dependenciesJonathan Nieder, Nov 27, 2009
  10. 1/2 Makefile: use target-specific variable to pass flags to ccJonathan Nieder, Nov 27, 2009
  11. 2/2 Makefile: automatically compute header dependenciesJonathan Nieder, Nov 27, 2009
  12. Sverre RabbelierNov 27, 2009
  13. Jonathan NiederNov 28, 2009
  14. 2/2 Makefile: lazily compute header dependenciesJonathan Nieder, Nov 28, 2009
  15. Andreas SchwabNov 28, 2009
  16. Jonathan NiederNov 28, 2009
  17. Nanako ShiraishiJan 1, 2010
  18. Junio C HamanoJan 6, 2010
  19. Johannes SchindelinJan 6, 2010
  20. Jonathan NiederJan 6, 2010
  21. 0/5 Lazily generate header dependenciesJonathan Nieder, Jan 7, 2010
  22. 1/5 Makefile: rearrange dependency rulesJonathan Nieder, Jan 7, 2010
  23. 2/5 Makefile: clear list of default rulesJonathan Nieder, Jan 7, 2010
  24. 3/5 Makefile: add OBJECTS variable listing object filesJonathan Nieder, Jan 7, 2010
  25. 4/5 Makefile: lazily compute header dependenciesJonathan Nieder, Jan 7, 2010
  26. 5/5 Teach Makefile to check header dependenciesJonathan Nieder, Jan 7, 2010
  27. Erik Faye-LundJan 7, 2010
  28. Junio C HamanoNov 27, 2009

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.