LV02-05-Makefile-07-条件判断和函数

本文主要是makefile——条件判断和函数相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。

点击查看使用工具及版本
Windows windows11
Ubuntu Ubuntu16.04的64位版本
VMware® Workstation 16 Pro 16.2.3 build-19376536
SecureCRT Version 8.7.2 (x64 build 2214) - 正式版-2020年5月14日
开发板 正点原子 i.MX6ULL Linux阿尔法开发板
uboot NXP官方提供的uboot,NXP提供的版本为uboot-imx-rel_imx_4.1.15_2.1.0_ga(使用的uboot版本为U-Boot 2016.03)
linux内核 linux-4.15(NXP官方提供)
STM32开发板 正点原子战舰V3(STM32F103ZET6)
点击查看本文参考资料
参考方向 参考原文
Makefile 跟我一起写Makefile
点击查看相关文件下载
--- ---

一、条件判断

1.条件判断格式

Makefile 编译文件时,可能会遇到需要分条件执行的情况,比如在一个工程文件中,可编译的源文件很多,但是它们的类型可能是不相同的,所以编译文件使用的编译器也可能是不同的。这个时候就用到了条件判断。

条件表达式语法如下:

1
2
3
4
5
6
7
8
9
10
11
# 1.语法格式一
<conditional-directive>
<text-if-true>
endif

# 2.语法格式二
<conditional-directive>
<text-if-true>
else
<text-if-false>
endif

<conditional-directive> 表示的是条件关键字。在这一行上,多余的空格是被允许的,但是不能以 Tab 键做为开始(不 然就被认为是命令)。注释符 # 同样也是安全的。 else 和 endif 也一样,只要不 是以 Tab 键开始就可以。

关键字功能
ifeq判断参数是否相等,相等为 true,不相等为 false。
ifneq判断参数是否不相等,不相等为 true,相等为 false。
ifdef判断是否有值,有值为 true,没有值为 false。
ifndef判断是否有值,没有值为 true,有值为 false。

【注意】

(1)在 make 读取 Makefile 文件时就会计算表达式的值,并根据表达式的值决定判断语句中的哪一个部分作为此 Makefile 所要执行的内容。因此在条件表达式中不能使用自动化变量,自动化变量在规则命令执行时才有效。

(2)为了避免混乱, make 不允许把整个条件语句分成两部分放在不同的 Makefile 的文件中。

2. ifeq

  • ifeq 判断参数是否相同,相同为 true
1
2
3
4
5
ifeq (ARG1, ARG2)
ifeq 'ARG1' 'ARG2'
ifeq "ARG1" "ARG2"
ifeq "ARG1" 'ARG2'
ifeq 'ARG1' "ARG2"

比较参数 ARG1 和 ARG2 的值是否相同,相同为 true ,不相同为 false ,例如

1
2
3
4
5
6
7
8
9
10
11
CC = a
test:
ifeq ($(CC),gcc)
@echo "True"
else
@echo "False"
endif

.PHONY: clean
clean:
rm -rf *.o main

在终端执行 make test ,会看到输出了以下内容:

1
False

3. ifneq

  • ifneq 判断参数是否不相等,不相等为 true
1
2
3
4
5
ifneq (ARG1, ARG2)
ifneq 'ARG1' 'ARG2'
ifneq "ARG1" "ARG2"
ifneq "ARG1" 'ARG2'
ifneq 'ARG1' "ARG2"

比较参数 ARG1 和 ARG2 的值是否不相同,不相同为 true ,相同为 false ,例如

1
2
3
4
5
6
7
8
9
10
11
CC = a
test:
ifneq ($(CC),gcc)
@echo "True"
else
@echo "False"
endif

.PHONY: clean
clean:
rm -rf *.o main

在终端执行 make test ,会看到输出了以下内容:

1
True

4. ifdef

  • ifdef 判断参数是否非空,非空值为 true
1
ifdef VARIABLE_NAME

判断参数 VARIABLE_NAME 是否非空值,非空值表达式为 true ,若为空值则表达式为 false ,例如

1
2
3
4
5
6
7
8
9
10
11
a:=
test:
ifdef a
@echo "True"
else
@echo "False"
endif

.PHONY: clean
clean:
rm -rf *.o main

在终端执行 make test ,会看到输出了以下内容:

1
False

5. ifndef

  • ifndef 判断参数是否是非空值,空值为 true
1
ifndef VARIABLE_NAME

