Makefile的内容

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

  • 显式规则:它描述了在何种情况下如何更新一个或者多个被称为目标的文件( Makefile 的目标文件)。书写 Makefile 时需要明确地给出目标文件、目标的依赖文件列表以及更新目标文件所需要的命令(有些规则没有命令,这样的规则只是纯粹的描述了文件之间的依赖关系)。
  • 隐含规则:它是make根据一类目标文件(典型的是根据文件名的后缀)而自动推导出来的规则。 make根据目标文件的名,自动产生目标的依赖文件并使用默认的命令来对目标进行更新(建立一个规则)。
  • 变量定义:使用一个字符或字符串代表一段文本串,当定义了一个变量以后,Makefile后续在需要使用此文本串的地方,通过引用这个变量来实现对文本串的使用。
  • Makefile 指示符:指示符指明在 make 程序读取 makefile 文件过程中所要执行的一个动作。其中包括:
    • 读取一个文件,读取给定文件名的文件,将其内容作为makefile文件的一部分。
    • 决定(通常是根据一个变量的得值)处理或者忽略Makefile中的某一特定部分。
    • 定义一个多行变量
  • 注释: Makefile 中“ #”字符后的内容被作为是注释内容(和 shell 脚本一样)处理。如果此行的第一个非空字符为“ #”,那么此行为注释行。注释行的结尾如果存在反斜线( \),那么下一行也被作为注释行。一般在书写 Makefile时推荐将注释作为一个独立的行,而不要和 Makefile 的有效行放在一行中书写。当在 Makefile 中需要使用字符“ #”时,可以使用反斜线加“ #”( \#)来实现(对特殊字符“ #”的转义),其表示将“ #”作为一字符而不是注释的开始标志。

  需要注意的地方:

    Makefile 中第一个规则之后的所有以[Tab]字符开始的的行, make 程序都会将其交给系统 shell 程序去解释执行。因此,以[Tab]字符开始的注释行也会被交给 shell 来处理,此命令行是否需要被执行( shell 执行或者忽略)是由系统 shell 程序来判决的。

Makefile文件的命名

  默认的情况下, make 会在工作目录(执行 make 的目录)下按照文件名顺序寻找makefile 文件读取并执行,查找的文件名顺序为:“ GNUmakefile”、“ makefile”、“ Makefile”。

  通常应该使用“ makefile”或者“ Makefile”作为一个 makefile 的文件名(我们推荐使用“ Makefile”,首字母大写而比较显著,一般在一个目录中和当前目录的一些重要 文 件 ( README,Chagelist 等 ) 靠 近 , 在 寻 找 时 会 比 较 容 易 的 发 现 它 ) 。 而“ GNUmakefile” 是我们不推荐使用的文件名, 因为以此命名的文件只有“ GNU make”才可以识别,而其他版本的 make 程序只会在工作目录下“ makefile”和“ Makefile”这两个文件。

  当 makefile 文件的命名不是这三个任何一个时,需要通过 make 的“ -f” 或者 “ --file” 选项来指定 make 读取的 makefile 文件。给 make 指定 makefile 文件的格式为:“ -fNAME” 或者 “ —file=NAME”, 它指定文件 “ NAME” 作为执行 make 时读取的 makefile文件。也可以通过多个“ -f”或者“ --file”选项来指定多个需要读取的 makefile 文件,多个 makefile 文件将会被按照指定的顺序进行链接并被 make 解析执行。当通过“ -f”或者“ --file”指定 make 读取 makefile 的文件时, make 就不再自动查找这三个标准命名的 makefile 文件。

包含其他Makefile文件和重建

   include”指示符告诉 make 暂停读取当前的 Makefile,而转去读取“ include”指定的一个或者多个文件,完成以后再继续当前 Makefile 的读取。 Makefile 中指示符“ include”书写在独立的一行,其形式如下:

    include FILENAMES...

  FILENAMES 是 shell 所支持的文件名(可以使用通配符)。不能以[tab]开头。

  make 在读入所有 makefile 文件之后,首先将所读取的每个 makefile 作为一个目标,寻找更新它们的规则。如果存在一个更新某一个 makefile 文件明确规则或者隐含规则,就去更新对应的 makefile 文件。完成对所有的 makefile 文件的更新之后,如果之前所读取任何一个 makefile 文件被更新,那么 make 就清除本次执行的状态重新读取一遍所有的 makefile 文件(此过程中,同样在读取完成以后也会去试图更新所有的已经读取的 makefile 文件,但是一般这些文件不会再次被重建,因为它们在时间戳上 已经是最新的)。读取完成以后再开始解析已经读取的 makefile 文件并开始执行必要 的动作。(——Makefile文件重建)

