原创 Makedile之八 使用函数

2009-6-26 11:21 2407 6 6 分类: MCU/ 嵌入式

#使用函数

    在Makefile中可以使用函数来处理变量, 从而让我们的命令或是规则更为的灵活且具有智能
make所支持的函数不是很多, 不过已经足够了. 函数调用后, 函数的返回值可以当做变量来使用

一. 函数的调用语法

#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#函数调用, 很像变量的使用, 也是以 '$' 来标识的, 其语法如下:
$(<function> <arguments> )
#或是
${<function> <arguments>}
#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    <function>就是函数名, <arguments>是函数的参数, 参数间以逗号 ',' 分隔. 而函数名和
参数之间以 "空格" 分隔. 函数调用以 '$' 开头, 以圆括号或花括号把函数名和参数括起.感觉
很像一个变量. 函数中的参数可以使用变量, 为了风格的统一, 函数和变量的括号最好一样, 如
使用 "$(subst a,b,$(x))" 这样的形式, 而不是 "$(subst a,b,${x})" 的形式.

#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#Exampke make start
#例1-1
comma:= ,
empty:=
space:= $(empty) $(empty)
foo:= a b c
bar:= $(subst $(space),$(comma),$(foo))
#Example make end
#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
在这个示例中, $(comma)的值是一个逗号. $(space)使用了$(empty)定义了一个空格, $(foo)的
值是 "a b c", $(bar)的定义调用了函数 "subst", 这是一个替换函数, 函数有三个参数, 第一
个参数是被替换字串, 第二个参数是替换字串, 第三个参数是替换操作作用的字串. 这个函数也
就是把$(foo)中的空格替换成逗号, 所以$(bar)的值是 "a,b,c".


二. 字符串处理函数

1. 字符串替换函数 subst

名  称: subst
原  型: $(subst <from>,<to>,<text> )
功  能: 把字串 <text> 中的 <from> 字符串替换成 <to>.
返回值: 函数返回被替换过后的字符串.
示  例:    $(subst ee,EE,feet on the street)
说  明: 把 "feet on the street" 中的 "ee" 替换成 "EE", 返回 "fEEt on the strEEt".

2. 模式字符串替换函数 patsubst

名  称:patsubst
原  型:    $(patsubst <pattern>,<replacement>,<text> )
功  能:查找 <text> 中的单词(单词以 "空格", "Tab" 或 "回车" "换行" 分隔)是否符合模式
        <pattern>, 如果匹配的话, 则以 <replacement> 替换. 这里, <pattern> 可以包括通
        配符 '%', 表示任意长度的字串. 如果 <replacement> 中也包含 '%', 那么,该字符将
        是 <pattern> 中的那个 '%' 所代表的字串.
返回值:函数返回被替换过后的字符串。
示  例:    $(patsubst %.c,%.o,x.c.c bar.c)
说  明: 把字串 "x.c.c bar.c" 符合模式 "%.c" 的单词替换成 "%.o"
        返回结果是 "x.c.o bar.o"
备  注:    这和我们前面 "变量章节" 说过的相关知识有点相似. 如:
        "$(var:<pattern>=<replacement> )" 相当于
        "$(patsubst <pattern>,<replacement>,$(var))", 而
        "$(var: <suffix>=<replacement> )" 则相当于
        "$(patsubst %<suffix>,%<replacement>,$(var))".

示  例:    objects = foo.o bar.o baz.o, 那么,
        "$(objects:.o=.c)" 和
        "$(patsubst %.o,%.c,$(objects))" 是一样的.

3. 去空格函数 strip

名  称:    strip
原  型:    $(strip <string>)
功  能:    去掉 <string> 字串中开头和结尾的空字符
返回值: 返回被去掉空格的字符串值
示  例: $(strip a b c )
说  明:    把字串 "a b c " 去到开头和结尾的空格, 结果是 "a b c".

4. 查找字符串函数 findstring

名  称: 查找字符串函数——findstring。
原  型:    $(findstring <find>,<in> )
功  能: 在字串<in>中查找<find>字串
返回值: 如果找到, 那么返回 <find>, 否则返回空字符串
示  例: $(findstring a,a b c)
        $(findstring a,b c)
说  明:    第一个函数返回 "a" 字符, 第二个返回空字符串.

5. 过滤函数 filter

