Makefile的伪目标

 以下内容源于C语言中文网的学习与整理,非原创,如有侵权请告知删除。

伪目标,它的目的并不是创建目标文件(所以称作“伪”),而是想去执行这个目标下面的命令。它有点像汇编语言里的标签。

使用伪目标的原因:避免Makefile中定义的(只为了执行命令的)目标与实际文件的名字出现冲突;提高执行 make 时的效率。

如果书写这样一个规则,规则所定义的命令不是去创建文件,而是通过 make 命令明确指定它来执行一些特定的命令,比如:

clean:rm -rf *.o test

规则中 rm 命令不是为了创建 clean 这个文件,而是执行删除某些文件的任务。当工作目录中不存在以 clean 命令的文件时,在 shell 中输入 make clean 命令,命令 rm -rf *.o test 总会被执行 ,这也是我们期望的结果。

但是如果当前目录下存在文件名为  clean 的文件时,我们在 shell 中执行命令 make clean时,由于这个规则没有依赖文件,所以目标被认为是最新的,从而不去执行规则所定义的命令,因此命令 rm 将不会被执行。为了解决这个问题,删除 clean 文件或者是在 Makefile 中将目标 clean 声明为伪目标。(这段话怎么理解?目录中是否存在clean这个文件,都改变不了目标clean没有依赖文件的事实啊!按理都不会执行啊!)

将一个目标声明称伪目标的方法,是把它作为特殊的目标.PHONY的依赖,如下:

.PHONY:clean

这样 clean 就被声明成一个伪目标,无论当前目录下是否存在 clean 这个文件,当我们执行 make clean 后 rm 都会被执行。而且当一个目标被声明为伪目标之后,make 在执行此规则时不会去试图查找隐含的关系去创建它。这样同样提高了 make 的执行效率,同时也不用担心目标和文件名重名而使编译失败。

在书写伪目标的时候,需要声明目标是一个伪目标,之后才是伪目标的规则定义。目标 "clean" 的完整书写格式如下:

.PHONY:clean
clean:rm -rf *.o test

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

SUBDIRS=foo bar baz
subdirs:for dir in $(SUBDIRS);do $(MAKE) -C $$dir;done

代码表达的意思是当前目录下存在三个子文件目录,每个子目录文件都有相对应的 Makefile 文件,代码中实现的部分是用当前目录下的 Makefile 控制其它子模块中的 Makefile 的运行,但是这种实现方法存在以下几个问题:

  •  当子目录执行 make 出现错误时,make 不会退出。就是说,在对某个目录执行 make 失败以后,会继续对其他的目录进行 make。在最终执行失败的情况下,我们很难根据错误提示定位出具体在哪个目录下执行 make 发生的错误。这样给问题定位造成很大的困难。为了解决问题可以在命令部分加入错误检测,在命令执行的错误后主动退出。不幸的是如果在执行 make 时使用了 "-k" 选项,此方式将失效。
  • 另外一个问题就是使用这种 shell 循环方式时,没有用到 make 对目录的并行处理功能,由于规则的命令是一条完整的 shell 命令,不能被并行处理。

有了伪目标之后,我们可以用它来克服以上方式所存在的两个问题,代码展示如下:

SUBDIRS=foo bar baz
.PHONY:subdirs $(SUBDIRS)
subdirs:$(SUBDIRS)
$(SUBDIRS):$(MAKE) -C $@
foo:baz

上面的实例中有一个没有命令行的规则“foo:baz”,这个规则是用来规定三个子目录的编译顺序。因为在规则中 "baz" 的子目录被当作成了 "foo" 的依赖文件,所以 "baz" 要比 "foo" 子目录更先执行,最后执行 "bar" 子目录的编译。

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

如果在一个文件里想要同时生成多个可执行文件,我们可以借助伪目标来实现。使用方式如下:

.PHONY:all
all:test1 test2 test3
test1:test1.ogcc -o $@ $^
test2:test2.ogcc -o $@ $^
test3:test3.ogcc -o $@ $^

在当前目录下创建了三个源文件,目的是把这三个源文件编译成为三个可执行文件。将重建的规则放到 Makefile 中,约定使用 "all" 的伪目标来作为最终目标,它的依赖文件就是要生成的可执行文件。这样的话只需要一个 make 命令,就会同时生成三个可执行文件。

之所以这样写,是因为伪目标的特性,它总会被执行,所以它依赖的三个文件的目标就不如 "all" 这个目标新,所以,其他的三个目标的规则总是被执行,这也就达到了我们一口气生成多个目标的目的。我们也可以实现单独编译这三个中的任意一个源文件,比如我们想去重建 test1,可以执行命令make test1 来实现 。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/460711.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Makefile中的文件包含

以下内容源于C语言中文网的学习与整理,非原创,如有侵权请告知删除。 Makefile 中包含其他的文件,使用的关键字是 "include"。 make 读取到 "include" 关键字时,会暂停读取当前的 Makefile,转去读取…

Eclipse高级使用技巧

1. Eclipse的配置文件导入和导出功能 说明:可以将Eclipse的自定义的工作空间配置文件导出和导入,这样创建多工作空间时候就省去了再设置的烦恼。 2. Eclipse设置显示行号 说明:设置文件现实行号,调试错误的…

hadoop hive 的安装问题

