zoukankan      html  css  js  c++  java
  • Makefile总述②文件命名、包含其他文件makefile、变量、重建重载、解析

    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. 执行“终极目标”所在的规则

  • 相关阅读:
    PHP学习笔记(三)
    简单的学习心得:网易云课堂Android开发第六章SQLite与ContentProvider 熊,我
    简单的学习心得:网易云课堂Android开发第三章自定义控件 熊,我
    简单的学习心得:网易云课堂Android开发第五章SharedPreferences与文件管理 熊,我
    简单的学习心得:网易云课堂Android开发第四章服务、广播与酷特性 熊,我
    本地Server发布外网Web应用(Oray实现)
    玩玩微信公众号Java版之准备
    C语言的第零次作业
    C语言博客作业02循环结构
    C语言博客作业03函数
  • 原文地址:https://www.cnblogs.com/ynxf/p/5954287.html
Copyright © 2011-2022 走看看