判断参数 VARIABLE_NAME 是否为空值,若为空值表达式为 true ,非空值的话表达式为 false 。

1
2
3
4
5
6
7
8
9
10
11
a:=
test:
ifdef a
@echo "True"
else
@echo "False"
endif

.PHONY: clean
clean:
rm -rf *.o main

在终端执行 make test ,会看到输出了以下内容:

1
True

二、 Makefile 函数

1.函数的调用

make 提供了一些函数供 Makefile 调用,函数调用后,函数的返回值可以当做变量来使用。函数的调用与变量很类似,一般语法格式如下:

1
2
3
$(<function> arg1, arg2, ...)
# 或者
${<function> arg1, arg2, ...}

function 就是函数名, argN 是函数的参数。

【注意】

(1)函数名与参数之间通过空格( space )分隔开。

(2)函数的多个参数之间使用 , 分割开来,并且在函数中可以使用变量。

(3)为了风格的统一,函数和变量的括号最好一样,如使用 $(subst a,b,$(x)) 这样的形式。

2.字符串处理函数

2.1字符串替换函数

2.1.1 subst

字符串替换函数 subst 一般语法格式如下:

1
$(subst <source_str>,<target_str>,<text>) 

【函数说明】该函数会将字符串 text 中的 source_str 字符串替换成 target_str 。

【返回值】函数返回被替换过后的字符串。

【注意】 <source_str>,<target_str>,<text> 的 , 号之间最好不要有空格,否则可能替换后会多个空格哦。

2.1.2使用实例

Makefile 文件内容如下:

1
2
3
4
5
6
var1 := main.o test.o
var2 := $(subst .o,.c,$(var1))

test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"

然后在终端中执行 make test 命令,可以看到输出如下:

1
2
var1=main.o test.o
var2=main.c test.c

2.2模式字符串替换函数

2.2.1 patsubst

模式字符串替换函数 patsubst 一般语法格式如下:

1
$(patsubst <pattern>,<replacement>,<text>) 

【函数说明】该函数会查找 <text> 中的单词(单词以“空格”、“Tab”或“回车”,“换行”分隔)是否符合模式 <pattern> ,如果匹配的话,则以 <replacement> 替换。

【返回值】函数返回被替换过后的字符串。

【注意】

(1) <pattern>,<replacement>,<text> 的 , 号之间最好不要有空格,否则可能替换后会多个空格哦。

(2) <pattern> 可以包括通配符 % , 表示任意长度的字符串。如果 <replacement> 中也包含 % ,那么, <replacement> 中的这个 % 将是 <pattern> 中的那个 % 所代表的字串。(另外可以用 \ 来转义一些字符,例如,以 % 来表示真实含义的 % 字符)。

2.2.2使用实例

这个函数与变量替换的时候很类似,可以看下边的例子。 Makefile 文件内容如下:

1
2
3
4
5
6
7
8
9
var1 := main.o test.o
var2 := $(patsubst %.o,%.c,$(var1))
var3 := $(var1:.o=.c)
var4 := $(var1:%.o=%.c)
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"
@echo "var3=$(var3)"
@echo "var4=$(var4)"

然后在终端中执行 make test 命令,可以看到输出如下:

1
2
3
4
var1=main.o test.o
var2=main.c test.c
var3=main.c test.c
var4=main.c test.c

2.3去空格函数

2.3.1 strip

去空格函数 strip 一般语法格式如下:

1
$(strip <string>) 

【函数说明】该函数会去掉字符串 <string> 中开头和结尾的空字符,并且将字符串中的空格合并成为一个空格。

【返回值】函数返回被去掉空格的字符串值。

2.3.2使用实例

Makefile 文件内容如下:

1
2
3
4
5
var1 := ma  in.o             tes    t.o
var2 := $(strip $(var1))
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"

然后在终端中执行 make test 命令,可以看到输出如下:

1
2
var1=ma  in.o             tes    t.o
var2=ma in.o tes t.o

2.4查找字符串函数

2.4.1 findstring

查找字符串函数 findstring 一般语法格式如下:

1
$(findstring <find_str>,<string>)

【函数说明】该函数会在字符串 <string> 中查找 <find_str> 字符串。

【返回值】函数如果找到要查找的字符串 <find_str> ,那么返回 <find_str> ,否则返回空字符串。

【注意】

(1) <find_str>,<string> 的 , 号之间最好不要有空格,否则可能会与预期的不太一样。

