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 只能保证此刻正在执行的进程中的一个进程读取标准输入流。而其他的进程键的标准输入流将设置为无效。因此在此一时刻多个执行命令的进程中只有一个进程获得标准输入,而其他的需要读取标准输入流的进程由于输入流无效而导致致命的错误。