《GNU make项目管理》笔记--规则(2)

1.模式规则

有如下的源代码树:

根目录

|---makefile

|----|include|

|           |___myutil.h

|___|src|

|----myutil.c

|__main.c

各文件内容如下:

main.c:

#include <stdio.h>

#include "myutil.h"

int main(void) {

myprint();

return 0;

}

myutil.h:

void myprint();

myutil.c:

#include <stdio.h>

void myprint(void) {

printf("this is myprint function.\n");

}

makefile:

VPATH=src include

main:main.o myutil.o

gcc $^ -o [email protected]

main.o:main.c myutil.h

gcc -c $^

myutil.o:myutil.c myutil.h

gcc -c $^

通过内置的规则,我们可以将makefile文件缩减到如下:

VPATH=src include

main:myutil.o

main.o:myutil.h

myutil.o:myutil.h

所有的内置规则都是模式规则的实例。上面的makefile之所以可行是因为make里存在三项内置规则。第一项描述了如何

从一个.c文件编译出一个.o文件:

%.o:%.c

$(COMPILE.c) $(OUTPUT_OPTION) $<

第二项规则描述了如何从.l文件产生一个.c文件:

%.c:%.l

@$(RM) [email protected]

$(LEX.l) $< > [email protected]

最后是一项特殊的规则,描述了如何从.c文件产生出一个不具扩展名的文件

%:%.c

$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o [email protected]

我们可以通过在脚本中更改变量的值来自定义内置规则,一个典型的规则包含一群变量,以所要执行的程序开头,并且

包括用来设定主要命令行选项的变量。可以通过运行make --print-data-base列出make具有哪些默认规则(和变量)。

1.1.模式

模式规则中的百分比字符%大体上等效于unix shell中的星号*,它可以代表任意多个字符,百分比字符可以放在模式中的

任何地方,不过只能出现一次。百分比字符的正确用法如下:

%,v

s%.o

wrapper_%

在文件中,百分比以外的字符按照字面进行匹配。一个模式可以包含一个前缀或一个后缀,或者两者同时存在。当make

所有所要的模式规则时,它首先会查找相符的模式规则工作目标。模式规则工作目标必须以前缀开头并且以后缀结尾(如

果它们存在的话)。如果找到相符的模式规则工作目标,则前缀和后缀之前的字符会被作为文件名的词干。接着make会

通过将词干替换到必要条件模式中来检查该模式规则的必要条件。如果产生的文件名存在,或是可以应用另一项规则进行

产生的工作,则会进行比较以及应用规则的动作。

事实上,我们还可以用到一个百分比字符的模式。此模式最常被用来编译Unix可执行程序。例如:

%:%.cpp

$(LINK.cpp) $^ $(LOADLIBES) $(LDLIBS) -o [email protected]

1.2.静态模式规则

静态模式规则只能应用在特定的工作目标上。

$(OBJECT):%.o:%.c

$(CC)  -c  $(CFLAGS)  $<  -o  [email protected]

此规则与一般模式规则的唯一差别是开头的$(OBJECTS):规范。这将使得该规则只能应用在$(OBJECTS)变量中所列举的

文件上。%.o模式会匹配$(OBJECTS)中所列举的每个目标文件并且取出其词干。然后该词干会被替换进%.c模式,以产生

工作目标的必要条件。

1.3.后缀规则

后缀规则是用来定义隐含规则的最初方法(也是过时的方法)。后缀规则中的工作目标,可以是一个扩展名或两个被衔接在一

起的扩展名:

.c.o:

$(COMPILE.c)  $(OUTPUT_OPTION) $<

这令人有些疑惑,因为必要条件的扩展名被摆到开头,而工作目标退居第二位。这个规则所匹配的工作目标以及必要条件跟

下面的规则一样:

%.o:%.c

$(COMPILE.c)  $(OUTPUT_OPTION) $<

上面这个后缀规则就是所谓的双后缀规则,因为它包含了两个扩展名。你还可以使用单后缀规则,单后缀规则只包含一个

扩展名,也就是源文件的扩展名。这个规则可用来创建可至执行文件,因为Unix上的可执行文件不需要扩展名。

.p:

$(LINK.p)  $^  $(LOADLIBES)  $(LDLIBS)  -o [email protected]

这个规则的作用等效于下面这个模式规则:

%:%.p

$(LINK.p)  $^  $(LOADLIBES)  $(LDLIBS)  -o [email protected]

2.特殊工作目标

特殊工作目标是一个内置的假想工作目标,用来变更make的默认行为,例如.PHONY这个特殊工作目标用来声明它的必要

条件并不代表一个实际的文件,而且应该被视为尚未更新。.PHONY将会是最常见的特殊工作目标,但是你还会看到其他

的特殊工作目标。

特殊工作目标的语法跟一般工作目标的语法没有不同,也就是target:prerequsite,但是target并非文件而是一个假想工作目

标。它们实际上比较像是用来修改make内部算法的指令。

目前共有12个特殊目标,可分为三类:第一类用来在更新工作目标时修改make的行为;第二类的动作就好像是make的全局

标记,用来忽略相应的工作目标;最后是.SUFFIXES这个工作目标,用来制定旧式的后缀规则。

下面列出(除了.PHONY之外的)最有用的工作目标修饰符。

.INTERMEDIATE

这个特殊工作目标的必要条件会被视为中间文件。如果make在更新另一个工作目标期间创建了该文件,则该文件将会在make

运行结束时被自动删除。如果在make想要更新该文件之际该文件已经存在了,则该文件不会被删除。

.SECONDARY

这个特殊工作目标的必要条件被视为中间文件,但是不会被自动删除。.SECONDARY最常用来标示存储在程序库(library)

里的目标文件(object file)。按照惯例,这些目标文件一旦被加入档案(archive)就会被删除。在项目开发期间保存这些

目标文件,但仍使用make进行程序库的更新,有时会比较方便。

.PRECIOUS

当make在运行期间被中断时,如果自make启动以来该文件被修改过,make将会删除它正在更新的工作目标文件,因此,

make不会再编译树中留下尚未编译完成的文件。但有些时候你却不希望make这么做,特别是在该文件很大而且编译的

代价很高时,如果该文件极为珍贵,你就用.PRECIOUS来标示它,这样make才不会在自己被中断时删除该文件。

.DELETE_ON_ERROR

.DELETE_ON_ERROR的作用于.PRECIOUS相反。将工作目标标示成.DELETE_ON_ERROR,表示如果与规则相应的

任何命令在运行时发生错误的话,就应该删除该工作目标。make通常只有在自己被信号中断时才会删除该工作目标文件。

3.自动产生依存关系

对于本文中的例子,我们可以轻易地在makefile文件中手动加入目标文件与C头文件的依存关系,但是在正常的程序里,这

是一个烦人的工作。事实上,在大多数程序中,这几乎是不可能的事,因为大多数的头文件还会包含其他头文件所形成的复杂

树状结构。比如,在我的系统上,头文件stdio.h会被扩展成包含15个其他的头文件。以手动方式解析这些关系是一个令人绝望

的工作,但是如果这些文件的重新编译失败,可能会导致数小时的调试。

在gcc中有一个选项,可以编写出这些依存关系。

[email protected]:~# echo "#include <stdio.h>" > stdio.c

[email protected]:~# gcc -M stdio.c

stdio.o: stdio.c /usr/include/stdio.h /usr/include/features.h \

/usr/include/i386-linux-gnu/bits/predefs.h \

/usr/include/i386-linux-gnu/sys/cdefs.h \

/usr/include/i386-linux-gnu/bits/wordsize.h \

/usr/include/i386-linux-gnu/gnu/stubs.h \

/usr/include/i386-linux-gnu/gnu/stubs-32.h \

/usr/lib/gcc/i686-linux-gnu/4.7/include/stddef.h \

/usr/include/i386-linux-gnu/bits/types.h \

/usr/include/i386-linux-gnu/bits/typesizes.h /usr/include/libio.h \

/usr/include/_G_config.h /usr/include/wchar.h \

/usr/lib/gcc/i686-linux-gnu/4.7/include/stdarg.h \

/usr/include/i386-linux-gnu/bits/stdio_lim.h \

/usr/include/i386-linux-gnu/bits/sys_errlist.h

有两种方法可用来将自动产生的依存关系纳入makefile:

第一种是编写一个脚本自动加入这些内容到makefile中。

第二种方法就是为make加入一个include指令。编写一个makefile工作目标,此工作目标的动作就是以-M选项对所有源文件

执行gcc,并将结果存入一个依存文件中,然后执行make以便把刚才产生的依存文件引入makefile,这样就可以出发我们

所需要的更新动作,在GNU make你可以使用如下的规则来实现此目的:

depend:count_words.c lexer.c counter.c

$(CC)  -M  $(CPPFLAGS)  $^ > [email protected]

include depend

---------------------------------------------------------------------------------------------------------------------------------------------------------

对include命令的说明:

make程序在处理指示符 include时,将暂停对当前使用指示符“include”的 makefile 文件的读取,而转去依此读取由

“include”指示符指定的文件列表。直到完成所有这些文件以后再回过头继续读取指示符“include”所在的 makefile

文件。通常指示符“include”用在以下场合:

1. 有多个不同的程序,由不同目录下的几个独立的Makefile来描述其创建或者更新规则。它们需要使用一组通用的

变量定义或者模式规则。通用的做法是将这些共同使用的变量或者模式规则定义在一个文件中,在需要使用的Makefile

中使用指示符“include”来包含此文件。

2.当根据源文件自动产生依赖文件时;我们可以将自动产生的依赖关系保存在另外一个文件中,主Makefile使用指示符

“include”包含这些文件。这样的做法比直接在主Makefile中追加依赖文件的方法要明智的多。其它版本的make已经

使用这种方式来处理。

时间: 2024-08-05 07:21:46

《GNU make项目管理》笔记--规则(2)的相关文章

《GNU make项目管理》笔记--规则(3)

1.管理程序库 程序库(archive library)是一个特殊的文件,该文件内含其他被称为成员的文件.程序库可用来将相关的目标文件聚集成 较容易操作的单元,例如,C的标准程序库lib.a就包含了许多低级的C函数.因为程序库如此常见,所以make对它们的创建. 维护以及引用提供了特别的支持.程序库的建立及修改可通过ar程序来进行. 下面我们看一个例子,程序包结构如下: 根目录 |---makefile |----|include| |           |___myutil.h |     

《GNU make项目管理》笔记--变量与宏(1)

make包含两种语言.第一种语言用来描述工作与必要条件所组成的依存图.第二种语言是宏语言,用来进行文字替换.像 C预处理器,m4以及宏汇编器. 一个变量名称几乎可以由任何字符自称.包括大部分的标点符号,即使空格也可以使用,但应该避免这么做.事实上只有: .#和=等字符不允许使用在变量名称中. 变量名称是区分大小写的.要取得某个变量的值,请使用$()括住该变量的名称,有一个特例:变量名称若为单一字母(letter) 则可以省略圆括号,所以请直接使用$letter. 你还可以使用花括号来扩展变量,例

GNU/Linux复习笔记(1)

第一次接触GNU/Linux还是大四上学期实习的那两个月在window里装了 个虚拟机玩红帽的系统,那段时间稍微学了一点命令就不玩了.后来大四下学期认识了王总,装了双系统,那段时间又对linux有了进一步认识并产生了很大的 兴趣.直到上学期突然发疯把笔记本装debian8以后才完全进入linux的世界.学习真的是一个螺旋式上升的过程.下面进入正题: ---Linux的基本原则: 1.由目的单一的小程序组成,组合小程序完成复杂任务(KISS:keep it simple,stupid)2.一切皆文

PMP项目管理笔记 项目定义

