一般在工程中,有不计其数的源文件,这些文件按类型、功能、模块分别放置在若干目录中,而这些源文件在使用前一般需要进行编译,如果一个个单独进行编译,将需要进行大量重复性操作,对此Makefile提供了解决办法,通过定义一系列规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至进行更为复杂的功能操作。
对此,本文针对Makefile的使用规则进行讲解,介绍。
1、Makefile的文件命名规则
Makefile或者makefile,一般使用Makefile
2、Makefile基本语法
目标:依赖
[tab] 命令
目标:一般是指要编译的目标,也可以是一个动作。
依赖:指执行当前目标所要依赖的先项,包括其他目标,某个具体文件或库等;
一个目标可以有多个依赖。
命令:该目标下要执行的具体命令,可以没有,也可以多条命令,当有多条命令时,每条命令单独一行。
hello : hello.c
gcc hello.c -o hello
3、Makefile 工作原理
当调用make命令执行Makefile时,make会先找到Makefile文件中的第一条规则,分析并执行相应动作。而当执行命令中的依赖不存在时,会自动检测下面是否有生成该依赖的规则,若存在,则执行该规则的命令。
4、文件时间戳
make命令在执行的时候会根据文件的时间戳进行判断,是否需要执行Makefile中有涉及的规则。具体表现如下:
1、一般情况下,目标文件通过依赖文件形成的,所以目标文件的时间戳小于所有依赖文件的时间戳;
2、当出现某一依赖文件的时间戳大于目标文件的时间戳,此时目标文件将通过该规则中的命令被重新生成。
5、变量
Makefile在进行规则定义时,为了避免脚本过于冗长,且增加灵活性,可以使用变量。
Makefile中的变量主要分为三种:
(1)自定义变量:用户可以设定自己的变量,并且在Makefile中变量没有类型,只需要直接创建变量并赋值即可。
(2)预定义变量:Makefile中预先定义的变量,用户可直接引用,无需重复定义;
常见预定义变量如下表所示:
变量名 | 含义 |
AR | 生成静态库库文件的程序名称 |
AS | 汇编编译器的名称 |
CC | C语言编译器的名称 |
CXX | C++语言编译器 |
FC | FORTRAN 语言编译器的名称 |
RM | 删除文件程序的名称 |
ARFLAGS | 生成静态库库文件程序的选项 |
ASFLAGS | 汇编语言编译器的编译选项 |
CFLAGS | C语言编译器的编译选项 |
CXXFLAGS | C++语言编译器的编译选项 |
FFLAGS | FORTRAN 语言编译器的编译选项 |
(3)自动变量:自动变量只能在规则中的命令使用,可以对一些目标以及依赖进行指代。具体使用方法如下:
变量 | 含义 |
$* | 表示目标文件的名称,不包含目标文件的扩展名 |
$@ | 表示目标文件的名称,包含目标文件的扩展名 |
$+ | 表示所有依赖文件,这些依赖文件之间以空格分开,按照出现的先后为顺序,其中可能包含重复的依赖文件 |
$< | 表示依赖项中第一个依赖文件的名称 |
$? | 依赖项中,所有比目标文件时间戳晚的依赖文件,依赖文件之间以空格分开 |
$^ | 依赖项中,所有不重复的依赖文件,这些文件之间以空格分开 |
6、模式匹配
在编写Makefile过程中,可能出现许多规则做一样的事情,而由于文件名不同,需要逐一编写规则,这会导致Makefile变得冗长。而通过模式匹配的方法可以完美解决该问题。模式匹配可以将相同操作整理成一个模板,使所有操作都会通过模板执行,大幅缩短脚本代码量。
app : main.o helloworld.o dev.o add.o
gcc main.o helloworld.o dev.o add.o -o app
#当需要将所有.c文件生成.o文件时,一个个编写过于繁琐,如下所示
main.o : main.c
gcc main.c -o main.o
helloworld.o : helloworld.c
gcc helloworld.c -o helloworld.o
dev.o : dev.c
gcc dev.c -o dev.o
add.o : add.c
gcc add.c -o add.o
#通过模式匹配则可以完美解决该问题,利用以下两行代码即可实现。其中%为通配符,用于匹配文件名
%.o : %.c
gcc $^ -o $@
7、函数
Makefile中也可以使用函数,其中所有函数均有返回值,写法为:
$(函数名 参数1, 参数2, 参数3,...)
下面介绍一些函数
wildcard:获得指定目录下指定类型的文件名,返回值以空格分割。
#该函数的参数只有一个,但该参数可以通过空格分割
$(wildcard PATTERN ...)
#示例
$(wildcard .c ./LinuxStudy/.c)
#返回值为当前目录下的.c文件以及LinuxStudy下的.c文件
patsubst:查找
#该函数有三个参数,参数之间使用逗号隔开
$(patsubst ,,)
#示例
a = main.c hello.c dev.c add.c
# 要将变量a中所有文件名的后缀.c替换为.o时可以进行如下操作
obj= $(patsubst %.c, %.o, $(a))
#obj的值为:main.o hello.o dev.o add.o
8、Makefile clean规则
在执行make指令后,我们发现在目录下会生成许多.o文件,而我们只需要目标文件,其他文件都是多余的,这时候就需要增加一条clean命令来处理。
最终一个简单的Makefile脚本就可以写成如下
src=$(wildcard ./*.c)
obj=$(patsubst %.c, %.o, $(src))
target : $(obj)
$(CC) $(obj) -o $@
%.o : %.c
$(CC) $< -o $@
clean:
rm $(obj) -f