2.4.2使用实例

Makefile 文件内容如下:

1
2
3
4
5
6
7
var1 := main.o test.o
var2 := $(findstring main,$(var1))
var3 := $(findstring hello,$(var1))
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"
@echo "var3=$(var3)"

然后在终端中执行 make test 命令,可以看到输出如下:

1
2
3
var1=main.o test.o
var2=main
var3=

2.5过滤函数

2.5.1 filter

过滤函数 filter 一般语法格式如下:

1
$(filter <pattern...>,<text>)

【函数说明】该函数会过滤出 <text> 中符合模式 <pattern> 的字符串,可以有多个 <pattern> 。

【返回值】函数返回符合模式 <pattern> 的字符串。

【注意】

(1) <pattern…>,<text> 的 , 号之间最好不要有空格,否则可能会与预期的不太一样。

2.5.2使用实例

Makefile 文件内容如下:

1
2
3
4
5
6
7
var1 := main.o test.o main.c test.s test.c
var2 := $(filter %.c %.s,$(var1))
var3 := $(filter %.o,$(var1))
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"
@echo "var3=$(var3)"

然后在终端中执行 make test 命令,可以看到输出如下:

1
2
3
var1=main.o test.o main.c test.s test.c
var2=main.c test.s test.c
var3=main.o test.o

2.6反过滤函数

2.6.1 filter-out

反过滤函数 filter-out 一般语法格式如下:

1
$(filter-out <pattern...>,<text>)

【函数说明】该函数会过滤出 <text> 中不符合模式 <pattern> 的字符串(就是会把符合的给去掉),可以有多个 <pattern> 。

【返回值】函数返回不符合模式 <pattern> 的字符串。

【注意】

(1) <pattern…>,<text> 的 , 号之间最好不要有空格,否则可能会与预期的不太一样。

2.6.2使用实例

Makefile 文件内容如下:

1
2
3
4
5
6
7
var1 := main.o test.o main.c test.s test.c
var2 := $(filter-out %.c %.s,$(var1))
var3 := $(filter-out %.o,$(var1))
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"
@echo "var3=$(var3)"

然后在终端中执行 make test 命令,可以看到输出如下:

1
2
3
var1=main.o test.o main.c test.s test.c
var2=main.o test.o
var3=main.c test.s test.c

2.7排序函数

2.7.1 sort

排序函数 sort 一般语法格式如下:

1
$(sort <list>)

【函数说明】该函数给字符串 <list> 中的单词排序(升序)。

【返回值】函数返回排序后的字符串。

2.7.2使用实例

Makefile 文件内容如下:

1
2
3
4
5
var1 := a.o b.c d.s a.c x.c 
var2 := $(sort $(var1))
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"

然后在终端中执行 make test 命令,可以看到输出如下:

1
2
var1=a.o b.c d.s a.c x.c 
var2=a.c a.o b.c d.s x.c

2.8取单词函数

2.8.1 word

取单词函数 word 一般语法格式如下:

1
$(word <n>,<text>)

【函数说明】该函数会取字符串 <text> 中第 n 个单词。( n 从 1 开始)。

【返回值】函数返回字符串 <text> 中第 n 个单词。如果 n 比 <text> 中的单词数要大,那么返回空字符串。

2.8.2使用实例

Makefile 文件内容如下:

1
2
3
4
5
6
7
var1 := main.o test.o main.c test.s test.c
var2 := $(word 1, $(var1))
var3 := $(word 3, $(var1))
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"
@echo "var3=$(var3)"

然后在终端中执行 make test 命令,可以看到输出如下:

1
2
3
var1=main.o test.o main.c test.s test.c
var2=main.o
var3=main.c

2.9单词个数统计函数

2.9.1 words

单词个数统计函数 words 一般语法格式如下:

1
$(words <text>)

【函数说明】该函数会统计字符串 <text> 中的单词个数。

【返回值】函数返回字符串 <text> 中的单词数。

2.9.2使用实例

Makefile 文件内容如下:

1
2
3
4
5
var1 := main.o test.o main.c test.s test.c
var2 := $(words $(var1))
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"

然后在终端中执行 make test 命令,可以看到输出如下:

1
2
var1=main.o test.o main.c test.s test.c
var2=5

2.10首单词函数

2.10.1 firstword

首单词函数 firstword 一般语法格式如下:

1
$(firstword <text>)