变量MAKEFILES

  如果在当前环境定义了一个“ MAKEFILES”环境变量, make执行时首先将此变量的值作为需要读入的Makefile文件,多个文件之间使用空格分开。类似使用指示符“ include”包含其它Makefile文件一样,如果文件名非绝对路径而且当前目录也不存在此文件, make会在一些默认的目录去寻找(参考 3.3 包含其它makefile文件 一节)。

  它和使用“ include”的区别:

    1. 环境变量指定的 makefile 文件中的“目标”不会被作为 make 执行的“终极目标”。就是说,这些文件中所定义规则的目标, make 不会将其作为“终极目标”来看待。如果在 make 的工作目录下没有一个名为“ Makefile”、“ makefile”或者“ GNUmakefile” 的文件,make 同样会提示“ make: *** No targets specifiedand no makefile found. Stop.”;而在 make 的工作目录下存在这样一个文件(“ Makefile”、“ makefile”或者“ GNUmakefile”),那么 make 执行时的“终极目标”就是当前目录下这个文件中所定义的“终极目标”。

    2. 环境变量所定义的文件列表,在执行 make 时,如果不能找到其中某一个文件(不存在或者无法创建)。 make 不会提示错误,也不退出。就是说环境变量“ MAKEFILES”定义的包含文件是否存在不会导致 make 错误(这是比较隐蔽的地方)。

    3. make 在执行时,首先读取的是环境变量“ MAKEFILES”所指定的文件列表,之后才是工作目录下的 makefile 文件,“ include”所指定的文件是在 make 发现此关键字的时、暂停正在读取的文件而转去读取“ include”所指定的文件。

变量 MAKEFILE_LIST

  make 程序在读取多个 makefile 文件时,包括由环境变量“ MAKEFILES”指定、命令行指、当前工作下的默认的以及使用指示符“ include”指定包含的,在对这些文件 进 行 解 析 执 行 之 前 make 读 取 的 文 件 名 将 会 被 自 动 依 次 追 加 到 变 量“ MAKEFILE_LIST”的定义域中。

  这样我们就可以通过测试此变量的最后一个字来获取当前 make 程序正在处理的makefile 文件名。具体地说就是在一个 makefile 文件中如果使用指示符“ include”包含另外一个文件之后,变量“ MAKEFILE_LIST”的最后一个字只可能是指示符“ include”指定所要包含的那个文件的名字。

  一个 makefile 的内容如下:

  name1 := $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))

  include inc.mk

  name2 := $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))

  all:

    @echo name1 = $(name1)

    @echo name2 = $(name2)

  执行 make,则看到的将是如下的结果:

    name1 = Makefile

    name2 = inc.mk

make如何解析Makefile文件

  GUN make 的执行过程分为两个阶段。

    第一阶段:读取所有的 makefile 文件(包括“ MAKIFILES”变量指定的、指示符“ include”指定的、以及命令行选项“ -f(--file)”指定的 makefile 文件),内建所有的变量、明确规则和隐含规则,并建立所有目标和依赖之间的依赖关系结构链表。

    在第二阶段:根据第一阶段已经建立的依赖关系结构链表决定哪些目标需要更新,并使用对应的规则来重建这些目标。

总结

  make 的执行过程如下:

    1. 依次读取变量“ MAKEFILES”定义的 makefile 文件列表

    2. 读取工作目录下的 makefile 文件(根据命名的查找顺序“ GNUmakefile”,“ makefile”,“ Makefile”,首先找到那个就读取那个)

    3. 依次读取工作目录 makefile 文件中使用指示符“ include”包含的文件

    4. 查找重建所有已读取的 makefile 文件的规则(如果存在一个目标是当前读取的某一个 makefile 文件,则执行此规则重建此 makefile 文件,完成以后从第一步开始重新执行)

    5. 初始化变量值并展开那些需要立即展开的变量和函数并根据预设条件确定执行分支

    6. 根据“终极目标”以及其他目标的依赖关系建立依赖关系链表

    7. 执行除“终极目标”以外的所有的目标的规则(规则中如果依赖文件中任一个文件的时间戳比目标文件新,则使用规则所定义的命令重建目标文件)

    8. 执行“终极目标”所在的规则

