148

考虑到每个命令都在自己的 shell 中运行,那么在 makefile 中运行多行 bash 命令的最佳方法是什么?例如,像这样:

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

5 回答 5

168

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

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

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

foo:
    gcc `find`

或者,使用更传统的 shell$(command)方法(注意$转义):

foo:
    gcc $$(find)
于 2012-04-12T10:13:15.070 回答
113

As indicated in the question, every sub-command is run in its own shell. This makes writing non-trivial shell scripts a little bit messy -- but it is possible! The solution is to consolidate your script into what make will consider a single sub-command (a single line).

Tips for writing shell scripts within makefiles:

  1. Escape the script's use of $ by replacing with $$
  2. Convert the script to work as a single line by inserting ; between commands
  3. If you want to write the script on multiple lines, escape end-of-line with \
  4. Optionally start with set -e to match make's provision to abort on sub-command failure
  5. This is totally optional, but you could bracket the script with () or {} to emphasize the cohesiveness of a multiple line sequence -- that this is not a typical makefile command sequence

Here's an example inspired by the 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 ;\
    }
于 2015-03-16T19:48:29.957 回答
10

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 $@

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

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

于 2020-07-09T16:39:34.377 回答
3

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

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

foo: $(wildcard *.h) $(wildcard *.c)
于 2012-05-07T15:30:27.057 回答
1

仅调用命令有什么问题?

foo:
       echo line1
       echo line2
       ....

而对于你的第二个问题,你需要$通过使用来逃避$$,即bash -c '... echo $$a ...'

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

gcc $(for i in `find`; do echo $i; done)
于 2012-04-12T09:57:10.117 回答