【函数说明】该函数会取出字符串 <text> 中的第一个单词。

【返回值】函数返回字符串 <text> 中的第一个单词。

2.10.2使用实例

Makefile 文件内容如下:

1
2
3
4
5
var1 := main.o test.o main.c test.s test.c
var2 := $(firstword $(var1))
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"

然后在终端中执行 make test 命令,可以看到输出如下:

1
2
var1=main.o test.o main.c test.s test.c
var2=main.o

2.11综合应用

  • 指定编译器头文件搜索路径
1
CFLAGS += = $(patsubst %,-I %,$(subst :, ,$(VPATH)))
点击查看变量赋值分析

我们先假设 VPATH:=./src : ./include ,那么:

CFLAGS是代表C编译器的选项
+=是代表追加赋值
$(VPATH)文件搜索路径,在这里表示 ./src : ./include
$(subst :, ,$(VPATH))调用 subst 字符串替换函数,将 ./src : ./include 中的 : 替换为空值(将会产生一个空格),最终得到字符串
./src ./include
patsubst模式字符串替换函数,将会把 ./src ./include 的每个单词进行整体匹配,会得到
-I ./src -I ./include

所以最终我们会得到 cc 或 gcc 搜索头文件路径的参数。放入 Makefile 文件,

1
2
3
4
5
6
7
8
VPATH := ./src : ./include
var1 := $(VPATH)
var2 := $(subst :, ,$(VPATH))
CFLAGS += $(patsubst %,-I %,$(subst :, ,$(VPATH)))
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"
@echo "CFLAGS=$(CFLAGS)"

接着执行 make test ,会看到输出如下:

1
2
3
var1=./src : ./include
var2=./src ./include
CFLAGS=-I ./src -I ./include

若修改为以下内容,限制会更强一点:

1
CFLAGS += $(patsubst %,-I %,$(filter %include,$(subst :, ,$(VPATH))))

这样最终就只剩下 -I ./include 了。

3.文件名操作函数

3.1取目录函数

3.1.1 dir

取目录函数 dir 一般语法格式如下:

1
$(dir <names...>) 

【函数说明】该函数会从文件名序列 <names…> 中取出目录部分。目录部分是指最后一个反斜杠( / )之前的部分。如果没有反斜杠,那么返回 ./ 。

【返回值】函数返回文件名序列的目录部分。

3.1.2使用实例

Makefile 文件内容如下:

1
2
3
4
5
var1 := main.c ./include/test.h ./src/test.c
var2 := $(dir $(var1))
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"

然后在终端中执行 make test 命令,可以看到输出如下:

1
2
var1=main.c ./include/test.h ./src/test.c
var2=./ ./include/ ./src/

3.2取文件函数

3.2.1 notdir

取文件函数 notdir 一般语法格式如下:

1
$(notdir <names...>) 

【函数说明】该函数会从文件名序列 <names…> 中取出非目录部分。非目录部分是指最后一个反斜杠( / )之后的部分。

【返回值】函数返回文件名序列的目录部分。

3.2.2使用实例

Makefile 文件内容如下:

1
2
3
4
5
var1 := main.c ./include/test.h ./src/test.c
var2 := $(notdir $(var1))
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"

然后在终端中执行 make test 命令,可以看到输出如下:

1
2
var1=main.c ./include/test.h ./src/test.c
var2=main.c test.h test.c

3.3取后缀函数

3.3.1 suffix

取后缀函数 suffix 一般语法格式如下:

1
$(suffix <names...>) 

【函数说明】该函数会从文件名序列 <names…> 中取出各个文件的后缀。

【返回值】函数返回文件名序列 <names …> 的后缀序列,如果文件没有后缀,则返回空字串。

3.3.2使用实例

Makefile 文件内容如下:

1
2
3
4
5
var1 := main.c ./include/test.h ./src/test.c
var2 := $(suffix $(var1))
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"

然后在终端中执行 make test 命令,可以看到输出如下:

1
2
var1=main.c ./include/test.h ./src/test.c
var2=.c .h .c

3.4取前缀函数

3.4.1 basename

取前缀函数 basename 一般语法格式如下:

1
$(basename <names...>) 

【函数说明】该函数会从文件名序列 <names…> 中取出各个文件的前缀部分。

【返回值】函数返回文件名序列 <names …> 的前缀序列,如果文件没有前缀,则返回空字串。

【注意】取出的前缀会包含目录部分(如果有目录部分的话)。

