makefile中的多行bash命令

Jof*_*sey 98 bash makefile

我有一种非常舒适的方式来通过几行bash命令编译我的项目.但现在我需要通过makefile编译它.考虑到每个命令都在自己的shell中运行,我的问题是在makefile中运行多行bash命令的最佳方法什么,相互依赖? 例如,像这样:

for i in `find`
do
    all="$all $i"
done
gcc $all
Run Code Online (Sandbox Code Playgroud)

另外,有人可以解释为什么即使单行命令bash -c 'a=3; echo $a > file'在终端中工作正常,但在makefile情况下创建空文件?

Eld*_*mov 116

我会使用反斜杠换行符:

foo:
    for i in `find`;     \
    do                   \
        all="$$all $$i"; \
    done;                \
    gcc $$all
Run Code Online (Sandbox Code Playgroud)

UPD.

或者,如果只想将返回的整个列表传递findgcc:

foo:
    gcc `find`
Run Code Online (Sandbox Code Playgroud)

  • 对于多行,您仍然需要转义美元符号,如其他注释中所示。 (2认同)

nob*_*bar 77

如问题所示,每个子命令都在自己的shell中运行.这使得编写非平凡的shell脚本有点乱 - 但它是可能的! 解决方案是将您的脚本合并到将考虑单个子命令(单行)的内容中.

在makefile中编写shell脚本的提示:

  1. $通过替换来逃避脚本的使用$$
  2. 通过;在命令之间插入,将脚本转换为单行
  3. 如果要在多行上编写脚本,请使用 \
  4. (可选)首先set -e匹配make的配置以在子命令失败时中止
  5. 这是完全可选的,但您可以将脚本括在(){}强调多行序列的内聚性 - 这不是典型的makefile命令序列

这是一个受OP启发的例子:

mytarget:
    { \
    set -e ;\
    msg="header:" ;\
    for i in $$(seq 1 3) ; do msg="$$msg pre_$${i}_post" ; done ;\
    msg="$$msg :footer" ;\
    echo msg=$$msg ;\
    }
Run Code Online (Sandbox Code Playgroud)

  • 微妙的一点:```之后的空格对于防止将`{set`解释为未知命令至关重要. (8认同)
  • 您可能还需要在makefile中使用[`SHELL:= /bin/bash`](http://stackoverflow.com/questions/589276/how-can-i-use-bash-syntax-in-makefile-targets)启用BASH特定功能,例如[进程替换](http://unix.stackexchange.com/questions/17107/process-substitution-and-pipe). (3认同)
  • 细微之处#2:在makefile中,这可能并不重要,但是如果您有时想复制脚本并直接从shell提示符运行脚本,则用{{}和`()`包装之间的区别会产生很大的不同。 。您可以在{}内声明变量,特别是使用set修改状态,从而对shell实例造成严重破坏。`()`防止脚本修改您的环境,这可能是首选。示例(**这将结束您的shell会话**):`{set -e; }; 错误的。 (3认同)

Jea*_*vin 6

ONESHELL 指令允许编写要在同一个 shell 调用中执行的多行配方。

all: foo

SOURCE_FILES = $(shell find . -name '*.c')

.ONESHELL:
foo: ${SOURCE_FILES}
    FILES=()
    for F in $^; do
        FILES+=($${F})
    done
    gcc "$${FILES[@]}" -o $@
Run Code Online (Sandbox Code Playgroud)

但是有一个缺点:特殊前缀字符('@'、'-' 和 '+')的解释不同。

https://www.gnu.org/software/make/manual/html_node/One-Shell.html