GNU_make chapter2


2.1 makefile 简介

  makefile是make执行的内容源,这个文件包含了工程源代码的编译方式与链接方式。可执行文件由一些 .o 即 目标文件按一定的顺序生成,当工程中已存在一个或若干个正确的makefile时,若对项目源文件(比如c/c++源代码进行了修改),则会对修改过的项目源文件进行编译,而不会是对所有的项目源文件进行重新编译。也可以通过在执行make时,增添命令来指定需要重新编译的项目源文件。

  当使用make进行编译时,工程中的以下几种文件会被编译或重新编译:

  1、没有编译过的源文件;2、距离上一次执行make后有过修改的源文件;3、距离上一次执行make后有过修改的头文件,将会连带头文件与对应的源文件进行重新编译;

  在第2、第3种情况下,对于修改过的头、源文件进行重新编译生成 .o 目标文件,新的 .o 文件将与旧的 .o 文件重新连接生成新的可执行文件。

2.2 Makefile规则介绍

  简单的Makefile的描述规则为:

1 target : prerequisites
2     command

  target : 规则的目标。有两种可能,一是最后需要生成的文件的文件名;二是为了生成最后文件而需要的中间文件的中间文件名。

  prerequisites : 规则的依赖。生成规则目标所需要的文件的文件名列表。

  command : 规则的命令行。规则要执行的操作。可能是shell命令或在shell下执行的程序,一个规则可以有多个命令行,每条命令占一行。一个规则可以没有依赖而只有操作命令行。每条命令必须以 Tab 开头,但不是以 Tab 开头的行就是命令行。但make程序会把出现在第一条规则之后的所有以 Tab 开始的行都作为命令行处理。

  clean规则是与上文有所不同的特殊情况,clean规则的目标“clean”,不是文件而是一个操作,称为“伪目标”。clean规则是可以没有依赖而只有操作的一个例子,这个规则的prerequisites部分可以为空,而只有target和command部分。

2.3 简单的示例

  其中的 \ 反斜线符号是换行符,若一行较长时,将一行分解为多行。但要注意反斜线符号后不能有空格。# 开头的一行为注释行。由上文可知, .o 目标文件既可以是目标也可以是依赖。若规则的目标是个文件,规则的依赖被修改以后,在执行make时,这个目标文件将会被重新编译或则重新链接。

2.4 make如何工作

 由前文可知,Makefile是由一个个的规则所组成的,第一个规则称作“最终目标”或“最终目的”。由前文的例子,“edit”作为最终目标,make在执行第一个规则之前,会先处理edit目标的所有依赖,即例子种的 .o 目标文件,和以这些依赖为目标的规则。对于这些 .o 目标文件,有三种处理方式:

  1、目标文件不存在,则创建它;2、目标文件存在,但目标文件所依赖的头文件和源文件比起上次执行make有改动,则需要重新编译生成这个目标文件;3、目标文件存在,但目标文件的依赖比起上次执行make没有改动,则什么都不用做。

  在Makefile中,若一个规则的目标没有出现在最终目标的依赖中,则这条规则不会被执行。除非在执行make时,明确指定执行这个规则,比如在Linux终端中执行make clean。

2.5 指定变量

   从上图的例子来看,最终目标的目标文件列表出现了两次,第一次是作为依赖列表,第二次是作为命令“cc”的参数列表。若需要为终极目标添加一个依赖文件时,就需要在两个地方分别添加,容易出现漏加或加错的问题。如果定义一个变量,让变量等于列表值,再出现添加或修改等问题时,就只需要修改这个变量即可:

   定义了变量“objects”后,它代表了所有的 .o 目标文件的列表,在需要使用 .o 文件列表的地方使用 “$(objects)” 来表示。因此可以这样写:

2.6 自动推导规则

  make在编译项目源文件时,存在一个默认的规则,能够自动完成对源文件的编译并生成对应的 .o 文件。在提供 .o 目标文件作为目标后,make会自动寻找合适的源文件,除开后缀,文件名与目标文件文件名相同的源文件。所以可以改写成这种样式:

2.7 另类风格的makefile

  略。

2.8 清除工作目录过程文件

  上文提到过,clean目标是“伪目标”,而其作用是清除编译与链接过程中的临时文件:

   但在实际中,一般写成这个样子:

   这么写目的是为了:1、通过 “.PHONY” 特殊目标将 “clean” 目标声明为伪目标,避免磁盘内存在一个名为 “clean” 的文件时,避免目标 “clean” 所在的规则的命令无法执行。2、在命令行之前使用 “-”,意思是忽略命令 “rm” 的执行错误。

  伪目标不能作为终极目标。