3.4.2使用实例

Makefile 文件内容如下:

1
2
3
4
5
var1 := main.c ./include/test.h ./src/test.c
var2 := $(basename $(var1))
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"

然后在终端中执行 make test 命令,可以看到输出如下:

1
2
var1=main.c ./include/test.h ./src/test.c
var2=main ./include/test ./src/test

3.5加后缀函数

3.5.1 addsuffix

加后缀函数 addsuffix 一般语法格式如下:

1
$(addsuffix <suffix>,<names...>) 

【函数说明】该函数会把后缀 <suffix> 加到 <names…> 中的每个单词后面。

【返回值】函数返回加过后缀的文件名序列。

3.5.2使用实例

Makefile 文件内容如下:

1
2
3
4
5
var1 := main.c ./include/test.h ./src/test.c
var2 := $(addsuffix -QN,$(var1))
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"

然后在终端中执行 make test 命令,可以看到输出如下:

1
2
var1=main.c ./include/test.h ./src/test.c
var2=main.c-QN ./include/test.h-QN ./src/test.c-QN

3.6加前缀函数

3.6.1 addprefix

加前缀函数 addprefix 一般语法格式如下:

1
$(addprefix <prefix>,<names...>) 

【函数说明】该函数会把前缀 <prefix> 加到 <names…> 中的每个单词前面。

【返回值】函数返回加过前缀的文件名序列。

3.6.2使用实例

Makefile 文件内容如下:

1
2
3
4
5
var1 := main.c include/test.h src/test.c
var2 := $(addprefix ./,$(var1))
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"

然后在终端中执行 make test 命令,可以看到输出如下:

1
2
var1=main.c include/test.h src/test.c
var2=./main.c ./include/test.h ./src/test.c

3.7连接函数

3.7.1 join

连接函数 join 一般语法格式如下:

1
$(join <list1>,<list2>)

【函数说明】该函数会把 <list2> 中的单词对应地加到 <list1> 的单词后面。

【返回值】函数返回连接过后的字符串。

【注意】如果 <list1> 的单词个数要比 <list2> 的多,那么, <list1> 中的多出来的单词将保持原样。如果 <list1> 的单词个数要比 <list2> 少,那么, <list2> 多出来的单词将被复制到 <list1> 中。

3.7.2使用实例

Makefile 文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
var1 := 111 112 
var2 := -221 -222 -223
var3 := 331
var4 := $(join $(var1),$(var2))
var5 := $(join $(var3),$(var2))
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"
@echo "var3=$(var3)"
@echo "var4=$(var4)"
@echo "var5=$(var5)"

然后在终端中执行 make test 命令,可以看到输出如下:

1
2
3
4
5
var1=111 112 
var2=-221 -222 -223
var3=331
var4=111-221 112-222 -223
var5=331-221 -222 -223

3.8获取匹配模式文件名函数

3.8.1 wildcard

获取匹配模式文件名函数 wildcard 一般语法格式如下:

1
$(wildcard  <pattern>)

【函数说明】该函数会列出当前目录下所有符合模式的 <pattern> 格式的文件名,可以有多个 <pattern> ,中间用空格隔开。

【返回值】函数返回返回值为空格分隔并且存在当前目录下的所有符合模式 <pattern> 的文件名。

【注意】

(1)在这个函数中似乎不太适合使用 % 来匹配,可以使用其他的通配符来进行匹配。

3.8.2使用实例

Makefile 文件内容如下:

1
2
3
var1 := $(wildcard *.c *.o)
test:
@echo "var1=$(var1)"

然后在终端中执行 make test 命令,可以看到输出如下:

1
var1=main.c test.c main.o test.o

便会列出当前目录下所有的 .c 和 .o 文件。

4.其它常用函数

4.1 foreach 函数

4.1.1 foreach

循环函数 foreach 一般使用格式如下:

1
$(foreach <var>,<list>,<text>)

【函数说明】把参数 <list> 中的单词逐一取出放到参数 <var> 所指定的变量中,然后再执行 <text> 所包含的表达式。每一次 <text> 会返回一个字符串。

循环过程中, <text> 的返所返回的每个字符串会以空格分割,最后当整个循环结束的时候, <text> 所返回的每个字符串所组成的整个字符串(以空格分隔)将会是 foreach 函数的返回值。

