[英]makefile - dependency of dependency
根据我在互联网上读到的内容,您可以说: A取决于B , B取决于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.hpp
后改变main.o
最后编译。 但这不会发生。
我是否完全误解了,它根本不像我描述的那样工作? 如果是这样,main.o 的目标应该是什么样的? 我是否必须检查文件包含的所有标头并使其依赖于所有这些标头?
编辑:
正如 Sam Miller 所说,即使b.hpp
已更改, a.hpp
的时间戳也不会更改,因为没有更新a.hpp
命令。 Sam Miller 建议了touch
命令。 但是由于我使用的是 Windows 并且无法找到一个简单的等效程序,因此我编写了一个名为WinTouch
的小程序。 效果很好,谢谢大家。
编辑2
Chnossos 向我展示了在 makefile 方面我有很多东西要学习。 我尝试了他提出的示例 makefile,它工作得很好,似乎它会让我将来的生活更轻松。
如果目标a.hpp
依赖于b.hpp
,则需要表明a.hpp
已更改:
a.hpp: b.hpp
touch $@
这将更新 a.hpp 的时间戳,触发重新构建main.o
目标。
我是否完全误解了,它根本不像我描述的那样工作?
你几乎完全明白了,@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)
如果你有任何问题。
我是否完全误解了,它根本不像我描述的那样工作?
目标具有依赖性。 当任何依赖文件更改时,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 很多地方,但是按照您的喜好安排文件和目录确实需要一些努力。 (例如,我不喜欢用 .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 目录)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.