Makefile 中的 include (依赖文件) 的执行过程

1. 疑问所在

博主在学习名为<<“万能makefile”写法详解,一步一步写一个实用的Makefile>>的博文的时候,始终对于 Makefile include 的执行过程心存疑惑。 建议大家在看本博文之前,先看下提到的那篇博文。

有疑问的代码大致如下:

    SRCS:$(wildcard *.c)
    DEPS=$(SRCS:*.c=*.d)
    .....

    include $(DEPS)
    %.d:%.c
        gcc -MM $< > $@

疑问 : 若是首次 make,目录下不存在 xxx.d 文件,同时 xxx.d 文件并不是哪个规则的依赖文件,所以 <%.d:%.c> 这条模式规则应该不会执行,可实际上执行了,因为目录下生成了 xxx.d 文件。

结果 : 经过测试,发现首次 make 时,当执行到 include $(DEPS) 的时候,终端在报告了如下警告:
makefile:6: xxx.d: No such file or dirctory
之后,会默认在 makefile 中去找以 xxx.d 为目标的规则并执行,若该规则也没发现,便会报错并中止执行。

2. 探索过程

以下是博主针对自己的疑问所做的测试过程

  • makefile 测试内容如下:
all:
    @echo "-------- $@ ---------"

include tmp.d
tmp.d:
    @echo "-------- $@ ---------"

键入 make 执行结果如下:

makefile:6: tmp.d: No such file or directory
-------- tmp.d ---------
-------- all ---------

结果显示,执行了以 tmp.d 为目标的规则。
注释:all 目标才是首目标,可输出的结果是首先打印了非首目标的 tmp.d 目标,这个是因为 include 语句执行于目标规则之前,就好比 C 文件中的 include 指令一样。

  • 倘若目录下存在 tmp.d, 又会是什么情况呢?

先在 makefile 所在目录下执行命令 touch tmp.d 生成空文件 tmp.d
键入 make 执行结果如下:

-------- all ---------

结果表明,当目录下存在 tmp.d 文件,则不会执行以 tmp.d 为目标的规则。

  • 倘若 makefile 文件中没有以 tmp.d 为目标的规则,makefile 所在目录下也没有 tmp.d 文件,又会出现什么情况呢?

在 makefile 文件中屏蔽以下行:

#tmp.d:
#   @echo "-------- $@ ---------"

键入 make 执行结果如下:

makefile:6: tmp.d: No such file or directory
make: *** No rule to make target `tmp.d'.  Stop.

结果表明,一旦 makefile 所在目录下,没有 tmp.d 文件,同时 makefile 中也没有以 tmp.d 为目标的规则,运行就会报错并中止,其实从错误消息的提示也可以看出,在运行到 include tmp.d 的时候,有两个动作:

  1. 检查 makefile 所在目录下是否有 tmp.d 文件;
  2. 查找 makefile 文件中是否有以 tmp.d 为目标的规则。

若有一个都会执行通过,若一个都没有就报错并中止执行。

实际开发过程中,对于使用了依赖文件的 makefile,不可能使用博文中提到的在首次 make 时,因为目录下不存在依赖文件,而为了 include $(DEPS) 不报错人工 touch 所有的依赖文件的。所以需要在 include 前面加上 ‘-’(忽略错误),即如下处理:

-include $(DEPS)

3. 结语

可能大牛会觉得以上实际过程本该如此,可是在我这个新手看了<<跟我一起写Makefile>>之后,还是对 include 关键字的理解不够全面,导致内心出现了文章开头所描述的疑惑。所以在此写给同样有如此疑问的新手,一起学习。

你可能感兴趣的:(Linux之Makefile)