Chinaunix首页 | 论坛 | 博客
  • 博客访问: 92606314
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类: C/C++

2008-04-17 17:25:05

 出处:Unix爱好者家园unix-cd.com   


本章我们开始讨论Makefile的一个重要内容,Makefile的规则。

Makefile中,规则描述了何种情况下使用什么命令来重建一个特定的文件,此文件被称为规则“目标”(通常规则中的目标只有一个)。规则所罗列的其他文件称为“目标”的依赖,而规则中的命令是用来更新或者创建此规则的目标。

除了makefile的“终极目标”所在的规则以外,其他规则的顺序在makefile文件中没有意义。“终极目标”就是当没有使用make 命令行指定具体目标时,make默认的哪一个目标。它是makefile文件中第一个规则的目标。如果在makefile中第一个规则有多个目标的话,那么多个目标中的第一个将会被作为make的“终极目标”。有两种情况的例外:1. 目标名是以点号“.”开始的其后不存在斜线“/”(“./”被认为是当前目录;“../”被认为是上一级目录);2. 作为模式规则的目标。此两种情况的Makefile的第一个目标都不会被作为“终极目标”来对待。

“终极目标”是执行make的唯一目的,其所在的规则作为第一个规则。而其他的规则是在完成重建“终极目标”的过程中被连带出来的。所以这些目标所在规则在Makefile中的顺序无关紧要。

因此,我们书写的makefile的第一个规则应该就是重建整个程序或者多个程序的依赖关系和执行命令的描述。

我们来看一个规则的例子:

 

foo.o : foo.c defs.h       # module for twiddling the frobs

cc -c -g foo.c

 

这是一个典型的规则。看到这个例子,大家也许能够说出这个规则的各个部分之间的关系。不过我们还是要把这个例子拿出来讨论。目的是让我们更加明确的理解Makefile的规则。本例第一行中,文件“foo.o”是规则需要重建的文件,而“foo.c”和“defs.h”是重建“foo.o”所要使用的文件。我们把规则所需要重建的文件称为规则的“目标”(foo.o),而把重新目标所需要的文件称为“目标”的“依赖”。规则中的第二行“cc -c -g foo.c”就是规则的“命令”。它描述了如何使用规则中的依赖文件重建目标。

而且,上面的规则告诉我们了两件事:

1.        如何确定目标文件是否过期(需要重建目标),过期是指目标文件不存在或者目标文件“foo.o”在时间戳上比依赖文件中的任何一个“foo.c”或者“defs.h”“老”。

2.        如何重建目标文件“foo.o”。这个规则中使用cc编译器。在命令中没有明确的使用到依赖文件“defs.h”。我们假设在源文件“foo.c”中已经包含了此头文件。这也是为什么它作为目标依赖出现的原因。

通常规则的语法格式如下:

 

TARGETS : PREREQUISITES

COMMAND

...

 

或者是这样:

 

TARGETS : PREREQUISITES ; COMMAND

      COMMAND

      ...

 

规则中“TARGETS”可以是空格分开的多个文件名,也可以是一个标签(执行清空的“clean”)。“TARGETS”的文件名可以使用通配符,格式“A(M)”表示档案文件(Linux下的静态库.a文件)的成员“M”(关于静态库的重建可参考 第十章 使用make更新静态库文件)。通常规则只有一个目标文件(建议这么做),偶尔会在一个规则中需要多个目标。

书写规则是我们需要注意的几点:

1.        规则的命令部分有两种书写方式:a. 命令可以和目标:依赖描述放在同一行。命令在依赖文件列表后并使用分号(;)和依赖文件列表分开。b. 命令在目标:依赖的描述的下一行,作为独立的命令行。当作为独立的命令行时此行必须以[Tab]字符开始。在Makefile中,在第一个规则之后出现的所有以[Tab]字符开始的行都会被当作命令来处理。

