Makefile笔记(3)——函数汇总

 一、语法

函数的使用语法是这样的:

$(function arguments)
或者
${function arguments}

参数之间用逗号","分隔,单个参数可以是以空格分隔的列表。

 

二、一些常见內建文本操作函数

1. 文本(文本)替换

$(subst from,to,text)

函数作用:
对目标文本(或列表)text执行文本替换,将主文本中的from替换成to,并返回替换后的新文本。
参数:
from: 将要被替换的子文本
to: 替换到文本text的新子文本
text: 被操作的主文本
返回:返回替换之后的新文本

#例1
TEXT = "hello world"
FROM = hello
TO   = HELLO
RESULT = $(subst $(FROM),$(TO),$(TEXT))

all:
    @echo $(RESULT)

#-------------
# make
HELLO world

 

2. 文本(文本)模式替换

$(patsubst pattern,replacement,text)

函数作用:
对目标文本(或列表)text执行文本替换,以模式替换的形式进行替换。
参数:
pattern: 将要被替换的模式匹配方式.
replacement: 替换后的模式匹配方式.
text: 被操作的文本
返回:返回替换后的新文本

#例2
TEXT = foo.c bar.c
RESULT = $(patsubst %.c,%.o,${TEXT})

all:
    @echo $(RESULT)

#-------------
# make
foo.o bar.o

同样的,TEXT可以是列表,这个操作可以使用一个更加简单的模式匹规则语法来操作,相当于:${TEXT : %.c=%.o} 结果是一样的。

 

3. 文本精简

$(strip string)

函数作用:将文本中前导和尾随的空格删除,在文本中存在多个连续空格时,使用一个空格替换。
参数参数:
string:目标文本
返回值:精简完的文本

#例3
RESULT=$(strip "Hello   world, nihao  ")

all:
    @echo $(RESULT)

#-------------
# make
Hello world, nihao 

 

4. 在主文本中寻找子文本

$(findstring find,in)

函数作用 :
这是文本查找函数,在in中寻找是否有find文本。
参数:
find: 子文本
in:主文本
返回值:如果in中存在find,返回find,否则返回""(空文本)。

#例4
RESULT=$(findstring main.c, "foo.c main.c bar.c")

all:
    @echo $(RESULT)

#-------------
# make
main.c

#例4-2
TEXT=foo.c main.c bar.c
RESULT=$(findstring main.c bar.c, ${TEXT})

all:
    @echo $(RESULT)

#-------------
# make
main.c bar.c

注:例4中的第一个参数main.c不能加引号,否则就找不到,返回空!

 

5. 过滤作用

$(filter pattern…,text) 和 $(filter-out pattern…,text)

函数作用:
过滤作用,将符合模式规则的text中的文本挑选出来。
参数:
pattern: 过滤的模式规则
text: 将要处理的文本
返回值:返回符合模式规则的文本

#例5
TEXT := foo.c bar.c foo.h bar.h
RESULT = $(filter %.c,$(TEXT))

all:
    @echo $(RESULT)

#--------------
# make
foo.c bar.c


#例5-2
TEXT := foo.c bar.c foo.h bar.h
RESULT = $(filter-out %.c,$(TEXT))

all:
    @echo $(RESULT)

#--------------
# make
foo.h bar.h

这里的pattern不一定是带 % 的模式匹配,也可以是文件列表。filter(filter-out)函数返回的是text文本中符合(不符合)条件的项目:

#例5-3
TEXT := foo.c
TEXT_P := foo.c bar.c main.c
RESULT = $(filter $(TEXT_P),$(TEXT))
RESULT_OUT = $(filter-out $(TEXT_P),$(TEXT))
RESULT_R1 = $(filter $(TEXT), $(TEXT_P))
RESULT_OUT_R1 = $(filter-out $(TEXT), $(TEXT_P))

all:
    @echo $(RESULT)
    @echo $(RESULT_OUT)
    @echo $(RESULT_R1)
    @echo $(RESULT_OUT_R1)

#------------------
# make
foo.c

foo.c
bar.c main.c

