第五章 规则的命令
5.1 命令回显
make 在执行命令行之前会把要执行的命令行输出到标准输出设备。
如果规则的命令行以字符“ @ ”开始,则 make 在执行这个命令时就不会回显这个将要被执行的命令。
如果使用 make 的命令行参数“ -n ”或“ --just-print ”,那么 make 执行时只显示所要执行的命令,但不会真正的去执行这些命令。
而 make 参数“ -s ”或“ --slient ”则是禁止所有执行命令的显示,就好像所有的命令行均使用“ @ ”开始一样。
在 Makefile 中使用没有依赖的特殊目标“ .SILENT ”也可以禁止命令的回显,但是它不如使用“ @ ”来的灵活。
5.2 命令执行
在 Makefile 中书写在同一行中的多个命令属于一个完整的 shell 命令行,书写在独立行的一条命令是一个独立的 shell 命令行。 因此:在一个规则的命令中,命令行“ cd ”改变目录不会对其后的命令的执行产生影响。就是说其后的命令执行的工作目录不会是之前使用“ cd ”进入的那个目录。如果要实现这个目的 ,就不能把“ cd ”和其后的命令放在两行来书写。而应该把这两条命令写在一行上,用分号分隔。这样它们才是一个完整的 shell 命令行。
5.3 并发执行命令
可以通过 make 的命令行选项“ -j ”或者“ --job ”来告诉 make 在同一时刻可以允许多条命令同时被执行。 如果选项“ -j ”之后存在一个整数,其含义是告诉 make 在同一时刻可允许同时执行命令的数目。这个数字被称为“ job slots ”。当“ -j ”选项之后没有出现一个数字时,那么同一时刻执行的命令数目没有要求。使用默认的“ job slots ”,值为 1 。表示 make 将串行的执行规则的命令(同一时刻只能有一条命令被执行)。
并行执行命令所带来的问题:
1. 多个同时执的命令的输出信息将同时被输出到终端。
2. 在同一时刻可能会存在多个命令执行进程同时读取标准输入,但是对于标准输入设备来说,在同一时刻只能存在一个进程访问它。 其它需要读取标准输入流的进程由于输入流无效而导致致命错误。
3. 会导致 make 的递归调用出现问题。
当 make 在执行命令时,如果某一条命令执行失败(被一个信号中止,或非零退出),且该条命令产生的错误不可忽略,那么其它的用于重建同一目标的命令执行也将会被终止。此种情况下,如果 make 没有使用“ -k ”或“ --keep-going ”选项, make 将停止执行而退出。另外:如果 make 在执行时,由某种原因(包括信号)被中止,此时它的子进程(那些执行规则命令行的 shell 子进程)正在运行,那么 make 将等到所有这些子进程结束之后才真正退出。
执行 make 时,如果系统运行于重负荷状态下,我们需要控制(减轻)系统在执行 make 时的负荷。可以使用“ -l ”选项告诉 make 限制当前运行的任务的数量( make 所限制的只是它本身所需要占用的系统负载,而不能通过它去控制其它的任务所占用的系统负载)。“ -l ”或“ --max-load ”选项一般后边需要跟一个浮点数。如:
-l 2.5
它的意思是告诉 make 当系统平均负荷高于 2.5 时,不再启动任何执行命令的子任务。不带浮点数的“ -l ”选项用于取消前面通“ -l ”给定的负荷限制。
5.4 命令执行错误
可以在命令之前加一个减号“ - ”(在 [Tab] 字符之后),来告诉 make 忽略此命令的执行失败。
在执行 make 时,如果使用命令行选项“ -i ”或者“ —ignore-errors ”, make 将忽略所有规则中命令执行的错误。
没有依赖的特殊目标“ .IGNORE ”在 Makefile 中有同样的效果。但是“ .IGNORE ”的方式已经很少使用,因为它没有在命令行之前使用“ - ”的方式灵活。
推荐的做法是:在 make 执行失败时,修改错误之后执行 make 之前,使用“ make clean ”明确的删除第一次错误重建的所有目标 。
5.5 Make的递归执行
1.变量Make
subsystem:
cd subdir && $(MAKE)
2.变量和递归
上层 make 过程要将所执行的 Makefile 中的变量传递给子 make 过程,需要明确地指出。在 GNU make 中,实现此功能的指示符是“ export ”。
export VARIABLE ...
unexport VARIABLE ...
一个不带任何参数的指示符“ export ”指示符:
export
含义是将此 Makefile 中定义的所有变量传递给子 make 过程。
变量“ MAKELEVEL ”代表了调用的深度
3.命令行选项和递归
传递过程中变量“ MAKEFLAGS ”的值会被主控 make 自动的设置为包含执行 make 时的命令行选项的字符串。如果在执行 make 时通过命令行指定了“ -k ”和“ -s ”选项,那么“ MAKEFLAGS ”的值会被自动设置为“ ks ”。子 make 进程在处理时,会把此环境变量的值作为执行的命令行参数,因此子 make 过程同样也会有“ -k ”和“ -s ”这两个命令行选项。
4.-w选项
选项“ -w ”或者“ --print-directory ”可以让 make 在开始编译一个目录之前和完成此目录的编译之后给出相应的提示信息,方便开发人员跟踪 make 的执行过程。 通常,选项“ -w ”会被自动打开。
make: Entering directory `/u/gnu/make'.
make: Leaving directory `/u/gnu/make'.
5.6 命令包(相当于函数)
define run-yacc
yacc $(firstword $^)
mv y.tab.c $@
endef
命令包中所有命令中对其它变量的引用,在规则被执行时会被完全展开。使用方法:
foo.c : foo.y
$(run-yacc)
如果一个规则在引用此命令包之前使用了控制命令的前缀字符。那么这个前缀字符将会被添加到命令包定义的每一个命令行之中。
frob.out: frob.in
@$(frobnicate)
5.7 空命令
空命令行可以防止 make 在执行时试图为重建这个目标去查找隐含命令(包括了使用隐含规则中的命令和“ .DEFAULT ”指定的命令。)
target: ;