makefile 中的多行 bash 命令
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10121182/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Multiline bash commands in makefile
提问by Jofsey
I have a very comfortable way to compile my project via a few lines of bash commands. But now I need to compile it via makefile. Considering, that every command is run in its own shell, my question is what is the best way to run multi-line bash command, depended on each other, in makefile?For example, like this:
我有一种非常舒服的方式来通过几行 bash 命令来编译我的项目。但现在我需要通过 makefile 编译它。考虑到每个命令都在自己的 shell 中运行,我的问题是在 makefile 中运行多行 bash 命令的最佳方法是什么?例如,像这样:
for i in `find`
do
all="$all $i"
done
gcc $all
Also, can someone explain why even single-line command bash -c 'a=3; echo $a > file'
works correct in terminal, but create empty file in makefile case?
另外,有人可以解释为什么即使单行命令bash -c 'a=3; echo $a > file'
在终端中也能正常工作,但在 makefile 情况下创建空文件吗?
回答by Eldar Abusalimov
You can use backslash for line continuation. However note that the shell receives the whole command concatenated into a single line, so you also need to terminate some of the lines with a semicolon:
您可以使用反斜杠进行换行。但是请注意,shell 接收连接成一行的整个命令,因此您还需要用分号终止某些行:
foo:
for i in `find`; \
do \
all="$$all $$i"; \
done; \
gcc $$all
But if you just want to take the whole list returned by the find
invocation and pass it to gcc
, you actually don't necessarily need a multiline command:
但是,如果您只想获取find
调用返回的整个列表并将其传递给gcc
,则实际上并不一定需要多行命令:
foo:
gcc `find`
Or, using a more shell-conventional $(command)
approach (notice the $
escaping though):
或者,使用更传统的 shell$(command)
方法(注意$
转义):
foo:
gcc $$(find)
回答by nobar
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).
如问题所示,每个子命令都在自己的 shell 中运行。这使得编写非平凡的 shell 脚本有点混乱——但这是可能的!解决方案是将您的脚本合并为 make 将考虑单个子命令(单行)的内容。
Tips for writing shell scripts within makefiles:
在 makefile 中编写 shell 脚本的技巧:
- Escape the script's use of
$
by replacing with$$
- Convert the script to work as a single line by inserting
;
between commands - If you want to write the script on multiple lines, escape end-of-line with
\
- Optionally start with
set -e
to match make's provision to abort on sub-command failure - 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
$
通过替换为来逃避脚本的使用$$
- 通过
;
在命令之间插入将脚本转换为单行 - 如果要在多行上编写脚本,请使用行尾转义
\
- 可选地开始
set -e
以匹配 make 的规定以在子命令失败时中止 - 这完全是可选的,但您可以用括号括起来
()
或{}
强调多行序列的内聚性——这不是典型的 makefile 命令序列
Here's an example inspired by the OP:
这是一个受 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 ;\
}
回答by JesperE
What's wrong with just invoking the commands?
只调用命令有什么问题?
foo:
echo line1
echo line2
....
And for your second question, you need to escape the $
by using $$
instead, i.e. bash -c '... echo $$a ...'
.
对于您的第二个问题,您需要$
通过使用来转义$$
,即bash -c '... echo $$a ...'
.
EDIT: Your example could be rewritten to a single line script like this:
编辑:您的示例可以重写为这样的单行脚本:
gcc $(for i in `find`; do echo $i; done)
回答by tripleee
Of course, the proper way to write a Makefile is to actually document which targets depend on which sources. In the trivial case, the proposed solution will make foo
depend on itself, but of course, make
is smart enough to drop a circular dependency. But if you add a temporary file to your directory, it will "magically" become part of the dependency chain. Better to create an explicit list of dependencies once and for all, perhaps via a script.
当然,编写 Makefile 的正确方法是实际记录哪些目标取决于哪些来源。在微不足道的情况下,建议的解决方案将foo
依赖于自身,但当然,make
它足够聪明,可以删除循环依赖。但是如果你在你的目录中添加一个临时文件,它会“神奇地”成为依赖链的一部分。最好一劳永逸地创建一个明确的依赖项列表,也许通过脚本。
GNU make knows how to run gcc
to produce an executable out of a set of .c
and .h
files, so maybe all you really need amounts to
GNU make 知道如何运行gcc
以从一组.c
和.h
文件中生成可执行文件,所以也许您真正需要的就是
foo: $(wildcard *.h) $(wildcard *.c)