Makefile patsubst使用shell变量的值

时间:2017-06-16 20:52:56

标签: linux bash shell makefile gnu-make

作为测试套件的make install规则的一部分,我想将一个目录(src目录)中的所有二进制可执行文件移动到bin目录。我认为一种简单的方法是简单地循环遍历src目录中的每个文件,然后使用patsubstsrc替换为每个路径中的bin。不幸的是,我无法让它工作,因为我无法在每次循环迭代中获得make来评估当前FILE的名称。我有权访问的是bash shell变量$$FILE,但当我将其与make patsubst函数一起使用时,它实际上并没有评估 shell变量$$FILE ...而是,patsubst函数似乎只看到字符串"$FILE"

所以,这就是我正在尝试的:

install :
    -- irrelevant stuff snipped --

    for FILE in $(BINARY_TARGETS); do \
        if [ -f $$FILE ]; then mv -f $$FILE $(patsubst %/src/,%/bin/,$$FILE); fi \
    done 

这会导致每个文件出错:

mv: ‘./src/foo/bar’ and ‘./src/foo/bar’ are the same file

这个错误让我明白patsubst中的make函数实际上并没有评估shell变量,只是看到了$FILE,结果就是它没有&#39}。找到替换模式,传递给mv的最终命令将源和目标路径作为相同的字符串。

那么,有没有办法让patsubst来评估shell变量的值?或者是否有更好的方法来实现我在这里尝试实现的目标?

1 个答案:

答案 0 :(得分:1)

(let [nums (range)] (time (nth nums 1e8)) (time (nth (range) 1e8))) "Elapsed time: 2127.814253 msecs" "Elapsed time: 2042.608043 msecs" 处理优先于将命令传递给shell。并且,一旦通过,它们将由shell执行。因此,首先make处理命令并在:

make

$(patsubst %/src/,%/bin/,$$FILE) $$FILE代替,然后按字面处理。因此,没有匹配的模式,实际上$FILE返回patsubst。请参阅以下示例:

$FILE

它给出了:

bar:
    echo $(patsubst %/src/,%/bin/,$$whatever)

作为makefile规则的结果,bash按以下命令执行:

arturcz@szczaw:/tmp/m$ make bar
echo $whatever

arturcz@szczaw:/tmp/m$ 

这就是你得到结果的原因。

解决方案

您可以依靠for FILE in src/a src/b src/c; do \ if [ -f $FILE ]; then mv -f $FILE $FILE; fi \ done 进行正确的替换,但您需要将其强制为shell(默认情况下为bash,缺少某些必需的功能):

sh

您也可以要求SHELL=bash install: for FILE in $(BINARY_TARGETS); do \ if [ -f $$FILE ]; then echo $$FILE $${FILE/\/src\//\/bin\/}; fi \ done 进行循环和替换。你可以通过几种方法实现这一目标。这个正在进行所有替换和准备命令。

make

您可以使用`$(通配符)函数停止检查文件是否存在install: $(foreach d,$(BINARY_TARGETS),if [ -f $(d) ]; then mv -f $(d) $(d:./src/%=./bin/%);fi;)

make

最后,我个人更喜欢的解决方案 - 使用适当的依赖关系和规则以install: $(foreach d,$(wildcard $(BINARY_TARGETS)),mv -f $(d) $(d:./src/%=./bin/%);) 方式进行。

make

如果install: $(BINARY_TARGETS:./src/%=./bin/%) bin/%: src/% mv -f $< $@ 中存在任何文件是可选的,您可能需要再次使用BINARY_TARGET技巧:

$(wildcard)