实战:根据平台配置宏来选择编译的文件,只针对列表中的平台选择v2下的文件

CONFIG_MTK_PLATFORM = "mt6765"

RESULT = $(filter $(CONFIG_MTK_PLATFORM), "mt6785" "mt6768" "mt6853" "mt6765")

ifneq (,$(filter $(CONFIG_MTK_PLATFORM), "mt6785" "mt6768" "mt6853")) #根据过滤出的结果是否为空来选择对应文件
obj-y := v2/mtk_xxxx.o
else
obj-y := v1/mtk_xxxx.o
endif

all:
    @echo $(RESULT)
    @echo $(obj-y)

#--------------------------

$ make
mt6765
v1/mtk_xxxx.o

 

6. 按照首字母字典排序

$(sort list)

函数作用:
将给定的list(通常是以空格分隔的文件列表)按照首字母字典排序。
参数:
list:目标列表
返回值:返回排序后的列表。

#例6
TEXT := main.c foo.c bar.c
RESULT = $(sort $(TEXT))

all:
    @echo $(RESULT)

#------------------
# make
bar.c foo.c main.c

 

7. 返回列表中的某个元素

$(word n,text)

函数作用:
返回text列表中第n个元素,通常来说,这个text为文件或文本列表,元素为单个的文件名或文本
参数:
n:第n个元素,比较特殊的是,元素列表的计数从1开始。
text: 文件列表
返回值:返回第n个元素

#例7
TEXT := main.c foo.c bar.c
RESULT = $(word 2, $(TEXT))

all:
    @echo $(RESULT)

#------------------
# make
foo.c

 

8. 返回列表的子列表

$(wordlist s,e,text)

函数作用:
返回text列表中指定的由s(start)开始由e(end)结尾的列表,s和e均为数字。
参数:
s:截取开始的地方,s从1开始
e:截取文本结束的地方。
text:目标文件列表
返回值:返回截取的文本

#例8
TEXT := main.c foo.c bar.c hello.c ku.c gou.c
RESULT = $(wordlist 2, 4, $(TEXT))

all:
    @echo $(RESULT)

#------------------
# make
foo.c bar.c hello.c

如果s大于text的最大列表数量,返回空文本,如果e大与text的最大列表数量,返回从s开始到结尾的列表,如果s大于e,返回空。

 

9. 列表中的元素数量

$(words text)

函数作用:
返回text列表中的元素数量
参数:
text:目标列
返回值:返回text列表中的元素数量

#例9
TEXT := main.c foo.c bar.c hello.c ku.c gou.c
RESULT = $(words $(TEXT))

all:
    @echo $(RESULT)

#------------------
# make
6

 

10. 返回列表第一个或最后一个元素

$(firstword names…) 和 $(lastword names…)

函数作用:返回names列表中的第一个元素或最后一个元素
参数:
names:目标列表
返回值:返回names列表中的第一个元素

#例10
TEXT := main.c foo.c bar.c hello.c ku.c gou.c
RESULT_F = $(firstword $(TEXT))
RESULT_L = $(lastword $(TEXT))

all:
    @echo $(RESULT_F)
    @echo $(RESULT_L)

#------------------
# make
main.c
gou.c

 

11. wildcard 函数

$(wildcard <pattern...>)

说明:该函数被展开为已经存在的,使用空格分开的,匹配此模式的所有文件列表。若不使用这个函数,若是匹配不到就返回pattern而不是空。

#例11
all:
    @echo *.c
    @echo $(wildcard *.c)

#-----------------------
# make
*.c

# touch bar.c foo.c main.c
# make
bar.c foo.c main.c
bar.c foo.c main.c

 

三、一些常见內建文件与目录操作函数

1. 截取文件路径名中的目录部分或文件名部分

$(dir names…) 和 $(notdir names…)

函数作用:截取文件路径中的目录部分,如:/home/usb/file.c,截取/home/usb/,目标可以是列表
参数:
names:目标文件,可以是列表
返回值:返回目录,如果目标是列表,返回以空格分隔的目录。

