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)
命令,正确为 sateesh指出,适用于上面的例子。但是,它不适用于下面的示例。此示例的主要区别在于新文件是在 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
我可以通过添加规则来解决上述问题。有没有更简单的方法?
In a makefile, I define a variable using the define
directive. This variable will hold a configurable list of commands that I want to execute.
I would like this variable to get a list of files (.foo
files, for example). These files are created during the makefile execution. For example 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
I do not get the desired results. It appears that MY_VAR2
is evaluated upon declaration.
Is there a way to get the desired behavior?
edit:
The $(shell)
command, as sateesh correctly pointed out, works for the example above. However, it does not work for the example below. The main difference in this example is that the new files are created inside 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
I can solve the above by adding rules. Is there a simpler method?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
在我看来,你正在滥用 make,试图在 make 中编写 shell 脚本。
如果你写一个shell脚本,就写一个shell脚本。您按顺序执行命令,并且可以知道执行每一行时存在哪些文件。
另一方面,如果你想使用make,那么就有规则和依赖关系,如果你采用make的思维方式,你甚至不需要使用define。
It looks to me like you are abusing make, trying to write a shell script in make.
If you write a shell script, write a shell script. You execute your commands in sequence, and you are able to know what files are present when executing each line.
On the other side, if you want to make usage of make, then have rules and dependencies, you won't even have to use define if you go the make way of thinking.
我假设您在这里使用的是 GNU Make。我想你可以得到想要的
使用 GNU Make 提供的“shell”内置函数得出结果。
下面是 make 文件片段,演示了如何获得结果:
针对目标“foo”运行上述 make 文件的结果是:
因此,如所演示的 shell 函数的用法一样,可以获得所需的结果。
来自 GNU make 文档:
shell
函数执行的功能与大多数情况下的反引号 (''') 执行的功能相同
shell:它确实进行命令扩展。这意味着它需要一个 shell 作为参数
命令并计算命令的输出。唯一的处理品牌是
结果是将每个换行符(或回车符/换行符对)转换为单个空格。
...
通过调用 shell 函数运行的命令将在函数调用展开时运行。
...
文件 := $(shell echo .c)
将文件设置为“.c”的扩展。除非 make 使用非常奇怪的 shell,否则它具有
与 '$(wildcard *.c)' 相同的结果(只要至少存在一个 '.c' 文件)。
所以我认为使用递归扩展变量(=形式)以及 shell 函数
可以得到想要的结果。
I'm presuming here that you are using here GNU Make. I think you can get the desired
result using the "shell" built-in function provided with GNU Make.
Below is the make file snippet that demonstrates how you can get the result:
The result of running the above make file for the target "foo" is:
So as demonstrated usage of shell function gets the desired result.
From the GNU make documentation:
The shell
function performs the same function that backquotes (‘‘’) perform in most
shells: it does command expansion. This means that it takes as an argument a shell
command and evaluates to the output of the command. The only processing make does on
the result is to convert each newline (or carriage-return / newline pair) to a single space.
...
The commands run by calls to the shell function are run when the function calls are expanded.
...
files := $(shell echo .c)
sets files to the expansion of ‘.c’. Unless make is using a very strange shell, this has the
same result as ‘$(wildcard *.c)’ (as long as at least one ‘.c’ file exists).
So I think using a recursively expanded variable (= form) along with shell function you
can get the desired result.
你可以围绕
eval
函数进行工作。这些创建的文件应该是另一个规则的依赖项,以便依赖关系图是正确的。
参考文献:
wildcard
eval
功能You may work your away around the
eval
function.These created files should be dependencies of another rule so that the dependency graph is correct.
References:
wildcard
eval
function你能尝试一下过滤命令吗?您可以在此处找到示例。
Could you try the filter command? You can find an example here.
使用 include 怎么样?
重点是 make 需要执行两遍。
首先,你需要让 make 创建它想要的东西,
然后让 make 在第二遍中解析生成的规则
第一条规则的执行。
我想它只是做你想要的。
两次通过评估并不意味着您必须输入 make 两次。
这将由 make 自动完成。
How about using include?
The point is that the make needs two pass of execution.
First, you need to let make create what it wants,
Then you'll let make to parse the generated rule in the second pass after
the execution of the first rule.
It just does what you want, I suppose.
Two pass evaluation doesn't mean you have to type make twice.
It will be done by make automagically.
在 shell 中而不是在 make 中进行扩展怎么样?
双 $ 将允许 shell 扩展文件搜索部分。我忍不住同意其他帖子关于有一种更优雅的方法来做到这一点,但这对你来说是一个选择。
也适用于你的第二个例子:
What about doing your expansion in the shell instead of in make?
The double-$ will allow the shell to expand the file search part. I can't help but agree with the other posts about there being a more elegant way to do this, but this is an option for you.
Works for your second example too: