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)

执行结果:
在这里插入图片描述

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