项目的定义 项目是为创造独特的产品,服务或成果而进行临时性的工作. 项目是组织的经营需要与战略目标服务的. PMBOK 指南描述的项目管理知识,从本质上讲,是用来管理中等或以上规模,跨部门,跨专业的目的.PMP考试中的项目,通常也是这类项目. 项目的三个特新 1.临时性 2.独特性 3.渐进明细性     项目许多地方需要渐进明细,例如    1.项目的范围    2.项目的计划    3.项目的目标    项目管理特别强调项目的特性和项目的计划都是逐渐细化出来的,因为:     项目的各种情况

Gnu make学习笔记

# 单行注释# 多行注释:脚本语言大多是行注释:若想多行注释,建议每行首用#号.可替代方法是行尾续行符,但这样不太好 # Makefile规则结构# target:[prerequisites]# command# 或者# target:[prerequisites]; command# 其中每条command需要以Tab开始,遵从shell语法.如果用";"隔开的话,就不用Tab了# 注意不要轻易以Tab开头,以Tab开头的命令都被交给系统shell去接手了# make后执行的默认是

2017.07.06 IT项目管理笔记整理 第二章

软件开发的目标--按时按预算开发出满足用户真实需要的软件.软件项目需求概述:软件开发的目标:按时按预算开发出满足用户真实需要的软件.需求:一个软件项目的开始阶段.软件需求的定义:1).用户解决问题或达到目标所需的条件或能力.2).系统或系统部件要满足合同.标准.规范或其他正式文档所需要具有的条件或能力 3).一种反映上面(1)或(2)所描述的条件或能力的文档说明. 软件需求4个抽象的层次 原始问题的描述.用户需求.系统需求和软件设计描述. 编写用户需求文档的原则 1标准的格式 2)使用一致的语言

2017.07.06 IT项目管理笔记整理 第五章软件项目风险管理

风险是不确定的事件,一旦发生,将会造成消极影响.风险发生的概率越高,造成的影响越大,就越是高风险,否则就是中等风险或低风险. 风险的三要素:一个未来的事件,事件发生的概率,事件的影响 风险的分类:(1)从风险的范围角度上看,风险分为三种类型:项目风险:潜在的项目预算.进度.人员.资源.用户和需求等方面的问题.技术风险:实现和交付产品过程中所应用的各种技术所包含的风险.技术的正确性.不确定性.复杂性.技术陈旧等因素都可带来技术风险.商业风险:与市场.企业产品策略等因素有关的风险. (2)从风险可预

2017.07.06 IT项目管理笔记整理 第四章

进度是对执行的活动和里程碑所制定的工作计划日期表. 进度问题是项目生命周期内造成项目冲突的主要原因. 时间管理原则: 1.区分重要与紧急的关系 2.适当运用Pareto原则 3.合理预算 4.有限反应 5.果断决策 6.大胆.完整的授权 7.例外管理 8.效能与效率 9.活动与效果 时间管理技巧: 1.每日计划 2.预料 3.分析时间 4.最后时限 5.上交问题 6.合并 7.反馈 8.计划躲避 9.可见性 10.习惯软件项目进度管理的主要过程: 1活动定义,确定项目团队成员和项目干系人为完成项

2017.07.07 IT项目管理笔记整理 第10章 敏捷软件开发

什么是敏捷软件开发方法 1.敏捷方法是一类软件开发流程的泛称: 2.敏捷方法是相对于传统的瀑布式软件过程提出的: 3.敏捷方法可以用敏捷宣言(4条).敏捷原则(12条)来概括: 4.敏捷原则通过一系列的敏捷实践来体现出来: 敏捷开发软件的特点:1敏捷软件开发更强调程序员与业务专家.用户之间的紧密合作,面对面的沟通,认为这种方式更有效 2能够很好地根据需求的变化编写代码 3频繁交付新的软件版本 4采用紧凑和自组织的软件开发团队 5更注重个体在软件开发中的作用 敏捷软件开发的方法有:1极限编程 2.