LV110-函数
本文主要是makefile——条件判断和函数相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。
一、函数的调用
make 提供了一些函数供 Makefile 调用,函数调用后,函数的返回值可以当做变量来使用。函数的调用与变量很类似,一般语法格式如下:
$(<function> arg1, arg2, ...)
# 或者
${<function> arg1, arg2, ...}function 就是函数名, argN 是函数的参数。
【注意】
(1)函数名与参数之间通过空格( space )分隔开。
(2)函数的多个参数之间使用 , 分割开来,并且在函数中可以使用变量。
(3)为了风格的统一,函数和变量的括号最好一样,如使用 $(subst a,b,$(x)) 这样的形式。
二、字符串处理函数
1. 字符串替换函数
1.1 subst
字符串替换函数 subst 一般语法格式如下:
$(subst <source_str>,<target_str>,<text>)【函数说明】该函数会将字符串 text 中的 source_str 字符串替换成 target_str 。
【返回值】函数返回被替换过后的字符串。
【注意】 <source_str>,<target_str>,<text> 的 , 号之间最好不要有空格,否则可能替换后会多个空格哦。
1.2 使用实例
Makefile 文件内容如下:
var1 := main.o test.o
var2 := $(subst .o,.c,$(var1))
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"然后在终端中执行 make test 命令,可以看到输出如下:
var1=main.o test.o
var2=main.c test.c2. 模式字符串替换函数
2.1 patsubst
模式字符串替换函数 patsubst 一般语法格式如下:
$(patsubst <pattern>,<replacement>,<text>)【函数说明】该函数会查找 <text> 中的单词(单词以“空格”、“Tab”或“回车”,“换行”分隔)是否符合模式 <pattern> ,如果匹配的话,则以 <replacement> 替换。
【返回值】函数返回被替换过后的字符串。
【注意】
(1) <pattern>,<replacement>,<text> 的 , 号之间最好不要有空格,否则可能替换后会多个空格哦。
(2) <pattern> 可以包括通配符 % , 表示任意长度的字符串。如果 <replacement> 中也包含 % ,那么, <replacement> 中的这个 % 将是 <pattern> 中的那个 % 所代表的字串。(另外可以用 \ 来转义一些字符,例如,以 % 来表示真实含义的 % 字符)。
2.2 使用实例
这个函数与变量替换的时候很类似,可以看下边的例子。 Makefile 文件内容如下:
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 命令,可以看到输出如下:
var1=main.o test.o
var2=main.c test.c
var3=main.c test.c
var4=main.c test.c3.去空格函数
3.1 strip
去空格函数 strip 一般语法格式如下:
$(strip <string>)【函数说明】该函数会去掉字符串 <string> 中开头和结尾的空字符,并且将字符串中的空格合并成为一个空格。
【返回值】函数返回被去掉空格的字符串值。
3.2 使用实例
Makefile 文件内容如下:
var1 := ma in.o tes t.o
var2 := $(strip $(var1))
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"然后在终端中执行 make test 命令,可以看到输出如下:
var1=ma in.o tes t.o
var2=ma in.o tes t.o4. 查找字符串函数
4.1 findstring
查找字符串函数 findstring 一般语法格式如下:
$(findstring <find_str>,<string>)【函数说明】该函数会在字符串 <string> 中查找 <find_str> 字符串。
【返回值】函数如果找到要查找的字符串 <find_str> ,那么返回 <find_str> ,否则返回空字符串。
【注意】
(1) <find_str>,<string> 的 , 号之间最好不要有空格,否则可能会与预期的不太一样。
4.2 使用实例
Makefile 文件内容如下:
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 命令,可以看到输出如下:
var1=main.o test.o
var2=main
var3=5. 过滤函数
5.1 filter
过滤函数 filter 一般语法格式如下:
$(filter <pattern...>,<text>)【函数说明】该函数会过滤出 <text> 中符合模式 <pattern> 的字符串,可以有多个 <pattern> 。
【返回值】函数返回符合模式 <pattern> 的字符串。
【注意】
(1) <pattern...>,<text> 的 , 号之间最好不要有空格,否则可能会与预期的不太一样。
5.2 使用实例
Makefile 文件内容如下:
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 命令,可以看到输出如下:
var1=main.o test.o main.c test.s test.c
var2=main.c test.s test.c
var3=main.o test.o6. 反过滤函数
6.1 filter-out
反过滤函数 filter-out 一般语法格式如下:
$(filter-out <pattern...>,<text>)【函数说明】该函数会过滤出 <text> 中不符合模式 <pattern> 的字符串(就是会把符合的给去掉),可以有多个 <pattern> 。
【返回值】函数返回不符合模式 <pattern> 的字符串。
【注意】
(1) <pattern...>,<text> 的 , 号之间最好不要有空格,否则可能会与预期的不太一样。
6.2 使用实例
Makefile 文件内容如下:
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 命令,可以看到输出如下:
var1=main.o test.o main.c test.s test.c
var2=main.o test.o
var3=main.c test.s test.c7. 排序函数
7.1 sort
排序函数 sort 一般语法格式如下:
$(sort <list>)【函数说明】该函数给字符串 <list> 中的单词排序(升序)。
【返回值】函数返回排序后的字符串。
7.2 使用实例
Makefile 文件内容如下:
var1 := a.o b.c d.s a.c x.c
var2 := $(sort $(var1))
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"然后在终端中执行 make test 命令,可以看到输出如下:
var1=a.o b.c d.s a.c x.c
var2=a.c a.o b.c d.s x.c8. 取单词函数
8.1 word
取单词函数 word 一般语法格式如下:
$(word <n>,<text>)【函数说明】该函数会取字符串 <text> 中第 n 个单词。( n 从 1 开始)。
【返回值】函数返回字符串 <text> 中第 n 个单词。如果 n 比 <text> 中的单词数要大,那么返回空字符串。
8.2 使用实例
Makefile 文件内容如下:
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 命令,可以看到输出如下:
var1=main.o test.o main.c test.s test.c
var2=main.o
var3=main.c9. 单词个数统计函数
9.1 words
单词个数统计函数 words 一般语法格式如下:
$(words <text>)【函数说明】该函数会统计字符串 <text> 中的单词个数。
【返回值】函数返回字符串 <text> 中的单词数。
9.2 使用实例
Makefile 文件内容如下:
var1 := main.o test.o main.c test.s test.c
var2 := $(words $(var1))
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"然后在终端中执行 make test 命令,可以看到输出如下:
var1=main.o test.o main.c test.s test.c
var2=510. 首单词函数
10.1 firstword
首单词函数 firstword 一般语法格式如下:
$(firstword <text>)【函数说明】该函数会取出字符串 <text> 中的第一个单词。
【返回值】函数返回字符串 <text> 中的第一个单词。
10.2 使用实例
Makefile 文件内容如下:
var1 := main.o test.o main.c test.s test.c
var2 := $(firstword $(var1))
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"然后在终端中执行 make test 命令,可以看到输出如下:
var1=main.o test.o main.c test.s test.c
var2=main.o11. 综合应用
- 指定编译器头文件搜索路径
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 文件,
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 ,会看到输出如下:
var1=./src : ./include
var2=./src ./include
CFLAGS=-I ./src -I ./include若修改为以下内容,限制会更强一点:
CFLAGS += $(patsubst %,-I %,$(filter %include,$(subst :, ,$(VPATH))))这样最终就只剩下 -I ./include 了。
三、文件名操作函数
1. 取目录函数
1.1 dir
取目录函数 dir 一般语法格式如下:
$(dir <names...>)【函数说明】该函数会从文件名序列 <names...> 中取出目录部分。目录部分是指最后一个反斜杠( / )之前的部分。如果没有反斜杠,那么返回 ./ 。
【返回值】函数返回文件名序列的目录部分。
1.2 使用实例
Makefile 文件内容如下:
var1 := main.c ./include/test.h ./src/test.c
var2 := $(dir $(var1))
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"然后在终端中执行 make test 命令,可以看到输出如下:
var1=main.c ./include/test.h ./src/test.c
var2=./ ./include/ ./src/2. 取文件函数
2.1 notdir
取文件函数 notdir 一般语法格式如下:
$(notdir <names...>)【函数说明】该函数会从文件名序列 <names...> 中取出非目录部分。非目录部分是指最后一个反斜杠( / )之后的部分。
【返回值】函数返回文件名序列的目录部分。
2.2 使用实例
Makefile 文件内容如下:
var1 := main.c ./include/test.h ./src/test.c
var2 := $(notdir $(var1))
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"然后在终端中执行 make test 命令,可以看到输出如下:
var1=main.c ./include/test.h ./src/test.c
var2=main.c test.h test.c3. 取后缀函数
3.1 suffix
取后缀函数 suffix 一般语法格式如下:
$(suffix <names...>)【函数说明】该函数会从文件名序列 <names...> 中取出各个文件的后缀。
【返回值】函数返回文件名序列 <names ...> 的后缀序列,如果文件没有后缀,则返回空字串。
3.2 使用实例
Makefile 文件内容如下:
var1 := main.c ./include/test.h ./src/test.c
var2 := $(suffix $(var1))
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"然后在终端中执行 make test 命令,可以看到输出如下:
var1=main.c ./include/test.h ./src/test.c
var2=.c .h .c4. 取前缀函数
4.1 basename
取前缀函数 basename 一般语法格式如下:
$(basename <names...>)【函数说明】该函数会从文件名序列 <names...> 中取出各个文件的前缀部分。
【返回值】函数返回文件名序列 <names ...> 的前缀序列,如果文件没有前缀,则返回空字串。
【注意】取出的前缀会包含目录部分(如果有目录部分的话)。
4.2 使用实例
Makefile 文件内容如下:
var1 := main.c ./include/test.h ./src/test.c
var2 := $(basename $(var1))
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"然后在终端中执行 make test 命令,可以看到输出如下:
var1=main.c ./include/test.h ./src/test.c
var2=main ./include/test ./src/test5. 加后缀函数
5.1 addsuffix
加后缀函数 addsuffix 一般语法格式如下:
$(addsuffix <suffix>,<names...>)【函数说明】该函数会把后缀 <suffix> 加到 <names...> 中的每个单词后面。
【返回值】函数返回加过后缀的文件名序列。
5.2 使用实例
Makefile 文件内容如下:
var1 := main.c ./include/test.h ./src/test.c
var2 := $(addsuffix -QN,$(var1))
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"然后在终端中执行 make test 命令,可以看到输出如下:
var1=main.c ./include/test.h ./src/test.c
var2=main.c-QN ./include/test.h-QN ./src/test.c-QN6. 加前缀函数
6.1 addprefix
加前缀函数 addprefix 一般语法格式如下:
$(addprefix <prefix>,<names...>)【函数说明】该函数会把前缀 <prefix> 加到 <names...> 中的每个单词前面。
【返回值】函数返回加过前缀的文件名序列。
6.2 使用实例
Makefile 文件内容如下:
var1 := main.c include/test.h src/test.c
var2 := $(addprefix ./,$(var1))
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"然后在终端中执行 make test 命令,可以看到输出如下:
var1=main.c include/test.h src/test.c
var2=./main.c ./include/test.h ./src/test.c7. 连接函数
7.1 join
连接函数 join 一般语法格式如下:
$(join <list1>,<list2>)【函数说明】该函数会把 <list2> 中的单词对应地加到 <list1> 的单词后面。
【返回值】函数返回连接过后的字符串。
【注意】如果 <list1> 的单词个数要比 <list2> 的多,那么, <list1> 中的多出来的单词将保持原样。如果 <list1> 的单词个数要比 <list2> 少,那么, <list2> 多出来的单词将被复制到 <list1> 中。
7.2 使用实例
Makefile 文件内容如下:
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 命令,可以看到输出如下:
var1=111 112
var2=-221 -222 -223
var3=331
var4=111-221 112-222 -223
var5=331-221 -222 -2238. 获取匹配模式文件名函数
8.1 wildcard
获取匹配模式文件名函数 wildcard 一般语法格式如下:
$(wildcard <pattern>)【函数说明】该函数会列出当前目录下所有符合模式的 <pattern> 格式的文件名,可以有多个 <pattern> ,中间用空格隔开。
【返回值】函数返回返回值为空格分隔并且存在当前目录下的所有符合模式 <pattern> 的文件名。
【注意】
(1)在这个函数中似乎不太适合使用 % 来匹配,可以使用其他的通配符来进行匹配。
8.2 使用实例
Makefile 文件内容如下:
var1 := $(wildcard *.c *.o)
test:
@echo "var1=$(var1)"然后在终端中执行 make test 命令,可以看到输出如下:
var1=main.c test.c main.o test.o便会列出当前目录下所有的 .c 和 .o 文件。
四、其它常用函数
1. foreach 函数
1.1 foreach
循环函数 foreach 一般使用格式如下:
$(foreach <var>,<list>,<text>)【函数说明】把参数 <list> 中的单词逐一取出放到参数 <var> 所指定的变量中,然后再执行 <text> 所包含的表达式。每一次 <text> 会返回一个字符串。
循环过程中, <text> 的返所返回的每个字符串会以空格分割,最后当整个循环结束的时候, <text> 所返回的每个字符串所组成的整个字符串(以空格分隔)将会是 foreach 函数的返回值。
所以 <var> 最好是一个变量名, <list> 可以是一个表达式,而 <text> 中一般会只用 <var> 这个参数来一次枚举 <list> 中的单词。
【注意】 foreach 中的 <var> 参数是一个临时的局部变量, foreach 函数执行完后,参数 <var> 的变量将可用,其作用域只在 foreach 函数当中。
1.1 使用实例
Makefile 文件内容如下:
var1 := a b c d
var2 := $(foreach n,$(var1),./$(n).o)
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"然后在终端中执行 make test 命令,可以看到输出如下:
var1=a b c d
var2=./a.o ./b.o ./c.o ./d.o$(var1) 中的单词会被挨个取出,并存到变量 n 中, $(n).o 每次根据 $(n) 计算出一个值,这些值以空格分隔,最后作为 foreach 函数的返回值。
2. if 函数
2.1 if
条件函数 if 一般使用格式如下:
$(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> 只会有一个被计算。
2.2 使用实例
Makefile 文件内容如下:
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 命令,可以看到输出如下:
var1=a b c d
var2=
var3=a b c d
var4=false3. call 函数
3.1 call
传递参数函数 call 一般使用格式如下:
$(call <expression>,<parm1>,<parm2>...)【函数说明】 <expression> 参数是 call 的表达式,我们可以在表达式 <expression> 中定义许多的参数,然后通过 call 函数向表达式传入 <parm1>,<parm2>... 参数。
【返回值】 <expression> 的返回值就是函数的返回值。
【注意】
(1) <expression> 可以定义为以下格式:
var1 = $(1) $(2) $(3)$(1) $(2) $(3) 分别表示第一个参数,第二个参数,第三个参数,参数的次序是可以自定义的,不一定是顺序的。另外说明一点就是,这里定义的时候不能用 := 否则无法对传入变量进行引用。
(2)传入参数多余或者少于表达式中定义的参数,都不会报错,若引用参数的编号超出了传入参数数量,会多出一个空格,下边例子中就有。
3.2 使用实例
Makefile 文件内容如下:
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 命令,可以看到输出如下:
var1=
var2=
var3=a b c
var4=c a b
var5=a b
var6= a b
var7=a b c
var8=c a b4. origin 函数
4.1 origin
溯源函数(哈哈🤣,我自己起的名字,感觉叫着方便) origin 一般使用格式如下:
$(origin <variable>)【函数说明】不操作变量的值,只是告诉我们 <variable> 这个变量是哪里来的。
【返回值】这个函数的返回值就多了:
| undefined | variable从来没有定义过,origin 函数返回这个值“undefined”。 |
| default | variable是一个默认的定义,比如“CC”这个变量, |
| environment | variable是一个环境变量,并且当 Makefile 被执行时,“-e”参数没有被打开。 |
| file | variable这个变量被定义在 Makefile 中。 |
| command line | variable这个变量是被命令行定义的。 |
| override | variable是被 override 指示符重新定义的。 |
| automatic | variable是一个命令运行中的自动化变量。 |
4.2 使用实例
Makefile 文件内容如下:
var1 := main.c
var2 := $(origin var1)
var3 := $(origin CC)
test:
@echo "var1=$(var1)"
@echo "var2=$(var2)"
@echo "var3=$(var3)"然后在终端中执行 make test 命令,可以看到输出如下:
var1=main.c
var2=file
var3=default5 shell 函数
5.1 shell
shell 函数一般使用格式如下:
$(shell <command>)【函数说明】 <command> 为函数的参数,可以是 shell 中的命令。这个函数就是可以调用 shell 命令,它与反引号 ` 功能相同。
【返回值】 shell 命令运行结果。
【注意】这个函数会新生成一个 Shell 程序来执行命令,所以我们需要注意其运行性能,如果我们的 Makefile 中有一些比较复杂的规则,并大量使用了这个函数,那么对于我们的系统性能是有害的。特别是 Makefile 的隐晦的规则可能会让 shell 函数执行的次数比想像的多得多。
5.2 使用实例
Makefile 文件内容如下:
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 命令,可以看到输出如下:
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