1、初步认识makefile
此文编写主要参考韦东山老师教程和《跟我一起写makefile》
一、什么是make?
–make是一个应用程序
–解析源程序之间的的依赖关系
–根据依赖关系自动维护编译工作
–执行宿主操作系统的各种命令
二、什么是makefile?
–makefile 是一种描述文件
–定义一系列的规则来指定源文件编译的先后顺序
–拥有特定的语法规则,支持函数定义和函数调用
–能够直接集成操作系统中的各种命令
三、为什么需要makefile?
(1)对于gcc -o test a.c b.c这条命令虽然简单,但是它完成的功能不简单。 我们来看看它做了哪些事情。
我们知道.c程序 --> 得到可执行程序,它们之间要经过四个步骤:
预处理(preprocessing)=> .i arm-linux-cpp
编译(compilation)==> .s cc1
汇编(assembly)==> .o arm-linux-as
连接(linking)==> OBJ (linux上表现为ELF) arm-linux-ld
我们经常把前三个步骤统称为编译了。我们具体分析gcc -o test a.c b.c这条命令它们要经过下面几个步骤:
对于a.c执行:预处理 编译 汇编 的过程,a.c -->xxx.s -->xxx.o 文件。
对于b.c执行:预处理 编译 汇编 的过程,b.c -->yyy.s -->yyy.o 文件。
最后:xxx.o和yyy.o链接在一起得到一个test应用程序。
(2)当我们只有少数的源程序时,我们可以通过输入命令行来编译和链接所有的程序,但是当有个别源文件被修改了之后那么是不是多有的源程序又得被重新编译一遍然后链接起来呢,显然这样效率非常的低且容易出错,所以就需要makefile这种文件了,makefile就是用来组织管理程序和文件的。
(3)make 命令执行时,需要一个 Makefile 文件,以告诉 make 命令需要怎么样的去编译和链接程序。
四、Makefile里面有什么?
显示规则 | 如何生成目标文件 |
---|---|
隐晦规则 | 自动推导功能 |
变量定义 | 类似于c语言中的宏定义 |
文件指示 | 1、在一个 Makefile 中引用另一个 Makefile;2、根据某些情况指定 Makefile 中的有效部分,像 C 语言中的预编译#if 一样;定义一个多行的命令。 |
注释 | 用#进行注释,要在Makefile 中使用“#”字符,可以用反斜框进行转义,如:“#”。 |
五、Makefile文件名
默认情况 | make 命令会在当前目录下按顺序找寻文件“GNUmakefile”、“makefile”、“Makefile”的文件,找到后解释这个文件 |
---|---|
特定情况 | 使用别的文件名来书写 Makefile,比如:“Make.Linux”,“Make.Solaris”,“Make.AIX”等,使用 make 的“-f”和“–file”参数,如:make -f Make.Linux 或 make --file Make.AIX。 |
六、引用其它的 Makefile
1、语法:inlcude filename
2、引用多个文件时可以用空格隔开,如include foo.make a.mk b.mk c.mk e.mk f.mk
3、引用过程:make 会首先在当前目录下寻找,如果 make 执行时,有“-I”或“–include-dir”参数,那么 make 就会在这个参数所指定的目录下去寻找。
七、自动维护编译工作的原理
它是通过比较目标和依赖之间的时间来实现的,如比较a.o和a.c的时间,如果a.c的时间比a.o的时间更加新的话,就表明a.c被修改了,同理b.o和b.c也会进行同样的比较。比较test和a.o, b.o的时间,如果a.o或者b.o的时间比test更加新的话,就表明应该重新生成test。
八、举例
下面我们在linux用gcc编译器编译一个c文件,把编译和链接的所有步骤都写出来,然后看能不能尝试将它写成Makefile,用gcc编译器对源码进行编译时,gcc常用选项有:
例程如下:
gcc -E hello.c -o hello.i
gcc -S hello.i -o hello.s
gcc -C hello.s -o hello.o
gcc -o hello hello.o
分析:我们的最终目标是要生成一个hello的可执行文件,然而这个可执行文件是依赖于hello.o的,而要生成hello.o那么就得取决于hello.i,以此类推,所以实质上文件和文件之间存在一定的依赖关系。即然存在依赖关系,我们就可以将它写成一个Makefile,此处我们只是为了有个初步的认识,接下来会具体的介绍如何编写Makefile。
hello:hello.o
gcc -o hello hello.o
hello.o:hello.s
gcc -c hello.s -o hello.o
hello.s:hello.i
gcc -S hello.i -o hello.s
hello.i:hello.c
gcc -E hello.c -o hello.i
clean:
rm *.i *.s *.o hello