一、Makefile结构说明

Makefile里主要包含了五个东西:变量定义、显式规则、隐晦规则、文件指示和注释。

  1. 变量的定义。在Makefile中我们要定义一系列的变量,变量一般都是字符串,这个有点像C语言中的宏,当Makefile被执行时,其中的变量都会被扩展到相应的引用位置上。
  2. 显式规则。显式规则说明了,如何生成一个或多的的目标文件。这是由Makefile的书写者明显指出,要生成的文件,文件的依赖文件,生成的命令。 刚才写的疑似shell脚本的Makefile全部都是显示规则。
  3. 隐晦规则。由于我们的make有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写Makefile,这是由make所支持的。
  4. 文件指示。其包括了三个部分,一个是在一个Makefile中引用另一个Makefile,就像C语言中的include一样。
  5. 注释。Makefile中只有行注释,和UNIX的Shell脚本一样,其注释是用“#”字符,这个就像C/C++中的“//”一样。如果你要在你的Makefile中使用“#”字符。

Makefile 基础 - 图1
Makefile 基础 - 图2
⼀个 Makefile 中可以定义多个⽬标。调⽤ make 命令时,我们得告诉它我们的⽬标是什么,即要它⼲什么。当没有指明具体的⽬标是什么 时,那么 make 以 Makefile ⽂件中定义的第⼀个⽬标作为这次运⾏的⽬标。这“第⼀个”⽬标也称之 为默认⽬标(和是不是all没有关系)。当 make 得到⽬标后,先找到定义⽬标的规则,然后运⾏规则中的命令来达到构建⽬标的⽬的。

二、变量

自动化变量

  • $* 不包含扩展名的目标文件名称。
  • $+ 所有的依赖文件,以空格分开,并以出现的先后为序,可能包含重复的依赖文件。
  • $< 第一个依赖文件的名称。
  • $? 所有的依赖文件,以空格分开,这些依赖文件的修改日期比目标的创建日期晚。
  • $@ 目标的完整名称。
  • $^ 所有的依赖文件,以空格分开,不包含重复的依赖文件。
  • $% 如果目标是归档成员,则该变量表示目标的归档成员名称。

    特殊变量

  • MAKE变量

  • MAKECMDGOALS变量 - 指的是⽤户输⼊的⽬标

    递归扩展变量

    “=” - 递归扩展变量

    ```makefile .PHONY: all foo = $(bar) bar = $(ugh) ugh = Huh? all: @echo $(foo)

结果

Huh?

  1. <a name="G5YWT"></a>
  2. #### ":=" - 简单扩展变量
  3. > 对于这种变量,make 只对其进⾏⼀次扫描和替换
  4. ```makefile
  5. .PHONY: all
  6. x = foo
  7. y = $(x) b
  8. x = later
  9. xx := foo
  10. yy := $(xx) b
  11. xx := later
  12. all:
  13. @echo "x = $(y), xx = $(yy)"
  14. #结果
  15. # 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)