makefile概述
makefile是一个自动化工具,在C语言项目管理中常用。以下整个笔记是为了应用而记录的,用词可能不准确。
makefile语法和组成部分
makefile由Macros和基础语法组成。
-
Macros: 一些宏定义,在整个makefile中可以使用$({MacrosName})对MacrosName进行引用
Macros的定义和赋值是绑定在一起的。赋值有两种方式
MACROS = VALUE $(OTHERMACROS) MACROS := VALUE $(OTHERMACROS)VALUE是一个字面量,OTHERMACROS是另一个MACROS。:= 表示立即展开赋值,MACROS的值将在之后不会根据OTHERMACROS改变而改变,=将记录整个展开过程,将在引用MACROS进行展开,确定当前MACROS的值。即如果需要MACROS是一个全局不会改变的确定值,则使用 := 。
-
基本语法:
{TARGET}: [{PREREQUEST}] <tab> {COMMEND} ...TARGET:生成目标
PREREQUEST:在生成目标前,需要提前满足的需求
需要执行的COMMEND前面必须使用tab进行缩进
makefile可以由多个这样的基本语法结构组成。在makefile中第一个出现的TARGET将会被当作make的默认目标,即make会自动执行这个结构
在下文中,每一个满足这种语法的结构,记为“make单元”。
makefile怎样执行
如果一个makefile中存在多个这样的语法结构,则执行方式如下:
-
make工具是否指定TARGET
如果make工具在运行时指定了make的TARGET(例如make test将查找TARGET为test的结构)将会从TARGET和make指定相同的make单元开始执行,否则默认执行在makefile中第一个出现的make单元
-
执行顺序
如果A make单元的TARGET被B make单元作为PREREQUEST需要,则针对A make单元:
- 建立TARGET:如果TARGET文件不存在,则这个make单元一定要执行
- 更新TARGET:如果PREREQUEST文件的修改事件比TARGET文件新,则这个make单元执行
- 否则:不执行
这个过程是一个可以递归的过程,表示为:
DEF execute_makefile (target) { make_unit: {__target, __prerequest, __command} = find_global_makefile(target) IF target NOT EXIST: // 对应第一条规则 execute_makefile(make_unit.__prerequest) shell(make_unit.__command) RETURN ELSE IF make_unit.__prerequest.getEditTime() > make_unit.__target.getEditTime(): // 对应第二条规则 execute_makefile(make_unit.__prerequest) shell(make_unit.__command) RETURN ELSE: RETURN }
makefile的其他组成部分
makefile的其他常用组成部分包括
-
其他符号
$@
当前make单元中的TARGET
$<
当前make单元中的PREREQUEST。
如果TARGET或者PREREQUEST是由空格分割的多个值,例如TARGET=file1 file2 file3,则使用$@只能输出file1
-
其他语法结构(例如循环结构等)
makefile也有循环结构和判断结构。其中循环结构为:
for {D} in {VALUES} ; do \ {具体执行的事务} ; \ done -
伪目标
语法: .PHONY: FANKTARGET, ...
功能:FANKTARGET代替TARGET
-
引用
语法:$(MacrosName)
功能:引用定义的Macros
特殊: $$转义$,即$$等于一个文本意义上的$
-
内置函数
$(wildcard <pattern>)
功能:这个函数将查找pattern中指定的文件,文件名之间用空格分割
返回:查找到的所有文件
示例:
FILES = $(wildcard ./testdir/*.c)
FILES为 ./testdir/test.c ./testdir/main.c
$(addprefix <prefix>, <names...>)
名称:加前缀函数——addprefix。
功能:把前缀<prefix>加到
中的每个单词后面。 返回:返回加过前缀的文件名序列。
示例:$(addprefix src/,foo bar)返回值是“src/foo src/bar”。
$(addsuffix <suffix>, <names...>)
名称:加后缀函数——addsuffix。
功能:把后缀<suffix>加到<names>中的每个单词后面。
返回:返回加过后缀的文件名序列。
示例:$(addsuffix .c,foo bar)返回值是“foo.c bar.c”
$(filter <pattern...>, <text>)
名称:过滤函数——filter。
功能:以<pattern>模式过滤<text>字符串中的单词,保留符合模式<pattern>的单词。可以有多个模式。
返回:返回符合模式
的字串。
$(patsubst <pattern>, <replacement>, <text>)
名称:子串替换——patsubst
功能:将<text>中匹配<pattern>的子串替换为<replacement>
返回:替换过后的<text>
示例:
FILES := ./testdir/test1.c ./testdir/test2.c OUT_FILES := $(patsubst %.c,%.o,$(patsubst ./testdir/%,./out/%,$(FILES)))OUT_FILES结果为:./out/test1.o ./out/test2.o
具体场景
-
TARGET和PREREQUEST包含多个文件
这种情况一般出现在多个文件编译过程中。例如:
SRC_C = ./test.c ./happend.c OBJ_O = ./test.o ./happend.o SRC_ASM = ... OBJ_ASM = ... .PHONY: all clean all: $(OBJ_O) $(OBJ_ASM) $(LD) $(OBJ_O) $(OBJ_ASM) $(LDFLAGS) -o $(PROJECT).elf $(OBJ_O):%o: %c $(CC) $(CFLAG) $< -o $@ $(OBJ_ASM):%o: %s $(AS) $(ASFLAG) $< -o $@上述流程为C语言项目编译过程中常用,命令行输入make all会将每一个在OBJ_O中的文件,首先将其后缀.o更换为.c作为PREREQUEST,再执行指定COMMAND;在OBJ_ASM中的文件也是用羊的处理方法。这段makefile首先会将指定的SRC_C和SRC_O进行编译并将编译结果存放在和源文件相同的文件夹中,之后再将他们链接生成一个{PROJECT}.elf文件。
浙公网安备 33010602011771号