Makefile:在用户定义函数中的变量内存储参数并打印它
我有一个简单的Makefile,我想在其中传递一个文件列表,并将它们存储在用户定义函数中的一个变量中,然后打印文件名Makefile:在用户定义函数中的变量内存储参数并打印它,makefile,gnu-make,Makefile,Gnu Make,我有一个简单的Makefile,我想在其中传递一个文件列表,并将它们存储在用户定义函数中的一个变量中,然后打印文件名 REQUESTS:=request/*.json define my_func file=${1} && \ echo ${file} endef run_test : $(REQUESTS) for f in $^ ; \ do \ $(call my_func , $$f) ; \
REQUESTS:=request/*.json
define my_func
file=${1} && \
echo ${file}
endef
run_test : $(REQUESTS)
for f in $^ ; \
do \
$(call my_func , $$f) ; \
done
当我运行make run\u test
for f in request/temp.json ; \
do \
file= $f
/bin/sh: 3: Syntax error: end of file unexpected (expecting "done")
Makefile:53: recipe for target 'run_test' failed
make: *** [run_test] Error 2
我希望它返回以下输出
request/file1.json
request/file2.json
这里有几个问题。首先,将空格放在不应放置的位置:
$(call my_func , $$f)
将宏的${1}
替换为$f
(请注意前导空格),最后得到文件=$f
,shell拒绝该文件,认为该文件在语法上不正确。使用:
$(call my_func,$$f)
相反,在Makefiles中避免使用无用的空格,它们有时是有意义的
接下来(假设您解决了第一个问题),在宏中使用${file}
,但是make会在将结果传递给shell之前对其进行扩展,并且没有名为file
的make变量(它是shell变量,而不是make变量),它扩展为空空间,执行的配方为:
for f in request/foo.json request/bar.json ...; \
do \
file=$f && echo ; \
done
要通过make退出第一次扩展,必须将此$
加倍(而不是对应于实际make变量的另一个):
现在,扩展的配方是:
for f in request/foo.json request/bar.json ...; \
do \
file=$f && echo ${file}; \
done
它应该按照你的意愿来运作
旁注
您必须记住,配方仅通过make扩展一次,就在将完整配方传递给shell之前,而不是在shell循环的每次迭代中。换句话说,当shell开始执行您的配方时,期待make进行任何额外处理已经太晚了;$(call…
已展开,结果将不再更改;make已完成此规则的工作。如果您期望$(call…
在不同的迭代中产生不同的效果,您会失望的
如果您不希望在不同的迭代中对$(call…
进行不同的扩展,那么您所编写的(几乎)是可以的。但如果在宏中使用其他make函数(patsubst
…)和变量,则需要另一种方法:还必须使用make迭代器(foreach
):
make会将配方扩展为:
file="request/foo" && echo "$file"; file="request/bar" && echo "$file" ...
在将其传递到外壳之前。Make以某种方式展开循环,对每次迭代进行预处理(patsubst
),shell以简单的命令序列执行结果,而不使用shell循环
最后但并非最不重要的一点是,每次我在Makefiles中的文件列表上看到这些循环时,我都想知道它们是否是作者不了解模式规则或多目标规则的标志。以防万一,下面是一个示例Makefile,它使用静态模式规则来处理(在本例中只是复制)每个request/xxx.json
文件,并生成一个foo/xxx.foo
文件:
REQUESTS := $(wildcard request/*.json)
FOOS := $(patsubst request/%.json,foo/%.foo,$(REQUESTS))
define my_func
cp "request/$(1).json" "foo/$(1).foo"
endef
.PHONY: run_test clean
run_test: $(FOOS)
$(FOOS): foo/%.foo: request/%.json | foo
$(call my_func,$*)
foo:
mkdir -p $@
clean:
rm -rf foo
一个潜在的好处是,所有配方都可以并行运行(
make-j
),这可以在多核计算机上产生真正的不同。这里有几个问题。首先,将空格放在不应放置的位置:
$(call my_func , $$f)
将宏的${1}
替换为$f
(请注意前导空格),最后得到文件=$f
,shell拒绝该文件,认为该文件在语法上不正确。使用:
$(call my_func,$$f)
相反,在Makefiles中避免使用无用的空格,它们有时是有意义的
接下来(假设您解决了第一个问题),在宏中使用${file}
,但是make会在将结果传递给shell之前对其进行扩展,并且没有名为file
的make变量(它是shell变量,而不是make变量),它扩展为空空间,执行的配方为:
for f in request/foo.json request/bar.json ...; \
do \
file=$f && echo ; \
done
要通过make退出第一次扩展,必须将此$
加倍(而不是对应于实际make变量的另一个):
现在,扩展的配方是:
for f in request/foo.json request/bar.json ...; \
do \
file=$f && echo ${file}; \
done
它应该按照你的意愿来运作
旁注
您必须记住,配方仅通过make扩展一次,就在将完整配方传递给shell之前,而不是在shell循环的每次迭代中。换句话说,当shell开始执行您的配方时,期待make进行任何额外处理已经太晚了;$(call…
已展开,结果将不再更改;make已完成此规则的工作。如果您期望$(call…
在不同的迭代中产生不同的效果,您会失望的
如果您不希望在不同的迭代中对$(call…
进行不同的扩展,那么您所编写的(几乎)是可以的。但如果在宏中使用其他make函数(patsubst
…)和变量,则需要另一种方法:还必须使用make迭代器(foreach
):
make会将配方扩展为:
file="request/foo" && echo "$file"; file="request/bar" && echo "$file" ...
在将其传递到外壳之前。Make以某种方式展开循环,对每次迭代进行预处理(patsubst
),shell以简单的命令序列执行结果,而不使用shell循环
最后但并非最不重要的一点是,每次我在Makefiles中的文件列表上看到这些循环时,我都想知道它们是否是作者不了解模式规则或多目标规则的标志。以防万一,下面是一个示例Makefile,它使用静态模式规则来处理(在本例中只是复制)每个request/xxx.json
文件,并生成一个foo/xxx.foo
文件:
REQUESTS := $(wildcard request/*.json)
FOOS := $(patsubst request/%.json,foo/%.foo,$(REQUESTS))
define my_func
cp "request/$(1).json" "foo/$(1).foo"
endef
.PHONY: run_test clean
run_test: $(FOOS)
$(FOOS): foo/%.foo: request/%.json | foo
$(call my_func,$*)
foo:
mkdir -p $@
clean:
rm -rf foo
一个潜在的好处是,所有配方都可以并行运行(make-j
),这在多核计算机上会产生真正的不同