1.什么是Makefile?
一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,Makefile定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 Makefile就像一个Shell脚本一样,也可以执行操作系统的命令。
在 Linux环境下使用make工具能够比较容易的构建一个属于你自己的工程,整个工程的编译只需要一个命令就可以完成编译、连接以至于最后的执行。不过这需要我们投入一些时间去完成一个或者多个称之为Makefile 文件的编写。
Makefile是一个文件,这个文件中写的是编译的规则,使用Makefile可以根据文件的时间戳来决定当前文件是否参与本次编译。
2.什么是make?
简单来说make是一个可执行程序,在/usr/bin/路径下存放。当执行make的时候就会解析当前目录下的Makefile文件,从而编译当前目录下的工程。
3.Makefile的编写实例
3.1第一个实例
在一个工程中创建text.c文件
#include <stdio.h>
int main(int argc,const char * argv[])
{
printf("hello world\n");
return 0;
}
创建Makefile文件
#:代表注释
all:#标签,在执行make的时候默认执行第一个标签后的语句
gcc text.c -o text
clean:#make clean可以执行这个标签
rm text
执行结果:
从图片中我们大致可以了解Makefile的作用。
3.2Makefile的语法规则
目标:依赖
(tab键)命令
text:text.c
gcc text.c -o text
clean:#伪命令 make clean不会生成clean的文件
rm text
执行结果:
3.3Makefile编译多文件
text.c
#include <stdio.h>
extern int add(int a,int b);
extern int sub(int a,int b);
int main(int argc,const char * argv[])
{
int a=100,b=200;
printf("%d\n",add(a,b));
printf("%d\n",sub(a,b));
return 0;
}
sub.c
int sub(int a,int b)
{
return (a-b);
}
add.c
int add(int a,int b)
{
return (a+b);
}
Makefile文件
text: text.o sub.o add.o
gcc text.o sub.o add.o -o text
text.o:text.c
gcc -c text.c -o text.o
sub.o:sub.c
gcc -c sub.c -o sub.o
add.o:add.c
gcc -c add.c -o add.o
clean:#伪命令 make clean不会生成clean的文件
rm *.o text
执行结果:
在函数sub.c中添加几个空格后改变sub.c
只编译了sub.c文件
3.4Makefile中变量的使用
Makefile中的变量不需要使用类型去定义,随用随写即可。
例如:a=123
变量的使用规则 $(变量名)或者${变量名}
@ 作用是取消命令执行的回显动作
a=123
all:
echo $(a)
执行结果:
a=123
all:
@echo $(a)
@#@的作用是取消命令执行的回显动作
执行结果:
3.5Makefile中变量的赋值
= 赋值
a=123
b=$(a)#在Makefile搜索a最后一次赋值的结果,将最后一次赋值的结果赋值给a
a=456
all:
@echo $(a)
@echo $(b)
@#@的作用是取消命令执行的回显动作
执行结果:
:= 立即赋值
a=123
b:=$(a) #立即赋值,将a当前的结果赋值给b变量
a=456
all:
@echo $(a)
@echo $(b)
@#@的作用是取消命令执行的回显动作
执行结果:
?= 询问赋值
a=123
b=456
b?=$(a) #询问b之前是否被赋值过,如果之前被赋值给,本次赋值不成立,否则本次赋值成立
all:
@echo $(b)
@#@的作用是取消命令执行的回显动作
执行结果:
a=123
#b=456
b?=$(a) #询问b之前是否被赋值过,如果之前被赋值给,本次赋值不成立,否则本次赋值成立
all:
@echo $(b)
@#@的作用是取消命令执行的回显动作
+= 附加赋值
a=123
b=hello
b+=$(a)#在b的后面附加上a
all:
@echo $(b)
@#@的作用是取消命令执行的回显动作
执行结果:
通过命令行赋值
a?=123
all:
@echo $(a)
@#@的作用是取消命令执行的回显动作
执行结果:
3.6在多文件编译中加上变量
(修改3.3Makefile文件,加入变量)
T?=text#可以通过询问赋值改变可执行程序的名字
TSAo:=text.o sub.o add.o
CC?=gcc#可以通过询问赋值不使用gcc进行编译
Cflag:= -c -o
$(T): $(TSAo)
$(CC) $(TSAo) -o $(T)
text.o:text.c
$(CC) text.c $(Cflag) text.o
sub.o:sub.c
$(CC) sub.c $(Cflag) sub.o
add.o:add.c
$(CC) add.c $(Cflag) add.o
clean:#伪命令 make clean不会生成clean的文件
rm $(TSAo) $(T)
执行结果:
3.7Makefile中的特殊符号
$@:目标名
$<:第一个依赖
$^:所有的依赖
$*:取出扩展名的目标
以目录下创建text.c和add.c文件为例:
main.o:text.c add.c
@echo $@
@echo $*
@echo $<
@echo $^
执行结果:
3.8在3.6的基础上加入特殊字符
T?=text#可以通过询问赋值改变可执行程序的名字
TSAo:=text.o sub.o add.o
CC?=gcc#可以通过询问赋值不使用gcc进行编译
Cflag:= -c -o
$(T): $(TSAo)
$(CC) $^ -o $@
text.o:text.c
$(CC) $< $(Cflag) $@
sub.o:sub.c
$(CC) $< $(Cflag) $@
add.o:add.c
$(CC) $< $(Cflag) $@
clean:#伪命令 make clean不会生成clean的文件
rm $(TSAo) $(T)
执行结果:
3.9Makefile中的通配符
%:Makefile中特有通配符
*:shell命令行的通配符
修改3.8中的Makefile文件,用上通配符
T?=text#可以通过询问赋值改变可执行程序的名字
TSAo:=text.o sub.o add.o
CC?=gcc#可以通过询问赋值不使用gcc进行编译
Cflag:= -c -o
$(T): $(TSAo)
$(CC) $^ -o $@
%.o:%.c#这里的%是通配符,上面程序编译的时候text.o add.o sub.o都能通配到这句话
$(CC) $< $(Cflag) $@
clean:#伪命令 make clean不会生成clean的文件
rm $(TSAo) $(T)
执行结果:
4.Makefile中的函数
Makefile中有很多的函数,以下面两个为例进行讲解。
wildcard搜索命令,搜索当前目录下的所有的.c结尾的文件
patsubst替换的命令,将a变量保存的.c文件替换为所有以.o 结尾的文件
a:=$(wildcard ./ *.c)
b:=$(patsubst %.c,%.o, $(a))
all:
@echo $(a)
@echo $(b)
执行结果: