makefile小结
平时也不怎么用makefile文件,都是看别人在用。今天看到一个开源项目用makefile玩的飞起,我也果断想尝试一下。所以有这篇流水日志,内容大多网上查来的,如果不当,欢迎拍砖。
makefile的基本格式:
target :prerequistites...
command
target:目标文件,可以是obj文件,也可以是可执行文件。
prerequistites:生成target所需要的文件
command: make需要执行的命令,(任意的shell命令),makefile中的命令必须以[tab]开头。command 如果太长,可以用""作为换行符!
点评:
Makefile的规则
目标 : 需要的条件
命令 (注意前面用tab键开头)
解释一下:
1 目标可以是一个或多个,可以是Object File,也可以是执行文件,甚至可以是一个标签。
2 需要的条件就是生成目标所需要的文件或目标
3 命令就是生成目标所需要执行的脚本
就是说一条makefile规则规定了编译的依赖关系,也就是目标文件依赖于条件,生成规则用命令来描述。在编译时,如果需要的条件的文件比目标更新的话,就会执行生成命令来更新目标。
一些基本的术语
1-> 通配符
* :任意长度的字符串
? :任意单个字符
[...] :e.g[abcd]表示abcd中的任意一个字符,[^abcd]除了abcd以外的字符[09]表示09任意一个数字
~ :表示home目录
点评:我平时用到的也就*和?多一些,其他没咋用。
2->变量定义
=(可以使用后面定义的变量)或者:=(只能使用之前定义好的变量)
变量替换(用到再说)
变量值追加+=
点评:只知道‘=’和‘:=’的区别,感觉就可以了。
3->变量值覆盖
override
override
override
点评:目前还没用过。
4->目标变量
作用是使变量的作用域仅限于这个目标(target)之中,而不是全局的,对整个makefile都有效
点评:也就是定义在command里面的那个变量。。。
5->makefile命令前缀,makefile中书写shell命令时可以加上2种前缀@,-,或者不加前缀
前缀@:只输出命令执行的结果,出错的话就停止
前缀-:命令执行有误的话,忽略错误,继续执行
不加前缀:输出执行的命令以及命令执行的结果,出错的话就停止
点评:平时用的时候,没加过前缀 = =
6->伪目标
并不是一个"目标(target)"不会真正的生成一个目标文件,典型的伪目标是makefile文件中用来清理编译过程中中间文件的clean伪目标。
点评:就是一个标签,执行了一些shell指令,没有生成文件。在清除生成的目标文件的时候用的比较多。
7->makefile的执行过程。
GNU make 的工作方式
1.读入主makefile文件
2.读入被include的其他makefile文件
3.初始化文件中的变量
4.推导隐晦规则,并分析所有规则
5.为所有的目标文件创建依赖关系
6.根据依赖关系,决定哪些目标文件需要重新生成
7.执行生成命令。
点评:就知道有这么个过程,我只用到了makefile中的很简单的规则。(摊手,规则复杂,对我来说,然并卵)
下面举例说明一下,看起来更清楚()
如果一个工程有3个头文件,和8个C文件,我们为了完成前面所述的那三个规则,我们的Makefile应该是下面的这个样子的。
edit : main.o kbd.o command.o display.o /
insert.o search.o files.o utils.o
cc -o edit main.o kbd.o command.o display.o /
insert.o search.o files.o utils.o
main.o : main.c defs.h
cc -c main.c
kbd.o : kbd.c defs.h command.h
cc -c kbd.c
command.o : command.c defs.h command.h
cc -c command.c
display.o : display.c defs.h buffer.h
cc -c display.c
insert.o : insert.c defs.h buffer.h
cc -c insert.c
search.o : search.c defs.h buffer.h
cc -c search.c
files.o : files.c defs.h buffer.h command.h
cc -c files.c
utils.o : utils.c defs.h
cc -c utils.c
clean :
rm edit main.o kbd.o command.o display.o /
insert.o search.o files.o utils.o
将上面的内容写入到Makefile文件中,然后执行make就可以进行编译,执行make clean就可以删除所有目标文件。解释一下,也就是说生成最终的目标文件edit,依赖于一系列的.o目标文件,而这些.o文件又是需要用源文件来编译生成的。
需要注意的是,clean后面没有条件,而clean本身也不是文件,它只不过是一个动作名字(也就一个伪目标啦,只执行其后的指令序列),其冒号后什么也没有,那么,make就不会自动去找文件的依赖性,也就不会自动执行其后所定义的命令。
make是如何工作的
在默认的方式下,也就是我们只输入make命令。那么,
1、make会在当前目录下找名字叫“Makefile”或“makefile”的文件。
2、如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“edit”这个文件,并把这个文件作为最终的目标文件。
3、如果edit文件不存在,或是edit所依赖的后面的 .o 文件的文件修改时间要比edit这个文件新,那么,他就会执行后面所定义的命令来生成edit这个文件。
4、如果edit所依赖的.o文件也不存在,那么make会在当前文件中找目标为.o文件的依赖性,如果找到则再根据那一个规则生成.o文件。(这有点像一个堆栈的过程)
5、当然,你的C文件和H文件是存在的啦,于是make会生成 .o 文件,然后再用 .o 文件生命make的终极任务,也就是执行文件edit了。
点评:上面的过程虽然麻烦,但是理解起来很通透,下面举例用makefile的规则优化一下上面的过程。
edit : main.o kbd.o command.o display.o /
insert.o search.o files.o utils.o
cc -o edit main.o kbd.o command.o display.o /
insert.o search.o files.o utils.o
我们可以看到[.o]文件的字符串被重复了两次,如果我们的工程需要加入一个新的[.o]文 件,那么我们需要在两个地方加(应该是三个地方,还有一个地方在clean中)。当然,我们的makefile并不复杂,所以在两个地方加也不累,但如果 makefile变得复杂,那么我们就有可能会忘掉一个需要加入的地方,而导致编译失败。所以,为了makefile的易维护,在makefile中我们 可以使用变量。makefile的变量也就是一个字符串,理解成C语言中的宏可能会更好。
于是,我们使用变量objects
objects = main.o kbd.o command.o display.o /
insert.o search.o files.o utils.o
这样一来,原来的makefile变成如下的样子:
objects = main.o kbd.o command.o display.o /
insert.o search.o files.o utils.o
edit : $(objects)
cc -o edit $(objects)
main.o : main.c defs.h
cc -c main.c
kbd.o : kbd.c defs.h command.h
cc -c kbd.c
command.o : command.c defs.h command.h
cc -c command.c
display.o : display.c defs.h buffer.h
cc -c display.c
insert.o : insert.c defs.h buffer.h
cc -c insert.c
search.o : search.c defs.h buffer.h
cc -c search.c
files.o : files.c defs.h buffer.h command.h
cc -c files.c
utils.o : utils.c defs.h
cc -c utils.c
clean :
rm edit $(objects)
点评:简单的变量替换,可以简洁一点儿。可是还是没有达到,开源项目中的那种爽的飞起的效果(sign...),毕竟就用那么点儿规则。
如有错误,请拍砖,不要客气。索引部分,权利归原作者所有。
感谢~参考索引
http://www.cnblogs.com/wang_yb/p/3990952.html
http://www.cnblogs.com/luchen927/archive/2012/02/05/2339002.html

浙公网安备 33010602011771号