考虑到每个命令都在自己的 shell 中运行,在 makefile 中运行多行 bash 命令的最佳方式是什么?例如,像这样:
for i in `find` do all="$all $i" done gcc $all
只调用命令有什么不对吗?
foo: echo line1 echo line2 ....
对于第二个问题,您需要使用 $$来转义 $,也就是 bash -c '... echo $$a ...'。
$$
$
bash -c '... echo $$a ...'
编辑: 您的示例可以重写为一行脚本,如下所示:
gcc $(for i in `find`; do echo $i; done)
可以使用反斜杠作为行的延续。但是请注意,shell 接收连接到一行中的整个命令,因此您还需要用分号结束一些行:
foo: for i in `find`; \ do \ all="$$all $$i"; \ done; \ gcc $$all
但是,如果只想获取由 find调用返回的整个列表并将其传递给 gcc,那么实际上不一定需要多行命令:
find
gcc
foo: gcc `find`
或者,使用一种更加传统的 shell 方法 $(command)(注意 $的转义) :
$(command)
foo: gcc $$(find)
当然,编写 Makefile 的正确方法是实际记录哪些目标依赖于哪些源。在这种简单的情况下,提出的解决方案将使 foo依赖于它自己,但是当然,make足够聪明,可以去掉循环依赖。但是如果您将一个临时文件添加到您的目录中,它将“神奇地”成为依赖链的一部分。最好是一劳永逸地创建一个明确的依赖项列表,也许可以通过脚本实现。
foo
make
GNU make 知道如何运行 gcc来从一组 .c和 .h文件中生成一个可执行文件,所以也许您真正需要的是
.c
.h
foo: $(wildcard *.h) $(wildcard *.c)
如问题所示,每个子命令都在自己的 shell 中运行。这使得编写非平凡的 shell 脚本变得有点麻烦—— 但这是有可能的!解决方案是将脚本合并到 make 将考虑的单个子命令(单行)中。
;
\
set -e
()
{}
下面是一个受 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 ;\ }
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