名  称: 过滤函数——filter。
原  型: $(filter <pattern...>,<text> )
功  能: 以 <pattern> 模式过滤 <text> 字符串中的单词, 保留符合模式 <pattern> 的单词.
        可以有多个模式.
返回值: 返回符合模式 <pattern> 的字串.
示  例: sources := foo.c bar.c baz.s ugh.h
        foo: $(sources)
            cc $(filter %.c %.s,$(sources)) -o foo
说  明: $(filter %.c %.s,$(sources)) 返回的值是 "foo.c bar.c baz.s".

6. 反过滤函数 filter-out

名  称: filter-out
原  型: $(filter-out <pattern...>,<text> )
功  能: 以 <pattern> 模式过滤 <text> 字符串中的单词, 去除符合模式 <pattern> 的单词,
        可以有多个模式.
返回值: 返回不符合模式 <pattern> 的字串.
示  例: objects="main1".o foo.o main2.o bar.o
        mains=main1.o main2.o
            $(filter-out $(mains),$(objects))
说  明: 返回值是 "foo.o bar.o".

7. 排序函数 sort

名  称: sort
原  型: $(sort <list> )
功  能: 给字符串<list>中的单词排序(升序).
返回值: 返回排序后的字符串
示  例: $(sort foo bar lose)
说  明: 返回 "bar foo lose"
备  注:    sort函数会去掉 <list> 中相同的单词.

8. 取单词函数 word

名  称: word
原  型:    $(word <n>,<text> )
功  能:    取字符串<text>中第<n>个单词(从1开始)
返回值:    返回字符串 <text> 中第 <n> 个单词. 如果 <n> 比 <text> 中的单词数要大, 那么返
        回空字符串.
示  例:    $(word 2, foo bar baz)

说  明:    返回值是 "bar"

9. 取单词串函数 wordlist
名  称:    wordlist
原  型:    $(wordlist <s>,<e>,<text> )
功  能:    从字符串 <text> 中取从 <s> 开始到 <e> 的单词串. <s> 和 <e> 是一个数字.
返回值:    返回字符串 <text> 中从 <s> 到 <e> 的单词字串.如果 <s> 比 <text> 中的单词数要
        大, 那么返回空字符串. 如果 <e> 大于 <text> 的单词数, 那么返回从 <s> 开始, 到
        <text> 结束的单词串.
示  例:    $(wordlist 2, 3, foo bar baz)
说  明:    返回值是 "bar baz"

10. 单词个数统计函数 words

名  称:    words
原  型:    $(words <text> )
功  能:    统计<text>中字符串中的单词个数
返回值:    返回<text>中的单词数
示  例:    $(words, foo bar baz)
说  明:    返回值是 "3"
备  注: 如果我们要取 <text> 中最后的一个单词, 我们可以这样:
        $(word $(words <text> ), <text> )。

11. 首单词函数 firstword

名  称:    firstword
原  型:    $(firstword <text> )
功  能:    取字符串<text>中的第一个单词
返回值:    返回字符串 <text> 的第一个单词
示  例:    $(firstword foo bar)
说  明:    返回值是 "foo"
备  注: 这个函数可以用word函数来实现: $(word 1,<text> )

    以上是所有的字符串操作函数, 如果搭配混合使用, 可以完成比较复杂的功能. 这里, 举一
个现实中应用的例子. 我们知道, make使用 "VPATH" 变量来指定 "依赖文件" 的搜索路径.于是
我们可以利用这个搜索路径来指定编译器对头文件的搜索路径参数CFLAGS, 如:
override CFLAGS += $(patsubst %,-I%,$(subst :, ,$(VPATH)))
如果我们的 "$(VPATH)" 值是 "src:../headers", 那么将返回 "-Isrc -I../headers", 这正是
cc或gcc搜索头文件路径的参数.


三. 文件名操作函数

1. 取目录函数 dir

名  称:    dir
原  型:    $(dir <names...> )
功  能:    从文件名序列 <names> 中取出目录部分. 目录部分是指最后一个反斜杠 '/' 之前的部
        分.
返回值:    返回文件名序列 <names> 的目录部分。
示  例:    $(dir src/foo.c hacks)
说  明:    返回值是 "src/ ./"

2. 取文件函数 notdir

