Why automate inclusion of header file dependencies: While working on a new project, I had to write a makefile from
scratch. I found it little challenging to find out how to
automatically include header dependencies in makefile, because everytime you include some header file in your source file, you can not modify your
makefile. So, I thought, there must be some mechanism that automatically takes
care of it. If you search on google, you will find various ways.
Manual solution is to use sed command that I guess searches for #includes
in your source code and puts all those dependencies in your makefile. But
with modern compiler, you dont need to do much. It will do your job. You
just need to pass some flags to it.
For instance, with gcc version 4.1.2 20080704 (Red Hat 4.1.2-51), before including header dependencies, target to make object file was
./%.o : ../%.cpp
g++ -c $(INC_PATH) $(FLAGS) $< -o $@
./%.o : ../%.cpp
g++ -c $(INC_PATH) $(FLAGS) -MMD -MP $< -o $@
-include $(SRC_FILES:.cpp=.d)
you just need to pass -MMD and _MP flag and need to include these dependencies (.d file).
See the below example that demonstrate it
Let us say we have 3 c++ and 3 header files :- test.cxx
- add.cxx
- sub.cxx
- test.h
- sub.h
- add.h
sub.cxx includes sub.h
test.cxx includes test.h , add.h and sub.h
Following is the makefile that only includes dependencies of .cxx files :
---------------------------------------------------------------------------------
### declaration of all variables
FLAGS := -g
COMPILER := g++
SRC_FILES := $(wildcard *.cxx)
OBJ_FILES := $(SRC_FILES:%.cxx=%.o)
.PHONY : all clean
EXE := my_exe
STATIC_LIB := my_exe.a
all : $(EXE)
### compile source files to make object files
### expand this section for each object file to include dependency of header files
## NAAAA I am not gonna do it.. :P
%.o : %.cxx
$(COMPILER) -c $(FLAGS) $< -o $@
### make static libary of object files
$(STATIC_LIB) : $(OBJ_FILES)
ar -crv $@ $^
### make executable
$(EXE) : $(STATIC_LIB)
$(COMPILER) $^ -o $@
# clean all the files
clean :
rm -rf $(OBJ_FILES) $(EXE) $(STATIC_LIB)
---------------------------------------------------------------------------------
If you do any changes in .h file and try to do "make" it will say nothing to be done for 'all' as we have no where mentioned that any of my target depends on header file.
Hence, to include dependency of header files I should explicitly include
header files in my makefile but what if I add one more header file in
test.cxx? I will again need to modify makefile which is a cumbersome
task and non-practical in a real project.
Today compiler provides you facility to automatically generate dependency graph. All you need to do is to just pass some flags.
e.g. with g++ compiler you should give -MMD -MP flag. It will generate dependency file(.d) for each object file and include those dependency files in makefile as follow :
---------------------------------------------------------------------------------
## not including variable declaration part
%.o : %.cxx
$(COMPILER) -c $(FLAGS) -MMD -MP $< -o $@
### include all dependency files
-include $(SRC_FILES:.cxx=.d)
$(STATIC_LIB) : $(OBJ_FILES)
ar -crv $@ $^
$(EXE) : $(STATIC_LIB)
$(COMPILER) $^ -o $@
clean :
rm -rf $(OBJ_FILES) $(EXE) $(STATIC_LIB)
---------------------------------------------------------------------------------
Test.d :
test.o: test.cxx add.h sub.h test.h
add.h:
sub.h:
test.h:
This is how a dependency files look like. Now test.o depends on test.h, add.h and sub.h along with test.cxx. similarly add.o includes dependency of add.h and sub.o takes sub.h into account.
Whenever time stamp of any of header file changes corresponding object file will be modified that solves our purpose. :)
Great precise explanation. Thanks.
ReplyDeleteThanks, really helpful!
ReplyDeleteThanks, really helpful!
ReplyDelete