1. shell 相关
1.1 默认 shell
Makefile
所使用的命令是由 shell
命令行组成,他们是一条一条执行的。
多个命令之间要使用分号隔开,Makefile
中的任何命令都要以 tab
键开始。
多个命令行之间可以有空行和注释行,在执行规则时空行会被自动忽略。
通常系统中可能存在不同的 shell
。但是 make
处理 Makefile
过程时,如果没有明确的指定,那么对所有规则中的命令行的解析使用 bin/sh
来完成。
如:
all:
echo $(SHELL)
执行 make
之后结果
wohu@ubuntu:~/cpp/func$ make
echo /bin/sh
/bin/sh
wohu@ubuntu:~/cpp/func$
1.2 执行 shell
语法:
$(shell <shell command>)
它的作用就是执行一个 shell
命令, 并将 shell
命令的结果作为函数的返回.
作用和 <shell command>
一样, ` 是反引号
all:
echo $(shell pwd)
执行 make
结果:
wohu@ubuntu:~/cpp/func$ make
echo /home/wohu/cpp/func
/home/wohu/cpp/func
wohu@ubuntu:~/cpp/func$
2. 命令回显
通常 make
在执行命令行之前会把要是执行的命令行输出到标准输出设备。我们称之为 “回显”,如果规则的命令行以字符 @
开始,则 make
在执行的时候就不会显示这个将要被执行的命令。
示例:
all:
@echo $(SHELL)
执行 make
之后结果
wohu@ubuntu:~/cpp/func$ make
/bin/sh
wohu@ubuntu:~/cpp/func$
在执行命令之前没有字符 @
,那么 make
的输出将是 /bin/sh
。
Makefile
中书写 shell
命令时可以加 2 种前缀 @
和 -
, 或者不用前缀。3 种格式的 shell
命令区别如下:
- 不用前缀:输出执行的命令以及命令执行的结果, 出错的话停止执行
- 前缀
@
: 只输出命令执行的结果, 出错的话停止执行 - 前缀
-
: 命令执行有错的话, 忽略错误, 继续执行
3. make 的参数
-n
或者是--just-print
,执行时只显示所要执行的命令,但不会真正的执行这个命令,其中包括了使用的@
字符开始的命令,通常用于检查编写的Makefile
内容;-s
或者是--slient
则是禁止所有的执行命令的显示,就好像所有的命令行都使用@
开始一样;
4. 命令的执行
当规则中的目标需要被重建的时候,此规则所定义的命令将会被执行,如果是多行的命令,那么每一行命令将是在一个独立的子 shell
进程中被执行。
因此,多命令行之间的执行命令时是相互独立的,相互之间不存在交互。
在 Makefile
中书写在同一行中的多个命令属于一个完整的 shell
命令行,书写在独立行的一条命令是一个独立的 shell
命令行。
因此:在一个规则的命令中命令行
cd
改变目录不会对其后面的命令的执行产生影响。就是说之后的命令执行的工作目录不会是之前使用cd
进入的那个目录。如果达到这个目的,就不能把cd
和其后面的命令放在两行来书写。而应该把这两个命令放在一行上用分号隔开。这样才是一个完整的shell
命令行。
all:
cd /home/wohu/cpp/func;\
pwd ; \
ls
执行 make 结果
wohu@ubuntu:~/cpp/func$ make
cd /home/wohu/cpp/func;\
pwd ; \
ls
/home/wohu/cpp/func
demo.cpp demo.h Makefile
wohu@ubuntu:~/cpp/func$
如果想把一个完整的 shell
命令行书写在多行上,需要使用反斜杠 \
来对处于多行的命令进行连接,表示他们是一个完整的 shell
命令行。
5. 并发执行命令
GNU make
支持同时执行多条命令。通常情况下,同一时刻只有一个命令在执行,下一个命令只有在当前命令结束之后才能够开始执行。不过可以通过 make
命令行选项 -j
或者 --jobs
来告诉 make
在同一时刻可以允许多条命令同时执行。
如果选项 -j
之后存在一个整数,其含义是告诉 make
在同一时刻可以允许同时执行的命令行的数目。这个数字被称为 job slots。当 -j
选项中没有出现数字的时候,使用默认的 job solts,值为 1,表示 make
将串行的执行规则的命令(同一时刻只能由一条命令被执行)。
并行执行命令所带来的问题是显而易见的:
- 多个同时执行的命令的输出信息将同时被输出到终端。当出现错误时很难根据一大堆凌乱的信息来区分那条命令执行错误;
- 在同一时刻可能会存在多个命令执行的进程同时读取到标准输入,但是对于标准输入设备来说,在同一时刻只能存在一个进程访问它。就是说在某个时间点,
make
只能保证此刻正在执行的进程中的一个进程读取标准输入流。而其他的进程键的标准输入流将设置为无效。因此在此一时刻多个执行命令的进程中只有一个进程获得标准输入,而其他的需要读取标准输入流的进程由于输入流无效而导致致命的错误。