#例1
TEXT := /home/usb/main.c /home/usb/foo.c /home/tx/bar.c /home/rx/hello.c
RESULT_D = $(dir $(TEXT))
RESULT_N = $(notdir $(TEXT))

all:
    @echo $(RESULT_D)
    @echo $(RESULT_N)

#------------------
# make
/home/usb/ /home/usb/ /home/tx/ /home/rx/
main.c foo.c bar.c hello.c

 

2. 获取和去除文件后缀

$(suffix names…) 和 $(basename names…)

函数作用 :获取文件列表中的后缀部分。
参数:
names:目标文件,可以是列表
返回值:返回文件列表中的后缀部分,如:".c",".o"

#例2
TEXT := /home/usb/main.c foo.h /home/tx/bar.h hello.c
RESULT_S = $(suffix $(TEXT))
RESULT_B = $(basename $(TEXT))

all:
    @echo $(RESULT_S)
    @echo $(RESULT_B)
#------------------
# make
.c .h .h .c
/home/usb/main foo /home/tx/bar hello

 

3. 为列表添加后缀

$(addsuffix suffix,names…)

函数作用:为目标文件列表添加后缀
参数:
suffix:添加的后缀内容
names:目标列表
返回值:返回添加完后缀的列表

#例3
TEXT := foo bar
RESULT := ${addsuffix .o , ${TEXT}}

all:
    @echo $(RESULT)

#------------------
# make
foo.o bar.o

 

4. 两个列表元素逐个衔接

$(join list1,list2)

函数作用 :逐个地将list2中的元素链接到list1。
参数:
list1:链接后元素在前的列表
list2:链接后元素在后的列表
返回值:返回链接后的链表

#例4
LIST1 := foo bar
LIST2 := .c .h
RESULT := ${join ${LIST1} , ${LIST2}}

all:
    @echo $(RESULT)

#------------------
# make
foo.c bar.h

当list1和list2不等长时,视为与空文本的链接,例如list1为3个元素,list2有两个元素,那么list1的第三个元素对应空文本。 list中的空格将始终被当做一个空格处理。

 

5. 获取绝对路径

$(realpath names…)

函数作用:对names中的每个文件,求其绝对路径,当目标为链接时,将解析链接。
参数:
names:目标文件名(列表)
返回值:目标文件名对应的绝对路径(列表)。

#例5
LIST := foo.c mf
RESULT := ${realpath ${LIST}}

all:
    @echo $(RESULT)

#------------------
root@ubuntu:/work/11.Makefile/2# make
/work/11.Makefile/2/foo.c /work/11.Makefile/4.pattern_rules/Makefile

注:mf是个软链接文件,这个是真的会去遍历目录,不仅仅是字符串列表操作。

 

6. abspath

$(abspath names…)

函数介绍:作用与realpath()函数相似,唯一的不同是不解析链接,将链接也当前一个普通文件。

#例6
LIST := foo.c mf
RESULT := ${abspath ${LIST}}

all:
    @echo $(RESULT)

#------------------
root@ubuntu:/work/11.Makefile/2# make
/work/11.Makefile/2/foo.c /work/11.Makefile/2/mf

 

四、其他常用函数

1. 对列表单个元素进行文本操作

$(foreach var,list,text)

函数作用:对list中的每个var,调用text命令。
参数:
var:被操作的目标元素
list:目标元素列表
text:对目标元素执行的操作。
返回值:返回执行操作后的文本.

#例1
TEXT := foo.c bar.c
RESULT := ${foreach file, ${TEXT}, /home/${file}pp}

all:
    @echo $(RESULT)

#------------------
# make
/home/foo.cpp /home/bar.cpp

注:单纯的文本操作,可以个列表价一些前缀或后缀。

 

2. file 函数

$(file op filename[,text])

函数作用 :向文件执行文本的输入输出
参数:
op:要对文件进行的操作,支持:>(覆盖写) >>(追加写) <(读)
filename:文件名
text:如果op为写,此参数表示要写入的文本。
返回值:返回值无意义

#例2
TEXT := "hello world"
RESULT := ${file >, test, ${TEXT}}

all:
    @echo ${RESULT}