所以 <var> 最好是一个变量名, <list> 可以是一个表达式,而 <text> 中一般会只用 <var> 这个参数来一次枚举 <list> 中的单词。

【注意】 foreach 中的 <var> 参数是一个临时的局部变量, foreach 函数执行完后,参数 <var> 的变量将可用,其作用域只在 foreach 函数当中。

4.1.1使用实例

Makefile 文件内容如下:

1
2
3
4
5
var1 := a b c d
var2 := $(foreach n,$(var1),./$(n).o)
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"

然后在终端中执行 make test 命令,可以看到输出如下:

1
2
var1=a b c d
var2=./a.o ./b.o ./c.o ./d.o

$(var1) 中的单词会被挨个取出,并存到变量 n 中, $(n).o 每次根据 $(n) 计算出一个值,这些值以空格分隔,最后作为 foreach 函数的返回值。

4.2 if 函数

4.2.1 if

条件函数 if 一般使用格式如下:

1
2
3
$(if <condition>,<then-part>) 
# 或者
$(if <condition>,<then-part>,<else-part>)

【函数说明】 <condition> 参数是 if 的表达式,如果其返回的是非空的字符串,那么这个表达式就相当于返回真,于是, <then-part> 就会被计算,否则 <else-part> 会被计算。

【返回值】

如果 <condition> 为真(非空字符串),那么 <then-part> 会是整个函数的返回值。

如果 <condition> 为假(空字符串),那么 <else-part> 将会是这个函数的返回值。此时如果 <else-part> 没有被定义(也就是说没有这一部分),那么整个函数返回空字串符。所以, <then-part> 和 <else-part> 只会有一个被计算。

4.2.2使用实例

Makefile 文件内容如下:

1
2
3
4
5
6
7
8
9
10
var1 := a b c d
var2 :=
var3 := $(if $(var1),$(var1),false)
var4 := $(if $(var2),$(var2))
var4 := $(if $(var2),$(var2),false)
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"
@echo "var3=$(var3)"
@echo "var4=$(var4)"

然后在终端中执行 make test 命令,可以看到输出如下:

1
2
3
4
var1=a b c d
var2=
var3=a b c d
var4=false

4.3 call 函数

4.3.1 call

传递参数函数 call 一般使用格式如下:

1
$(call <expression>,<parm1>,<parm2>...)

【函数说明】 <expression> 参数是 call 的表达式,我们可以在表达式 <expression> 中定义许多的参数,然后通过 call 函数向表达式传入 <parm1>,<parm2>… 参数。

【返回值】 <expression> 的返回值就是函数的返回值。

【注意】

(1) <expression> 可以定义为以下格式:

1
var1 = $(1) $(2) $(3)

$(1) $(2) $(3) 分别表示第一个参数,第二个参数,第三个参数,参数的次序是可以自定义的,不一定是顺序的。另外说明一点就是,这里定义的时候不能用 := 否则无法对传入变量进行引用。

(2)传入参数多余或者少于表达式中定义的参数,都不会报错,若引用参数的编号超出了传入参数数量,会多出一个空格,下边例子中就有。

4.3.2使用实例

Makefile 文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var1 = $(1) $(2) $(3)
var2 = $(3) $(1) $(2)
var3 := $(call var1,a,b,c)
var4 := $(call var2,a,b,c)
var5 := $(call var1,a,b)
var6 := $(call var2,a,b)
var7 := $(call var1,a,b,c,d)
var8 := $(call var2,a,b,c,d)
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"
@echo "var3=$(var3)"
@echo "var4=$(var4)"
@echo "var5=$(var5)"
@echo "var6=$(var6)"
@echo "var7=$(var7)"
@echo "var8=$(var8)"

然后在终端中执行 make test 命令,可以看到输出如下:

1
2
3
4
5
6
7
8
var1=  
var2=
var3=a b c
var4=c a b
var5=a b
var6= a b
var7=a b c
var8=c a b

4.4 origin 函数

4.4.1 origin

溯源函数(哈哈🤣,我自己起的名字,感觉叫着方便) origin 一般使用格式如下:

1
$(origin <variable>)

【函数说明】不操作变量的值,只是告诉我们 <variable> 这个变量是哪里来的。

【返回值】这个函数的返回值就多了:

