`

makefile 文件基本规则

阅读更多
    makefile 文件中包含了一组用来编译应用程序的规则。make 命令执行时所看到的第一项规则,会被作为默认规则使用。一项规则可分成三个部分:工作目标(target)、它的必要条件(prerequisite)以及所要执行的命令(commend)。
# 注释:没指定必要条件时,只有在工作目标代表的文件不存在时才会进行更新。
target1 [target2...]: [prereq1 prereq2...]
    command1
    command2
    ...

    其中,工作目标(target)是一个必须建造的的文件或进行的事情;必要条件或依存对象是工作目录得以创建之前,必须已存在的那些文件;而所要执行的命令则是必要条件成立时将会创建工作目标的那些 shell 命令。这三部分均支持 shell 通配符模式,不过当模式出现在工作目标或必要条件中时,是由 make 进行通配符的扩展,而当模式出现在命令中时,是由 subshell 来进行扩展的。
    当 make 处理某项规则时,它首先会找出必要条件和工作目标中所指定的文件。如果必要条件中存在关联到其他规则的文件,则 make 会先完成相应规则的更新动作。如果必要条件中存在时间戳在工作目标的之后的文件,则 make 会执行命令以便重新建立工作目标。脚本会被传递给 shell 并在其 subshell 中运行。
    示例:
count_words: count_words.o lexer.o -lfl
        gcc count_words.o lexer.o -lfl -o count_words
count_words.o: count_words.c
        gcc -c count_words.c
lexer.c: lexer.l
        flex -t lexer.l > lexer.c

    但执行 make 命令时,将会看到这样的输出:
$ make
gcc -c count_words.c
flex -t lexer.l > lexer.c
gcc -c lexer.c
gcc count_words.o lexer.o -lfl -o count_words

    可看出 make 是先把必要条件完成后,才能实现最终的工作目标。注意这里的 lexer.c 文件是由 flex 程序产生的。此处指定了“-lfl”这个参数,“-l”参数要求 gcc 必须将其所指定的系统程序库链接进应用程序,这里代表实际的程序库名称为 libfl.a。根据 GNU make 规定:当 -l<NAME> 形式的必要条件被发现时,make 会搜索 libNAME.so 形式的文件;如果找不到,make 接着会搜索 libNAME.a 形式的文件。
    如果要更新另一个(或多个)不同的工作目标,应在命令行上明确指定,如:
        $ make lexer.c
    make 提供了许多命令行选项,其中较为有用的选项之一是“--just-print/-n”,用来要求 make 显示它将为特定工作目标执行的命令,但不要实际执行它们。
    另外,有时我们可能希望提供类似如下的假想工作目标:
...
clean:
        rm -f *.o lexer.c

    因为大多数假想工作目标并未指定必要条件,而 make 又无法区分文件形式的工作目标与假想工作目标,所以如果当前目录中刚好出现与假想工作目标同名的文件,make 将会在它的依附图中建立该文件与假想工作目标的关系,从而可能导致对应的工作目标总是会被视为已经更新,也就永远不会再执行相应的命令。
    为避免这个问题,GNU make 提供了一个特殊的工作目标“.PHONY”,用来表面该工作目标不是一个真正的文件,总是把工作目标标记为尚未更新。当想声明假想工作目标时,只要将该工作目标指定成“.PHONY”的一个必要条件即可:
...
.PHONY: clean
clean:
        rm -f *.o lexer.c

    以假想工作目标作为实际文件的一个必要条件似乎不太有意义,因为假想工作目标总是尚未更新,这总会使得该实际文件(工作目标)被重新建立。但将其作为假想工作目标的必要条件却有些用处。比如,all 工作目标常会用来指定所要编译的一串程序:
...
.PHONY: all
all: bash bashbug

    这样,all 工作目标将会创建 bash 和 bashbug(一个错误报告工具)。
    此外,还可将假想工作目标作为内置在 makefile 里的 shell 脚本来用,让 make 在进行实际工作目标之前调用假想工作目标所代表的脚本。比如,假如我们很在意磁盘空间的使用情况,因而在进行磁盘密集的工作之前,想要显示磁盘尚有多少空间可用,则可以这样写:
...
.PHONY: make-documentation
make-documentation: df
        javadoc ...
.PHONY: df
df:
        df -k . | awk 'NR == 2 {printf("%d available\n", $$4)}'

    makefile 中支持使用变量,引用形式是 $(varaible_name) 或 ${varaible-name},当变量名只有一个字符时可以不用括号,而且变量名可以包含大多数字符(包括标点符号)。为了方便取用工作目标以及必要条件中的元素,当规则相符时,make 会设定自动变量(因而也只能应用在规则中的命令脚本部分)。以下是几个常用的自动变量:
自动变量描述
$@工作目标的文件名
$%档案文件成员结构中的文件名元素,可通过 archive(member) 这样的语法在档案文件 archive 中指定名为 member 的成员
$<第一个必要条件的文件名
$?时间戳在工作目标之后的所有必要条件,并以空格隔开这些必要条件
$^所有必要条件的文件名,并以空格隔开,而且会删除重复的文件
$+同 $^,但会包含重复的文件名。
$*工作目标的主文件名(即无扩展名部分)。建议不要在模式规则以外使用

    此外,为了兼容其它 make 版本,这些变量都具有两个变体。其中一个只会返回值的目录部分,是通过在原有的符号之后附加 D 这个字母实现的,如 $(@D);另一个只返回值的文件部分,是通过附加 F 字母实现的,如 $(@F)。
    现在先前的那个 makefile 文件可写出如下形式:
count_words: count_words.o lexer.o -lfl
        gcc $^ -o $@
count_words.o: count_words.c
        gcc -c $<
lexer.c: lexer.l
        flex -t $< > $@

    默认情况下,make 只会在当前目录下寻找工作目标和必要条件。所以当需要的文件出现在多个目录时,就需要借助其他手段。此时就可考虑使用 VPATH 变量和 vpath 指令了。
    VPATH 变量的内容是一份目录列表。make 在当前目录下找不到的文件就会去搜索该目录列表。其定义格式为:
        VPATH = dir1 [dir2 ...]
    但是 make 只取用第一个找到的文件,因此当多个目录中出现同名文件时可能会出乎我们的预期。此时就可以使用 vpath 指令了,其语法如下:
        vpath pattern directory-list
    举个例子,假设我们所需的头文件在 ./include/ 目录下,而源文件在 ./src/ 目录下,我们就可以类似这样编写 makefile,通过 vpath 告诉 make 在目录 src 中搜索“.c”和“.l”文件,而在 include 目录中搜索“.h”文件:
# VPATH = src include        # 这是使用 VPATH 变量的情况
# CPPFLAGS = -I include      # 指定隐含编译规则
vpath %.l %.c src
vpath %.h include
count_words: count_words.o counter.o lexer.o -lfl
        gcc $^ -o $@
count_words.o: count_words.c counter.h
        gcc -c $<
lexer.c: lexer.l
        flex -t $< > $@

    注意,这里的“%.c”等用到了模式规则,该规则中的“%”大体上等效于 shell 中的“*”,可以代表任意多个字符。“%”可以放在文件名中的任何地方,不过只能出现一次。另外,你还有可能用到只有一个“%”的模式,通常用来表示可执行程序,因为 Unix 上的可执行文件一般不需要扩展名。
分享到:
评论

相关推荐

    Windows 下的 Makefile 编写(一)Makefile的基本规则

    ### Windows 下的 Makefile 编写(一)Makefile 的基本规则 #### 一、Makefile 概述 Makefile 是一种广泛应用于软件构建过程中的自动化脚本文件,主要用于描述项目构建过程中的依赖关系和构建步骤。对于习惯于集成...

    makefile基本语法规则

    **Makefile基本语法规则详解** Makefile是Unix/Linux环境下的一种构建工具,它定义了一系列的规则来决定哪些文件需要更新,以及如何更新。在软件开发过程中,Makefile可以帮助我们自动化编译、链接等过程,提高工作...

    Makefile文件的制作

    通过阅读博文《Makefile文件的制作》(链接:https://shihaiyang.iteye.com/blog/442421)和学习Makefile的基本概念,开发者可以更好地理解和掌握构建过程,从而提高开发效率。同时,了解并熟练使用Makefile是每个IT...

    Makefile书写规则.pdf

    Makefile的书写规则是编写Makefile文件的基本要求,使得Makefile可以正确地工作。 依赖关系 Makefile书写规则中,依赖关系是指目标文件依赖于哪些源文件的关系。在Makefile中,规则的顺序是很重要的,因为Makefile...

    Makefile文件格式详解.pdf

    "Makefile文件格式详解" Makefile是自动化编译的关键文件,它规定了整个工程的编译规则,告诉make命令如何编译和链接程序。Makefile的内容主要包括目标文件、依赖关系和编译命令三个部分。目标文件是make的最终结果...

    如何写makefile文件

    **如何编写Makefile文件** Makefile是软件构建自动化工具,用于协调编译和链接过程,尤其是在大型项目中,它可以简化构建过程,节省时间并避免重复劳动。以下是对Makefile基本语法和常见用法的详细解释。 ### 1. ...

    makefile 文件详细说明

    makefile包含一系列内建的隐含规则,知道如何处理常见的文件类型,如编译C/C++源文件为对象文件,链接对象文件为可执行文件等。 **四、条件语句(Conditional Statement)** 允许根据特定条件执行不同的规则或设置...

    Linux下Makefile文件的编写

    #### Makefile文件的基本概念与作用 Makefile是一种用于自动化构建过程的脚本文件,在Linux环境下广泛应用于软件项目的编译、链接等操作中。通过定义一系列规则,Makefile能够自动识别哪些源文件已经被修改,并仅对...

    makefile 文件详解

    makefile 由一系列的规则组成,这些规则指定了哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,以及一些复杂的功能操作。makefile 带来的好处是“自动化编译”,一旦写好,只需要一个 make 命令,...

    GNU Makefile 文件编写

    - **规则**:Makefile 的基本组成部分,用来描述文件之间的依赖关系和构建这些文件所需的命令。 - **目标**:规则中的左端,通常是需要创建的文件或需要执行的操作。 - **依赖项**:规则中的右端,是目标文件所需的...

    linux下makefile文件编写详细步骤

    #### 二、Makefile文件的基本结构 一个典型的Makefile文件包含以下几部分: 1. **目标(Targets)**:定义了Make执行的目标。 2. **依赖(Dependencies)**:指明目标依赖于哪些文件或目标。 3. **命令(Commands...

    Makefile文件中的等号左右两边能不能有空格

    在探讨Makefile文件中等号两侧是否可以有空格这一问题之前,我们首先需要了解Makefile的基本概念及其在软件构建过程中的作用。 ### Makefile基本概念 Makefile是一种用于自动化构建程序或软件项目的脚本文件,它...

    Makefile文件详细解释.zip

    在这个“Makefile文件详细解释.zip”中,我们很可能会找到关于Makefile语法、目标、依赖关系、规则、变量、函数等内容的详细解析。 1. **Makefile的基本结构**: Makefile由一系列的目标(target)和规则(rule)...

    linux makefile 编写 规则 编译多个文件

    本篇将详细介绍如何在`Makefile`中编写规则来编译多个文件。 ### 1. Makefile基本结构 `Makefile`通常包含目标(target)、依赖文件(dependency)和命令(command)。一个简单的规则示例: ```makefile target: ...

    Linux内核Makefile文件.doc

    目标定义是 Makefile 文件中最基本的概念,定义了编译过程的入口和出口。目标定义包括目标名称、依赖关系和编译命令等信息。 3.2 内嵌对象 - obj-y 内嵌对象是指在编译过程中生成的中间文件,作为编译过程的中间...

    Android 安卓 jni开发 MakeFile文件分析和编写

    本篇内容将详细介绍Makefile文件的分析和编写,包括Makefile的基本规则、变量使用、规则的书写、命令的书写、条件判断、函数使用、Makefile的运行方式、隐含规则以及更新函数库文件的有关知识。 首先,Makefile文件...

    makefile文件写法

    【Makefile文件写法】和【手工生成VC++工程需要用到的Makefile】是关于在Windows环境下,使用nmake工具和Makefile进行C++程序编译的主题。Makefile是描述项目构建规则的文件,用于自动化编译和链接过程,极大地提高...

    Linux系统下轻松学习写MakeFile文件

    在Linux系统中,Makefile是用于自动化编译和链接过程的文件,它定义了一系列规则来构建、测试和安装软件项目。这个实验的目的是帮助你理解如何编写Makefile,以便更高效地管理C语言程序的编译过程。下面将详细介绍...

    makefile详解中文版-详细描写makefile语法

    Makefile 文件中可以包含删除文件的规则,例如: clean: rm *.o main 编写 Makefile 文件 编写 Makefile 文件需要遵守一定的格式和语法规则。Makefile 文件的编写需要考虑到项目的构建过程和依赖关系。 GNU ...

    make命令及makefile文件

    makefile文件由一系列规则组成,包括目标、依赖项和命令。其基本格式如下: ```makefile target : dependencies command ``` - **target**:要构建的目标文件。 - **dependencies**:构建目标所需的依赖文件。 - ...

Global site tag (gtag.js) - Google Analytics