名  称:    notdir
原  型:    $(notdir <names...> )
功  能:    从文件名序列 <names> 中取出非目录部分.
返回值:    返回文件名序列 <names> 的非目录部分
示  例:    $(notdir src/foo.c hacks)
说  明:    返回值是 "foo.c hacks"

3. 取后缀函数 suffix

名  称:    suffix
原  型:    $(suffix <names...> )
功  能:    从文件名序列 <names> 中取出各个文件名的后缀
返回值:    返回文件名序列 <names>的后缀序列, 如果文件没有后缀, 则返回空字串.
示  例:    $(suffix src/foo.c src-1.0/bar.c hacks)
说  明:    返回值是 ".c .c"

4. 取前缀函数 basename

名  称:    basename
原  型:    $(basename <names...> )
功  能:    从文件名序列 <names> 中取出各个文件名的前缀部分
返回值:    返回文件名序列 <names> 的前缀序列
示  例:    $(basename src/foo.c src-1.0/bar.c hacks)
说  明:    返回值是 "src/foo src-1.0/bar hacks"

5. 加后缀函数 addsuffix

名  称:    addsuffix
原  型:    $(addsuffix <suffix>,<names...> )
功  能:    把后缀 <suffix> 加到 <names> 中的每个单词后面
返回值:    返回加过后缀的文件名序列
示  例:    $(addsuffix .c,foo bar)
说  明:    返回值是 "foo.c bar.c"

6. 加前缀函数 addprefix

名  称:    addprefix
原  型:    $(addprefix <prefix>,<names...> )
功  能:    把前缀 <prefix> 加到 <names> 中的每个单词后面
返回值:    返回加过前缀的文件名序列
示  例:    $(addprefix src/,foo bar)
说  明:    返回值是 "src/foo src/bar"

7. 连接函数 join

名  称:    join
原  型:    $(join <list1>,<list2> )
功  能:    把 <list2> 中的单词对应地加到 <list1> 的单词后面.如果 <list1> 的单词个数要比
        <list2>的多, 那么, <list1> 中的多出来的单词将保持原样. 如果 <list2> 的单词个
        数要比 <list1> 多, 那么, <list2> 多出来的单词将被复制到 <list1> 中.
返回值:    返回连接过后的字符串
示  例:    $(join aaa bbb , 111 222 333)
说  明:    返回值是 "aaa111 bbb222 333"

四. foreach 函数

介  绍:    foreach与别的函数不同. 因为这个函数是用来做循环用的, Makefile中的foreach函数
        几乎是仿照于Unix标准Shell中的for语句, 或是C-Shell(/bin/csh)中的foreach语句而
        构建的.
名  称: foreach
原  型: $(foreach <var>,<list>,<text> )
功  能: 把参数 <list> 中的单词逐一取出放到参数 <var>所指定的变量中,然后再执行 <text>
        所包含的表达式. 每一次 <text> 会返回一个字符串, 循环过程中, <text>的所返回的
        每个字符串会以空格分隔, 最后当整个循环结束时, <text>所返回的每个字符串所组成
        的整个字符串是foreach函数的返回值.
返回值:    字符串

示  例: names := a b c d
        files := $(foreach n,$(names),$(n).o)
说  明: name中的单词会被逐个取出, 并存到变量n中, "$(n).o" 每次根据 "$(n)" 计算出一个
        值, 这些值以空格分隔, 作为foreach的返回, $(files)的值是 "a.o b.o c.o d.o".

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

五. if 函数

名  称: if
原  型:    $(if <condition>,<then-part> )
        $(if <condition>,<then-part>,<else-part> )
功  能:    if函数可以包含else部分. 即if函数的参数可以是两个, 也可以是三个. <condition>
        参数是if的表达式, 若返回非空字符串, 表达式为真, <then-part>会被计算,否则
        <else-part> 会被计算.
返回值:    如果 <condition>为真, <then-part>会是整个函数的返回值, 否则, <else-part>会是
        整个函数的返回值, 如果 <else-part>没有被定义, 整个函数返回空字串.
说  明:    if函数很像GNU的make所支持的条件语句ifeq.

六、call函数

介  绍: call函数是唯一一个可以用来创建新的参数化的函数. 你可以写一个非常复杂的表达式
        这个表达式中, 你可以定义许多参数, 然后你可以用call函数来向这个表达式传递参数
