为什么在我的 Makefile 中包含一个文件会更改我的 Makefile 目录变量?

Why does including a file in my Makefile change my Makefile-directory variable?

为了从不同位置调用我的 Makefile 而不会弄乱相对路径,我使用 another answer:

中给出的 Makefile 变量引用路径
DIR=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))

我知道当我包含其他文件时 MAKEFILE_LIST 不同,但由于我在进行任何包含之前将其值存储在变量中,我很惊讶变量值不同。

示例:

$ tree .
.
├── another_file
└── subdirectory
    └── Makefile

$ cat Makefile
DIR=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))

test:
    @echo $(DIR)

#include $(DIR)/../another_file

$ make
/subdirectory

果然不出所料。但是如果我取消注释 include 行,我会得到

$ make
/

这对我来说没有意义,因为 another_file 仍然包含而没有错误表明 $(DIR) 的值是 /subdirectory

注意make目标放在include语句之前,顺序切换时行为不会改变。猜猜这是由于预处理,但它仍然没有向我解释为什么 $(DIR) 似乎有不同的值。

$ make --version
GNU Make 3.81
...
This program built for i386-apple-darwin11.3.0

这是因为 MAKEFILE_LIST 的值在 include 之后发生了变化,变量 DIR 的扩展发生在使用时。

我在你的 Makefile 中添加了 info 用于演示

DIR=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))

$(info list1 $(MAKEFILE_LIST))
$(info dir1 $(DIR))

test:
    @echo $(DIR)

include $(DIR)/../another_file

$(info list2 $(MAKEFILE_LIST))
$(info dir2 $(DIR))

输出

$ make
list1  Makefile
dir1 /home/lesmana/tmp/maek/subdir
list2  Makefile /home/lesmana/tmp/maek/subdir/../another_file
dir2 /home/lesmana/tmp/maek
/home/lesmana/tmp/maek

请注意 MAKEFILE_LIST 的值在 include 之后如何变化以及 DIR 的值如何变化。

解决此问题的一种方法是使用 := 而不是 =

强制立即扩展 DIR
DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))

这样 DIR 的值只计算一次,即使 MAKEFILE_LIST 改变也不会改变。

另一种方法是使用 firstword 而不是 lastword

另请注意,test 配方中 DIR 的扩展恰好发生在执行该配方之前。这就是为什么 include 相对于 test.

发生在哪里并不重要

阅读此处了解更多信息:


我不知道如何看待这个 shell 构造来获取 Makefile 的目录。通常来自更高层的 Makefile 包括来自子目录的 Makefile。但是你有你的用例。我不会在这里争论这个问题。我希望我对变量的解释有所帮助。