Makefile定义:递归扩展问题

时间:2010-01-03 08:34:28

标签: makefile

在makefile中,我使用define指令定义变量。该变量将包含我想要执行的可配置命令列表。

我希望此变量获取文件列表(例如.foo个文件)。这些文件是在makefile执行期间创建的。例如makefile:

MY_VAR = $(wildcard *.foo)
define MY_VAR2
    echo $(1) $(MY_VAR)
endef

foo: create_files
    $(call MY_VAR2, ls)
    rm -f *.foo

create_files:
    touch foo.foo
    touch bar.foo

我没有得到预期的结果。似乎MY_VAR2在声明时进行评估。

有没有办法获得理想的行为?


修改

正确指出的$(shell) MY_VAR2命令适用于上面的示例。但是,它不适用于下面的示例。此示例的主要区别在于新文件是在MY_VAR = $(wildcard *.foo) TEST_VAR = $(shell ls *.foo) define MY_VAR2 @touch foo.foo @touch bar.foo @echo "MY_VAR" $(1) $(MY_VAR) @echo "TEST_VAR" $(1) $(TEST_VAR) endef foo: $(call MY_VAR2, ls) @rm -f *.foo 内创建的。

{{1}}

我可以通过添加规则来解决上述问题。有更简单的方法吗?

6 个答案:

答案 0 :(得分:2)

我在这里假设你在这里使用GNU Make。我想你可以得到所希望的 结果使用GNU Make提供的“shell”内置函数。

以下是make文件摘要,演示了如何获得结果:

MY_VAR = $(wildcard *.foo) 
TEST_VAR = $(shell ls *.foo)

define MY_VAR2 
    @echo "MY_VAR" $(1) $(MY_VAR)
    @echo "TEST_VAR" $(1) $(TEST_VAR)
endef 

foo: create_files 
    $(call MY_VAR2, ls) 
    @rm -f *.foo 

create_files: 
    @touch foo.foo 
    @touch bar.foo

为目标“foo”运行上述make文件的结果是:

MY_VAR ls
TEST_VAR ls bar.foo foo.foo

因此, shell 函数的演示使用得到了理想的结果。

来自GNU make文档:

shell 函数执行与反引号(''')相同的函数 shell:它确实命令扩展。这意味着它将shell作为参数 命令并计算命令的输出。唯一的处理工具就是 结果是将每个换行符(或回车符/换行符对)转换为单个空格。
...
通过调用shell函数运行的命令在扩展函数调用时运行。 ... files:= $(shell echo .c) 将文件设置为' .c'的扩展。除非make使用一个非常奇怪的shell,否则就有了 结果与'$(通配符* .c)'相同(只要存在至少一个'.c'文件)。

所以我认为使用递归扩展变量(= form)和 shell 来运行你 可以得到理想的结果。

答案 1 :(得分:2)

在我看来,你正在滥用make,试图在make中编写一个shell脚本。

如果编写shell脚本,请编写shell脚本。您可以按顺序执行命令,并且可以在执行每一行时知道存在哪些文件。

touch foo.foo
touch bar.foo
your-command `ls *.foo`

另一方面,如果你想使用make,那么就有了规则和依赖关系,如果你采用make方式思考,你甚至不需要使用define。

foo: create_files
    your-command $(wildcard *.foo)
    rm -f *.foo

create_files:
    touch foo.foo
    touch bar.foo

答案 2 :(得分:1)

  

4.4.3功能通配符

     

通配符扩展在规则中自动发生。但是,通常不会在设置变量时或在函数的参数内部进行通配符扩展。如果要在这些位置进行通配符扩展,则需要使用通配符函数

您可以在eval函数周围工作。

这些创建的文件应该是另一个规则的依赖项,以便依赖图是正确的。

参考文献:

答案 3 :(得分:0)

您可以尝试过滤命令吗?您可以找到示例here

答案 4 :(得分:0)

如何使用include?
重点是make需要两次执行。
首先,你需要让make创造它想要的东西,
然后你将让make在第二遍之后解析生成的规则 执行第一条规则。

define MY_VAR2
    echo $(1) $(MY_VAR)
    $(1) $(MY_VAR)
endef

-include .listoffiles

foo: create_files
    $(call MY_VAR2, ls -al)
    rm -f *.foo .listoffiles

create_files: .listoffiles

.listoffiles:
    touch foo.foo
    touch bar.foo
    @echo "MY_VAR = \$$(wildcard *.foo)" > $@

我认为它只是做你想要的 双通评估并不意味着你必须输入两次。
它将通过make自动完成。

% make -f test.mk
touch foo.foo
touch bar.foo
echo  ls -al bar.foo foo.foo
ls -al bar.foo foo.foo
ls -al bar.foo foo.foo
-rw-rw-r-- 1 yo-hei clearusers 0 Jan  8 08:44 bar.foo
-rw-rw-r-- 1 yo-hei clearusers 0 Jan  8 08:44 foo.foo
rm -f *.foo .listoffiles

答案 5 :(得分:0)

如何在shell中进行扩展而不是make?

MY_VAR = $$(ls *.foo)
define MY_VAR2
    @echo $(1) $(MY_VAR)
endef

foo: create_files
    $(call MY_VAR2, ls)
    @rm -f *.foo

create_files:
    @touch foo.foo
    @touch bar.foo

double-$将允许shell扩展文件搜索部分。我不禁同意其他有关更优雅的方式的帖子,但这是一个选择。

也适用于你的第二个例子:

MY_VAR = $(wildcard *.foo) 
TEST_VAR = $$(ls *.foo)

define MY_VAR2 
    @touch foo.foo
    @touch bar.foo
    @echo "MY_VAR" $(1) $(MY_VAR)
    @echo "TEST_VAR" $(1) $(TEST_VAR)
endef 

foo:
    $(call MY_VAR2, ls) 
    @rm -f *.foo