在学习开发Linux的过程中,我们时常需要编译繁多的C文件,而仅靠gcc编译器来进行编译,所执行的操作语句繁多,并且每次编译都要重新编译所有相关文件,占用系统内存较大,因此需要使用Make工具来进行批量的编译,类似于在visual studio中点击编译,系统自动将大量文件编译成程序一样。
本文从以下几点介绍编写Makefile
1.Make和Makefile的关系
2.Makefile的基本格式
3.使用特殊符号改造Makefile
4.使用函数改造Makefile
下载Make工具命令:sudo apt install make -y
一、Make和Makefile的关系
使用Make工具时,在Linux中执行的语句为:sudo make
语句执行时,make工具会在当前目录下寻找名称为Makefile或者makefile的文件,执行里面的语句去编译相应的文件,文件开头M或m大小写都可以
如果不想起名为Makefile,使用命令:make -f 你的文件名
二、Makefile的基本格式
基本格式: targeta: targetc targetb # 最终目标A:A的第一个依赖B A的第二个依赖C ls # 达成A所需要执行的语句/目标要执行的命令 targetb: # 目标B:无依赖 touch hello.c # 达成B执行的语句/目标要执行的命令 targetc: # 目标C:无依赖 pwd # 达成C执行的语句/目标要执行的命令 clear: # 目标clear,用户自定义,可有可无 rm -f hello.c # 达成clear执行的语句/目标要执行的命令第一个目标A是最终目标和默认目标,
Make使用Makefile的过程:首先目的是达成A,为了生成A,需要B和C,达成B和C又分别需要执行相应的命令语句,执行完后最终生成A。
三、使用特殊符号$改造Makefile
假设现在有多个C文件和头文件,分别为helloA.c,helloB.c,helloH.h,两个C文件都包含头文件helloH.h。
编写Makefile编译
Hello:helloA.c helloB.c
gcc -o Hello helloA.c helloB.c -I.
clear:
rm -f *.o Hello
# -I表示告诉编译器头文件所在的路径,I后面的.表示当前文件目录
#-o后面生成的Hello文件名称和目标名称Hello一致,这样make再次执行时,如果Hello依赖的两个文件helloA.c和helloB.c没有修改过,则不会再重新编译生成Hello一遍
以上的Makefile文件用特殊符号$改造后为
Hello:helloA.c helloB.c
gcc -o $@ $^ -I.
clear:
rm -f *.o Hello
改造后效果不变:
改造规则:
$@
匹配目标文件
$%
与$@类似,但$%仅匹配“库”类型的目标文件
$<
依赖中的第一个目标文件
$^
所有的依赖目标,如果依赖中有重复的,只保留一份
$+
所有的依赖目标,即使依赖中有重复的也原样保留
$?
所有比目标要新的依赖目标
,四、使用函数改造Makefile
改造函数有以下三个:
notdir函数:去除文件路径中的目录部分
$(notdir 文件名)例子:Build_dir = /home/xyq/linux/hello.c
File=$(notdir $(Build_dir)) // $() 表示取变量的值
结果:File=hello.c
wildcard函数:获取文件列表,将其使用空格分开
$(wildcard 匹配规则)例子:SRC_dir = source //变量等于目录source
SRCS = $(wildcard $(SRC_dir)/*.c)
结果:SRCS = 目录source下的所有.c文件
patsubst函数:模式字符串替换
$(patsubst 匹配规则, 替换规则, 输入的字符串)例子: INC_DIR = includes . //变量等于头文件路径includes和当前路径 “.” CFLAGS = $(patsubst %, -I%, $(INC_DIR))
结果:CFLAGS = INC_DIR包含的两个目录下的所有符合匹配规则“%”的文件,替换成 “-I%”规则的文件。比如includes目录,被替换后为:-Iincludes
结合前面讲的-I表示编译器头文件所在的路径,这里就表示让变量等于头文件所在的路径,方便接下来编译器调用