在生成文件先决条件中包含头文件的原因
reason for including header files in Makefile pre-requisites
我正在学习这个制作教程。在这里,他们在先决条件中提到了头文件。这真的有必要吗?我运行了没有标头的相同代码,它有效。例如,我有以下代码
funcs.h
#ifndef FUNCS_H
#define FUNCS_H
int add(int a, int b);
#endif
funcs.cpp
#include "funcs.h"
int add(int a, int b){
return a+b;
}
main.cpp
#include<iostream>
#include "funcs.h"
int main(){
std::cout << add(1,2) << "n";
}
Makefile
add : main.o funcs.o
g++ -o add main.o funcs.o
main.o : main.cpp funcs.h
g++ -c main.cpp
funcs.o : funcs.cpp funcs.h
g++ -c funcs.cpp
clean :
rm add main.o funcs.o
即使我从funcs.o
和main.o
目标中删除头文件,它仍然有效。那么,还有其他原因可以放置头文件吗?
生成文件中冒号后面的文件名是目标的依赖项。Make 检查它们,如果任何依赖项比目标新,则使用下一行中的命令重新生成目标。
因此,当然,当您从依赖项中删除头文件时,您仍然可以构建和运行,但是如果您只在头文件中更改某些内容,则 make 将无法正确重新构建所有目标。
@Rene对您的问题有正确的答案,但我想我会指出,最佳做法是自动生成标头依赖项。 否则,中型和大型构建系统将变得非常难以维护。 例如,如果第三方将行#include "foo.h"
添加到您的主.cpp中,那么很有可能 makefile 不会更新以匹配。 如果 foo.h 依赖于另一个标头,它会变得更加复杂。 更好的做法是让生成文件和编译器自动生成依赖项。 以下内容将更简洁地构建您的示例:
SRCS := main.cpp funcs.cpp
OBJS := $(SRCS:%.cpp=%.o)
DEPS := $(OBJS:%.o=%.d)
DEPFLAGS = -MMD -MP
add: $(OBJS)
$(CC) -o $@ $^
$(OBJS) : %.o : %.cpp
$(CXX) $(DEPFLAGS) -c $<
-include $(DEPS)
clean:
rm -f $(OBJS) $(DEPS) add
由于您正在运行一个教程,我将假设您是新手,因此我将稍微介绍一下:
首先,将变量SRCS
设置为所需的所有源。 然后,使用模式替换基于SRCS
设置OBJS
(在此处描述(
完成此操作后,目标add
将依赖于所有OBJS
。 我在链接配方中使用了自动变量$@
和$^
来表示目标,以及所有依赖项的列表。 这又是为了避免有人更新一件事,而忘记在其他地方更新。
然后使用静态模式规则生成$(OBJS)
中的任何文件。 这就是乐趣所在。 有一些额外的标志传递到编译器 -$(DEPFLAGS)
(这假设是GCC编译器(。 传入的标志是-MMD
,它告诉make构建依赖项,-MP
防止在构建之间删除头文件的极端情况。 这些将导致编译器生成 .d 文件以及 .o 文件。 有关标志确切作用的详细信息,请参阅此处。 .d 文件将如下所示:
main.o: main.cpp funcs.h
funcs.h:
请注意,这是一个仅列出依赖项的小型生成文件。 因此,它可以包含在主 makefile 中,这就是下一行发生的情况。 你会得到:
-include $(DEPS)
前面的-
在这里很重要 - 这意味着如果.d文件不存在(在第一次迭代中不存在(,则不要包含它。 如果它确实存在,则读取文件,就像它是内联键入的一样。 请注意,在第一次迭代中,.o 文件也不存在,因此无论如何都会构建目标,因此列出依赖项是没有意义的。 在后续迭代中,您的目标将读取当前构建版本所依赖的依赖项,如果其中有任何更改,它将知道当前对象已过期,并重新生成它。
最后,在清理中,您需要清除生成的依赖项以及生成的对象。
如果你想更深入地了解,你可以参考自动依赖生成,它有一些我没有提到的技巧(例如将 deps 保存在他们自己的目录中等(。
- 使用mongocxx驱动程序时包含头文件问题
- 如何为包含头文件的目标编写生成文件?
- 如何在 CMakeLists.txt Qt Creator 中包含头文件?
- 当包含头文件的文件不在根项目文件夹中时,如何包含它
- 在生成文件先决条件中包含头文件的原因
- My Project的属性配置正确,但Visual Studio仍然无法打开包含头文件
- 在 PostgreSQL C 扩展中包含头文件
- 是否可以在C++中以间接方式包含头文件
- 是否需要包含头文件?
- 如何在不包含完整的文件系统头的情况下使用文件系统的类路径C++17?
- 我收到未声明的标识符错误,但我已包含头文件?
- 为什么我们需要构建一个提升库,仅仅包含头文件还不够吗,因为提升是模板
- C++:当顺序真正重要时,如何保证在项目中包含头文件的顺序
- 如何在C++中包含头文件时错误地重载
- 我在C++中无效使用不完整的类型类错误,如何正确包含头文件?
- 虚幻引擎4.16,C++包含头文件
- C++多次包含头文件
- 令牌之前的预期类名 '{' - 包含头文件和 CPP 文件
- 可以将标头文件包含在多个源文件中,而无需重复保护
- 有条件地将文件包含在C++标头中