[001-Makefile-笔记] Makefile简介

来源:互联网 发布:2016网络流行语字母 编辑:程序博客网 时间:2024/06/05 17:05

Makefile规则描述

一个简单的Makefile规则描述如下:

TARGET... : PREREQUISITES...    COMMAND    ...

target:规则的目标
通常是最后需要生成的文件名或者为了实现这个目的而必需生成的中间过程文件名,也可以是一个伪目标。
prerequisites:规则的依赖
是生成规则目标所需要的文件名列表,文件名也可以是其它的规则目标。
command:规则的命令行
是规则所要执行的动作集合。

规则的书写建议是:单目标,多依赖。尽量做到一个规则中只存在一个目标文件,但可以有多个依赖文件。

规则的处理方式:
1. 如果目标文件不存在,则使用其描述的规则创建它
2. 如果目标文件存在,但所依赖的任何一个依赖文件比这个目标文件更新,则根据规则重新生成它
3. 如果目标文件存在,但目标文件比它的任何一个依赖文件更新,则什么也不做

Makefile的内容

在一个完整的Makefile中,包含了5个方面:显式规则、隐含规则、变量定义、指示符和注释。

  • 显式规则:描述了在何种情况下如何更新一个或者多个被称为目标的文件。需要明确地给出目标文件、目标的依赖文件列表以及更新目标文件所需要的命令
  • 隐含规则:是根据一类目标文件自动推导出来的规则。make根据目标文件的名,自动产生目标的依赖文件并使用默认的命令对目标进行更新
  • 变量定义:使用一个字符或字符串代表一段文本串,当定义了一个变量以后,Makefile后续在需要使用此文本串的地方,通过引用这个变量来实现对文本串的使用
  • 指示符:指明在读取Makefile文件过程中所要执行的动作,包括
    • 使用include读取给定文件名的文件
    • 使用条件语句控制Makefile的执行或者忽略Makefile的特定部分
    • 定义多行变量
  • 注释:在“#”字符后的内容被作为是注释内容处理。如果需要使用字符“#”时,可以使用“\#”替代

Makefile的文件名

  1. 默认情况下,会在工作目录下按照文件名顺序寻找makefile文件,查找的文件名顺序为:GNUmakefile -> makefile -> Makefile
  2. 通过命令指定目标使用的隐含规则
    比如存在一个源文件foo.c,我们可以使用“make foo.o”来使用隐含规则自动生成foo.o
  3. 通过“-f”或者“–file”选项来指定读取的makefile文件。当指定多个makefile文件时,会按照指定的顺序进行链接并解析执行

包含其它Makefile文件

include FILENAMES...

可以将共同使用的变量、模式规则或者自动生成的依赖关系保存在另外的文件中,主Makefile使用指示符“include”包含这些文件。

文件的查找顺序如下:
1. 在当前目录下查找
2. 在命令行选项“-I”或者“–include-dir”指定的目录下查找
3. 在特定目录下查找 “/usr/gnu/include”“/usr/local/include”“/usr/include”
4. 使用规则创建未找到的文件

注意:1~3步失败后会继续处理Makefile的后续内容。当完成读取整个Makefile后才执行第4步,即通过规则生成文件。

也可以使用“-include”或“sinclude”包含文件,与“include”的区别是:
当所包含的文件不存在或者不存在一个规则去创建它时
- 前者会继续执行
- 后者会提示错误并退出

Makefile解析与变量展开

make的执行过程分为两个阶段:
- 第一阶段:读取所有的makefile文件,内建所有的变量,明确规则和隐含规则,并建立所有目标和依赖之间的依赖关系结构链表
- 第二阶段:根据第一阶段已经建立的依赖关系结构链表决定哪些目标需要更新,并使用对应的规则来重建这些目标

变量的展开分为两种:
- 在make执行的第一阶段中,如果变量和函数被展开,那么称为 立即展开
- 在第二阶段的展开称之为 延后展开

变量取值

使用“ :=”定义的变量为简单变量,会立即展开。

foo=nullbar:=${foo}foo=fooall:        @echo ${bar}

