makefile 学习笔记
学习的目标:
了解make的历史
了解make的作用以及工作过程
掌握makefile的基本规则和变量的使用
一.什么是makefile?
a) Makefile是工程编译的规则。这些规则指定,哪些文件需要先编译,哪些文件后编译,哪些文件需要重新编译
b) 目的:编译源程序
c) 基础:都是以文件的依赖性为基础
二.为什么要用makefile?
a) 可以高效的自动化编译
b) 简化编译时所需要的执行的命令
三.Makefile包含什么?
a) 显示规则
i. 显示规则明显说明,目标文件,依赖文件和执行的指令
b) 隐晦规则
i. 由make自动推导。是根据文件自动推导出依赖文件,决定是否编译。
c) 变量的定义
d) 文件指示
i. 可以像C语言中使用include 包含其它的makefile文件
e) 注释
四.Make的工作方式
a) 读入所有的Makefile
b) 读入被include的其它makefile
c) 初始化文件中的变量
d) 推导隐晦规则,并分析所有的规则
e) 为所有的目标文件创建关系链
f) 根据依赖关系,决定哪些目标要重新生成
g) 执行生成命令
五.文件的搜索
a) 在大工程中会有大量的源文件,通常的做法是把这些源文件分类放好,并存在不同的目录下面。所以当make去寻找文件的依赖性时,最后是把文件的路径告诉make。做法是在makefile中使用VPATH特殊变量。如果没有定义VPATH,make只会在当前目录寻找。当设置了VPATH,make如果没有在当前目录没有找到,那么就会在VPATH中定义的的路径中寻找。(这个好像用的并不多,因为一般我们都会在每个目录下面建个makefile)设置的方法是:VPATH=src:../headers
b) 当然不一定要使用VPATH,通往文件搜索的路径不止一条。你可以使用vpath这个make的关键字 格式是:vpath %.c foo 意思是.c文件在foo目录中寻找。当然首先寻找的第一目录还是当前目录。
六.伪目标
a) 什么是伪目标?
伪目标表示,没有目标这个文件。但是make的基础就是文件的依赖性,如果没有文件就没有不存在依赖性之说了。所以所有的伪目标都是make 直接调用。当然也不完全是,伪目标也可以是其它目标的依赖,那么也就可以有其它的目标来调用。为了区分伪目标和其它目标文件,使用.PHONY关键字说明伪目标。
七.命令
a) 显示命令
i. Make时,首先会把要执行的命令显示出来然后在打印。但是有时我们不需要打印这个信息,那么@ 就可以派上用场了,如果在命令前面加上@那么这个命令不会显示,不会执行。例如:@echo $PATH 结果是只会打印PATH的值。
b) 命令的执行
i. Make可以执行makefile中所定义的命令,命令可以是shell里面所有的命令,这就使make实现更复杂的功能。命令执行时需要注意的是当前命令执行的进程,因为在子进程中做了事情,其环境是不会返回到父环境中来 。最典型的例子是:cd /etc/ ;pwd 和 cd /etc pwd结果不会相同的。
c) 命令出错
i. 虽然make在执行的过程中并不会管编译的错误。但是如果命令执行错误时,将会终止后面的命里。但是有时有的错误我们并不关心,比如,删除一个文件,这个文件可能不存在,但是我们的目的只是把这个文件删除掉。还有即使增加一个目录,如果这个目录已经存在那也不用mkdir了,但这是mkdir就会出错。所以这种错误同样会使make停止工作。这是我们不希望的。解决的办法还是有的可以在命令的前面加上-号,意思是忽略命令执行的错误。
d) 嵌套执行make
i. 刚才说了如果在一个makefile中使用其它的makefile那么可以使用include包含进来。但是这里有个问题两个makefile中不能有相同的目标,否则必有有些目标make找不到的。那么有没有其它的办法呢。这时就可以使用make的嵌套的执行。在一个大项目中往往在最顶层有个makefile,其它的各个目录都有makefile,但是我们只要在顶层执行make就行了,因为顶层的makefile会调用子目录中的makefile。比如,在顶层makefile中 cd subdir && $(MAKE)中。在嵌套执行make中,有个很重要的东西,那就是变量。顶层的makefile可能要传递某些变量给底层的makefile,这时可以使用export。需要注意的是有两个变量一定会传给底层的makefile,一个是MAKEFLAGES,另外一个是SHELL。另外,有时我们需要知道什么时候进入了哪个makefile执行,虽然可以根据make回显的命令来判别,但是makefile中的命令大部分都差不多,所以判别起来有点难度,这里有个简答的方法,那就是在make 时加入参数 -w,那么在进入子目录中make时就会打印出:进入哪个目录执行了make
八.变量
a) 变量的定义:有四个赋值符号要区分清楚
i. = 赋值,后面的变量可以是前面定义,也可以是后面定义
ii. := 后面出现的变量只可以是前面定义的,如果是后面定义的,那么该值为空
iii. ?= 后面出现的变量如果没有定义,那么就定义,如果已经定义过,那么就不再定义,用原来的值
iv. += 追加赋值
b) 变量的读取 $()或${},如果是用shell的变量,可以用$$加以区分
c) 变量的高级应用:有些时候替换变量中内容。那么可以这样$(foo:%.o=%.c)把.o换成.c
Makefile的学习暂时到这里,后面还有些高级应用,但是一般是用不到的,还有些函数的应用,用到的时候可以再查没必用记住。
Make的历史
Make历史,就是要说make的变化。其实,世界任何新事物的产生和它的持久不衰,都是因为需求。当一个产品满足不了需求时,那么就必须改进。那么这里可以说到make的改进,以及为什么要改。改了之后有什么作用?等等。