undefinedvariable从来没有定义过,origin 函数返回这个值“undefined”。
defaultvariable是一个默认的定义,比如“CC”这个变量,
environmentvariable是一个环境变量,并且当 Makefile 被执行时,“-e”参数没有被打开。
filevariable这个变量被定义在 Makefile 中。
command linevariable这个变量是被命令行定义的。
overridevariable是被 override 指示符重新定义的。
automaticvariable是一个命令运行中的自动化变量。

4.4.2使用实例

Makefile 文件内容如下:

1
2
3
4
5
6
7
var1 := main.c
var2 := $(origin var1)
var3 := $(origin CC)
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"
@echo "var3=$(var3)"

然后在终端中执行 make test 命令,可以看到输出如下:

1
2
3
var1=main.c
var2=file
var3=default

4.5 shell 函数

4.5.1 shell

shell 函数一般使用格式如下:

1
$(shell <command>)

【函数说明】 <command> 为函数的参数,可以是 shell 中的命令。这个函数就是可以调用 shell 命令,它与反引号 ` 功能相同。

【返回值】 shell 命令运行结果。

【注意】这个函数会新生成一个 Shell 程序来执行命令,所以我们需要注意其运行性能,如果我们的 Makefile 中有一些比较复杂的规则,并大量使用了这个函数,那么对于我们的系统性能是有害的。特别是 Makefile 的隐晦的规则可能会让 shell 函数执行的次数比想像的多得多。

4.5.2使用实例

Makefile 文件内容如下:

1
2
3
4
5
6
7
8
9
var1 := $(shell pwd)
var2 := $(shell ls)
var3 := pwd
var4 := ls
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"
@echo "var3=$(var3)"
@echo "var4=$(var4)"

然后在终端中执行 make test 命令,可以看到输出如下:

1
2
3
4
5
6
7
8
9
10
var1=/mnt/hgfs/sharedfiles/2Linux/test/LV02/05Makefile/test1
var2=main main.c main.o Makefile test.c test.h test.o
var3=/home/hk/0sharedfiles/2Linux/test/LV02/05Makefile/test1
var4=main
main.c
main.o
Makefile
test.c
test.h
test.o

三、 make 控制函数

Makefile 中提供了两个控制 make 运行方式的函数。其作用是当 make 执行过程中检测到某些错误时为用户提供消息,并且可以控制 make 执行过程是否继续。

1. error 函数

1.1 error

一般语法格式:

1
$(error <text ...>)

【函数说明】产生致命错误,并提示 <text …> 信息给用户,并退出 make 的执行。

error 函数是在函数展开时(函数被调用时)才提示信息并结束 make 进程。因此如果函数出现在命令中或者一个递归的变量定义时,读取 Makefile 时不会出现错误。而只有包含 error 函数引用的命令被执行,或者定义中引用此函数的递归变量被展开时,才会提示致命信息 <text …> 同时退出 make 。

【返回值】

【注意】 error 函数一般不出现在直接展开式的变量定义中,否则在 make 读取 Makefile 时将会提示致命错误。

1.2使用实例

  • 读取时直接报错

Makefile 文件内容如下:

1
2
3
4
5
ERROR := E1
test:
ifdef ERROR
$(error error is $(ERROR))
endif

然后在终端中执行 make test 命令,可以看到输出如下:

1
Makefile:4: *** error is E1。 停止。
  • 执行时报错

Makefile 文件内容如下:

1
2
3
4
ERROR=$(error found an error!)
.PHONY:error
error:
$(ERROR)

然后在终端中执行 make error 命令,可以看到输出如下:

1
Makefile:4: *** found an error!。 停止。

在 make 读取 Makefile 时不会出现致命错误,只有目标 error 被作为是一个目标被执行时才会出现。

2. warning 函数

2.1 warning

一般语法格式:

1
$(warning <text ...>)

【函数说明】产生警告信息 <text …> , make 的执行过程会继续。

【返回值】

【注意】用法和 error 类似,展开过程相同。

四、 Makefile 中的 for 循环

1. for 格式

在 Makefile 中也是可以使用 for 循环的,格式如下:

1
2
3
4
5
6
for var in $(LIST);do command;done
# 或者
for var in $(LIST);\
do \
command; \
done

【注意】使用 var 的时候,一定要是 $$var ,且不能用 () 或者 { } 将 var 包裹。

2.使用实例

1
2
3
4
5
6
x = +O
main:
@for var in a b c d; \
do \
echo $$var $(x) $$var.o;\
done

在终端执行 make main 会有如下输出:

1
2
3
4
a +O a.o
b +O b.o
c +O c.o
d +O d.o