C++ makefile-依赖项的依赖项

C++ makefile-依赖项的依赖项,c++,makefile,C++,Makefile,从我在互联网上读到的内容来看,你可以说:A取决于B和B取决于CA取决于C 因此,如果我们有一个如下所示的生成文件: CC=g++ OUTPUT=app.exe SOURCES=$(wildcard *.cpp) OBJECTS=$(patsubst %.cpp, %.o, $(SOURCES)) $(OUTPUT): $(OBJECTS) $(CC) -o $(OUTPUT) $(OBJECTS) main.o: main.cpp a.hpp $(CC) -c main

从我在互联网上读到的内容来看,你可以说:A取决于BB取决于CA取决于C

因此,如果我们有一个如下所示的生成文件:

CC=g++

OUTPUT=app.exe

SOURCES=$(wildcard *.cpp)
OBJECTS=$(patsubst %.cpp, %.o, $(SOURCES))


$(OUTPUT): $(OBJECTS)
    $(CC) -o $(OUTPUT) $(OBJECTS)

main.o: main.cpp a.hpp
    $(CC) -c main.cpp

a.hpp: b.hpp
我希望
main.o
依赖于
b.hpp
,因此,如果
b.hpp
在上次编译
main.o
后发生更改,则应进行编译。但事实并非如此

我是否完全误解了这一点,它根本没有按照我所描述的方式工作?如果是,main.o的目标应该是什么?我是否必须检查一个文件包含的所有标题,并使其依赖于所有这些标题



编辑
正如Sam Miller所说,
a.hpp
的时间戳不会改变,即使
b.hpp
已经改变,因为没有更新
a.hpp
的命令。 Sam Miller建议使用
touch
命令。但由于我在windows上,找不到一个简单的等效程序,所以我编写了一个名为
WinTouch
的小程序。非常好,谢谢大家



EDIT2

Chnossos向我展示了我在制作文件方面还有很多需要学习的地方。我尝试了他提出的makefile示例,效果非常好,似乎它将使我今后的生活更加轻松。

如果目标
a.hpp
取决于
b.hpp
您需要指出
a.hpp
已发生变化:

a.hpp: b.hpp                                                                                                              
    touch $@
这将更新a.hpp的时间戳,触发要重建的
main.o
目标

我是否完全误解了这一点,并且它没有按照我的方式工作 有什么描述吗

目标具有依赖性。当任何依赖项文件发生更改时,make将触发make文件中标识的操作

在您的文件中,目标main不依赖于b.hpp,因此在b.hpp更改时不会发生任何操作

在您的文件中,目标a.hpp确实依赖于b.hpp,并且您所拥有的是允许的,但是您没有提供任何操作来导致a.hpp或main.cpp都无法更新

有没有一个原因,你没有简单地使用

main.o: main.cpp a.hpp b.hpp
$(CC) -c main.cpp
我是否必须检查一个文件包含的所有标题,并使其符合要求 从所有这些中解脱出来

您似乎缺少的是依赖项文件

g++编译器和sed脚本可以为您生成并保持最新

我找到了以下目标,并在许多地方使用了sed,但要根据您的喜好安排文件和目录确实需要一些努力。(例如,我不喜欢将src目录与.o或.d文件混在一起,从而导致DEPPATH)

