makefile三要素
例如:
main : main.c
gcc main.c -o main
那么问题就来了,Makefile中的两行语句分别是什么意思呢?拆解来看,两行语句可以分为三部分,分别是目标(target)、依赖(prerequisite)和执行语句(recipe):
target:可以是一个 object file(目标文件),也可以是一个执行文件,还可以是一个标签(label)。
prerequisites:生成该 target 所依赖的文件和/或 target 。
command :该 target 要执行的命令(任意的 shell 命令)
这是一个文件的依赖关系,也就是说,target 这一个或多个的目标文件依赖于 prerequisites 中的文件,其生成规则定义在 command 中。

如果有3个头文件和8个c文件,则按照规则来写makefile,则如下图所示

在这个 makefile 中,目标文件(target)包含:执行文件 edit 和中间目标文件(*.o ),依赖文件(prerequisites)就是冒号后面的那些 .c 文件和 .h 文件。每一个 .o 文件都有一组依赖文件,而这些 .o文件又是执行文件 edit 的依赖文件。依赖关系的实质就是说明了目标文件是由哪些文件生成的,换言
之,目标文件是哪些文件更新的。在定义好依赖关系后,后续的那一行定义了如何生成目标文件的操作系统命令,一定要以一个 Tab键作为开头。记住,make 并不管命令是怎么工作的,他只管执行所定义的命令。make 会比较 targets 文件和 prerequisites 文件的修改日期,如果 prerequisites 文件的日期要比 targets 文件的日期要新,或者target 不存在的话,那么,make 就会执行后续定义的命令。
makefile 规则
1 变量命名
1、使用wildcard函数
$(wildcard pattern…)
如果我们想匹配当前目录下的所有源文件,就可以这样写:$(wildcard *.c),其中通配符 * 用于匹配任意长度的任何字符,可以是 main、bar,也可以是其他任何你能想得到的字符组合,后面加上 .c 则是要求匹配的字符组合必须以 .c 结尾。
这样改进之后就是:
# Makefile
main : $(wildcard *.c)
gcc $(wildcard *.c) -o main
如果把 $(wildcard *.c)整成一个变量,则再次改进之后是这样:
# Makefile
SRCS := $(wildcard *.c) ##SRCS就是新增的变量
main : $(SRCS)
gcc $(SRCS) -o main
几个常用的赋值修改命令如下:
递归赋值 “=”:使用变量赋值时,会优先展开引用的变量。
foo = $(bar)
bar = $(ugh)
ugh = Huh?
all:;echo $(foo)
# 打印的结果为 Huh?,$(foo)展开得到$(bar),$(bar)展开得到$(ugh),$(ugh)展开得到Huh?最终$(foo)展开得到Huh?
简单赋值 “:=”:最常用的赋值符号。
x := foo
y := $(x) bar
x := later
# 等效于:
# y := foo bar
# x := later
文本增添 “+=”:用于向已经定义的变量添加文本。
objects = main.o foo.o bar.o utils.o
objects += another.o
# objects最终为main.o foo.o bar.o utils.o another.o
**条件赋值 “?=” **:仅在变量没有定义时创建变量。
FOO ?= bar
# FOO最终为bar
foo := ugh
foo ?= Huh?
# foo最终为ugh
2 Make的工作方式
GNU 的 make 工作时的执行步骤如下:(想来其它的 make 也是类似)
- 读入所有的 Makefile。
- 读入被 include 的其它 Makefile。
- 初始化文件中的变量。
- 推导隐晦规则,并分析所有规则。
- 为所有的目标文件创建依赖关系链。
- 根据依赖关系,决定哪些目标要重新生成。
- 执行生成命令。
1-5 步为第一个阶段,6-7 为第二个阶段。第一个阶段中,如果定义的变量被使用了,那么,make 会把其展开在使用的位置。但 make 并不会完全马上展开,make 使用的是拖延战术,如果变量出现在依赖关系的规则中,那么仅当这条依赖被决定要使用了,变量才会在其内部展开。
3 书写规则
规则包含两个部分,一个是依赖关系,一个是生成目标的方法。
在 Makefile 中,规则的顺序是很重要的,因为,Makefile 中只应该有一个最终目标,其它的目标都是被这个目标所连带出来的,所以一定要让 make 知道你的最终目标是什么。一般来说,定义在 Makefile中的目标可能会有很多,但是第一条规则中的目标将被确立为最终的目标。如果第一条规则中的目标有很多个,那么,第一个目标会成为最终的目标。make 所完成的也就是这个目标。
在规则中使用通配符
如果我们想定义一系列比较类似的文件,我们很自然地就想起使用通配符。make 支持三个通配符:* ,? 和 ~ 。这是和 Unix 的 B-Shell 是相同的。
波浪号(~ )字符在文件名中也有比较特殊的用途。如果是 ~/test ,这就表示当前用户的 $HOME 目录下的 test 目录。而 ~hchen/test 则表示用户 hchen 的宿主目录下的 test 目录。而在 Windows 或是 MS-DOS 下,用户没有宿主目录,那么波浪号所指的目录则根据环境变量“HOME”而定。
通配符代替了你一系列的文件,如 *.c 表示所有后缀为 c 的文件。一个需要我们注意的是,如果我们的文件名中有通配符,如 * ,那么可以用转义字符 \ ,如 \ * 来表示真实的 * 字符,而不是任意长度的字符串。
文件搜寻路径
Makefile 文件中的特殊变量 VPATH 就是完成这个功能的,如果没有指明这个变量,make 只会在当前的目录中去找寻依赖文件和目标文件。如果定义了这个变量,那么,make 就会在当前目录找不到的情况下,到所指定的目录中去找寻文件了。
VPATH = src:../headers
##这里提供了两个路径,两个路径之间以冒号相隔
另一个设置文件搜索路径的方法是使用 make 的“vpath”关键字(注意,它是全小写的),这不是变量,这是一个 make 的关键字,这和上面提到的那个 VPATH 变量很类似,但是它更为灵活。它可以指定不同的文件在不同的搜索目录中。这是一个很灵活的功能。它的使用方法有三种:
vpath <pattern> <directories> 为符合模式 <pattern> 的文件指定搜索目录 <directories>。
vpath <pattern> 清除符合模式 <pattern> 的文件的搜索目录。
vpath 清除所有已被设置好了的文件搜索目录。
vapth 使用方法中的 < pattern > 需要包含 % 字符。% 的意思是匹配零或若干字符,(需引用 % ,使用 \ )例如,%.h 表示所有以 .h 结尾的文件。
< pattern > 指定了要搜索的文件集,而 < directories> 则指定了
< pattern> 的文件集的搜索的目录。例如:
vpath %.h ../headers
本文详细解释了Makefile的基本结构,包括目标、依赖和执行语句的概念,以及变量命名的规则,特别强调了wildcard函数的应用。还介绍了Make的工作方式,特别是其处理依赖关系和文件搜寻路径的方式,如VPATH和vpath关键字。
&spm=1001.2101.3001.5002&articleId=137233945&d=1&t=3&u=8b8ee6360b114b79b366d938d61c8bde)
521

被折叠的 条评论
为什么被折叠?



