Makefile 关于GNU生成依赖文件*.d

Makefile 关于GNU生成依赖文件*.d,makefile,gnu-make,Makefile,Gnu Make,在程序的makefile中,必须编写规则来定义每个对象文件的依赖关系。考虑对象文件文件。很明显,此对象文件依赖于源文件fileA.c。但它也将取决于此源文件包含的所有头文件。因此,应将以下规则添加到makefile中: # This rule states that fileA.o depends on fileA.c (obviously), but also # on the header files fileA.h, fileB.h and fileC.h file

在程序的makefile中,必须编写规则来定义每个对象文件的依赖关系。考虑对象文件<代码>文件。很明显,此对象文件依赖于源文件
fileA.c
。但它也将取决于此源文件包含的所有头文件。因此,应将以下规则添加到makefile中:

    # This rule states that fileA.o depends on fileA.c (obviously), but also
    # on the header files fileA.h, fileB.h and fileC.h
    fileA.o: fileA.c fileA.h fileB.h fileC.h
请注意,该规则没有配方。可以向其中添加一个配方,但严格来说这不是必需的,因为GNU make可以依赖一个隐式规则(带有配方)将
*.c
文件编译成
*.o
文件

无论如何,手工编写这样的规则是一项可怕的任务。想象一下,如何使makefile规则与源代码中的#include语句保持同步

GNU make手册在第4.14章“自动生成先决条件”中描述了自动化此过程的方法。该过程首先为每个源文件生成
*.d
文件。我引述:

对于每个源文件name.c都有一个makefilename.d,其中列出了目标文件name.o所依赖的文件

手册的内容如下:

下面是从名为name.C的C源文件生成名为name.d的先决条件文件(即makefile)的模式规则:

%.d:%.c
@set-e;rm-f$@\
$(CC)-M$(CPPFLAGS)$<>$@.$$$\
sed's,\($*\)\.o[:]*,\1.o$@:,g'<$@.$$>$@\
rm-f$@$$$$
遗憾的是,手册没有详细解释这条规则实际上是如何工作的。是的,它给出了所需的名称.d文件,但为什么?这条规则很模糊

当看到这个规则时,我感觉它的配方只能在Linux上顺利运行。我说得对吗?有没有办法让这个菜谱也能在Windows上正确运行

非常感谢您的帮助:-)

退出所有错误

@set -e;
删除现有的dep文件(
$@
=target=
%.d

让编译器生成dep文件,并将其输出到一个临时文件,该临时文件使用shell pid进行后期修复(
$
$$
->pid)

删除临时部门

rm -f $@.$$$$
让我们插入
foo
CC=gcc
CPPFLAGS='
,看看make完成扩展后会发生什么:

foo.d: foo.c
    @set -e; rm -f foo.d; \
     gcc -M foo.c > foo.d.$$; \
     sed 's,\(foo\)\.o[ :]*,\1.o foo.d : ,g' < foo.d.$$ > foo.d; \
     rm -f foo.d.$$

请注意,这是一种非常过时的生成依赖项的方法,如果您使用的是GCC或clang,则可以使用
CPPFLAGS+=-MMD-MP
作为编译本身的一部分

假设您有一个名为
foo
的程序:

objs := foo.o bar.o
deps := $(objs:.o=.d)

vpath %.c $(dir $(MAKEFILE_LIST))

CPPFLAGS += -MMD -MP

foo: $(objs)

.PHONY: clean
clean: ; $(RM) foo $(objs) $(deps)

-include $(deps)
这就是您所需要的,内置规则将完成其余的工作。显然,如果您希望将对象文件放在不同的文件夹中,或者如果您希望在源代码树之外进行构建,那么事情会稍微复杂一些

vpath
指令允许您在不同的目录中运行make,并在那里创建文件,例如
make-f path/to/source/Makefile
响应K Mulier: 试试:gmake-C$workdir。。。 这将设置CURDIR=${workdir},但只剩下$PWD(来自env)。 所有临时/输出文件都是在${workdir}中创建的。 此外,我还设置了变量$${PWD}并使用它指定与运行gmake的目录(即源目录)相关的任何内容。 因此,与其

CPPFLAGS += -I../include CPPFLAGS+=-I../include 有

CPPFLAGS += -I$. -I$./../include
CPPFLAGS+=-I$-我$./../includeow,非常感谢你的解释。我仍在仔细阅读你的解释,以便完全理解。但是你确实给了我很大的帮助:-)我确实在使用GCC编译器。那么有没有一种更优雅的方法来生成依赖项呢?你能描述一下吗?我有点不好意思问这个问题,因为我知道这可能会占用你很多时间。但我非常感激:-)@K.Mulier添加了一个简短的示例。哇,非常感谢您提供了这个示例。不幸的是,我想“在源代码树之外构建”。这样,我就可以保持源文件夹的整洁。但老实说,我不知道如何生成依赖项,有几种方法可以“在源代码树之外”生成—在源代码树中生成时,将路径放在.o和.d文件的其他位置,或者在源代码树中使用VPATH或路径,并在纯对象树中生成。
foo.d: foo.c
    @set -e; rm -f foo.d; \
     gcc -M foo.c > foo.d.$$; \
     sed 's,\(foo\)\.o[ :]*,\1.o foo.d : ,g' < foo.d.$$ > foo.d; \
     rm -f foo.d.$$
foo.o foo.d : foo.c foo.h someheader.h
objs := foo.o bar.o
deps := $(objs:.o=.d)

vpath %.c $(dir $(MAKEFILE_LIST))

CPPFLAGS += -MMD -MP

foo: $(objs)

.PHONY: clean
clean: ; $(RM) foo $(objs) $(deps)

-include $(deps)
gmake -C $workdir ... CURDIR = ${workdir} CPPFLAGS += -I../include CPPFLAGS += -I$. -I$./../include