博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
第2天.make的学习(第二部分)对伪目标的理解
阅读量:5951 次
发布时间:2019-06-19

本文共 4127 字,大约阅读时间需要 13 分钟。

一、目标,依赖,命令
        也许大家觉得这个不重要,但今天我有了新的认识,所以写了下来。这三个就是Makefile的全部,但今天我要重点说一下它的执行顺序。每个Makefile都有且只有一个终极目标,下设若干子目标,make的规则会检查目标与依赖的时间戳,依赖中的某一个比目标新,说明目标已经过时,需要更新。这里要着重说一下,make会将目标的依赖及依赖的依赖全部展开,然后才能决定是否需要更新终极目标。
                                                                                                       a.out
                                                                                                    /     |    \
                                                                                                  /       |     \
                                                                                             _  /       _       \_
                                                                                           /             |            \
                                                                                    hello.o       world.o      main.o
                                                                                   _/                   |                  \_
                                                                                  /                      |                     \
                                                                              hello.c             world.c                main.c
 
  对于这个例子,相信大家都能写出Makefile。make在解析Makefile时,就会生成上面的依赖树,它会自底向上比较时间戳,若下层的新,则执行上层目标所对应的命令,然后,依次执行上上层的命令(因为,底层更新了,所以上面的都需要更新)。如果底层不比上层的新,则不执行上层目标所对应的命令(这就是make的聪明之处)。例如:我们更改了hello.c文件,make在解析Makefile时,首先比较的不是a.out与hello.o谁更新(如果make真的这么做,那么make就会直接退出,因为自你上次执行make时,a.out会比hello.o更新,而我们修改hello.c,并不会影响hello.o的时间戳), 而是依赖树的最底端,hello.c与hello.o的时间戳,因为hello.c的修改,目标hello.o的命令会被执行,进而触发a.out所对应的命令。目标werld.o与main.o所对应的命令当然不会被执行。make的输出看上去是这个样子的
gcc -c hello.c
gcc hello.o world.o main.o     
 
