将Makefile变量的值分配给Bash命令结果?

51

我正在尝试将这个命令的输出(在我的makefile中)分配给makefile HEADER变量,就像以下代码行中一样:

HEADER = $(shell for file in `find . -name *.h`;do echo $file; done)

问题在于如果我在makefile中使用以下命令打印HEADER:

print:
    @echo $(HEADER)

我得到了

ile ile ile ile ile ile ile ile ile ile ile ile ile ile ile ile ile ile ile ile ile ile ile ile ile ile ile ile ile ile ile ile ile ile ile ile ile ile ile ile ile

如果我直接在控制台中运行此命令,并直接在我的 makefile 目录中运行:

myaccount$ for file in `find . -name *.h`;do echo $file; done
./engine/helper/crypto/tomcrypt/headers/._tomcrypt_pk.h
./engine/helper/crypto/tomcrypt/headers/tomcrypt.h
./engine/helper/crypto/tomcrypt/headers/tomcrypt_argchk.h
./engine/helper/crypto/tomcrypt/headers/tomcrypt_cfg.h
./engine/helper/crypto/tomcrypt/headers/tomcrypt_cipher.h
./engine/helper/crypto/tomcrypt/headers/tomcrypt_custom.h
./engine/helper/crypto/tomcrypt/headers/tomcrypt_hash.h
./engine/helper/crypto/tomcrypt/headers/tomcrypt_mac.h
....

所以我获取了所有的头文件。我这样做是为了避免在我的makefile中手动指定所有的.h文件。

有什么想法吗?


我认为这并不值得回答,因为它并不是你真正想问的,但我只能假设你这样做是为了依赖关系;如果修改了头文件,则需要重新编译相应的源文件?如果是这样,您可能会发现cc(技术上是cpp)的-MM选项很有用。您甚至可以为具有单独(不相关)源文件的目录制作这样的Makefile。这对于制表完成非常有用。但它的价值在于它还为源文件生成依赖项(就像如果它是一个单一项目一样)。 - Pryftan
3个回答

102

在shell命令中,您需要对$字符进行双重转义:

HEADER = $(shell for file in `find . -name *.h`;do echo $$file; done)
问题在于 make 将尝试将 $f 扩展为变量,由于找不到任何内容,它只是用 "" 替换掉了它。 这样,您的 shell 命令只剩下 echo ile,它会如实执行。
添加 $$ 告诉 make 在该位置放置单个 $,从而使 shell 命令看起来完全符合您的要求。

非常好的回复:),我之所以这样做是因为在我的for循环中,我实际上执行更复杂的操作,所以我只是发布了一个小片段。非常感谢 @e.James。 - Goles
需要注意的是,当执行shell命令并引用变量(例如在for循环中),您还必须在shell内置之外执行此操作(毕竟,并不总是需要使用shell内置)。 - Pryftan
我该如何转义“)”字符? - luckydonald
1
注意:$(shell ...) 语法是 GNU Makefile 扩展,可能不受本地可用的 make 支持。此外,请注意 HEADER = $(shell ...)HEADER := $(shell ...) 的区别,前者在每次使用时都会扩展,而后者仅扩展一次。如果您的 shell 命令需要很长时间,这种差异可能会导致巨大的性能差异。:= 语法也是 GNU Makefile 扩展。 - Mikko Rantalainen

20
为什么不简单地这样做呢?
HEADER = $(shell find . -name '*.h')

3
这是针对特定问题的正确解决方法,但并没有解释原始命令失败的原因(即需要使用$$$进行编码)。 - Mikko Rantalainen

8

Makefile 教程 建议使用 wildcard 获取目录中的文件列表。在您的情况下,意味着这样:

HEADERS=$(wildcard *.h)

11
这并不等同于问题中的代码。通配符替换是在解析Makefile时进行的,而例如shell命令只有在执行Makefile规则时才会执行。这在测试Makefile生成的文件是否存在时会产生差异。 - Étienne
HEADERS=$(wildcard ...) 可以被执行多次,但 HEADERS:=$(wildcard ...) 只会被执行一次。据我所知,这里的 wildcard 函数并没有特殊之处。 - Mikko Rantalainen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接