最近在学makefile,顺便写点学习体会,兴许后来的某一天我忘了,回来翻翻博客还能找点思路。
本文仅基于GCC讲解,至于其他编译器暂时不会涉及,如果没听过啥是GCC就不要往下看了。
简单介绍一下makefile是个什么东东,makefile是一个编译和链接规则的集合,主要的作用是告诉make,怎么去调用gcc或g++编译源文件,然后怎么去链接目标文件。
当前的大部分IDE,在用户单击编译按钮后,都会生成一个makefile,然后在后台去调用编译器和链接器生成可执行程序。
开始的时候先简单介绍一下程序的生命周期,源码到可执行程序,一般需要经过四个过程,
上图截取自《深入理解计算机系统》,图中说明了,一个程序要从源文件变为一个可执行的机器文件,需要至少四个步骤(python之类的语言还有一个解释过程)。
举个简单的栗子,我们要在屏幕上面打印一句“hello world!”,除去编辑的过程,源文件先要经过预处理得到*.i文件,然后经过编译得到*.s文件,在经过汇编得到.o文件,最后链接成为可执行文件。
预处理是预处理器将*.c文件的宏展开,然后直接将宏替换,去除注释,得到纯asicii文件;
编译是指将*.i文件转换为汇编语句的过程;
汇编是将汇编文件转换为机器语言,也就是0101的计算机可识别的文件;
链接是将汇编后的目标文件链接为可执行的二进制文件。
值得注意的是预处理器被集成到编译器上面了,但是调用gcc的时候仍然会生成*.i文件,命令为
gcc -E hello.c -o hello.i
有了上面的基本了解,接下来贴一段makefile的内容
#sample Makefile
hello : main.o key.o command.o display.o
cc -o hello main.o kbd.o command.o display.o
main.o : main.c globle.h
cc -c main.c
key.o : key.c globle.h command.h
cc -c key.c
command.o : command.c globle.h command.h
cc -c command.c
display.o : display.c globle.h display.h
cc -c display.c
clean :
rm hello main.o key.o command.o display.o
一个简单的makefile的规则如下,
目标:依赖规则
命令
目标:可以是一个*.o文件,也可以是可执行文件,也可以是一个可执行的命令,这个命令又称为伪目标。
依赖规则:执行目标需要的文件列表,如果是命令的话,这个可以省略。
命令:需要执行的动作,可以是shell命令,也可以是可执行程序。
上文中的hello是终极目标,在一个makefile的第一个目标就是这个make的最终目的,下面的所有规则都是为了完成终极目标的一些规则,或者说前提条件。
我们可以这样来解读,为了得到可执行文件hello,需要当前存在main.o key.o command.o display.o 这几个文件作为前提条件,而为了得到这几个文件,我需要执行以下的规则。
make执行的时候有一个默认条件,只编译当前有变更的文件,也就是说,如果main的修改时间没有变化,那么不会执行。
cc -c main.c
别的文件一样,而如果某一个文件是多个目标文件的依赖规则,那么涉及到这个文件的所有命令都会执行,比如command.h有变更,那么
cc -c command.c
cc -c display.c
都会被执行。
当然,只要有任意文件编译过,hello都会重新链接。
说说最后一个规则
clean :
rm edit main.o key.o command.o display.o
这个是伪命令,在输入make的时候,不会执行这句话,除非给make一个参数clean,也就是输入
make clean
这句话才会被执行。
这句话其实有个小问题,当我们的磁盘下有这个clean的同名文件的时候,会造成这个规则无法执行,而且会返回一些奇怪的错误,所以,这个规则得加点修饰。
.PTONY:clean
clean :
-rm edit main.o key.o command.o display.o
以上是我一天的学习成果,如果有错,请扶正。
写在后面的话。
IDE,虽然帮我们完成了很多事情,但是也隐藏了很多东西,而我不甘被蒙蔽,总想着搞事情( •̀ ω •́ )y。
写于2017年5月24日
深圳 夜