2.        Makefile中对“$”有特殊的含义(表示变量或者函数的引用),如果我们的规则如果需要“$”,需要书写两个连续的(“$$”)。

3.        在前边我们也提到过,Makefile一个较长的行,可以使用反斜线“\”将其书写到几个独立的物理行上。虽然makeMakefile文本行的最大长度是没有限制的,但是还是建议这样做。不仅书写方便而且更有利于别人的阅读(这也是一个程序员修养的体现)。

一个规则告诉“make”两件事:1. 目标在什么情况下已经过期; 2. 在需要重建目标的时候,怎么样去重建这个目标。目标是否过期是由那些使用空格分开的规则的依赖文件所决定的。当目标文件不存在或者目标文件的最后修改时间比依赖文件中的任何一个都晚,则目标就会被创建或者重建。也就是说执行规则命令行的前提条件是:1 目标文件不存在; 2. 存在一个依赖的最后修改时间比目标的最后修改时间晚。规则的中心思想就是:目标文件的内容是由依赖文件文件决定,依赖文件的任何一处改动,将导致目前已经存在的目标文件的内容过期。规则的命令为重建目标提供了方法。这些命令运行在系统shell之上。

GNU make的规则中可以使用两种不同类型的依赖:1. 在以前章节所提到的规则中使用的是常规依赖,这是我们书写的Makefile规则中最常用的一种。2. 另外一种在我们书写Makefile时不会经常使用,它比较特殊、称之为“order-only”依赖。一个规则的常规依赖(通常是多个依赖文件)表明了两件事:首先,它决定了重建规则目标所要执行命令的顺序;表明在更新这个规则的目标(执行此规则的命令行)之前必需要按照什么样的顺序、执行那些命令来重建这些依赖文件(对所有依赖文件的重建,使用明确或者隐含规则。就是说对于这样的规则:A:B C,那么在重建目标A之前,首先需要完成对它的依赖文件BC的重建。重建BC的过程就是执行Makefile中文件BC所在的规则)。其次,它确定了一个依存关系;规则中如果依赖文件的任何一个比目标文件新,则被认为规则的目标已经过期同时需要重建目标。

通常,如果规则中依赖文件中的任何一个被更新,则规则的目标相应地也应该被更新。

有时,我们需要定义一个这样的规则,在更新目标(目标文件已经存在)时只需要根据依赖文件中的部分来决定目标是否需要被重建,而不是在依赖文件的任何一个被修改后都重建目标。为了实现这个目的,我们需要对依赖进行分类,一类是这些依赖文件的更新需要对应更新目标文件,另一类是这些依赖的更新不会导致目标被重建。第二类的依赖我们就称他为:“order-only”依赖。在书写规则时,“order-only”依赖使用管道符号“|”开始,作为目标的一个依赖文件。规则的依赖列表中管道符号“|”左边的是常规依赖文件,所有出现在管道符号右边的就是“order-only”依赖。这样的规则书写格式如下:

 

TARGETS : NORMAL-PREREQUISITES | ORDER-ONLY-PREREQUISITES

 

规则中常规依赖文件可以是空。允许对一个目标声明多行按正确顺序依次追加的依赖。需要注意:规则依赖文件中如果一个文件被同时声明为常规依赖和“order-only”依赖,那么此文件被作为常规依赖处理(因为常规依赖所实现的动作是“order-only”依赖所实现的动作的一个超集)。

 

order-only”依赖的使用举例:

    LIBS = libtest.a

foo : foo.c | $(LIBS)

       $(CC) $(CFLAGS) $< -o $@ $(LIBS)

make在执行这个规则时,如果目标文件“foo”已经存在。当“foo.c”被修改以后,目标“foo”将会被重建,但是当“libtest.a”被修改以后。将不执行规则的命令来重建目标“foo”。

就是说,规则中依赖文件$(LIBS)只有在目标文件不存在的情况下,才会参与规则的执行。当目标文件存在时此依赖不会参与规则的执行过程。

阅读(235) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~