关于GNU make依赖文件* .d

时间:2016-08-17 16:42:00

标签: makefile gnu-make

在程序的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章“自动生成先决条件”中描述了一种自动执行此过程的方法。该过程从为每个源文件生成*.d文件开始。我引用:

  

对于每个源文件 name.c ,都有一个makefile name.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 $@.$$$$

可悲的是,手册没有详细解释这条规则是如何运作的。是的,它提供了所需的 name.d 文件,但为什么呢?该规则非常混淆..

在查看此规则时,我感觉它的配方只能在Linux上顺利运行。我对吗?有没有办法让这个配方在Windows上正确运行?

非常感谢任何帮助: - )

2 个答案:

答案 0 :(得分:8)

退出所有错误

@set -e;

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

rm -f $@;

让编译器生成dep文件并输出到后缀为pid的临时文件($< = first prerequisite = %.c$$$$ - &gt; $$ - &gt; pid)

$(CC) -M $(CPPFLAGS) $< > $@.$$$$;

捕获匹配$*.o$* = match stem = %)的目标,将其替换为目标后跟依赖项文件本身,输出到dep文件

sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \

删除temp dep

rm -f $@.$$$$

让我们插入fooCC = gccCPPFLAGS = '',看看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.$$

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并在其中创建文件,例如make -f path/to/source/Makefile

答案 1 :(得分:0)

回复K Mulier: 试试:

gmake -C $workdir ... 
设置了
CURDIR = ${workdir}
,但仅留下了$ PWD(来自环境)。 所有临时文件/输出文件都在$ {workdir}中创建。 另外,我设置变量$。 = $ {PWD}并使用它来指定相对于运行gmake的目录(即源目录)的任何内容。 因此,代替了

CPPFLAGS += -I../include

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