为C/C++项目生成makefile的依赖关系

44

我有一个项目,其中Makefile的依赖关系出现了问题。 除了手动检查每个源文件或使用手写的perl脚本之外,是否有任何已知的最佳方法来生成可用于Makefile的项目依赖项列表?

5个回答

56

GNU make的文档提供了一个很好的解决方案。

当然。 g++ -MM <your file>会生成一个GMake兼容的依赖列表。我使用类似这样的东西:

# Add .d to Make's recognized suffixes.
SUFFIXES += .d

#We don't need to clean up when we're making these targets
NODEPS:=clean tags svn
#Find all the C++ files in the src/ directory
SOURCES:=$(shell find src/ -name "*.cpp")
#These are the dependency files, which make will clean up after it creates them
DEPFILES:=$(patsubst %.cpp,%.d,$(SOURCES))

#Don't create dependencies when we're cleaning, for instance
ifeq (0, $(words $(findstring $(MAKECMDGOALS), $(NODEPS))))
    #Chances are, these files don't exist.  GMake will create them and
    #clean up automatically afterwards
    -include $(DEPFILES)
endif

#This is the rule for creating the dependency files
src/%.d: src/%.cpp
    $(CXX) $(CXXFLAGS) -MM -MT '$(patsubst src/%.cpp,obj/%.o,$<)' $< -MF $@

#This rule does the compilation
obj/%.o: src/%.cpp src/%.d src/%.h
    @$(MKDIR) $(dir $@)
    $(CXX) $(CXXFLAGS) -o $@ -c $<

注意:$(CXX) / gcc 命令必须以硬制表符开头
这将自动生成每个已更改文件的依赖项,并根据您设置的任何规则进行编译。这使我可以将新文件放入 src/ 目录中,自动编译它们,包括依赖关系。

1
如果你有超过100个文件,不要陷入这个陷阱,因为第一次太慢了。在这种情况下,你应该使用只被调用一次的东西,而不是每个文件都调用一次。Makedepend可能有这个选项。在工作中,我们使用一个自定义的perl脚本。 - Steve Hanov
1
谢谢,这真的帮了我很多。你可以将$(patsubst src/%,obj/%,$(patsubst %.cpp,%.o,$<))简化为$(patsubst src/%.cpp,obj/%.o,$<)。另外,使用选项-MF $@而不是重定向输出到> $@会更有意义吧?g++手册警告可能会在stdout上产生一些不需要的调试输出,但使用-MF $@则不会出现这种情况。 - Maarten
1
为了避免@SteveHanov的反对,如果依赖关系不是最新的,您将不得不重新编译文件,而如果您必须重新编译文件,则依赖关系可能不是最新的。因此,我在编译时无条件地生成.d文件,并没有特殊的规则来重新制作它们。 - AProgrammer
我相信(尚未验证)您的Makefile在仅修改.h文件时不会重新构建依赖文件。(对于简单而健壮的修复方法没有想法,我现在所有的想法都感觉太过hackish,所以我就在这里停止了,只是指出这可能仍然会失败) - Ped7g
如果源文件不仅以“.cpp”为后缀,而且以“.cu”为后缀,那么这个解决方案还有效吗? - Ziqi Fan
显示剩余4条评论

25

现在我已经阅读了特别的这一部分,我认为有一个更简单的解决方案,只要你有一个相当新的版本的gcc/g++。如果你只是将-MMD添加到你的CFLAGS中,定义一个表示所有对象文件的变量OBJS,然后执行:

-include $(OBJS:%.o=%.d)

那么这应该可以帮助您获得高效且简单的自动依赖构建系统。


7
GNU C 预处理器 cpp 有一个选项 -MM,它根据包含模式生成适合 make 的依赖关系集。

5

我只是在 makefile 中添加了这个,它很好地运行:

-include Makefile.deps

Makefile.deps:
    $(CC) $(CFLAGS) -MM *.c > $@

我知道这个答案很老,但应该是 *.c 而不是 *.[ch] - 没有必要将每个 *.h 文件都引入编译器 - 因为如果它们被使用,它们都应该由一些 .c 文件包含 [如果它们没有被使用,则依赖关系无关紧要]。 - Mats Petersson
这种方法与每个源文件的依赖关系相比有什么好处吗?看起来你会使所有文件的预处理器通过次数翻倍,但实际上并没有任何好处。 - underscore_d
有没有办法重复使用输出,生成Makefile规则或类似的东西? - PoVa

0

Digital Mars C/C++编译器附带makedep工具。


这个可用于哪些平台? - Nathan Fellman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接