linux - Makefile patsubst 使用 shell 变量的值

标签 linux bash shell makefile gnu-make

作为测试套件的 make install 规则的一部分,我想将一个目录(src 目录)中的所有二进制可执行文件移动到 bin 目录。我认为一个简单的方法是简单地遍历 src 中的每个文件。目录,然后使用 patsubst替换 srcbin在每个路径中。不幸的是,我无法让它工作,因为我无法获得 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

这个错误让我明白 patsubstmake 中发挥作用实际上并没有评估 shell 变量,而只是看到 $FILE , 所以结果是它没有找到替换模式,最终命令传递给 mv具有相同字符串的源路径和目标路径。

那么,有没有办法得到patsubst评估shell变量的值?还是总体上有更好的方法来实现我在这里想要实现的目标?

最佳答案

make 处理优先于将命令传递给 shell。并且,一旦通过,它们将由 shell 执行。因此,首先 make,处理命令并输入:

$(patsubst %/src/,%/bin/,$$FILE)

$$FILE 被替换为 $FILE 然后按字面意思处理。因此,没有模式匹配,实际上 patsubst 返回 $FILE。请看下面的例子:

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

它给出:

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

arturcz@szczaw:/tmp/m$ 

作为你的 makefile 规则的结果,bash 给出了以下命令来执行:

for FILE in src/a src/b src/c; do \
    if [ -f $FILE ]; then mv -f $FILE $FILE; fi \
done 

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

解决方案

您可以依靠 bash 进行适当的替换,但您需要将其强制执行为 shell(默认情况下它是 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;)

您也可以使用`$(wildcard) 函数停止检查要制作 的文件是否存在:

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) 技巧:

install: $(patsubst ./src/%,./bin/%,$(wildcard $(BINARY_TARGETS)))

bin/%: src/%
    mv -f $< $@

关于linux - Makefile patsubst 使用 shell 变量的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44597823/

相关文章:

linux - 用于移动包含文件的子文件夹的命令,同时保持原始结构

linux - 如何切割特定的数据并将其存储在 Shell 脚本中的字符串中

asp.net - 无法在 mono/linux 上运行 kestrel

java - 用于 Linux 的硬件中断 API

linux - bash shell 脚本变量赋值

linux - 文件删除后进程继续保留文件

linux - Signals Delivered Field of time 命令似乎不起作用

在 bash 脚本上调用 execve bash 找不到参数

php - 将 GET 变量从一个 Bash/PHP 脚本传递到另一个脚本

sql - 能够在命令行中创建 postgres 数据库,但不能在 bash 脚本中创建