1、Makefile
Makefile是一种文本文件,通常用于定义项目的编译规则和依赖关系。它通常与GNU Make工具一起使用,用于自动化软件项目的构建过程。Makefile中包含了一系列规则,每个规则定义了如何生成一个或多个目标文件以及生成这些目标文件所需的依赖关系和命令。通过使用Make工具,用户可以根据Makefile中定义的规则来自动执行编译、链接和其他构建任务,而不需要手动输入每个命令。Makefile的核心是规则的定义,其中包括目标、依赖关系和命令。通常情况下,Makefile中的规则遵循以下格式:
target: dependencies
command
target:是一个或多个要生成的目标文件。
dependencies:是生成目标文件所依赖的文件或目标。
command:是生成目标文件所需的命令。
Makefile还能智能的识别哪些文件需要被编译更新,哪些不用。使用make编译Makefile文件,make 命令会在当前目录下查找是否存在“Makefile”这个文件,如果存在的 话就会按照 Makefile 里面定义的编译方式进行编译,make 命令会为 Makefile 中的每个以TAB 开始的命令创建一个 Shell 进程去执行。
2、基础语法举例
1 main: main.o input.o calcu.o
2 gcc -o main main.o input.o calcu.o
3 main.o: main.c
4 gcc -c main.c
5 input.o: input.c
6 gcc -c input.c
7 calcu.o: calcu.c
8 gcc -c calcu.c
9
10 clean:
11 rm *.o
12 rm main
上述解析,根据序号:
1 main是目标,冒号后面这些是依赖项,生成main需要依赖这些.o文件,同时,如果要更新目标 main,就必须先更新它的所有依赖文件,如果依赖文件中的任何一个有更新,那么目标也必须更新,“更新”就是执行一遍规则中的命令列表。
2 这条是生成所需命令,同时记住命令列表中的每条命令必须以 TAB 键开始,不能使用空格!执行到这里就会发现需要main.o等.o文件,就会匹配到 3
3 这里又发现mian.o依赖于main.c,就会去执行4的命令
4 执行命令生成mian.o
5-8类似
10 clean清除,没有依赖,所以不会被执行,需要执行输入make clean清除.o文件和main。
3、扩展
(1) Makefile支持变量操作,引用方式为$(xxx),有三种赋值方式:
1 name = tux
2 curname = $(name)
3 name = tuxtux
# 最终为tuxtux ,=会使用引用变量最后一次赋值的值
1 name = tux
2 curname := $(name)
3 name = tuxtux
# 最终为tux,:=会使用之前定义好的变量的值
1 name = tux
2 curname ?= $(name)
3 name = tuxtux
# 最终为tux,?=会判断之前是否会有定义,有定义就用之前的值,没有就用
(2)Makefile支持模式规则,使用%进行匹配,目标中的“%”表示对文件名的匹配,“%”表示长度任意的非空字符串,比如“%.c”就是所有的以.c 结尾的文件,类似于通配符,a.%.c 就表示以 a.开头,以.c 结束的所有文件。当“%”出现在目标中的时候,目标中“%”所代表的值决定了依赖中的“%”值如:
%.o : %.c
(3)Makefile支持自动化变量,但是只用在规则的命令中。目标和依赖都是一系列的文件,每一次对模式规则进行解析的时候 都会是不同的目标和依赖文件,而命令只有一行,可以通过自动化变量来从不同的依赖文件中生成对应的目标。
比较常用的有$@、$<和$^。
%.o : %.c
gcc -c $<
# $<代表依赖的文件集合
(4)Makefile伪目标,一般的目标名都是要生成的文件,而伪目标不代 表真正的目标名,在执行 make 命令的时候通过指定这个伪目标来执行其所在规则的定义的命令。使用伪目标主要是为了避免 Makefile 中定义的执行命令的目标和工作目录下的实际文件出 现名字冲突,有时候我们需要编写一个规则用来执行一些命令,但是这个规则不是用来创建文件的,比如我们常定义clean这个目标来清除不需要的文件,但是当有一个文件名叫clean,那就不会执行了,因为没有依赖目标,不会更新不会执行规则命令。
.PHONY : clean
clean:
rm *.o
(5) Makefile的条件判断,条件关键字有 4 个:ifeq、ifneq、ifdef 和 ifndef,语法有
<条件关键字>
<条件为真时执行的语句>
endif
<条件关键字>
<条件为真时执行的语句>
else
<条件为假时执行的语句>
endif
//ifeq 判断是否相等,ifneq 判断是否不相等
ifeq (<参数 1>, <参数 2>)
ifeq ‘<参数 1 >’,‘ <参数 2>’
ifeq “<参数 1>”, “<参数 2>”
ifeq “<参数 1>”, ‘<参数 2>’
ifeq ‘<参数 1>’, “<参数 2>
//ifdef 判断是否定义值了,ifndef判断是否没定义
ifdef <变量名>
(6)Makefile函数使用方法:
$(函数名 参数集合) 或 ${函数名 参数集合}
常用函数:
# 将字符串<text>中的<from>内容替换为<to>,返回替换后的字符串
$(subst <from>,<to>,<text>)
# 例子
$(subst tux,TUX,my name is tux) => my name is TUX
# 查找字符串<text>中的单词是否符合模式<pattern>,如果匹配就用<replacement>来
# 替换掉,<pattern>可以使用通配符“%”,表示任意长度的字符串,函数返回值就是替换后的字
# 符串。如果<replacement>中也包涵“%”,那么<replacement>中的“%”将是<pattern>中的那个
# “%”所代表的字符串,
$(patsubst <pattern>,<replacement>,<text>)
# 例子
$(patsubst %.c,%.o,a.c b.c c.c) => a.o b.o c.o
# 获取目录名和去掉目录名
$(dir <names…>)
# 例子
$(dir </src/a.c>) => /src
$(notdir <names…>)
# 例子
$(notdir </src/a.c>) => a.c
# 通配符“%”只能用在规则中,只有在规则中它才会展开,如果在变量定义和函数使用时,
# 通配符不会自动展开,这个时候就要用到函数wildcard
$(wildcard PATTERN…)
# 例子
$(wildcard *.c) => 获取当前目录下所有的.c 文件,类似“%”
# 把参数<list>中的单词逐一取出来放到参数<var>中,然后再执行<text>所包含的表达式。每次<text>都会
# 返回一个字符串,循环的过程中,<text>中所包含的每个字符串会以空格隔开,最后当整个循环结束时,
# <text>所返回的每个字符串所组成的整个字符串将会是函数 foreach 函数的返回值。
$(foreach <var>, <list>,<text>)
# 例子:在 all 目标中,使用 $(foreach fruit,$(fruits),echo $(fruit);) 来遍历 fruits 列表中的每个水果。这个表达式的含义是:对于列表 fruits 中的每个元素,将其赋给变量 fruit,然后执行 echo $(fruit); 命令,将每个水果名称打印到标准输出:
fruits := apple orange banana
all:
@$(foreach fruit,$(fruits),echo $(fruit);) => apple
orange
banana
总结:
make命令会在当前目录下查找名为Makefile(或makefile)的文件。一旦找到了Makefile,它将按照其中定义的规则进行编译,生成最终的目标文件。如果目标文件不存在,或者目标文件的依赖项比目标文件更新(即最后修改时间晚),则会执行相应的命令来更新目标文件。