origin: http://blog.163.com/songyalong1117126/blog/static/1713918972014124481752/hadoop hive 的安装问题 2014-02-24 16:10:13| 分类: hadoop|举报|字号 订阅能了一下午终于把hive搞好了,其中出现很多的问题1、hadoop和hive的版本问题&#xff0…

熬之滴水成石:最想深入了解的内容--windows内核机制(6)

58 进程和线程(3) 说完进程再说说线程,线程相比于进程其实有更多可说的内容。首先实现线程调用的数据结构是个栈,该栈记录了调用方法的信息这里面也包括了函数调用及返回的地址。线程肯定是属于某个进程,其控制流可以访…

Google搜索技巧总结

http://blog.sciencenet.cn/blog-44407-229042.html转载于:https://www.cnblogs.com/aze-003/p/4105261.html

【linux】学习6

鸟哥13章的东西 shell script速度较慢,适合用于系统管理,但不适合处理大量数值运算 var$((运算内容)) 可以用来做变量的加减乘除求余运算 total$(($firstnum*$secnu)) declare -i total"$firstnum*$secnu" 上面两句功能一样,建议用…

Makefile嵌套执行make

概述 在一个大的工程文件中,不同的文件按照功能被划分到不同的模块中,每个模块可能都会有自己的编译顺序和规则。如果在一个 Makefile 文件中描述所有模块的编译规则,就会显得很杂乱,执行时也会很不方便。 如果在不同的模块中分别…

core--线程同步(内核模式)

什么是内核?windows操作系统为了更好的管理进程,线程,创建了很多数据结构,这些数据结构运行在windows的底层,并不开放给开发人员;所以开发人员称这些结构为内核,但是为了开发人员能够使用&#…

hive cli启动判断hadoop version的问题

测试环境的hive cli启动时报错:Unable to determine Hadoop version information.hive是一个shell:使用sh -x跟踪运行过程,可以看到其通过hadoop version获取hdfs的版本相关的代码如下:# Make sure were using a compatible version of Hadoo…

Makefile变量的高级用法:变量的替换引用、变量的嵌套使用

以下内容源于C语言中文网的学习与整理,非原创,如有侵权请告知删除。 我们之前已经学习过变量的定义和基本的赋值运算,我们可以更深入的了解一下变量的一些高级的用法。高级使用方法有两种:第一种是变量的替换引用,第二…

SAP Study Notes: BW Queriy-Variables(变量)

About Variable:1.Variable 是和InfoObject绑定的,可用于任何含有该IO的query中。2.Variable有以下几种类型:Characteristic:用于限制Char。 Text:用于在报表动态显示文本。 Hierarchy:用于限制Hierarchy。 Hieararchy…

Makefile中的通配符

以下内容源于C语言中文网的学习与整理,非原创,如有侵权请告知删除。 Makefile 是可以使用 shell 命令的,所以 shell 支持的通配符在 Makefile 中也是同样适用的。 shell 中使用的通配符有:"*","?&qu…

SCCM2012 R2集成WSUS服务器-4:部署软件更新组

在之前的文章中,我们已经创建好的软件更新组,也下载好了补丁,下面我们来部署这些补丁。右击软件更新组,选择”部署“,如图。进入到部署软件更新向导,输入部署的名称,并指定部署的集合。如图。在…

JavaScript Iframe富文本编辑器中的光标定位

最近在项目中碰到一个比较棘手的问题: 在iframe富文本编辑器中,有个工具栏,这个工具栏在iframe标签之外,工具栏上有一个按钮,点击该按钮向iframe正在编辑中的光标处插入一个图片,图片会插入到当前光标所在的…

Makefile目标类型大汇总

模式规则中的目标形式是多种多样的,它可以是一个或多个的文件,也可以是一个伪目标,或者其他的类型,下面是对这些类型的详细说明。 强制目标 如果一个目标中没有命令或者依赖,并且它的目标不是一个存在的文件名&#xf…

网站故障排查几个简单步骤

1、top命令查看cpu消耗多少(id%的值和%cpu要是一直是几百就是问题了。%wa要是大于30%也是压力大了)。还有看负载的3个值(和cpu线程是1比1关系。要是值大于线程书,那么也是压力过大。)top命令要是发现cpu消耗过多,可以知道是哪几个进程了。2、查看硬盘使用…

isset、empty、var==null、is_null、var===null详细理解

//isset: 判断变量是否被初始化 //它并不会判断变量是否为空,并且可能用来判断数组中元素是否被定义 //听说在数组用isset与array_key_exists高出4倍 $a ""; $ar[c] ""; if(!isset($a)){echo $a not isset\r\n; }else{echo $a iss…

Makefile中常见的错误信息

以下内容源于C语言中文网的学习与整理,非原创,如有侵权请告知删除。 make 执行过程中所产生错误并不都是致命的,特别是在命令行之前存在 "-"、或者 make 使用 "-k" 选项执行时。 make 执行过程的致命错误都带有前缀字符…

Javascript中call函数和apply函数的使用

Javascript 中call函数和apply的使用: Javascript中的call函数和apply函数是对执行上下文进行切换,是将一个函数从当前执行的上下文切换到另一个对象中执行,例如: sourceObj.method.call(destObj,params1,params2) 是将sourceObj中…

Makefile隐含规则

以下内容源于C语言中文网的学习与整理,非原创,如有侵权请告知删除。 隐含规则的含义 隐含规则,就是我们做出一些具体的操作后,系统自动推导完成。 编写 Makefile 的时候,可以使用隐含规则来简化Makefile 文件编写。 下…