一、Makefile结构说明
Makefile里主要包含了五个东西:变量定义、显式规则、隐晦规则、文件指示和注释。
- 变量的定义。在Makefile中我们要定义一系列的变量,变量一般都是字符串,这个有点像C语言中的宏,当Makefile被执行时,其中的变量都会被扩展到相应的引用位置上。
- 显式规则。显式规则说明了,如何生成一个或多的的目标文件。这是由Makefile的书写者明显指出,要生成的文件,文件的依赖文件,生成的命令。 刚才写的疑似shell脚本的Makefile全部都是显示规则。
- 隐晦规则。由于我们的make有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写Makefile,这是由make所支持的。
- 文件指示。其包括了三个部分,一个是在一个Makefile中引用另一个Makefile,就像C语言中的include一样。
- 注释。Makefile中只有行注释,和UNIX的Shell脚本一样,其注释是用“#”字符,这个就像C/C++中的“//”一样。如果你要在你的Makefile中使用“#”字符。
⼀个 Makefile 中可以定义多个⽬标。调⽤ make 命令时,我们得告诉它我们的⽬标是什么,即要它⼲什么。当没有指明具体的⽬标是什么 时,那么 make 以 Makefile ⽂件中定义的第⼀个⽬标作为这次运⾏的⽬标。这“第⼀个”⽬标也称之 为默认⽬标(和是不是all没有关系)。当 make 得到⽬标后,先找到定义⽬标的规则,然后运⾏规则中的命令来达到构建⽬标的⽬的。
二、变量
自动化变量
- $* 不包含扩展名的目标文件名称。
- $+ 所有的依赖文件,以空格分开,并以出现的先后为序,可能包含重复的依赖文件。
- $< 第一个依赖文件的名称。
- $? 所有的依赖文件,以空格分开,这些依赖文件的修改日期比目标的创建日期晚。
- $@ 目标的完整名称。
- $^ 所有的依赖文件,以空格分开,不包含重复的依赖文件。
-
特殊变量
MAKE变量
- MAKECMDGOALS变量 - 指的是⽤户输⼊的⽬标
递归扩展变量
“=” - 递归扩展变量
```makefile .PHONY: all foo = $(bar) bar = $(ugh) ugh = Huh? all: @echo $(foo)
结果
Huh?
<a name="G5YWT"></a>
#### ":=" - 简单扩展变量
> 对于这种变量,make 只对其进⾏⼀次扫描和替换
```makefile
.PHONY: all
x = foo
y = $(x) b
x = later
xx := foo
yy := $(xx) b
xx := later
all:
@echo "x = $(y), xx = $(yy)"
#结果
# x = later b , xx = foo b
“?=” - 条件赋值
条件赋值的意思是当变量以前没有定义时,就定义它并且将左边的值赋值给它,如果已经定义了那么就不再改变其值。条件赋值类似于提供了给变量赋缺省值的功能。
.PHONY: all
foo = x
foo ?= y
bar ?= y
all:
@echo "foo = $(foo), bar = $(bar)"
# 结果
#
“+=” - 对变量进行累加赋值
.PHONY: all
objects = main.o foo.o bar.o utils.o
objects += another.o
all:
@echo $(objects)
override指令
在设计 Makefile 时,我们并不希望⽤户将我们在 Makefile 中定义的某个变量覆盖掉,那就得⽤ override 指令了
三、函数
addprefix函数
addprefix 函数是⽤来在给字符串中的每个⼦串前加上⼀个前缀,其形式是:$(addprefix prefix, names…)
.PHONY:all
without_dir= foo.c bar.c main.c
with_dir:=$(addprefix objs/, $(without_dir))
all:
@echo $(with_dir)
filter函数
filter 函数⽤于从⼀个字符串中,根据模式得到满⾜模式的字符串,其形式是:$(filter pattern…, text)
.PHONY: all
sources = foo.c bar.c baz.s ugh.h
sources := $(filter %.c %.s, $(sources))
all:
@echo $(sources)
filter-out函数
filter-out 函数⽤于从⼀个字符串中根据模式滤除⼀部分字符串,其形式是:$(filter-out pattern…, text)
.PHONY: all
objects = main1.o foo.o main2.o bar.o
result := $(filter-out main%.o, $(objects))
all:
@echo $(result)
patsubst函数(☆☆☆)
patsubst 函数是⽤来进⾏字符串替换的,其形式是:$(patsubst pattern, replacement, text)
.PHONY:all
mixed=foo.c bar.c main.o
objects:=$(patsubst %.c, %.o, $(mixed))
all:
@echo $(objects)
上述代码中 mixed 变量中包括了.c ⽂件也包括了.o ⽂件,采⽤patsubst 函数进⾏字符串替换时,我们希望将所有的.c ⽂件都替换成.o ⽂件。上图是最后的运⾏结果。
strip函数
strip 函数⽤于去除变量中的多余的空格,其形式是:$(strip string)
.PHONY:all
original=foo.c bar.c
stripped:=$(strip $(original))
all:
@echo "original = $(original)"
@echo "stripped = $(stripped)"
wildcard函数(☆☆☆)
wildcard 是通配符函数,通过它可以得到我们所需的⽂件,这个函数类似我们在 Windows 或Linux 命
令⾏中的“*”。其形式是:$(wildcard pattern)
.PHONY:all
SRC=$(wildcard *.c)
all:
@echo "SRC = $(SRC)"
规则
%.o : %.c
把所有的[.c]文件都编译成[.o]文件.
GCC= gcc
GCCFLAGS = -Wall -Werror -Wextra -pedantic -g -fsanitize=address -I./
LDFLAGS = -fsanitize=address
SRC = wub_lib.c debug.c main.c
OBJ = $(SRC:.c=.o)
EXEC = test
all: $(OBJ) $(EXEC)
$(OBJ): %.o: %.c
$(GCC) -c $< -o $@
$(EXEC):
$(GCC) $(LDFLAGS) -o $@ $(OBJ) $(LBLIBS)
clean:
rm -rf $(OBJ) $(EXEC)