注:测试失败,读写都不会有任何动作。也没查到相关资料。


3. 调用自定义函数和自定义函数

$(call variable,param,param,…)

函数作用:call函数在makefile中是一个特殊的函数,因为它的作用就是创建一个新的函数。你可以使用call函数创建各种实现复杂功能的函数。
参数:
variable:函数名
param:函数参数,是被传递给自定义的variable函数。
param ...
返回值:返回定义函数的结果.

当call函数被调用时,make将展开这个函数,函数的参数会被赋值给临时参数$1,$2,$0则代表函数名本身,参数没有上限也没有下限。对于call函数需要注意:当定义的函数名与内建函数名同名时,总是调用内建函数。call函数在分配参数之前扩展它们,意味着对具有特殊扩展规则的内置函数的引用的变量值可能不会正常执行。

#例3
func = $1.$2
foo = $(call func,a,b)
all:
    @echo $(foo)

#---------------
# make
a.b


#例3-2
define func1
    @echo "my name is $(0)"
endef

define func2
    @echo "my name is $(0)"
    @echo "param1 => $(1)"
    @echo "param2 => $(2)"
endef

all:
    $(call func1)
    $(call func2, hello, world)

#-----------------------
# make
my name is func1
my name is func2
param1 =>  hello
param2 =>  world


#例3-3
define func_my
    gcc -c $(1)
    gcc -c $(2)
endef

all:
    $(call func_my, bar.c, foo.c)

#---------------
# make
gcc -c  bar.c
gcc -c  foo.c

define是定义变量的一种方式,这种定义变量的特殊之处在于它可以定义带有换行的变量,所以它可以定义一系列的命令,在这里就可以定义一个函数。

 

4. 获取未展开的变量值

$(value variable)

函数作用:获取未展开的变量值。
参数:
variable:目标变量,不需要添加"$"
返回值:返回变量的未展开的值.

#例4
FOO = $PATH
all:
    @echo $(FOO)
    @echo $(PATH)
    @echo $(value FOO)

#----------------------------
# make
ATH
/usr/local/sbin:/usr/local/bin:.../usr/sbin:/usr/bin:/sbin:/bin:/usr/games
/usr/local/sbin:/usr/local/bin:.../usr/sbin:/usr/bin:/sbin:/bin:/usr/games

打印系统环境变量。第一个结果${FOO}为ATH是因为,make将$P解析成makefile中的变量,而不是将(PATH)作为一个整体来解析。


5. 使函数中能执行编译指令

$(eval text)

函数作用:eval在makefile中是一个非常特别的函数,它允许此函数新定义一个makefile下的结构,包含变量、目标、隐式或者显示的
规则。eval函数的参数会被展开,然后再由makeifle进行解析。也就是说,eval函数会被make解析两次,第一次是对eval函数的解析,
第二次是make对eval参数的解析。
参数:
text:一个makefile结构
返回值:返回值无意义.

#例5
define func
foo:
    gcc -c foo.c -o foo 
endef 

$(eval $(call func))

# make
gcc -c foo.c -o foo 


#例5-2
define func
$1:
    gcc -c $2 -o $$@
endef

$(eval $(call func,main,main.c))

all:
    @echo hello

#-----------------
# make
gcc -c main.c -o main

不要"all:" make也可以执行,此时就算有"all:",但是make也不会执行它!

例5-2的func函数返回值依旧是一个makefile规则的表达式,这时候如果需要执行这个规则,那就要使用makefile的规则对其进行再一次地解析,就需要用到eval()函数,eval()函数通常与call()一起使用。

例5-2第三行中出现的"$$",在makefile的语法中,$是一个特殊字符,通常与其他符号结合表示特定的含义,如果我们单纯的就想打出"$"字符,我们需要使用"$$"表示"$"符号,就像C语言中的转义符号'\',如果我们要使用真实的'\'符号,我们就得使用'\'来进行转义。

 

6. 判断变量的来源

$(origin variable)