执行结果如下:

$ makenull

使用“ =”定义的变量为扩展变量,会延后展开。

foo=nullbar=${foo}foo=fooall:        @echo ${bar}   

执行结果如下:

$ makefoo

条件语句

所有使用到条件语句在产生分支的地方,都是立即展开。

foo=immediateifeq (immediate, ${foo})bar=immediateendiffoo=deferredall:        @echo ${foo}        @echo ${bar}

执行结果如下:虽然foo的最终结果为deferred,但是在ifeq…endif时,foo被立即展开为immediate,所以bar最终被赋为immediate。

$ makedeferredimmediate 

规则的定义

所有的规则在make执行时,都按照如下的模式展开:

IMMEDIATE : IMMEDIATE ; DEFERREDDEFERRED
foo=immediateimmediate:        @echo tearget=immediatedeferred:        @echo target=deferredall: ${foo}        @echo foo=${foo}foo=deferred

执行结果如下:虽然foo的最终结果为deferred,但在终极目标all的依赖解析时,foo为immediate。

$ make alltearget=immediatefoo=deferred 

这几个例子可以总结如下:除非显示标识为简单变量(:=),否则Makefile会尽量延后展开(比如命令中的变量在第一阶段不需要使用,故在第二阶段展开)。而对于必须展开才能建立规则链的部分(比如需要根据条件语句分析不同分支或者需要根据依赖寻找目标)则会在第一阶段立即展开。

Makefile文件的重建

如果Makefile由其它文件重建,那么make的处理过程是这样的:

  1. 读入所有makefile文件
  2. 将所读取的每个makefile作为一个目标,寻找更新它们的规则。如果存在一个更新规则(包含隐含规则),就去更新对应的makefile文件
  3. 完成所有的makefile文件的更新之后,清除本次执行的数据,从第 1 点重新开始执行
  4. 读取完成以后,开始解析已经读取的makefile文件并执行必要的动作

对于第 2 点:在Makefile规则中,如果使用一个没有依赖只有命令行的双冒号规则去更新一个文件,那么每次执行make时,此规则的目标文件将会被无条件的更新。但如果这样一个规则的目标是Makefile文件,会使得make的执行陷入到一个死循环。为了防止这种情况的发生,make在遇到一个目标是Makefile文件的双冒号规则时,将忽略对这个规则的执行。

${warning include a.mk}include a.mk${warning target=a.mk}a.mk:        @echo target=a.mk        @echo foo=foo > a.mk${warning target=all}all:        @echo target=all 

执行结果如下:可以看见,对Makefile文件解析了两遍,第一遍找不到a.mk,根据规则会生成该文件;然后make进行了第二次解析,此时a.mk存在,因此正常结束。

$ make allMakefile:1: include a.mkMakefile:3: a.mk: 没有那个文件或目录Makefile:5: target=a.mkMakefile:10: target=alltarget=a.mkMakefile:1: include a.mkMakefile:5: target=a.mkMakefile:10: target=alltarget=all

重载另外一个Makefile

有些情况下,makefile-A会使用makefile-B中定义的某个规则,但这两个Makefile文件中可能存在相同的目标文件和不同的规则命令。此时不能使用include方式简单的进行包含处理。Makefile提供另外一种途径来实现这个目的:

foo:frobnicate > foo%: force@$(MAKE) -f Makefile $@force: ;

当执行make foo时,会执行当前Makefile的规则;而如果执行make bar时,会执行另一个Makefile文件的规则。

其它注意

  1. make是通过比较目标和依赖的最后修改时间来决定是否需要更新
  2. 每一个命令行必须以[Tab]字符开始,[Tab]字符告诉make此行是一个命令行
  3. 可以将一个较长行使用反斜线“\”来分解为多行,但反斜线之后不能有空格
  4. 默认的情况下,make执行第一个规则,此规则称之为终极目标
  5. make不对规则的命令做任何错误检查。在更新过程中,如果任何一个规则的执行命令出现错误,make就立即报错并退出。可以在命令行之前使用“-”来忽略命令的执行错误
1 0
原创粉丝点击