- 可以自动将项目涉及的所有源文件编译成可执行文件的工具
- makefile写好之后,一键make就可以全部自动编译,非常的快捷和方便
- make是一个命令工具,用来解释和执行makefile
- 基本上所有的编译工具链都自带make命令
- 源文件 ------(预处理)------.i文件
- .i文件 ------(编 译)------.S文件
- .S文件 ------(汇 编)------.o文件
- .o文件 ------(链 接)------.elf文件(elf文件只能在OS下运行,由操作系统解析成bin文件然后运行)
- .elf文件------(objcopy)------.bin文件(bin文件比elf文件更小)
Makefile都包含什么内容?
- 规则:
target : prerequisites... command ... ...
target:目标,最终需要生成的文件
prerequisites:依赖,生成最终文件需要的依赖文件
command:命令,在依赖文件的基础上,执行命令,生成目标文件
- Makefile是如何工作:
- make会在当前目录下寻找名称为“makefile”和“Makefile”的文件
- 找到文件中的第一个目标,并把这个文件作为最终的目标
- 使用command将依赖变成目标,如果依赖不存在,就先生成依赖,递归执行
- 综述:
- 规则(显式规则和隐式规则)
- 变量
- 条件判断
- 函数
- 注释
- 命令
变量
- 在 Makefile 中的定义的变量,就像是 C/C++语言中的宏一样,直接展开,其与 C/C++所不同的是,你可以在 Makefile 中改变其值
- 变量在声明时需要给予初值,而在使用时,需要给在变量名前加上“$”符号,但最好用小括号“ () ”或是大括号“{}”把变量给包括起来。如果你要使用真实的“$”字符,那么你需要用“$$”来表示
- 几种赋值符号的差别
- = 是最基本的赋值,make会将整个makefile展开后,再决定变量的值。也就是说,变量的值将会是整个makefile中最后被指定的值
- := 是覆盖之前的值,变量的值决定于它在makefile中的位置,而不是整个makefile展开后的最终值
- ?= 是如果没有被赋值过就赋予等号后面的值
- += 是添加等号后面的值(类似字符串的接续)
- 变量值的替换
foo := a.o b.o c.o bar := $(foo:.o=.c) # 以“.o”字串“结尾”全部替换成“.c” foo := a.o b.o c.o bar := $(foo:%.o=%.c) # 以“.o”字串“结尾”全部替换成“.c”
- “把变量的值再当成变量”
x = y y = z a := $($(x)) #在这个例子中,$(x)的值是“y” ,所以$($(x))就是$(y),于是$(a)的值就是“z”
条件判断
- 类似C语言中的条件判断
<conditional-directive> <text-if-true> else <text-if-false> endif
- 例子
#判断$(CC)变量是否“gcc”,如果是的话,则使用GNU函数编译目标 libs_for_gcc = -lgnu normal_libs = foo: $(objects) ifeq ($(CC),gcc) $(CC) -o foo $(objects) $(libs_for_gcc) else $(CC) -o foo $(objects) $(normal_libs) endif
#判断变量的值是否为空 bar = foo = $(bar) ifdef foo frobozz = yes else frobozz = no endif
函数
- 在 Makefile 中可以使用函数来处理变量,从而让我们的命令或是规则更为的灵活和具有智能
- 函数调用后,函数的返回值可以当做变量来使用
- 函数调用语法:
- 字符串处理函数:
#将"feet on the street"中的"ee"替换成"EE",结果是"fEEt on the strEEt" $(subst ee,EE,feet on the street)
#把字串“x.c.c bar.c”符合模式[%.c]的单词替换成[%.o],返回结果是“x.c.o bar.o” $(patsubst %.c,%.o,x.c.c bar.c)
#第一个函数返回“a”字符串,第二个返回“”字符串(空字符串) $(findstring a,a b c) $(findstring a,b c)
#保留符合格式的字符串 sources := foo.c bar.c baz.s ugh.h foo: $(sources) cc $(filter %.c %.s,$(sources)) -o foo $(filter %.c %.s,$(sources))返回的值是“foo.c bar.c baz.s”
- 文件名操作函数
#$(files)的值是“a.o b.o c.o d.o” names := a b c d files := $(foreach n,$(names),$(n).o)
reverse = $(1) $(2) foo = $(call reverse,a,b) #foo的值就是“a b” reverse = $(2) $(1) foo = $(call reverse,a,b) #foo的值就是“b a”
- 调试打印函数
- $(error <text ...>) 打印信息 make会停止
- $(warning <text ...>) 打印信息 make不会停止
- $(info <text ...>) 和waring类似,级别更低
注释
Makefile没有多行注释,只有单行注释,注释标记是:#
命令
- 所有的shell命令都可以在Makefile中使用
- 命令必须是以tab开头
- 同事急需要执行多条命令时,需要写在同一行,使用接续符 链接
总结
Makefile只是帮助编译大型工程的工具,有自己独特的语法(可以将Makefile理解为一种小型的脚本语言),通常工程中使用的Makefile都很类似,参考已有的Makfile就可以写出自己需要的Makefile,难度不是很大,需要的就是熟练使用,如果要写出通用性很强,且高效的Makfile就需要一定的技术积累。