Make:Dependency
lastmod 2018-08-17created 2018-06-172 edits
Notes on generating dependencies in Make.
Automatic dependency generation
The main reason to use make is that when a file is modified, it automatically regenerates the files that depend on it, that is, the files generated from the modified file, according to the rules given in the Makefile. The problem is whether this Makefile is written correctly. If a Makefile is written sloppily, the dependencies between files are not all described precisely, so after modifying some files and running make, it is likely to fail, or even if it succeeds, to produce wrong results. So with a sloppy Makefile, out of anxiety you end up recompiling the whole project often. But in practice, for programs above a certain size, it is very hard to write a Makefile that marks accurate dependencies by hand. This is because files have dependencies not at a single level but across multiple levels.
Therefore, most compilers that run in Unix environments have a built-in feature that outputs information about the other source files needed when compiling a source file, usually in a format that can be used directly when fed into a Makefile as-is. (For gcc, the options starting with -M do this.) There are also utilities such as gccmakedep, makedepend, and mkdep that integrate such compiler output directly with make. However, because these traditional utilities were developed as part of specific projects, they lack flexibility, for example in specifying extra options to the compiler. They also share the drawback of generating dependencies into a single file. So even if you modify just one file, the dependencies for all source files in the same directory have to be rewritten, which is inefficient in terms of computer execution time, and tedious since you have to issue a command at the command prompt every time. Therefore, as the manual 4.14 Generating Prerequisites Automatically also states, it recommends generating a dependency file for each file directly using a pattern rule, as follows.
%.d: %.c
$(SHELL) -ec '$(CC) -M $(CPPFLAGS) $< \
| sed '\''s/\($*\)\.o[ :]*/\1.o $@ : /g'\'' > $@; \
[ -s $@ ] || rm -f $@'
gccmakedep
For automatic dependency generation, use gccmakedep. gccmakedep is a utility that examines a file's dependencies and automatically appends them to the end of the Makefile.
Auto-Dependency Generation
Rather than using the content from the reference site as-is, you must use the sed script precisely to fit the nature of your project.
For example, when generating src/main.d from src/main.cpp, apply it as follows.
CC=gcc
CXX=g++
SED=sed
TEMP_EXTENSION=.tmp
define MAKE_DEPENDENCY
$($(1)) -MM $< $(CPPFLAGS) $($(1)FLAGS) > $@$(TEMP_EXTENSION)
@$(SED) -e 's;^.*\.o: ;$(subst .d,.o,$@) $(subst .d,_g.o,$@) $@: ;g' < $@$(TEMP_EXTENSION) > $@
@rm -f $@$(TEMP_EXTENSION)
endef
MAKE_DEPENDENCY_CC=$(call MAKE_DEPENDENCY,CC)
MAKE_DEPENDENCY_CXX=$(call MAKE_DEPENDENCY,CXX)
...
%.d: %.cpp
$(MAKE_DEPENDENCY_CXX)
-include $(DEPS)
...
The reason for writing it this way is that applying gcc -MM produces a Target without the directory path, as below.
So this target must be expanded to Targets including the path: the .o file, the _g.o file, and the .d file.
See also
- Make
- gccmakedep
Favorite site
References
-
Gnu-software-make.zip ↩