- 浏览: 140785 次
文章分类
最新评论
makefile 文件中包含了一组用来编译应用程序的规则。make 命令执行时所看到的第一项规则,会被作为默认规则使用。一项规则可分成三个部分:工作目标(target)、它的必要条件(prerequisite)以及所要执行的命令(commend)。
其中,工作目标(target)是一个必须建造的的文件或进行的事情;必要条件或依存对象是工作目录得以创建之前,必须已存在的那些文件;而所要执行的命令则是必要条件成立时将会创建工作目标的那些 shell 命令。这三部分均支持 shell 通配符模式,不过当模式出现在工作目标或必要条件中时,是由 make 进行通配符的扩展,而当模式出现在命令中时,是由 subshell 来进行扩展的。
当 make 处理某项规则时,它首先会找出必要条件和工作目标中所指定的文件。如果必要条件中存在关联到其他规则的文件,则 make 会先完成相应规则的更新动作。如果必要条件中存在时间戳在工作目标的之后的文件,则 make 会执行命令以便重新建立工作目标。脚本会被传递给 shell 并在其 subshell 中运行。
示例:
但执行 make 命令时,将会看到这样的输出:
可看出 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 显示它将为特定工作目标执行的命令,但不要实际执行它们。
另外,有时我们可能希望提供类似如下的假想工作目标:
因为大多数假想工作目标并未指定必要条件,而 make 又无法区分文件形式的工作目标与假想工作目标,所以如果当前目录中刚好出现与假想工作目标同名的文件,make 将会在它的依附图中建立该文件与假想工作目标的关系,从而可能导致对应的工作目标总是会被视为已经更新,也就永远不会再执行相应的命令。
为避免这个问题,GNU make 提供了一个特殊的工作目标“.PHONY”,用来表面该工作目标不是一个真正的文件,总是把工作目标标记为尚未更新。当想声明假想工作目标时,只要将该工作目标指定成“.PHONY”的一个必要条件即可:
以假想工作目标作为实际文件的一个必要条件似乎不太有意义,因为假想工作目标总是尚未更新,这总会使得该实际文件(工作目标)被重新建立。但将其作为假想工作目标的必要条件却有些用处。比如,all 工作目标常会用来指定所要编译的一串程序:
这样,all 工作目标将会创建 bash 和 bashbug(一个错误报告工具)。
此外,还可将假想工作目标作为内置在 makefile 里的 shell 脚本来用,让 make 在进行实际工作目标之前调用假想工作目标所代表的脚本。比如,假如我们很在意磁盘空间的使用情况,因而在进行磁盘密集的工作之前,想要显示磁盘尚有多少空间可用,则可以这样写:
makefile 中支持使用变量,引用形式是 $(varaible_name) 或 ${varaible-name},当变量名只有一个字符时可以不用括号,而且变量名可以包含大多数字符(包括标点符号)。为了方便取用工作目标以及必要条件中的元素,当规则相符时,make 会设定自动变量(因而也只能应用在规则中的命令脚本部分)。以下是几个常用的自动变量:
此外,为了兼容其它 make 版本,这些变量都具有两个变体。其中一个只会返回值的目录部分,是通过在原有的符号之后附加 D 这个字母实现的,如 $(@D);另一个只返回值的文件部分,是通过附加 F 字母实现的,如 $(@F)。
现在先前的那个 makefile 文件可写出如下形式:
默认情况下,make 只会在当前目录下寻找工作目标和必要条件。所以当需要的文件出现在多个目录时,就需要借助其他手段。此时就可考虑使用 VPATH 变量和 vpath 指令了。
VPATH 变量的内容是一份目录列表。make 在当前目录下找不到的文件就会去搜索该目录列表。其定义格式为:
VPATH = dir1 [dir2 ...]
但是 make 只取用第一个找到的文件,因此当多个目录中出现同名文件时可能会出乎我们的预期。此时就可以使用 vpath 指令了,其语法如下:
vpath pattern directory-list
举个例子,假设我们所需的头文件在 ./include/ 目录下,而源文件在 ./src/ 目录下,我们就可以类似这样编写 makefile,通过 vpath 告诉 make 在目录 src 中搜索“.c”和“.l”文件,而在 include 目录中搜索“.h”文件:
注意,这里的“%.c”等用到了模式规则,该规则中的“%”大体上等效于 shell 中的“*”,可以代表任意多个字符。“%”可以放在文件名中的任何地方,不过只能出现一次。另外,你还有可能用到只有一个“%”的模式,通常用来表示可执行程序,因为 Unix 上的可执行文件一般不需要扩展名。
# 注释:没指定必要条件时,只有在工作目标代表的文件不存在时才会进行更新。 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 上的可执行文件一般不需要扩展名。
发表评论
-
vimrc
2022-03-06 16:13 0" Vim with all enhancement ... -
vim命令速记
2020-04-07 16:56 626Vim 原生就具备了很强大的功能,在 vim ... -
shell 判断条件总结(转载)
2018-03-13 19:49 857一篇详细总结了 shell 中各种判断条件的博客,值得 ... -
iptables 命令详解(转载)
2017-12-13 11:28 893话不多说,直接 call iptables详解 -
wget 命令详解(转载)
2017-07-25 08:11 650一篇不错的帖子,命令详见 linux wget 命令用 ... -
ps 命令输出解释
2017-06-10 21:57 609“ps aux”命令可以查看正在运行的进程的全貌,输出 ... -
sudo配置文件/etc/sudoers概述
2017-05-31 21:18 637sudo命令可以用来 ... -
linux手册页组成
2017-03-22 22:36 346linux的在线手册非常方便,但有些命令的文档却是非常 ... -
find命令攻略
2016-10-25 09:57 592find命令在linux中的地位可谓举足轻重,所以了解该命令的 ... -
linux系统启动过程概述
2016-10-15 10:06 437注:以下是对Centos6中运 ... -
linux重要标准目录概计
2016-09-19 10:54 442linux目录繁多,各目录 ... -
linux常忘命令
2016-07-31 11:19 548声明:这不是一篇linux命令大全,只是记录我本人不常用的一些 ...
相关推荐
### Windows 下的 Makefile 编写(一)Makefile 的基本规则 #### 一、Makefile 概述 Makefile 是一种广泛应用于软件构建过程中的自动化脚本文件,主要用于描述项目构建过程中的依赖关系和构建步骤。对于习惯于集成...
**Makefile基本语法规则详解** Makefile是Unix/Linux环境下的一种构建工具,它定义了一系列的规则来决定哪些文件需要更新,以及如何更新。在软件开发过程中,Makefile可以帮助我们自动化编译、链接等过程,提高工作...
通过阅读博文《Makefile文件的制作》(链接:https://shihaiyang.iteye.com/blog/442421)和学习Makefile的基本概念,开发者可以更好地理解和掌握构建过程,从而提高开发效率。同时,了解并熟练使用Makefile是每个IT...
Makefile的书写规则是编写Makefile文件的基本要求,使得Makefile可以正确地工作。 依赖关系 Makefile书写规则中,依赖关系是指目标文件依赖于哪些源文件的关系。在Makefile中,规则的顺序是很重要的,因为Makefile...
"Makefile文件格式详解" Makefile是自动化编译的关键文件,它规定了整个工程的编译规则,告诉make命令如何编译和链接程序。Makefile的内容主要包括目标文件、依赖关系和编译命令三个部分。目标文件是make的最终结果...
**如何编写Makefile文件** Makefile是软件构建自动化工具,用于协调编译和链接过程,尤其是在大型项目中,它可以简化构建过程,节省时间并避免重复劳动。以下是对Makefile基本语法和常见用法的详细解释。 ### 1. ...
makefile包含一系列内建的隐含规则,知道如何处理常见的文件类型,如编译C/C++源文件为对象文件,链接对象文件为可执行文件等。 **四、条件语句(Conditional Statement)** 允许根据特定条件执行不同的规则或设置...
#### Makefile文件的基本概念与作用 Makefile是一种用于自动化构建过程的脚本文件,在Linux环境下广泛应用于软件项目的编译、链接等操作中。通过定义一系列规则,Makefile能够自动识别哪些源文件已经被修改,并仅对...
makefile 由一系列的规则组成,这些规则指定了哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,以及一些复杂的功能操作。makefile 带来的好处是“自动化编译”,一旦写好,只需要一个 make 命令,...
- **规则**:Makefile 的基本组成部分,用来描述文件之间的依赖关系和构建这些文件所需的命令。 - **目标**:规则中的左端,通常是需要创建的文件或需要执行的操作。 - **依赖项**:规则中的右端,是目标文件所需的...
#### 二、Makefile文件的基本结构 一个典型的Makefile文件包含以下几部分: 1. **目标(Targets)**:定义了Make执行的目标。 2. **依赖(Dependencies)**:指明目标依赖于哪些文件或目标。 3. **命令(Commands...
在探讨Makefile文件中等号两侧是否可以有空格这一问题之前,我们首先需要了解Makefile的基本概念及其在软件构建过程中的作用。 ### Makefile基本概念 Makefile是一种用于自动化构建程序或软件项目的脚本文件,它...
在这个“Makefile文件详细解释.zip”中,我们很可能会找到关于Makefile语法、目标、依赖关系、规则、变量、函数等内容的详细解析。 1. **Makefile的基本结构**: Makefile由一系列的目标(target)和规则(rule)...
本篇将详细介绍如何在`Makefile`中编写规则来编译多个文件。 ### 1. Makefile基本结构 `Makefile`通常包含目标(target)、依赖文件(dependency)和命令(command)。一个简单的规则示例: ```makefile target: ...
目标定义是 Makefile 文件中最基本的概念,定义了编译过程的入口和出口。目标定义包括目标名称、依赖关系和编译命令等信息。 3.2 内嵌对象 - obj-y 内嵌对象是指在编译过程中生成的中间文件,作为编译过程的中间...
本篇内容将详细介绍Makefile文件的分析和编写,包括Makefile的基本规则、变量使用、规则的书写、命令的书写、条件判断、函数使用、Makefile的运行方式、隐含规则以及更新函数库文件的有关知识。 首先,Makefile文件...
【Makefile文件写法】和【手工生成VC++工程需要用到的Makefile】是关于在Windows环境下,使用nmake工具和Makefile进行C++程序编译的主题。Makefile是描述项目构建规则的文件,用于自动化编译和链接过程,极大地提高...
在Linux系统中,Makefile是用于自动化编译和链接过程的文件,它定义了一系列规则来构建、测试和安装软件项目。这个实验的目的是帮助你理解如何编写Makefile,以便更高效地管理C语言程序的编译过程。下面将详细介绍...
Makefile 文件中可以包含删除文件的规则,例如: clean: rm *.o main 编写 Makefile 文件 编写 Makefile 文件需要遵守一定的格式和语法规则。Makefile 文件的编写需要考虑到项目的构建过程和依赖关系。 GNU ...
makefile文件由一系列规则组成,包括目标、依赖项和命令。其基本格式如下: ```makefile target : dependencies command ``` - **target**:要构建的目标文件。 - **dependencies**:构建目标所需的依赖文件。 - ...