通过上个章节的描述,我们已经知道了 Makefile 的规则是什么,他是由依赖关系规则和命令组成的。所使用的命令是由 shell 命令行组成,他们是一条一条执行的。多个命令之间要使用分号隔开,Makefile 中的任何命令都要以tab键开始。多个命令行之间可以有空行和注释行,在执行规则时空行会被自动忽略。
通常系统中可能存在不同的 shell 。但是 make 处理 Makefile 过程时,如果没有明确的指定,那么对所有规则中的命令行的解析使用bin/sh来完成。执行过程中使用的 shell 决定了规则中的命令的语法和处理机制。当使用默认的bin/sh时,命令中出现的字符“#”到行末的内容被认为是注释。当然了“#”可以不在此行的行首,此时“#”之前的内容不会被作为注释处理。
通常 make 在执行命令行之前会把要是执行的命令行输出到标准输出设备。我们称之为 "回显",就好像我们在 shell 环境下输入命令执行时一样。如果规则的命令行以字符“@”开始,则 make 在执行的时候就不会显示这个将要被执行的命令。典型的用法是在使用echo命令输出一些信息时。
实例 1:
OBJ=test main list
all:
@echo $(OBJ)
执行时将会得到test main list这条输出信息,如果在执行命令之前没有字符“@”,那么make的输出将是 echo test main list。
我们在执行 make 时添加上一些参数,可以控制命令行是否输出。当使用 make 的时候机加上参数-n或者是--just-print ,执行时只显示所要执行的命令,但不会真正的执行这个命令。只有在这种情况下 make 才会打印出所有的 make 需要执行的命令,其中包括了使用的“@”字符开始的命令。这个选项对于我们调试 Makefile 非常的有用,使用这个选项就可以按执行顺序打印出 Makefile 中所需要执行的所有命令。而 make 参数-s或者是--slient则是禁止所有的执行命令的显示。就好像所有的命令行都使用“@”开始一样。
当规则中的目标需要被重建的时候,此规则所定义的命令将会被执行,如果是多行的命令,那么每一行命令将是在一个独立的子 shell 进程中被执行。因此,多命令行之间的执行命令时是相互独立的,相互之间不存在以来。
在 Makefile 中书写在同一行中的多个命令属于一个完整的 shell 命令行,书写在独立行的一条命令是一个独立的 shell 命令行。因此:在一个规则的命令中命令行 “cd”改变目录不会对其后面的命令的执行产生影响。就是说之后的命令执行的工作目录不会是之前使用“cd”进入的那个目录。如果达到这个目的,就不能把“cd”和其后面的命令放在两行来书写。而应该把这两个命令放在一行上用分号隔开。这样才是一个完整的 shell 命令行。
实例 2:
foo:bar/lose
cd bar;gobble lose >../foo
如果想把一个完整的shell命令行书写在多行上,需要使用反斜杠 (/)来对处于多行的命令进行连接,表示他们是一个完整的shell命令行。例如上例我们也可以这样书写:
foo:bar.lose
cd bar; \
gobble lose > ../foo
make 对所有规则的命令的解析使用环境变量“SHELL”所指定的那个程序。在 GNU make 中,默认的程序时 “/bin/sh”。不像其他的绝大多数变量,他们的只可以直接从同名的系统环境变量那里获得。make 的环境变量 “SHELL”没有使用环境变量的定义。因为系统环境变量“SHELL”指定的那个程序被用来作为用户和系统交互的接口程序,他对于不存在直接交互过程的 make 显然不合适。在 make 环境变量中“SHELL”会被重新赋值;他作为一个变量我们也可以在 Makefile 中明确的给它赋值,变量“SHELL“的默认值时“/bin/sh”。
GNU make 支持同时执行多条命令。通常情况下,同一时刻只有一个命令在执行,下一个命令只有在当前命令结束之后才能够开始执行。不过可以通过 make 命令行选项 "-j" 或者 "--jobs" 来告诉 make 在同一时刻可以允许多条命令同时执行。
如果选项 "-j" 之后存在一个整数,其含义是告诉 make 在同一时刻可以允许同时执行的命令行的数目。这个数字被称为job slots。当 "-j" 选项中没有出现数字的时候,那么同一时间执行的命令数目没有要求。使用默认的job solts,值为1,表示make将串行的执行规则的命令(同一时刻只能由一条命令被执行)。
并行执行命令所带来的问题是显而易见的: