【发布时间】:2012-04-24 15:47:16
【问题描述】:
考虑到每个命令都在其自己的 shell 中运行,在 makefile 中运行多行 bash 命令的最佳方式是什么?例如,像这样:
for i in `find`
do
all="$all $i"
done
gcc $all
【问题讨论】:
考虑到每个命令都在其自己的 shell 中运行,在 makefile 中运行多行 bash 命令的最佳方式是什么?例如,像这样:
for i in `find`
do
all="$all $i"
done
gcc $all
【问题讨论】:
您可以使用反斜杠来续行。但是请注意,shell 接收的整个命令连接成一行,因此您还需要用分号终止某些行:
foo:
for i in `find`; \
do \
all="$$all $$i"; \
done; \
gcc $$all
但如果您只想获取find 调用返回的整个列表并将其传递给gcc,您实际上不一定需要多行命令:
foo:
gcc `find`
或者,使用更传统的外壳 @987654325@ 方法(注意 $ 转义):
foo:
gcc $$(find)
【讨论】:
如问题所示,每个子命令都在其自己的 shell 中运行。这使得编写非平凡的 shell 脚本有点混乱 -- 但这是可能的! 解决方案是将你的脚本合并到 make 将考虑单个子命令(单行)的内容中。
$$ 来逃避脚本对$ 的使用
; 将脚本转换为单行\ 转义行尾
set -e 开头,以匹配 make 的规定以在子命令失败时中止() 或{} 将脚本括起来以强调多行序列的内聚性——这不是典型的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 ;\
}
【讨论】:
SHELL := /bin/bash 来启用 BASH 特定的功能,例如 process substitution。
{ 之后的空格对于防止将 {set 解释为未知命令至关重要。
{} 和 () 包装之间的区别会产生很大的不同它直接从shell提示符。你可以通过声明变量对你的 shell 实例造成严重破坏,尤其是在{} 内部使用set 修改状态。 () 防止脚本修改您的环境,这可能是首选。示例(这将结束您的 shell 会话):{ set -e ; } ; false.
command ; ## my comment \` (the comment is between ;` 和 `\`)。这似乎工作正常,除了 if 您手动运行命令(通过复制和粘贴),命令历史记录将以破坏命令的方式包含注释(如果您尝试重用它)。 [注意:由于在反引号中使用了反斜杠,此注释的语法突出显示被破坏。]
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
【讨论】:
当然,编写 Makefile 的正确方法是实际记录哪些目标取决于哪些源。在简单的情况下,建议的解决方案将使foo 依赖于自己,但当然,make 足够聪明,可以放弃循环依赖。但是如果你将一个临时文件添加到你的目录中,它会“神奇地”成为依赖链的一部分。最好一劳永逸地创建一个明确的依赖关系列表,也许通过脚本。
GNU make 知道如何运行 gcc 以从一组 .c 和 .h 文件中生成可执行文件,所以也许你真正需要的只是
foo: $(wildcard *.h) $(wildcard *.c)
【讨论】:
只调用命令有什么问题?
foo:
echo line1
echo line2
....
对于您的第二个问题,您需要转义 $,而是使用 $$,即 bash -c '... echo $$a ...'。
编辑:您的示例可以像这样重写为单行脚本:
gcc $(for i in `find`; do echo $i; done)
【讨论】: