什么是Makefile?
为什么要使用Makefile?
如何使用make命令?
Makefile 文件描述了整个工程的编译、连接等规则,make是一个命令工具,它解释Makefile中的指令(规则)。
一个基本的makefile主要由目标对象、依赖文件、变量和命令4部分组成。
命令行中执行makefile内容:
◆宏定义
◆ 源文件之间的相互依赖关系
◆ 可执行的命令
通常makefile文件中的一条规则的编写形式如下:
target ... : prerequisites ...(tab)command......
解释为:
目标:依赖文件
(制表符)执行指令 ...
下面来看一个具体的例子:
新建 三个文件: main.c add.c fun.h
fun.h
#include#include int add(int a,int b);
add.c
int multi(int a,int b){ return a+b;}
main.c
#include"fun.h"int main(){ int a=12,b=6; c=add(a,b); printf("%d\n",add(a,b)); return 0;}
下图体现了文件间的依赖关系:
我们先使用gcc 命令来构建这个工程:
gcc -c main.c add.c
查看当前文件目录:
文件夹中多了main.o 和 add.o这两个文件,接着在执行下面的命令:
gcc main.o add.o -o math -l m//用main.o add.o 进一步生成目标 ,最后两个参数 -l m 为连接数学函数库
我们发现生成目标文件math需要两步,也就是要先生成main.o 和 add.o 这两个中间文件,这两个文件称为目标文件的直接依赖文件,那么main.c和add.c分别又是main.o和add.o的直接依赖文件。
makefile正事依据这样一层一层的的依赖关系和连接 依赖文件 和 目标文件 的命令 所构成的。
下面来看一个最基本的makefile文件:
以下makefile文件显示了各个目标与依赖文件直接的关系,以及生成它们的命令
add:main.o add.o //目标文件add的依赖文件为main.o、add.o gcc -o add main.o add.o -l m //将目标文件连接为可执行文件,并连接数学函数库 main.o:main.c //main.o的依赖文件为main.c gcc -c main.c //将源文件main.c编译成目标文件main.oadd.o:add.c gcc -c test.cclean: //清理中间文件 rm main.o add.o add
编写makefile文件中要注意的几点:
1、clean没有被第一个目标add直接或间接依赖,那么它后面的命令就不会被自动执行可以在make 命令后面跟clean目标作为参数来执行其后所定义的命令,
即执行"make clean"命令,用于清除make过程中生成的目标,以便重新编译
2、在定义好依赖关系后,后续的那一行定义了如何生成目标文件的操作系统命令,一定要以一个Tab键作为开头。 3、记住,make并不管命令是怎么工作的,他只管执行所定义的命令。make会比较目标文件和依赖文件的修改日期,即时间戳如果依赖文件的日期要比目标文件的日期要新,或者目标不存在的话,那么,make就会执行后续定义的命令
先执行rm main.o add.o math 清除之前生成的中间文件和目标文件
然后用ls命令查看以下当前目录所包含的文件:
执行make命令,再用ls查看当前目录下的文件:
我们发现,make命令已经生成了add目标文件,还有依赖文件main.o, add.o
执行结果:
执行make命令时,可以通过参数为makefile文件的宏变量CC赋值,通过宏变量CC指定不同的编译器来编译源文件
CC=add:main.o add.o $(CC) -o add main.o add.omain.o:main.c $(CC) -c main.cadd.o:add.c $(CC) -c add.cclean: rm main.o add.o add
下面,对makefile做一点小小的改动:
OBJS=main.o add.o #使用了变量OBJSCC=gccCFLAGS=-Wall -O -gadd:$(OBJS) $(CC) $(OBJS) -o addmain.o:main.c $(CC) $(CFLAGS) -c main.c add.o:add.c $(CC) $(CFLAGS) -c add.cclean: rm *.o add
这里使用到了变量,用CC代替了gcc, CFLAGS是makefile中预定义的变量,我们为将它初始化为-Wall -O -g (开启警告信息、编译链接过程中执行优化处理、增加调试信息),这三个参数都是gcc参数的常用的值,关于gcc参数常用值,这里不做具体介绍。
Makefile中允许使用简单的宏指代源文件及其相关编译信息,在Linux中也称宏为变量。在引用宏时只需在变量前加$符号,
但值得注意的是,如果变量名的长度超过一个字符,在引用时就必须加圆括号()。有效的宏引用$(CFLAGS)$Z$(Z)
makefile中常见的预定义变量及其部分默认值
我们先使用make clean 清除之前生成的目标文件,再执行make命令,得到的结果是一样的.
下面再对makefile进行升级:
#MakefileCC=gccCFLAGS=-Wall -O -gOBJS=main.o add.oadd:$(OBJS) $(CC) $^ -o $(OBJS)main.o:main.c $(CC) $(CFLAGS) -c $< -o $@add.o:add.c $(CC) $(CFLAGS) -c $< -o $@clean: rm -f *.o
这里使用了makefile 的自动变量,下表是makefile中常见的自动变量:
makefile中常见的自动变量
自动变量通常可以代表编译语句中出现的目标文件和依赖文件等,自动变量的使用进一步简化makefile的编写,自动变量的书写比较难记,但是在熟练了之后会非常方便。
下面是一个使用二进制作为目标文件的makefile模板:
.PHONY:clean allCC=gccCFLAGS=-Wall -g -I../include //-I[头文件目录路径] :用来找到不再当前目录下的头文件BIN=main add //这一行添加依赖文件的名称all:$(BIN)%.o:%.c $(CC) $(CFLAGS) -c $< -o $@clean: rm -f *.o $(BIN)
终极版makefile
关于maefile的写法,其形式可能有很多种,makefile还支持带有条件语句的条件编译、函数、以及一些隐含规则等,这里不做深入介绍,只有多加练习、实践,才能真正掌握make这个强大的工具。