makefile中的多行bash命令

时间:2012-04-12 09:47:25

标签: bash makefile

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

for i in `find`
do
    all="$all $i"
done
gcc $all

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

5 个答案:

答案 0 :(得分:103)

您可以使用反斜杠进行续行。但请注意,shell接收整个命令连接成一行,因此您还需要使用分号终止某些行:

foo:
    for i in `find`;     \
    do                   \
        all="$$all $$i"; \
    done;                \
    gcc $$all

但是如果您只想获取find调用返回的整个列表并将其传递给gcc,您实际上不一定需要多行命令:

foo:
    gcc `find`

或者,使用更常规的$(command)方法(注意$转义):

foo:
    gcc $$(find)

答案 1 :(得分:69)

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

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

  1. 通过替换$
  2. 来逃避脚本对$$的使用
  3. 通过在命令之间插入;
  4. ,将脚本转换为单行
  5. 如果您想在多行上编写脚本,请使用\
  6. 转义行尾
  7. 可选择以set -e开头,以匹配make的配置,以便在子命令失败时中止
  8. 这是完全可选的,但您可以将脚本括在(){}以强调多行序列的内聚性 - 这不是典型的makefile命令序列
  9. 这是一个受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 ;\
        }
    

答案 2 :(得分:2)

当然,编写Makefile的正确方法是实际记录哪些目标取决于哪些来源。在简单的情况下,建议的解决方案将使foo依赖于自身,但当然,make足够聪明,可以放弃循环依赖。但是如果你将一个临时文件添加到你的目录中,它将“神奇地”成为依赖链的一部分。最好是一劳永逸地创建一个明确的依赖列表,可能是通过脚本。

GNU make知道如何运行gcc从一组.c.h文件中生成可执行文件,所以你真正需要的就是

foo: $(wildcard *.h) $(wildcard *.c)

答案 3 :(得分:1)

只是调用命令有什么问题?

foo:
       echo line1
       echo line2
       ....

对于第二个问题,您需要使用$来代替$$bash -c '... echo $$a ...'

编辑:您的示例可以重写为单行脚本,如下所示:

gcc $(for i in `find`; do echo $i; done)

答案 4 :(得分:1)

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

echo t(1)

尽管有一个缺点:特殊前缀字符(“ @”,“-”和“ +”)的解释不同。

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