通过两步依赖关系计算了解Makefile 我想建立一些C++代码。我已经有了一个可以自动计算依赖项的Makefile,但是我想把对象文件保存在单独的目录中。所以结构看起来像: 生成文件 来源/a/ 来源/b/ 资料来源/c/ obj/

通过两步依赖关系计算了解Makefile 我想建立一些C++代码。我已经有了一个可以自动计算依赖项的Makefile,但是我想把对象文件保存在单独的目录中。所以结构看起来像: 生成文件 来源/a/ 来源/b/ 资料来源/c/ obj/,makefile,build-automation,gnu,gnu-make,building,Makefile,Build Automation,Gnu,Gnu Make,Building,我能够运行Makefile,使用obj/prefix将源代码转换为对象,但当我想将依赖项计算后传时,事情变得一团糟 问题在于,几乎所有Makefile示例都是一步完成的,即从.cpp(%.d:%.cpp)创建.d。我花了一些时间试图理解Makefile,并通过尝试和错误修复它。最后,我有了一个工作脚本: DIRS := a b c SOURCES := $(foreach dir,$(DIRS),$(wildcard source/$(dir)/*.cpp)) OBJECTS := $(pats

我能够运行Makefile,使用obj/prefix将源代码转换为对象,但当我想将依赖项计算后传时,事情变得一团糟

问题在于,几乎所有Makefile示例都是一步完成的,即从.cpp(
%.d:%.cpp
)创建.d。我花了一些时间试图理解Makefile,并通过尝试和错误修复它。最后,我有了一个工作脚本:

DIRS := a b c
SOURCES := $(foreach dir,$(DIRS),$(wildcard source/$(dir)/*.cpp))
OBJECTS := $(patsubst %.cpp,obj/%.o,$(SOURCES))

obj/%.d: %.cpp
    @mkdir -p $(@D)
    @$(CXX) -E $(CXXFLAGS) -MM -MP -MF $@ -MQ $(@:.d=.o) -MQ $@ $<

obj/%.o: %.cpp obj/%.d
    @$(CXX) $(CXXFLAGS) -o $@ -c $<

project: $(OBJECTS)
    ...

-include $(OBJECTS:.o=.d)
DIRS:=a b c
源代码:=$(foreach dir,$(DIRS),$(通配符源代码/$(dir)/*.cpp))
对象:=$(patsubst%.cpp,obj/%.o,$(源))
obj/%.d:%.cpp
@mkdir-p$(@D)
@$(CXX)-E$(CXXFLAGS)-MM-MP-MF$@-MQ$(@:.d=.o)-MQ$@$<
obj/%.o:%.cpp obj/%.d
@$(CXX)$(CXXFLAGS)-o$@-c$<
项目:$(对象)
...
-包括$(对象:.o=.d)

但是我仍然不知道为什么我需要为cpp->d和cpp&d->o分别设置步骤(或者我理解-但是我不知道为什么大多数示例不需要这些步骤)。

假设源文件是
foo.cpp
bar.cpp
,标题是
foo.h
bar.h
,使
foo.cpp
包括
foo.h
bar.h
bar.cpp
包括
bar.h

您可以有一个完全不涉及依赖项文件的简单makefile:

project: $(OBJECTS)
    ...

%.o: %.cpp
    ...
现在,如果修改
foo.cpp
,Make将重建
foo.o
(和
project
)。如果修改
bar.cpp
,Make将重建
bar.o
(和
项目
)。如果修改标题,Make将什么也不做,因为Make不知道对象以任何方式依赖于标题

您可以为依赖项文件设置规则:

project: $(OBJECTS)
    ...

%.o: %.cpp
    ...

%.d:
    ...

-include *.d
现在Make将构建并使用依赖项文件——如果您记得告诉它的话。如果您这样做,Make将知道,当您修改
foo.h
时,它必须重建
foo.o
,当您修改
bar.h
时,它必须重建
foo.o
bar.o

记住重建依赖文件是一件痛苦的事情。最好让Make来做。什么时候必须重建
foo.d
?那么,当
foo.cpp
被修改时,当然:

project: $(OBJECTS)
    ...

%.o: %.cpp
    ...

%.d: %.cpp
    ...

-include *.d
但是当
foo.o
的任何其他先决条件(即
foo.h
bar.h
)被修改时,也必须重新生成
foo.d
。我还没有详细说明规则中的命令(我对
%.d
规则中的命令也不太理解),但是一个简单的规则将构建一个
foo.d
如下所示:

foo.o: foo.cpp foo.h bar.h
foo.o: foo.cpp foo.h bar.h

foo.d: foo.cpp foo.h bar.h
可以编写一个命令,生成如下所示的
foo.d

foo.o: foo.cpp foo.h bar.h
foo.o: foo.cpp foo.h bar.h

foo.d: foo.cpp foo.h bar.h
有更复杂的方法,但这对于今天来说已经足够了


至于为什么许多示例makefiles共享某个次优特性,这是因为人们在不严格检查或理解每个特性的情况下复制彼此的makefiles。

不需要单独的步骤。你可以把它们结合起来。这回答了你的问题吗?@Beta:我不明白为什么所有示例都显示转换
%.d:%.cpp
。目标二进制文件依赖于对象文件(.o),而不是依赖文件,但在Makefile中,除非存在某些依赖文件,否则没有对象文件的规则。