Makefile伪目标
https://www.zybuluo.com/lishuhuakai/note/210174
本节我们讨论一个Makefile
中的一个重要的特殊目标:伪目标。
伪目标是这样一个目标:它不代表一个真正的文件名,在执行make
时可以指定这个目标来执行其所在规则定义的命令,有时我们也可以将一个伪目标称为标签。使用伪目标有两点原因:
避免在我们的
Makefile
中定义的只执行命令的的目标(此目标的目的为了执行执行一系列命令,而不需要创建这个目标)和工作目录下的实际文件出现名字冲突。提高执行
make
时的效率,特别是对于一个大型的工程来说,编译的效率也许你同样关心。以下就这两个问题我们进行分析讨论:
如果我们需要书写这样一个规则:规则所定义的命令不是去创建目标文件,而是使用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
伪目标的另外一使用场合在make
的并行和递归执行过程中。此情况下一般存在一个变量,其定义为所有需要make
的子目录。对多个目录进行make
的实现方式可以在一个规则中可以使用shell
的循环来完成。如下:
SUBDIRS = foo bar baz
subdirs:
for dir in $(SUBDIRS); do \
$(MAKE) -C $$dir; \
done
但这种实现方法存在以下几个问题。
当子目录执行
make
出现错误时,make
不会退出。就是说,在对某一个目录执行make
失败以后,会继续对其他的目录进行make
。在最终执行失败的情况下,我们很难根据错误的提示定位出具体是是那个目录下的Makefile
出现错误。这给问题定位造成了很大的困难。为了避免这样的问题,我们可以在命令行部分加入错误的监测,在命令执行错误后make
退出。不幸的是,如果在执行make时使用了-k
选项,此方式将失效。另外一个问题就是使用这种
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伪目标的更多相关文章
- Makefile 文件格式;makefile伪目标
Makefile包含 目标文件.依赖文件.可运行命令三部分. 每部分的基本格式例如以下: test: prog.o code.o gcc -o test prog.o code.o 当中 ...
- 第3课 - makefile伪目标的引入
第3课 - makefile伪目标的引入 1. makefile 中的目标究竟是什么? (1)默认情况下,make 认为目标对应着一个文件 ==> 目标即文件名 (2)make 首先会检测目 ...
- Makefile的伪目标
1.Makefile伪目标的格式: .PHONY : cleanclean: rm xxxx 2.Makefile伪目标的作用: 第一种情况: 如果我们需要书写这样的一个规则:规则所定义的命令不是去创 ...
- Makefile 描述的是文件编译的相关规则,它的规则主要是两个部分组成,分别是依赖的关系和执行的命令 PHONY伪目标实践
Makefile的工作流程 http://c.biancheng.net/view/7091.html Makefile文件是什么? 我们教程主要是讲的是 Makefile .很多 Linux(Uni ...
- Makefile目标,伪目标,头文件自动依赖
目标 即我们最终要生成的文件,make默认生成第一个目标,注意 makefile中tab和空格不是一回事,规则使用tab缩进,编辑器不要设置诸如"将tab替换为空格之类的选项",目 ...
- makefile中的伪目标
伪目标就是总是被执行的目标,相对于目标来说,伪目标不会去考虑它的依赖的时间戳与自己时间戳的新旧关系,从而决定是否执行规则.伪目标格式: .PHONY:clean clean: -rm *.o 在mak ...
- makefile中伪目标的理解
1. 我们知道Makefile中的语法是这样: target ... : prerequisites ... command - - 2. 假如编译两个文件可以这么写: a.o:a.c gcc -c ...
- 第三篇 makefile的伪目标
我们来思考一下makefile中的目标究竟是什么?实际上,在默认情况下: 1.make将makefile的目标认为是一个文件: 2.make解释器比较目标文件和依赖文件的新旧关系,决定是否 ...
- Makefile编写 三 伪目标的作用
本节我们讨论一个Makefile中的一个重要的特殊目标:伪目标. 伪目标是这样一个目标:它不代表一个真正的文件名,在执行make时可以指定这个目标来执行其所在规则定义的命令,有时我们也可以将一个伪目标 ...
随机推荐
- ecshop You don't have permission to access / on this server
回复 6# 晓天 确实是这个短标签的事情,谢谢了啊. 第一种方法:替换程序里的内容,以后就省心了. 针对所有的php脚本 在DW里面运行查找替换l 主要做替换操作 当然是短标签替换为整标签 注意顺序 ...
- 纯js实现最简单的文件上传(后台使用MultipartFile)
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- storm学习之六-使用Maven 生成jar包多种方式
Maven可以使用mvn package指令对项目进行打包,如果使用java -jar xxx.jar执行运行jar文件,会出现"no main manifest attribute, in ...
- Maven 与 IntelliJ IDEA 的完美结合
你是否正在学习Maven?是否因为Maven难用而又不得不用而苦恼?是否对Eclipse于Maven的冲突而困惑? 那么我告诉你一个更直接更简单的解决方案: IntelliJ IDEA! 1. 什么是 ...
- mongodb:修改oplog.rs 的大小size
其内容字段说明: ts:操作日志的timestamp t: 未知? h:操作唯一随机值 v:oplog.rs的版本 op:操作类型: i:insert操作 u:update操作 d:delete操作 ...
- HTML5媒体(音频/视频)
摘要: 在HTML5出现之前,web媒体大部分通过Flash来实现.这种方式造成了文件大加载慢,影响网站性能,开发难度高,维护麻烦,不易扩展等.这就导致HTML5自己开始支持媒体功能.HTML5 DO ...
- 使用d3.v3插件绘制出svg图
众所周知,这个插件使用的svg技术,而IE8(包括IE8)之前的浏览器是不支持svg的 接下来看代码吧 从后台获取到带id和父id的目录数据[json格式] var module = requestU ...
- mongodb 搭建主从服务器
mongodb 主从配置比较简单,只需要在启动的时候添加参数(-master.-slave -source IP:PORT). Ubuntu 16.04 系统环境 监听端口分别为:27010.2701 ...
- Express框架中如何引用ejs模板引擎
1.如何在项目中安装ejs模板引擎 在NodeJS指南中利用利用以下命令建立网站的基本结构: express -t ejs microblog 运行这个命令后继续运行 cd microblog &am ...
- TCP三次握手原则
“已失效的连接请求报文段”的产生在这样一种情况下: client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server. 本来这是一 ...