为什么这个简单的食谱不起作用?
.PHONY: test
test:
foo := $(shell ls | grep makefile) ;\
echo $(foo)
结果是
$> make test
makefile:65: warning: undefined variable 'foo'
foo := makefile ;\
echo
/bin/sh: 1: foo: not found
那么,据我了解,该变量foo
已设置好值makefile
,但之后无法使用?然而,它是一个单行命令,在同一个 shell 中执行?
然而,这有效
@$(eval export foo := $(shell ls | grep makefile)) \
echo $(foo)
echo
所以我猜第一个示例中的变量不可访问,因为在我们尝试?时尚未评估赋值。
如果我进一步挖掘,如何完成这项工作
.PHONY: test
test:
@$(eval export files = $(shell ls))
for f in $(files) ; do \
t = $(ls | grep $$f) ; \
echo $$t;\
done
答案1
我看了你的循环...引用在这里:
.PHONY: test
test:
@$(eval export files = $(shell ls))
for f in $(files) ; do \
t = $(ls | grep $$f) ; \
echo $$t;\
done
所以...$(eval ... )
在 make 中运行一个命令。
$(shell ls)
ls
在 shell 中运行命令,并替换其输出。
因此,由 运行的命令$(eval ... )
类似于export files = file file2 makefile source.c
。该命令创建一个名为 files 的 make 变量并将其导出到子 make。因此,可能不需要导出。
整个$(eval ... )
可以被替换为files = $(wildcard *)
并且它可以使用:=
并放置在规则之外。
该for
循环(四行)在 shell 中运行。完成的第一件事是替换 make 变量和函数。奇怪的是$(ls | grep $$f)
。由于 ls 不是 make 函数,因此它将尝试扩展未定义的变量。这是一个空字符串。如果这是 shell 的$(...)
运算符,则需要将 $ 加倍。 $$
被扩展为$
. $(files)
在eval的基础上进行扩展。
这变成(使用我之前的例子):
for f in file file2 makefile source.c ; do
t =
echo $t;
done
乍一看,这可能会回显四个空行,但事实并非如此。该命令t =
实际上运行程序t
并传递等号作为参数。 t
可能不存在。因此,我们得到四个错误,表明 t 不是有效程序,每个错误后面都有一个空行(除非 t 在其他地方定义)。
更接近您想要的可能是:
files := $(wildcard *)
.PHONY: test
test:
for f in $(files) ; do \
t=$$(ls | grep $$f) ; \
echo $$t ; \
done
这将输出:
file file2
file2
makefile
source.c
请注意,第一行列出了两个文件,因为它们的名称中都包含“文件”。如果这不是您想要的,您可以考虑:
files := $(wildcard *)
.PHONY: test
test:
for f in $(files) ; do \
echo $$f ; \
done
甚至(可能是 GNU 特定的):
files := $(wildcard *)
.PHONY: test
test:
$(foreach f, $(files), echo $f ; )
答案2
在 make 目标配方内部,命令的处理方式与配方外部的逻辑不同(通过生成 shell)。
您可以将变量移到配方之外:
.PHONY: test
foo := $(shell ls | grep makefile)
test:
echo $(foo)
或者,礼貌地这个问题,使用评估:
.PHONY: test
test:
$(eval foo=$(shell ls | grep makefile))
echo $(foo)
两者都输出以下内容:
echo makefile
makefile