生成包含头文件的文件头文件

Makefile with headers including headers

本文关键字:文件 包含头      更新时间:2023-10-16

In app.c:

#include "app.h"

In app.h:

#include "model/world.h"
#include "controller/controller.h"

如何在makefile中编写app.o的目标?我应该在先决条件中包括这三个头文件吗?

是的,你应该列出所有可能需要重新编译的app.c的依赖项。

你可能会发现g++ -MM app.c很有用:-MM会以make格式列出app.c的所有依赖项。你甚至可以自动化它,让你的makefile半自动地处理依赖关系。

app.o : app.c app.h model/world.h controller/controller.h
    gcc -c app.c 

是的,你需要包含所有三个头文件作为依赖项。Makefiles:如果:右边的任何东西发生了变化,那么它需要重新制作左边的东西。如果你修复了控制器中的一个bug,并从其中一个函数中删除了三个参数,而应用又从控制器中调用了这个函数,那么应用就需要重新制作来处理这个变化。

否则,当应用程序走到控制器并请求带有5个参数的函数X时,新的和改进的控制器将不知道应用程序到底在说什么。将抛出错误。到处都是火和血。一切都以眼泪结束。

这是我如何解决这个问题的一个例子。gcc -MM从给定源文件的include指令生成规则。在包含include指令的源文件上尝试一下,看看它的输出。

# src/x.c src/y.c ... => build/x.o build/y.o ...
OBJ = $(patsubst src/%.c,build/%.o,$(wildcard src/*.c))
# src/x.c src/y.c ... => build/x.d build/y.d ...
#                        `-> these files will include the generated rules
INCLUDE_PREQS = $(patsubst src/%.c,build/%.d,$(wildcard src/*.c))
all: main
main: $(OBJ)
    gcc -o $@ $^
## compile object from src/x.c to build/x.o
# src/x.c src/y.c ... => build/x.o build/y.o
build/%.o : src/%.c
    gcc -o $@ -c $<
## generate header prerequisite rules
# -MT $(patsubst build/%.d,build/%.o,$@)
#   `-> set the generated target to be build/%.o
build/%.d: src/%.c
    gcc -MM -MT $(patsubst build/%.d,build/%.o,$@) $< > $@
## include the generated rules
include $(INCLUDE_PREQS)

你永远不需要在makefiles中手动指定头文件依赖项。

-MMD -MP添加到编译器标志中。它将使编译器除了输出.o文件外,还输出.d文件。这些是指定依赖项的小make文件。然后将它们-include放到主makefile中。

如下所示:

SOURCES := 1.c 2.c
program: $(patsubst %,%.o,$(SOURCES))
    gcc $^ -o $@
%.c.o: %.c
    gcc -MMD -MP $< -c -o $@
-include $(patsubst %,%.d,$(SOURCES))

这可能有帮助:

SRC     = $(wildcard *.c)
OBJ     = $(patsubst %.c, %.o, $(SRC))
DEP     = $(patsubst %.o, %.mm, $(OBJ))
include $(DEP)
app:    $(OBJ)
    $(CC) -o $@ $(OBJ)
.FORCE:
%.mm:  .FORCE
    $(CC) -MM $*.c > $*.mm

这里:DEP是需要包含的依赖文件列表(以mm结尾)。有一条规则用于构建生成文件依赖的mm文件。您强制构建随后作为依赖项包含的依赖项,以检查您的实际依赖项

不,您不应该将头文件列为依赖项!这对于已经以#include指令的形式存在的规范来说是多余的。迟早,冗余会引起问题,因为随着项目的发展,你最终会得到不一致的列表。

还有一个普遍但幼稚的误解,认为只有头文件是依赖项。这可能导致错误的构建,因为许多其他原因,如更改命令行开关,更改编译器或更改硬件架构,都被监视到。

这两个问题的解决方案是使用一个可靠的构建工具:makepp处理这些情况,甚至可以扫描包含文件中的子包含,当你启动它时,甚至还没有构建。

还有很多事情要做。除了做GNU make所能做的几乎所有事情之外,还有很多更有用的事情,您甚至可以使用一些Perl编程扩展您的make文件。