本节我们讨论一个Makefile中的一个重要的特殊目标:伪目标。

伪目标是这样一个目标:它不代表一个真正的文件名,在执行make时可以指定这个目标来执行其所在规则定义的命令,有时我们也可以将一个伪目标称为标签。使用伪目标有两点原因:1. 避免在我们的Makefile中定义的只执行命令的的目标(此目标的目的为了执行执行一系列命令,而不需要创建这个目标)和工作目录下的实际文件出现名字冲突。2. 提高执行make时的效率,特别是对于一个大型的工程来说,编译的效率也许你同样关心。以下就这两个问题我们进行分析讨论:

1. 如果我们需要书写这样一个规则:规则所定义的命令不是去创建目标文件,而是使用make指定具体的目标来执一些特定的命令。像下边那样:

clean:

rm *.o temp

规则中“rm”不是创建文件“clean”的命令,只是删除当前目录下的所有.o文件和temp文件。在工作目录下不存在“clean”这个文件时,我们输入“make clean”后,“rm *.o temp”总会被执行。这是我们的初衷。

但当前工作目录下存在文件“clean”时情况就不一样了,在我们输入“make clean”时。规则没有依赖文件,所以目标被认为是最新的而不去执行规则作定义的命令,命令“rm”将不会被执行。这并不是我们的初衷。为了避免这个问题,我们可以将目标“clean”明确的声明为伪目标。将一个目标声明为伪目标需要将它作为特殊目标.PHONY”的依赖。如下:

.PHONY : clean

这样目标“clean”就是一个伪目标,无论当前目录下是否存在“clean”这个文件。我们输入“make clean”之后。“rm”命令都会被执行。而且,当一个目标被声明为伪目标后,make在执行此规则时不会试图去查找隐含规则来创建这个目标。这样也提高了make的执行效率,同时我们也不用担心由于目标和文件名重名而使我们的期望失败。在书写伪目标规则时,首先需要声明目标是一个伪目标,之后才是伪目标的规则定义。目标“clean”书写格式应该如下:

.PHONY: clean

clean:

rm *.o temp

2. 伪目标的另外一使用场合在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”目录处理完成。在书写一个并行执行make的Makefile时,目录的处理顺序是需要特别注意的。

一般情况下,一个伪目标不作为一个另外一个目标文件的依赖。这是因为当一个目标文件的依赖包含伪目标时,每一次在执行这个规则时伪目标所定义的命令都会被执行(因为它是规则的依赖,重建规则目标文件时需要首先重建它的依赖)。当伪目标没有作为任何目标(此目标是一个可被创建或者已存在的文件)的依赖时,我们只能通过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”的所有依赖文件(prog1、prog2和prog3)。当需要单独更新某一个程序时,我们可以通过make的命令行选项来明确指定需要重建的程序。(例如: “make prog1”)。 当一个伪目标作为另外一个伪目标依赖时,make将其作为另外一个伪目标的子例程来处理(可以这样理解:其作为另外一个伪目标的必须执行的部分,就行C语言中的函数调用一样)。下边的例子就是这种用法:

.PHONY: cleanall cleanobj cleandiff

cleanall : cleanobj cleandiff

rm program

cleanobj :

rm *.o

cleandiff :

rm *.diff

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

说明:

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

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

