读代码时发现目前工程中的makefile文件中有一个问题或bug,.即cpp文件没有和该.cpp文件include的头文件建立依赖性。这个危害是,当头文件被修改后,受影响的.cpp文件对应的.o文件不会被重新创建。
而目前的代码中大量使用C++模板,模板的实现全部写在.h文件中.
我做了个实验,修改了单件模板的实现文件 SingletonHolder.h。虽然这个修改影响了大量include了SingletonHolder.h的.cpp文件,但它们对应的.o全被没有被重新编译。
解决方法是用g++编译器提供的 -MM 选项。这个选项会让g++在把.cpp依赖的头文件(除系统头文件)全部列出来。具体的使用方法可以查阅手册。思路是,把cpp文件和头文件的依赖性写入到.d文件,在主makefile文件中include所有的.d文件。
以tcpd工程为列,修改后的makefile如下(亦见附件),该makefile可以检查到.cpp依赖的头文件被修改,使得重新生成目标文件。
include ./makefile.def
SRCS = $(wildcard *.cpp)
OBJS = $(patsubst %.cpp,%.o,$(SRCS))
# 每个.cpp都对应一个.d文件,.d文件由g++ -MM生成,列出了.cpp依赖的头文件.
DEPENDENCIES = $(subst .cpp,.d,$(SRCS))
TARGET = tcpd
OK = \\e[1m\\e[32m OK \\e[m
FAILURE = \\e[1m\\e[31m FAILURE \\e[m
all:$(TARGET)
# 使包含.d文件,.d文件指定了.o文件依赖哪些头文件。
# 如果不是make clean 就include所有的.d文件。
ifneq "$(MAKECMDGOALS)" "clean"
-include $(DEPENDENCIES)
endif
# 此函数生成.d文件,参考g++的 -MM -MF -MT选项
#$(call make-depend,source-file,object-file,depend-file)
define make-depend
g++ -MM -MF $3 -MT $2 $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) $1
endef
$(TARGET):$(OBJS)
@echo -ne Linking $(TARGET) …
@$(CXX) $(C_FLAGS) $(INC) -fPIC -o $@ $^ $(LIB) && echo -e $(OK) || echo -e $(FAILURE)
%.o:%.cpp
#如果.cpp文件被修改,就重新生成.d文件.
$(call make-depend, $<,$@,$(subst .o,.d,$@))
@echo -ne Compiling $< …
@$(CXX) $(C_FLAGS) $(INC) -fPIC -c -o $@ $< && echo -e $(OK) || echo -e $(FAILURE)
clean:
@rm -f *.o
@rm -f ./$(TARGET)
install:clean all
# strip $(TARGET)