Makefile 学习笔记


前言

       一般在工程中,有不计其数的源文件,这些文件按类型、功能、模块分别放置在若干目录中,而这些源文件在使用前一般需要进行编译,如果一个个单独进行编译,将需要进行大量重复性操作,对此Makefile提供了解决办法,通过定义一系列规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至进行更为复杂的功能操作。

       对此,本文针对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 

 Makefile运行示例Makefile 学习笔记_第1张图片

你可能感兴趣的:(linux)