依赖的依赖

dependency of dependency

本文关键字:依赖      更新时间:2023-10-16

从我在网上看到的你可以说:A依赖于BB依赖于C -> A依赖于C

如果我们有一个像这样的makefile:

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.hppmain.o最后一次编译后被更改,则应该编译。但这并没有发生。

我是否完全误解了,它完全不像我描述的那样工作?如果有,目标应该是什么?看起来像?我是否需要遍历文件包含的所有头文件并使其依赖于所有这些?



编辑:
正如Sam Miller所说,即使b.hpp被更改,a.hpp的时间戳也不会更改,因为没有更新a.hpp的命令。山姆·米勒建议使用touch命令。但是由于我使用的是windows,无法找到一个简单的等效程序,所以我编写了一个名为WinTouch的小程序。它工作得很好,谢谢大家。



EDIT2
Chnossos告诉我,在制作文件时,我还有很多东西要学。我尝试了他提出的makefile示例,它工作得很好,似乎它将使我将来的生活更轻松。

我是否完全误解了,它完全不像我描述的那样工作?

你几乎完全得到了,@Sam Miller的回答解释你的尝试中缺少了什么。你需要告诉make, a.hpp也改变了。

我想解决这个问题:

我必须通过所有的头文件包括,并使其依赖于所有这些吗?

GCC或clang现在都可以自动为你处理这个问题:

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

EXE := app.exe
SRC := $(wildcard *.cpp)
OBJ := $(SRC:.cpp=.o)
DEP := $(OBJ:.o=.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 $@
# 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)

这就是你所需要的。现在,对于文件夹中给定的.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)

如果您有任何问题。

如果目标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脚本可以为您生成并保持最新。

我找到了下面的目标并访问了许多地方,但是按照您的喜好安排文件和目录确实需要一些努力。(例如,我不喜欢用。o或。d文件混淆我的src目录,因此使用DEPPATH)

$(DEPPATH)/%.d : %.cpp
@echo
@echo R22 :  $<
rm -f  $(addprefix ../i686o/, $(addsuffix .o, $(basename $(@F))))
g++ -M $(CC_FLAGS)  $< > $@.$$$$; sed 's,($*).o[ :]*,1.o $@ : ,g' < $@.$$$$ > $@; rm $@.$$$$

了解这个sed脚本和g++的-M选项应该可以帮助您开始。

好吧,也许直接使用sed就足够了。我承认我不是一个sed大师,我总是使用它,因为我发现它。我确实花了一些时间在我希望依赖和目标文件驻留的地方(相对于src目录)。