$(DEPPATH)/%.d:%.cpp
@回音
@回声R22:$<
rm-f$(addprefix../i686o/,$(addsuffix.o,$(basename$(@f)))
g++-M$(CC_标志)$<>$@.$$$;sed's,\($*\)\.o[:]*,\1.o$@:,g'<$@.$$>$@;$@马来西亚令吉$$$$
了解这个sed脚本和g++的-M选项应该可以帮助您开始

好吧,也许按原样使用sed就足够了。我承认我不是sed大师,我一直在使用它,因为我发现了它。我确实花了时间在我希望依赖项和对象文件驻留的位置(相对于src目录)

我是否完全误解了这一点,它根本没有按照我所描述的方式工作

山姆·米勒解释说,你几乎完全掌握了它,你的尝试中遗漏了什么。您需要告诉make
a.hpp
也发生了变化

我想谈谈这个问题:

我是否必须检查一个文件包含的所有标题,并使其依赖于所有这些标题

现在,GCC或clang都可以为您自动处理此问题:

让我们构建一个简单的工作示例

EXE:=app.EXE
SRC:=$(通配符*.cpp)
对象:=$(SRC:.cpp=.o)
部门:=$(对象:.o=.d)
CPPFLAGS+=-MMD-MP#用于预处理器标志的内置变量,如-I
$(EXE):$(OBJ)
#连接相
#LDFLAGS是一个内置变量,用于链接器标志,如-L
#LDLIBS是一个内置变量,用于链接器标志,如-l
#它们在下一行中的顺序对于避免未定义的引用很重要
$(CXX)$(LDFLAGS)$^$(LDLIBS)-o$@
#Makefile包含命令,将其参数的内容随意复制并粘贴到
#生成文件。开头的破折号防止在文件丢失时输出错误
#找不到。
-包括美元(DEP)
这就是你所需要的。现在,对于文件夹中给定的
.cpp
文件,您将有一个相应的
.o
文件和一个
.d
文件,用于跟踪标题依赖关系。 如果要在文件夹中隐藏这些额外文件,请执行以下操作:

EXE := app.exe

SRC := $(wildcard *.cpp)
DIR := build
OBJ := $(SRC:%.cpp=$(DIR)/%.o) # toto.cpp => build/toto.o
DEP := $(OBJ:.o=.d) # build/toto.o => build/toto.d

CPPFLAGS += -MMD -MP # built-in variable meant for preprocessor flags, like -I

$(EXE): $(OBJ)
# Linker phase
# LDFLAGS is a built-in variable meant for linker flags such as -L
# LDLIBS is a built-in variable meant for linker flags such as -l
# Their order in the next line IS IMPORTANT to avoid undefined references
    $(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $@

# We need to override the implicit rule for .o files since we want a special
# destination. The right side of the pipe will only be evaluated once, it is
# called "order-only prerequisite".
$(DIR)/%.o: %.cpp | $(DIR)
    $(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $@ -c $<

$(DIR):
    @mkdir -p $@

# Makefile include command, litteraly copy and paste its arguments' content into
# the makefile. The dash in the beginning prevent outputting an error if a file
# cannot be found.
-include $(DEP)
EXE:=app.EXE
SRC:=$(通配符*.cpp)
DIR:=构建
OBJ:=$(SRC:%.cpp=$(DIR)/%.o)#toto.cpp=>build/toto.o
DEP:=$(对象:.o=.d)#build/toto.o=>build/toto.d
CPPFLAGS+=-MMD-MP#用于预处理器标志的内置变量,如-I
$(EXE):$(OBJ)
#连接相
#LDFLAGS是一个内置变量,用于链接器标志,如-L
#LDLIBS是一个内置变量,用于链接器标志,如-l
#它们在下一行中的顺序对于避免未定义的引用很重要
$(CXX)$(LDFLAGS)$^$(LDLIBS)-o$@
#我们需要重写.o文件的隐式规则,因为我们需要特殊的
#目的地。管道的右侧将只评估一次,它是
#称为“仅订单先决条件”。
$(DIR)/%.o:%.cpp |$(DIR)
$(CXX)$(CPPFLAGS)$(CXXFLAGS)-o$@-c$<
$(目录):
@mkdir-p$@
#Makefile包含命令,将其参数的内容随意复制并粘贴到
#生成文件。开头的破折号防止在文件丢失时输出错误
#找不到。
-包括美元(DEP)

如果您有任何问题。

我现在懒得检查,但我想这是因为
a.hpp
(即,完全没有)的命令没有更新
a.hpp
。现在不需要这个脚本。像clang或GCC这样的编译器可以同时生成依赖项文件
EXE := app.exe

SRC := $(wildcard *.cpp)
DIR := build
OBJ := $(SRC:%.cpp=$(DIR)/%.o) # toto.cpp => build/toto.o
DEP := $(OBJ:.o=.d) # build/toto.o => build/toto.d

CPPFLAGS += -MMD -MP # built-in variable meant for preprocessor flags, like -I

$(EXE): $(OBJ)
# Linker phase
# LDFLAGS is a built-in variable meant for linker flags such as -L
# LDLIBS is a built-in variable meant for linker flags such as -l
# Their order in the next line IS IMPORTANT to avoid undefined references
    $(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $@

# We need to override the implicit rule for .o files since we want a special
# destination. The right side of the pipe will only be evaluated once, it is
# called "order-only prerequisite".
$(DIR)/%.o: %.cpp | $(DIR)
    $(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $@ -c $<

$(DIR):
    @mkdir -p $@

# Makefile include command, litteraly copy and paste its arguments' content into
# the makefile. The dash in the beginning prevent outputting an error if a file
# cannot be found.
-include $(DEP)