在make 的info文档中有这样一段话:(注意粗体字)
 3.9 How `make' Reads a Makefile
===============================
GNU `make' does its work in two distinct phases.  During the first
phase it reads all the makefiles, included makefiles, etc. and
internalizes all the variables and their values, implicit and explicit
rules, and constructs a dependency graph of all the targets and their
prerequisites.  During the second phase, `make' uses these internal
structures to determine what targets will need to be rebuilt and to
invoke the rules necessary to do so.
 
4 Writing Rules
***************
A "rule" appears in the makefile and says when and how to remake
certain files, called the rule's "targets" (most often only one per
rule).  It lists the other files that are the "prerequisites" of the
target, and "commands" to use to create or update the target.
   
The order of rules is not significant, except for determining the
"default goal": the target for `make' to consider, if you do not
otherwise specify one.  The default goal is the target of the first
rule in the first makefile.  If the first rule has multiple targets,
only the first target is taken as the default.  There are two
exceptions: a target starting with a period is not a default unless it
contains one or more slashes, `/', as well; and, a target that defines
a pattern rule has no effect on the default goal.  (*Note Defining and
Redefining Pattern Rules: Pattern Rules.)
 
二、伪目标
     
伪目标总被认为是过期的,总被认为需要被更新。伪目标又称标签,之所以这样叫,是为了与真实的文件进行区别。那伪目标是如何工作的,我们可以将它当作普通文件,但不管出现在目标中,还是依赖中,都以为着它是将要被更新的普通文件。
 
1、伪目标做目标,普通文件做依赖
     这是最常见的一种,典型的all伪目标  .PHONY:all
                                                                       all: prog1 prog2       #执行make后,会一次生成两个可执行程序
                                                                       prog1:  a.c  ...
                                                                          command
                                                                           ...
                                                                       prog2:  b.c ...
                                                                           command
                                                                           ...
分析:在这个Makefile中。.PHONY是第一个目标,但它以点开头,不会作为终极目标(在上面的英文中有解释),所以终极目标是all,make的职责所在就是重建这个all目标。因为all是伪目标,make命令总认为它需要被更新,而更新它,需要首先更新prog1 和 prog2 ,这就达到了一次make而生成两个可执行文件。
 
2、伪目标做目标,伪目标又做依赖(虽然称为伪目标,但也可做依赖,目标与依赖是相互转化的,就像上面的hello.o,它是hello.c的目标,又是a.out的依赖)
                                                               .PHONY: all subdir apps
                                                               all: subdir apps
                                                               subdir: prog1 prog2
                                                               apps:  prog3 prog4
                                                               prog1: a.c
                                                                  command...   
                                                               prog2: b.c
                                                                  command...
                                                               prog3: c.c
                                                                  command...
                                                               prog4: d.c
                                                                  command...
分析:all是终极目标,它依赖于subdir 和 apps ,因这两个都是伪目标,即:他们需要被更新。subdir又依赖于prog1 和 prog2 这就回到了上面的那种情况。这种形式经常出现在大的工程中,是对上面一种情况的扩展,我们可以修改all 或 subdir 或  apps 中的依赖,来决定我们需要那些应用程序,裁剪掉那些应用程序。你应该听说过内核裁剪与移植吧,所谓裁剪,就是修改Makefile的目标,不生成我们不需要的东东;所谓移植,就是修改Makefile的编译参数,换成其他的编译工具。
 
3、普通文件做目标,伪目标做依赖
                                                              all: prog
                                                              prog: a.c prt
                                                                  command...
                                                              .PHONY: prt
                                                               prt:
                                                                  @echo "this is prt"
分析:每次执行make时,this is prt都会出现在屏幕上。尽管prog不需要被更新,但prt中的命令依然要被执行。make会这样来解析,prog依赖于prt,而prt有需要被更新(因为它是伪目标),这意味着this si prt会出现在屏幕上,prt更新完成后,prog目标中的command...就会被执行(我们假定a.c没有被更改)。事实上我们那个文件也没有更改,但是prog目标中的命令还是被执行了,info make中不建议这样做
A phony target should not be a prerequisite of a real target file;
if it is, its commands are run every time `make' goes to update that
file.
 
总结:在伪目标中始终贯穿着这样一句话:伪目标总被认为是需要被更新的。我也是依据这句话来分析上述伪目标的应用。伪目标可以与真实文件重名,典型的clean用法,因为make知道,我们只是想执行clean下的命令,而不是去重建一个叫做clean的文件,这也是我们有时把它解释称标签的原因。关于上述第二种情况,info make中有这样一个解释
When one phony target is a prerequisite of another, it serves as a
subroutine of the other.  For example, here `make cleanall' will delete
the object files, the difference files, and the file `program':
     .PHONY: cleanall cleanobj cleandiff
     cleanall : cleanobj cleandiff
             rm program
     cleanobj :
             rm *.o
     cleandiff :
             rm *.diff
一、目标,依赖,命令
    这三个是makefile的全部内容,现在来说一下它的执行顺序

转载于:https://www.cnblogs.com/SFTD/p/3622126.html

你可能感兴趣的文章
ADODB类库操作查询数据表
查看>>
博客搬家了
查看>>
Python中使用ElementTree解析xml
查看>>
sed处理文本
查看>>
jquery 操作iframe、frameset
查看>>
解决vim中不能使用小键盘
查看>>
jenkins权限管理,实现不同用户组显示对应视图views中不同的jobs
查看>>
我的友情链接
查看>>
CentOS定时同步系统时间
查看>>
批量删除用户--Shell脚本
查看>>
如何辨别android开发包的安全性
查看>>
Eclipse Java @Override 报错
查看>>
知道双字节码, 如何获取汉字 - 回复 "pinezhou" 的问题
查看>>
linux中cacti和nagios整合
查看>>
Parallels Desktop12推出 新增Parallels Toolbox
查看>>
正则表达式验证身份证格式是否正确
查看>>
xml格式文件解析
查看>>
ios百度地图-路径规划
查看>>
Python高效编程技巧
查看>>
配置Eclipse使用maven构建项目默认JDK为1.8
查看>>