Makefile总述②文件命名、包含其他文件makefile、变量、重建重载、解析的更多相关文章

  1. [转] Makefile 基础 (2) —— Makefile 总述

    该篇文章为转载,是对原作者系列文章的总汇加上标注. 支持原创,请移步陈浩大神博客:(最原始版本) http://blog.csdn.net/haoel/article/details/2886 我转自 ...

  2. C_文件包含.h文件和包含.c文件总结

    很多人对C语言中的 “文件包含”都不陌生了,文件包含处理在程序开发中会给我们的模块化程序设计带来很大的好处,通过文件包含的方法把程序中的各个功能模块联系起来是模块化程序设计中的一种非常有利的手段. 文 ...

  3. makefile笔记2 - makefile总述

    一.makefile的组成 Makefile 里主要包含了五个东西:显示规则.隐晦规则.变量定义.文件指示和注释. 1. 显示规则.显示规则说明了,如何生成一个或多的的目标文件.这是由 Makefil ...

  4. 《GNU_Makefile》——第3章,Makefile总述

    1.makefile的内容 一个完整的makefile包含5个东西: 显示规则,隐含规则,变量定义,指示符,注释 (1)显示规则 描述如何更新目标文件. (2)隐含规则 make程序内置的规则. ma ...

  5. 利用字节流文件生成包含多文件的zip文件

    InputStream[] inputStreamsList = new InputStream[jsonArr.size()]; String[] fileNameList = new String ...

  6. 很详细、很移动的Linux makefile教程:介绍,总述,书写规则,书写命令,使用变量,使用条件推断,使用函数,Make 的运行,隐含规则 使用make更新函数库文件 后序

    很详细.很移动的Linux makefile 教程 内容如下: Makefile 介绍 Makefile 总述 书写规则 书写命令 使用变量 使用条件推断 使用函数 make 的运行 隐含规则 使用m ...

  7. Linux makefile教程之总述二[转]

    Makefile 总述——————— 一.Makefile里有什么? Makefile里主要包含了五个东西:显式规则.隐晦规则.变量定义.文件指示和注释. 1.显式规则.显式规则说明了,如何生成一个或 ...

  8. python 实现文件夹下所有文件或文件夹重命名

    os.listdir() 方法用于返回指定的文件夹包含的文件或文件夹的名字的列表. 它不包括 . 和 .. 即使它在文件夹中. 只支持在 Unix, Windows 下使用. os.path 模块主要 ...

  9. C++中头文件相互包含与前置声明

    一.类嵌套的疑问 C++头文件重复包含实在是一个令人头痛的问题,前一段时间在做一个简单的数据结构演示程序的时候,不只一次的遇到这种问题.假设我们有两个类A和B,分别定义在各自的有文件A.h和B.h中, ...

随机推荐

  1. HTML基础知识总结

    经过这段时间的学习,对于html的一些基础知识有了一定的了解.所谓好记性不如烂笔头,唯有一点点累积,才能汇聚成知识的海洋.现在,我对这段时间的学习做一个总结. 一.HTML的定义 HTML,超文本标记 ...

  2. 错误 24 无法嵌入互操作类型“ESRI.ArcGIS.Geometry.PointClass”。请改用适用的接口。 E:\MyGIS\MyGIS\Form1.cs 78 37 MyGIS

    解决办法:选中那个引用,在属性页,将“嵌入互操作”设置为false

  3. SDWebImage 加载网络图片失败,重新运行,就能加载成功。

    现象: 使用SDWebImage 加载网络图片,偶尔会有一两张图片就是显示不出来.重新运行有时又可以了. 这个问题的原因是: 当SDWebImage 在加载图片的时候 我用的是- (void)sd_s ...

  4. SharePoint:WebPartPageUserException This page has encountered a critical error

    遇到如下webpart莫名错误,很常见吧.一般用户是直接删掉,知道原因的不算太多. 解决办法(Solution): Usually, This error caused by wrong entrie ...

  5. ReactiveCocoa基础知识内容

    本文记录一些关于学习ReactiveCocoa基础知识内容,对于ReactiveCocoa相关的概念如果不了解可以网上搜索:RACSignal有很多方法可以来订阅不同的事件类型,ReactiveCoc ...

  6. 手机影音1--SplashActivity

    /** * 1.设置被启动的Activity为单例模式 */ public class SplashActivity extends Activity { /** * 是否已经启动主页面 */ pri ...

  7. C# 得到sqlserver 数据库存储过程,触发器,视图,函数 的定义

    经常从 生产环境 到测试环境, 需要重新弄一整套的数据库环境, 除了表结构以及表结构数据,可以用动软代码生成器 生成之外, 像 存储过程,触发器,等,好像没有批量操作的,意义哥哥农比较麻烦, 所以最近 ...

  8. EMLS项目推进思考

    解决难度从小到大来看: 一.技术与运营层面1. 到企业级层面需要的技术与运营的支撑________前端推送__________________|________后台支撑系统_________|____ ...

  9. SQL Server(五)——常用函数

    1.数学函数:操作一个数据,返回一个结果 --取上限ceiling select code,name,ceiling(price) from car ; --取下限 floor select floo ...

  10. Ztree插件,定位节点时(focus)不能进入可视区域BUG解决方案

    相关插件版本: jquery.ztree.exedit-3.4.js jquery.ztree.all-3.4.js jquery-1.8.0.js function onAsyncSuccess(e ...