Makefile编写 三 伪目标的作用的更多相关文章

  1. makefile中的伪目标

    伪目标就是总是被执行的目标,相对于目标来说,伪目标不会去考虑它的依赖的时间戳与自己时间戳的新旧关系,从而决定是否执行规则.伪目标格式: .PHONY:clean clean: -rm *.o 在mak ...

  2. .PHONY makefile中的伪目标

    我的理解: 拿clean举例,如果make完成后,自己另外定义一个名叫clean的文件,再执行make clean时,将不会执行rm命令. 为了避免出现这个问题,需要.PHONY: clean === ...

  3. Makefile编写 一 *****

    编译:把高级语言书写的代码转换为机器可识别的机器指令.编译高级语言后生成的指令虽然可被机器识别,但是还不能被执行.编译时,编译器检查高级语言的语法.函数与变量的声明是否正确.只有所有的语法正确.相关变 ...

  4. Makefile 描述的是文件编译的相关规则,它的规则主要是两个部分组成,分别是依赖的关系和执行的命令 PHONY伪目标实践

    Makefile的工作流程 http://c.biancheng.net/view/7091.html Makefile文件是什么? 我们教程主要是讲的是 Makefile .很多 Linux(Uni ...

  5. Makefile的伪目标

    1.Makefile伪目标的格式: .PHONY : cleanclean: rm xxxx 2.Makefile伪目标的作用: 第一种情况: 如果我们需要书写这样的一个规则:规则所定义的命令不是去创 ...

  6. makefile之伪目标

    伪目标 1. 伪目标的语法: 在书写伪目标时,首先需要声明伪目标,然后再定义伪目标规则. 1.1 声明伪目标: .PHONY clean (这里声明clean是伪目标) 1.2 定义伪目标规则: cl ...

  7. 第3课 - makefile伪目标的引入

    第3课 - makefile伪目标的引入 1. makefile 中的目标究竟是什么? (1)默认情况下,make 认为目标对应着一个文件  ==>  目标即文件名 (2)make 首先会检测目 ...

  8. Makefile伪目标

    https://www.zybuluo.com/lishuhuakai/note/210174 本节我们讨论一个Makefile中的一个重要的特殊目标:伪目标. 伪目标是这样一个目标:它不代表一个真正 ...

  9. makefile编写--引用

    1. Makefile 简介 Makefile 是和 make 命令一起配合使用的. 很多大型项目的编译都是通过 Makefile 来组织的, 如果没有 Makefile, 那很多项目中各种库和代码之 ...

随机推荐

  1. 20145204《Java程序设计》第3周学习总结

    20145204<Java程序设计>第3周学习总结 教材学习内容总结 对象和类. Java有基本类型和类类型这两个类型系统.本章主要介绍类类型.定义类时用关键词class,利用类建立对象实 ...

  2. double、float等多字节数据处理

    一.常规的多字节: 有2,4,8字节 float和double是具有自身算法的数据类型,和其他整型不一样[整型数据,可以直接通过移位来进行计算值的大小,float和double不行] 值 = 尾数x ...

  3. Git命令速查表【转】

    本文转载自:http://www.cnblogs.com/kenshinobiy/p/4543976.html 一. Git 常用命令速查 git branch 查看本地所有分支git status ...

  4. Bootstrap and Angular

  5. Java网络编程学习A轮_04_TCP连接异常

    参考资料: https://huoding.com/2016/01/19/488 示例代码: https://github.com/gordonklg/study,socket module A. C ...

  6. PHPUnit简介及使用(thinkphp5的单元测试安装及使用)

    PHPUnit简介及使用(thinkphp5的单元测试安装及使用) 一.总结 一句话总结:直接google这个phpunit(how to use phpunit),然后去官网看使用样例和手册,那些英 ...

  7. C# Word转PDF/HTML/XML/XPS/SVG/EMF/EPUB/TIFF

    一款有着强大的文档转换功能的工具,无论何时何地都会是现代办公环境极为需要的.在本篇文章中,将介绍关于Word文档的转换功能(Word转XPS/SVG/EMF/EPUB/TIFF).希望方法中的代码能为 ...

  8. TTL的具体含义

    TTL(Time To Live)生存时间值,在IP数据包从源到目的的整个转发路径上,每经过一个路由器,路由器都会修改这个TTL字段值,具体的做法是把该TTL的值减1,然后再将IP包转发出去.如果在I ...

  9. Android手机无线adb

    1.首先电脑,手机通过数据线链接电脑,然后通过adb devices 查看到已连接 2.输入:adb tcpip 5555 3.输入:adb connect 222.222.221.137:5555 ...

  10. 2016 CCPC Hangzhou Onsite

    A:题意:n个格子排成一排,每个a[i],要求重排成k个,每个人数相同,合并两个和划分成两个(可以不等)都是花费为1,问最小花费 题解:从前往后贪心即可,由于哪个地方忘开ll,wa了,全改成ll就过了 ...