以下内容源于C语言中文网的学习与整理,非原创,如有侵权请告知删除。
简述
Makefile的规则,是由依赖关系规则和命令组成的。
Makefile中所使用的命令是由 shell 命令行组成,它们是一条一条执行的。
Makefile 中的任何命令都要以
tab
键开始。一行中的多个命令之间要使用分号隔开。
多个命令行之间可以有空行和注释行,在执行规则时空行会被自动忽略。
命令中出现的字符“#”到行末的内容被认为是注释。“#”可以不在此行的行首,此时“#”之前的内容不会被作为注释处理。
通常系统中可能存在不同的 shell 。但是 make 处理 Makefile 过程时,如果没有明确的指定,那么对所有规则中的命令行的解析使用
bin/sh
来完成。执行过程中使用的 shell 决定了规则中的命令的语法和处理机制。
命令回显
通常 make 在执行命令行之前,会把将执行的命令行输出到标准输出设备,我们称之为 "回显"。如果规则的命令行以字符“@”开始,则不会再显示这个将要被执行的命令。典型的用法是在使用
echo
命令输出一些信息时,在echo命令前加字符“@”。OBJ=test main list all:@echo $(OBJ)
执行时将会得到
test main list
这条输出信息。如果在执行命令之前没有字符“@”,那么make的输出将是echo test main list,即把命令也输出了。
我们在执行 make 时添加上一些参数,可以控制命令行是否输出。(1)当使用 make 的时候机加上参数
-n
或者是--just-print
,执行时只显示所要执行的命令,但不会真正的执行这个命令。只有在这种情况下 make 才会打印出所有的 make 需要执行的命令,其中包括了使用的“@”字符开始的命令。这个选项对于我们调试 Makefile 非常的有用,使用这个选项就可以按执行顺序打印出 Makefile 中所需要执行的所有命令。(2)而 make 参数
-s
或者是--slient
则是禁止所有的执行命令的显示。就好像所有的命令行都使用“@”开始一样。
命令的执行
当规则中的目标需要被重建的时候,此规则所定义的命令将会被执行。
如果是多行的命令,则每行命令(一行可能包括多个命令,多个命令之间用分号隔开)都是在一个独立的子 shell 进程中被执行。因此执行命令时,命令行之间是相互独立的,不存在依赖。
比如说,在某一命令行使用cd命令改变目录,不会对之后的命令行的执行产生影响,也就是说之后的命令行执行的工作目录,不会是之前使用cd命令进入的那个目录。因此如果想使用命令cd,就不能把cd命令和它后面的命令放在两行来书写,而应该放在一行上用分号隔开。
实例
foo:bar/losecd bar;gobble lose >../foo
如果一个完整的shell命令行太长,不方便写在一行,那么可以使用反斜杠 (\)来对处于多行的命令进行连接,表示它是一个完整的shell命令行。例如上例也可以这样书写:
foo:bar.losecd 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" ,则同一时刻可以执行多条命令。如果选项 "-j" 之后存在一个整数,其含义是同一时刻可以执行的命令行的数目。这个数字被称为“
job slots
”。当 "-j" 选项后没有数字时,同一时间执行的命令数目没有要求。默认的job solts
的值为1,表示make将串行执行规则的命令,即同一时刻只执行一条命令。并行执行命令所带来的问题:
- 多个同时执行的命令的输出信息将同时被输出到终端。当出现错误时很难根据一大堆凌乱的信息来区分哪条命令执行错误。
- 在同一时刻可能会存在多个命令执行的进程同时读取标准输入,但是对于标准输入设备来说,在同一时刻只能存在一个进程访问它。在某个时间点,make只能保证此刻正在执行的进程中的一个进程读取标准输入流,其他进程的标准输入流将设置为无效。因此在此一时刻多个执行命令的进程中只有一个进程获得标准输入,而其他需要读取标准输入流的进程由于输入流无效而导致致命的错误。