名  称: call
原  型:    $(call <expression>,<parm1>,<parm2>,<parm3>...)
功  能: 当make执行函数时, <expression>中的变量, 如$(1),$(2),$(3)等, 会被参数 <parm1>
        <parm2>, <parm3>依次取代. 而 <expression>的返回值就是call函数的返回值.
返回值: <expression>的返回值
示  例: reverse = $(1) $(2)
        foo = $(call reverse,a,b)        ## foo的值就是 "a b"
        reverse = $(2) $(1)
        foo = $(call reverse,a,b)        ## foo的值就是 "b a"
说  明: 参数的次序是可以自定义的,不一定是顺序的.

七. origin函数

介  绍: origin函数不像其它的函数, 他并不操作变量的值, 他只是告诉你变量是哪里来的
名  称: origin
原  型: $(origin <variable> )
功  能: <variable>是变量的名字, 不应该是引用. 最好不要在 <variable>中使用 '$' 字
        符. Origin以其返回值来告诉你这个变量的 "出生情况".
返回值:
    undefined:    变量从未定义过
    default:    变量是一个默认的定义, 比如 "CC".
    environment:环境变量, 并且当Makefile被执行时, "-e" 参数没有被打开.
    file:        变量定义在Makefile中.
    command line: 变量是被命令行定义的.
    override:    变量override指示符重新定义的.
    automatic:    变量是一个命令运行中的自动变量.
示  例: 这些信息对于我们编写Makefile是非常有用的, 假设我们有一个Makefile其包了一个定
        义文件Make.def, 在Make.def中定义了一个变量 "bletch",而我们的环境中也有一个环
        境变量 "bletch", 此时, 我们想判断一下, 如果变量来源于环境,那么我们就把之重定
        义了, 如果来源于Make.def或是命令行等非环境的, 那么我们就不重新定义它. 于是,
        在我们的Makefile中, 我们可以这样写:
        
        ifdef bletch
            ifeq "$(origin bletch)" "environment"
                bletch = barf, gag, etc.
            endif
        endif
        
        当然, 使用override关键字也可以重新定义环境中的变量, 为什么需要使用这样的步骤
        呢? 我们用override是可以达到这样的效果, 可是override过于粗暴, 它同时会把从命
        令行定义的变量也覆盖了, 而我们只想重新定义环境传来的, 而不想重新定义命令行传
        来的.

八. shell函数

介  绍: shell函数也不像其它的函数. 它的参数应该就是操作系统Shell的命令.
名  称: shell
原  型: $(origin <shell-command> )
功  能: 它和反引号 '`' 是相同的功能. 这就是说, shell函数把执行操作系统命令后的输出作
        为函数返回.
返回值: shell命令的输出
示  例: 我们可以用操作系统命令以及字符串处理命令awk,sed等等命令来生成一个变量
        contents := $(shell cat foo)
        files := $(shell echo *.c)
说  明: 该函数会新生成一个Shell程序来执行命令,所以要注意其运行性能, 如果你的Makefile
        中有一些比较复杂的规则, 并大量使用了这个函数, 这对于你的系统性能是有害的. 特
        别是Makefile的隐晦的规则可能会让你的shell函数执行的次数比你想像的多得多.

九. 控制make的函数

    make提供了一些函数来控制make的运行. 通常, 你需要检测一些运行Makefile时的运行时信
息, 并且根据这些信息来决定make是否继续运行.

1. 产生错误函数error

名  称: error
原  型: $(error <text ...> )
功  能: 产生一个致命的错误, <text ...>是错误信息. 注意,error函数不会在一被使用就会产
        生错误信息, 如果你把其定义在某个变量中, 并在后续的脚本中使用这个变量, 那么也
        是可以的.
示  例: ifdef ERROR_001
            $(error error is $(ERROR_001))
        endif
        在变量ERROR_001定义了后执行时产生error调用.
        
        ERR = $(error found an error!)
        .PHONY: err
        err:
            $(ERR)
        在目标err被执行时才发生error调用

2. 产生警告信息函数warning

名  称: warning
原  型: $(warning <text ...> )
功  能: 这个函数很像error函数, 只是它并不会让make退出, 只是输出一段警告信息,而make继
        续执行.


【2006-12-26】

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
我要评论
0
6
关闭 站长推荐上一条 /3 下一条