关于 GNU make 依赖文件 *.d
About the GNU make dependency files *.d
在程序的 makefile 中,必须编写定义每个目标文件的依赖关系的规则。考虑目标文件 fileA.o
。很明显,这个目标文件依赖于源文件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 章中描述了 "Generating Prerequisites Automatically" 一种自动执行此过程的方法。该过程从为每个源文件生成一个 *.d
文件开始。我引用:
For each source file name.c there is a makefile name.d which lists what files the object file name.o depends on.
手册进行:
Here is the pattern rule to generate a file of prerequisites (i.e, a makefile) called name.d from a C source file called name.c :
%.d: %.c
@set -e; rm -f $@; \
$(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
遗憾的是,手册并未详细解释此规则的实际运作方式。是的,它给出了所需的 name.d 文件,但为什么呢?规则很混乱..
看这条规则,感觉它的配方只会运行顺利Linux。我对吗?有没有办法在 Windows 上也正确地制作这个食谱 运行?
非常感谢任何帮助:-)
出现所有错误时退出
@set -e;
删除现有的 dep 文件 ($@
= target = %.d
)
rm -f $@;
让编译器生成 dep 文件并输出到以 shell pid 为后缀的临时文件($<
= 第一个先决条件 = %.c
、$$$$
-> $$
-> pid)
$(CC) -M $(CPPFLAGS) $< > $@.$$$$;
抓取目标匹配$*.o
($*
=match stem=%
),替换为目标后跟依赖文件本身,输出到dep文件
sed 's,\($*\)\.o[ :]*,.o $@ : ,g' < $@.$$$$ > $@; \
删除临时文件
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[ :]*,.o foo.d : ,g' < foo.d.$$ > foo.d; \
rm -f foo.d.$$
shell 本身会扩展 $$
到 pid,dep 文件中的最终规则看起来像
foo.o foo.d : foo.c foo.h someheader.h
请注意,这是一种非常过时的生成依赖项的方式,如果您使用的是 GCC 或 clang,您可以 generate them 作为编译本身的一部分 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 -f path/to/source/Makefile
.
回复 K 穆里尔:
尝试:
gmake -C $workdir ...
这设置了 CURDIR = ${workdir}
但单独留下了 $PWD(来自 env)。
所有 temp/output 个文件都在 ${workdir} 中创建。
另外,我设置了变量 $。 = ${PWD} 并使用它来指定与 gmake 所在目录相关的任何内容 运行 (即源目录)。
所以,而不是
CPPFLAGS += -I../include
有
CPPFLAGS += -I$. -I$./../include
在程序的 makefile 中,必须编写定义每个目标文件的依赖关系的规则。考虑目标文件 fileA.o
。很明显,这个目标文件依赖于源文件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 章中描述了 "Generating Prerequisites Automatically" 一种自动执行此过程的方法。该过程从为每个源文件生成一个 *.d
文件开始。我引用:
For each source file name.c there is a makefile name.d which lists what files the object file name.o depends on.
手册进行:
Here is the pattern rule to generate a file of prerequisites (i.e, a makefile) called name.d from a C source file called name.c :
%.d: %.c
@set -e; rm -f $@; \
$(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
遗憾的是,手册并未详细解释此规则的实际运作方式。是的,它给出了所需的 name.d 文件,但为什么呢?规则很混乱..
看这条规则,感觉它的配方只会运行顺利Linux。我对吗?有没有办法在 Windows 上也正确地制作这个食谱 运行?
非常感谢任何帮助:-)
出现所有错误时退出
@set -e;
删除现有的 dep 文件 ($@
= target = %.d
)
rm -f $@;
让编译器生成 dep 文件并输出到以 shell pid 为后缀的临时文件($<
= 第一个先决条件 = %.c
、$$$$
-> $$
-> pid)
$(CC) -M $(CPPFLAGS) $< > $@.$$$$;
抓取目标匹配$*.o
($*
=match stem=%
),替换为目标后跟依赖文件本身,输出到dep文件
sed 's,\($*\)\.o[ :]*,.o $@ : ,g' < $@.$$$$ > $@; \
删除临时文件
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[ :]*,.o foo.d : ,g' < foo.d.$$ > foo.d; \
rm -f foo.d.$$
shell 本身会扩展 $$
到 pid,dep 文件中的最终规则看起来像
foo.o foo.d : foo.c foo.h someheader.h
请注意,这是一种非常过时的生成依赖项的方式,如果您使用的是 GCC 或 clang,您可以 generate them 作为编译本身的一部分 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 -f path/to/source/Makefile
.
回复 K 穆里尔: 尝试:
gmake -C $workdir ...这设置了
CURDIR = ${workdir}但单独留下了 $PWD(来自 env)。 所有 temp/output 个文件都在 ${workdir} 中创建。 另外,我设置了变量 $。 = ${PWD} 并使用它来指定与 gmake 所在目录相关的任何内容 运行 (即源目录)。 所以,而不是
CPPFLAGS += -I../include
有
CPPFLAGS += -I$. -I$./../include