函数作用:这个函数与其他函数的区别在于,它不超作变量的值,而是返回变量的定义信息,告诉你变量是哪来的,告诉你变量的出生。
参数:
variable:被操作的目标变量,注意是变量的名字,不是引用,所以不要加“$”字符
返回值:返回变量的定义信息。这些定义信息是一些枚举值:
undefined:变量未定义
default:变量被默认定义,就像CC.
environment: 传入的环境变量
environment override:本来在makefile中被定义为环境变量,但是新定义的变量覆盖了环境变量。
file:在makefile中被定义
command line:在命令行中被定义
override:使用override定义的变量
automatic:在规则的命令部分被定义的自动变量,也可以理解为临时变量.

#例6
RESULT=false
ifeq "$(origin PATH)" "environment"
RESULT=true
endif

VAL := 1

override USER = ZhangShan

all:
    @echo $(RESULT)
    @echo $(origin SHELL)
    @echo $(origin CC)
    @echo $(origin VAL)
    @echo $(origin CmdVal) # passed when make
    @echo $(origin USER)
    @echo $(origin @)

#-----------------------------------------
# make CmdVal=hello
true
file
default
file
command line
override
automatic

# make
true
file
default
file
undefined
override
automatic

PATH是个环境变量,因此打印为true; make时传参CmdVal了,就是命令行参数类型,若没有传参就是undefined; 将环境变量USER在makefile中使用override定义的变量进行覆盖,因此是override; 如果是自动化变量(如 @,< 等),那么返回automatic。


7. 判断变量的展开方式

$(flavor variable)

函数作用: 与origin的属性类似,这个函数返回变量的展开方式,在之前章节有提到过,变量展开方式有两种:循环递归扩展和简单扩展。
参数:
variable:目标变量
返回值:返回变量的展开方式,这是一个枚举值:
undefined:变量未定义
recursive:循环递归扩展
simple:简单扩展

#例7
foo:=foo
bar=bar

all:
    @echo $(flavor $(foo))
    @echo $(flavor $(bar))

#------------------
# make
simple
recursive

 

五、控制执行流和打印函数

1. 返回错误信息并终止执行

$(error text…)

函数作用: 生成一个错误,并返回错误信息text。
参数:
text:将要打印的错误信息。
返回值:返回值无意义,makefile执行终止。

只要调用了这个函数,错误信息就会生成,但是如果将其作为一个循环递归变量的右值,它会被最后扩展的时候才被调用,或者放在规则的命令部分,它将被shell解析,可能结果并不是你想要的。

#例1
all:
    $(error there is an error!)
    @echo "won't be excute!"

#-------------------
# make
Makefile:2: *** there is an error!.  Stop.

 

2. 打印警告和提示信息

$(warning text…) 和 $(info text…)

这两个函数属性与error相似,但是这两个函数并不会导致makefile的执行中断,而是警告和提示,警告会打印出行号,而info不会。

#例2
all:
    $(warning just a warning test)
    $(info just a info test)
    @echo "excute!"

#---------------------
# make
Makefile:2: just a warning test
just a info test
excute!

 

六、shell函数

1. makefile中以shell方式执行函数

$(shell command...)

函数作用: shell函数与其他函数不一样的地方在于,它将它的参数当做一条shell命令来执行,shell命令是不遵循makefile的语法的,也就是说不由make解析,将传递给shell,这一点和规则中的命令部分是一样的。
参数:
command:命令部分
返回值:返回shell命令执行结果

值得注意的是,make会对最后的返回值进行处理,将所有的换行符替换成单个空格。在makefile中可以使用另一种做法来调用shell命令,就是用"`xxx`"(键盘左上角ESC下的键)将命令包含。

#例1
KDIR1 := /lib/modules/`uname -r`/build
KDIR2 := /lib/modules/$(shell uname -r)/build

all:
    @echo $(KDIR1)
    @echo $(KDIR2)

#--------------------
# make
/lib/modules/4.2.0-27-generic/build
/lib/modules/4.2.0-27-generic/build

 

 

 

 

参考:https://blog.csdn.net/qxb1229/article/details/8651060 TODO还有很多没写完。

 

posted on 2020-05-06 00:05  Hello-World3  阅读(636)  评论(0编辑  收藏  举报

导航