Chinaunix首页 | 论坛 | 博客
  • 博客访问: 520969
  • 博文数量: 257
  • 博客积分: 1666
  • 博客等级: 上尉
  • 技术积分: 1535
  • 用 户 组: 普通用户
  • 注册时间: 2012-04-02 23:02
文章分类

全部博文(257)

文章存档

2013年(2)

2012年(255)

分类: Delphi

2012-07-25 12:34:46

所谓伪目标就是这样一个目标,它不代表一个真正的文件名,在执行make时可以指定这个目标来执行其所在规则定义的命令,有时我们将一个伪目标成为标签。

那么到底什么是伪目标呢?可能作为初学者还不会在乎这个问题,下面我们来看下我们将在什么时候需要它。

首先来看下面一个例子:

当前目录下只有一个myls1.c,于是为了让程序让makefile来管理,写了一个如下的简单的makefile。

执行:

大家会发现,真的可以利用这个makefile管理当前的工程,也能如期按照我们的要求生成执行文件myls。

执行make clean,这样就可以删除可执行程序。

接着我做了个手脚,在当前目录下建立一个叫clean的文件,那么这样执行的效果是如何?

那么这个时候为什么又不能执行了?在我的makefile中其实并没有修改任何东西,为什么这个时候已经能管理工程的makefile又不能来管理文件了。

那要解决这个问题就是添加两行,修改后的makefile如下:

再次返回执行:

这样就解决了问题,那具体的原因是什么?

在makefile中我们使用伪目标就可以解决上述的问题,那为什么要使用伪目标,一种就是如例题,为了避免在makefile中定义的只执行命令的目标和工作目录下的实际文件出现名字冲突,另一种是提交执行makefile时的效率。

第一种情况:

如果我们需要书写这样的一个规则:规则所定义的命令不是去创建目标文件,而是通过make命令行明确指定它来执行一些特点的命令,就像例题中的clean。当文件夹中没有clean这个文件的时候,我们输入“make clean”能按照初衷执行,但是一旦文件夹中出现clean文件,我们再次输入“make clean”,由于这个规则没有任何依赖文件,所以目标被认为是最新的而不去执行规则所定义的命令。所以rm命令不会被执行。为了解决问题,我们将目标clean定义成伪目标。

也就是添加:

.PHONY:clean

那么目录中不论是否有clean文件,只要输入“make clean”就能执行rm命令了。

当一个目标被声明为伪目标后,make在执行规则时不会去试图去查找隐含规则来创建它。这样就提高了make的执行效率,也不用担心由于目标和文件名重名了。

第二种情况:

 伪目标的另外一使用场合在make的并行和递归执行过程中。此情况下一般存在一个变量,其定义为所有需要make的子目录。对多个目录进行make的实现方式可以在一个规则中可以使用shell的循环来完成。如下: 

SUBDIRS = foo bar baz 

subdirs: 

for dir in $(SUBDIRS); do \ 

$(MAKE) -C $$dir; \ 

done 

但这种实现方法存在以下几个问题。1. 当子目录执行make出现错误时,make不会退出。就是说,在对某一个目录执行make失败以后,会继续对其他的目录进行make。在最终执行失败的情况下,我们很难根据错误的提示定位出具体是是那个目录下的Makefile出现错误。这给问题定位造成了很大的困难。为了避免这样的问题,我们可以在命令行部分加入错误的监测,在命令执行错误后make退出。不幸的是,如果在执行make时使用了-k选项,此方式将失效。2. 外一个问题就是使用这种shell的循环方式时,没有用到make对目录的并行处理功能,因为规则的命令是一条完整的shell命令,不能被并行的执行。 

我们可以通过伪目标方式来克服以上实现方式所存在的两个问题。 

SUBDIRS = foo bar baz 

.PHONY: subdirs $(SUBDIRS) 

subdirs: $(SUBDIRS) 

$(SUBDIRS): 

$(MAKE) -C $@ 

foo: baz 

上边的实现中使用了一个没有命令行的规则foo: baz,用来限制子目录的make顺序。此规则的含义时在处理foo目录之前,需要等待baz目录处理完成。在书写一个并行执行makeMakefile时,目录的处理顺序是需要特别注意的。 

一般情况下,一个伪目标不作为一个另外一个目标文件的依赖。这是因为当一个目标文件的依赖包含伪目标时,每一次在执行这个规则时伪目标所定义的命令都会被执行(因为它是规则的依赖,重建规则目标文件时需要首先重建它的依赖)。当伪目标没有作为任何目标(此目标是一个可被创建或者已存在的文件)的依赖时,我们只能通过make的命令行选项明确指定这个伪目标,来执行它所定义的命令。例如我们的make clean 

Makefile中,伪目标可以有自己的依赖。在一个目录下如果需要创建多个可执行程序,我们可以将所有程序的重建规则在一个Makefile中描述。因为Makefile中第一个目标是终极目标,约定的做法是使用一个称为all的伪目标来作为终极目标,它的依赖文件就是那些需要创建的程序。下边就是一个例子: 

#sample Makefile 

all : prog1 prog2 prog3 

.PHONY : all 

prog1 : prog1.o utils.o 

cc -o prog1 prog1.o utils.o 

prog2 : prog2.o 

cc -o prog2 prog2.o 

prog3 : prog3.o sort.o utils.o 

cc -o prog3 prog3.o sort.o utils.o 

执行make时,目标all被作为终极目标。为了完成对它的更新,make会创建(不存在)或者重建(已存在)目标all的所有依赖文件(prog1prog2prog3)。当需要单独更新某一个程序时,我们可以通过make的命令行选项来明确指定需要重建的程序。(例如: “make prog1)。 当一个伪目标作为另外一个伪目标依赖时,make将其作为另外一个伪目标的子例程来处理(可以这样理解:其作为另外一个伪目标的必须执行的部分,就行C语言中的函数调用一样)。下边的例子就是这种用法: 

.PHONY: cleanall cleanobj cleandiff 

cleanall : cleanobj cleandiff 

rm program 

cleanobj : 

rm *.o 

cleandiff : 

rm *.diff 

cleanobjcleandiff这两个伪目标有点像子程序的意思(执行目标clearall时会触发它们所定义的命令被执行)。我们可以输入make cleanallmake cleanobjmake cleandiff命令来达到清除不同种类文件的目的。例子首先通过特殊目标.PHONY声明了多个伪目标,它们之间使用空各分割,之后才是各个伪目标的规则定义。 

说明: 

通常在清除文件的伪目标所定义的命令中rm使用选项–f--force)来防止在缺少删除文件时出错并退出,使make clean过程失败。也可以在rm之前加上-来防止rm错误退出,这种方式时make会提示错误信息但不会退出。为了不看到这些讨厌的信息,需要使用上述的第一种方式。 

另外make存在一个内嵌隐含变量RM,它被定义为:RM = rm –f。因此在书写clean规则的命令行时可以使用变量$(RM)来代替rm,这样可以免出现一些不必要的麻烦!这是我们推荐的用法。

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