跳转至

make函数

makefile 有系统提供的库函数,却本质上不支持自定义函数,但可以使用 define 定义具有类似函数特性的多行变量。

1 函数调用

  • 函数调用语法形式
  • $(<function> <arguments>)
  • ${<function> <arguments>}
OBJ=$(subst ee,EE,feet on the street)
all:
    @echo $(OBJ)

上例中表示将 feet on the street 字符串中 ee 字符串替换为 EE,echo 输出结果为 fEEt on the strEEt

2 define 自定义函数、call 调用自定义函数

使用 define 定义多行变量,具有函数特性,但与库函数调用还是有区别的,且需要通过 call 函数来调用

define func1
    @echo "My name is $(0)"
endef
var := $(call func1)

3 库函数-字符串处理

  • 函数调用形式:$(fun par1,par2,..parN), 参数间由逗号分隔 详见参考资料

3.1 subst 字符串替换函数

  • 语法形式:$(subst <from>,<to>,<text>)
  • 功能:把字串 <text> 中的 <from> 字符串替换成 <to>
  • 返回:函数返回被替换过后的字符串
  • 示例
## 将feet on the street中的ee替换成EE
$(subst ee,EE,feet on the street)
## return:fEEt on the strEEt

3.2 patsubst 模式字符串替换函数

  • 语法形式:$(patsubst <pattern>,<replacement>,<text>)
  • 功能:查找 <text> 中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)匹配 pattern 部分替换成 replacement 部分
  • 返回:函数返回被替换过后的字符串
  • 示例
## 将x.c.c bar.c中以.c结尾部分替换成以.o结尾
$(patsubst %.c,%.o,x.c.c bar.c)
## return: x.c.o bar.o

3.3 strip 去掉开头结尾空格

  • 语法形式:$(strip <string>)
  • 功能:去掉 <string> 字串中开头和结尾的空字符。
  • 返回:返回被去掉空格的字符串值
  • 示例
str1=" abc "
str2=$(strip $(str1))
## str1 != str2,因为str2没有首尾空格字符

3.4 findstring 查找字符串

  • 语法形式:$(findstring <find>,<in>)
  • 功能:在字串 <in> 中查找 <find> 字串
  • 返回:如果找到,那么返回 <find> ,否则返回空字符串
  • 示例
## 在a b c中查找a
$(findstring a,a b c)
## return:a
## 在b c中查找a,由于找不到,返回空
$(findstring a,b c)
## return:空字符串

3.5 filter 过滤字符串

  • 语法形式:$(filter <pattern...>,<text>)
  • 功能:以 <pattern> 模式过滤 <text> 字符串中的单词,保留符合模式 <pattern> 的单词。可以有多个模式。
  • 返回:返回符合模式 <pattern> 的字串。
  • 示例
## 过滤以.c和.s结尾的字符串
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

3.6 filter-out 反过滤字符串

与 filter 过滤作用相反 - 语法形式:$(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))
## return foo.o bar.o

3.7 sort 按升序排序并排重

  • 语法形式:$(sort <list>)
  • 功能:给字符串 <list> 中的单词排序(升序)
  • 返回:返回排序后的字符串
  • 示例:$(sort foo bar lose) 返回 bar foo lose
  • 备注:sort 函数会去掉 <list> 中相同的单词
  • 示例
## 按升序排序并排重
$(sort foo bar lose foo)
## return bar foo lose

3.8 word 取字符串中某个单词

  • 语法形式:$(word <n>,<text>)
  • 功能:取字符串 <text> 中第 <n> 个单词。(从一开始)
  • 返回:返回字符串 <text> 中第 <n> 个单词。如果 <n><text> 中的单词数要大,那么返回空字符串
  • 备注:单词间是以空格或 tab 分割的
  • 示例
## 获取foo bar baz中第2个单词bar
$(word 2, foo bar baz)
## return bar

3.9 wordlist 取字符串中区间单词列表

  • 语法形式:$(wordlist <start>,<end>,<text>)
  • 功能:从字符串 <text> 中取从 <start> 开始到 <end> 的单词串。 <start><end> 是一个数字。
  • 返回:返回字符串 <text> 中从 <start><end> 的单词字串。如果 <start><text> 中的单词数要大,那么返回空字符串。如果 <end> 大于 <text> 的单词数,那么返回从 <start> 开始,到 <text> 结束的单词串。
  • 示例
## 获取foo bar lose中第2个到第3个单词bar baz
$(wordlist 2,3, foo bar baz)
## return bar baz

3.10 words 统计单词个数

  • 语法形式:$(words <text>)
  • 功能:统计 <text> 中字符串中的单词个数。
  • 返回:返回 <text> 中的单词数。
  • 示例
## 统计单词数
$(words, foo bar baz)
## return 3
## 获取foo bar baz 中最后一个单词
$(word $(words foo bar baz),foo bar baz )
## return baz

3.11 lastword 取尾单词

  • 语法形式:$(lastword <text>)
  • 功能:取字符串 <text> 中的最后一个单词。
  • 返回:返回字符串 <text> 的最后一个单词。
  • 示例
$(lastword, foo bar baz)
## return baz

3.12 firstword 取首单词

  • 语法形式:$(firstword <text>)
  • 功能:取字符串 <text> 中的第一个单词。
  • 返回:返回字符串 <text> 的第一个单词。
  • 示例
$(firstword, foo bar baz)
## return foo

4 库函数-文件处理

4.1 dir 获取文件目录部分

  • 语法形式:$(dir <names...>)
  • 功能:从文件名序列 <names> 中取出目录部分。目录部分是指最后一个反斜杠(/)之前的部分。如果没有反斜杠,那么返回 ./ 。
  • 返回:返回文件名序列 <names> 的目录部分。
  • 示例:
$(dir src/foo.c hacks)
## return src/ ./

4.2 notdir 获取文件名(非目录部分)

  • 语法形式:$(notdir <names...>)
  • 功能:从文件名序列 <names> 中取出非目录部分。非目录部分是指最後一个反斜杠(/ )之后的部分。
  • 返回:返回文件名序列 <names> 的非目录部分。
  • 示例:
$(notdir src/foo.c hacks)
## return foo.c hacks

4.3 suffix 取文件扩展名

  • 语法形式:$(suffix <names...>)
  • 功能:从文件名序列 <names> 中取出各个文件名的后缀。
  • 返回:返回文件名序列 <names> 的后缀序列,如果文件没有后缀,则返回空字串,后缀是以最后一个. 之后的内容。
  • 示例:
## 返回后缀.d而不是.c.d
$(notdir src/foo.c.d hacks)
## return .d

4.4 basename 取文件名前缀(包含目录部分)

  • 语法形式:$(basename <names...>)
  • 功能:从文件名序列 <names> 中取出各个文件名的前缀部分。
  • 返回:返回文件名序列 <names> 的前缀序列,如果文件没有前缀,则返回空字串
  • 示例:
## 返回前缀src/foo.c hacks
$(notdir src/foo.c.d hacks)
## return src/foo.c hacks

4.5 addsuffix 添加文件后缀

  • 语法形式:$(addsuffix <suffix>,<names...>)
  • 功能:后缀 <suffix> 加到 <names> 中的每个单词后面。
  • 返回:返回加过后缀的文件名序列。
  • 示例:
$(addsuffix .c,foo bar)
## return foo.c bar.c

4.6 addprefix 添加文件前缀

  • 语法形式:$(addprefix <prefix>,<names...>)
  • 功能:把前缀 <prefix> 加到 <names> 中的每个单词后面。
  • 返回:返回加过前缀的文件名序列。
  • 示例:
$(addprefix src/,foo bar)
## return src/foo src/bar

4.7 join 拼接

  • 语法形式:$(join <list1>,<list2>)
  • 功能:把 <list2> 中的单词对应地加到 <list1> 的单词后面。如果 <list1> 的单词个数要比 <list2> 的多,那么,<list1> 中的多出来的单词将保持原样。如果 <list2> 的单词个数要比 <list1> 多,那么, <list2> 多出来的单词将被复制到 <list1> 中。
  • 返回:返回连接过后的字符串。
  • 示例:
$(join a b,.c .o)
## return a.c b.o
## .i被输出
$(join a b,.c .o .i)
## return a.c b.o .i
## c原样输出
$(join a b c,.c .o)
## return a.c b.o c

4.8 wildcard 匹配通配符

  • 语法形式:$(wildcard pattern…)
  • 功能:pattern 模糊匹配文件名,如 *.c, 表示当前路径下所有 c 头文件文件
  • 返回:返回所有匹配的文件名。
  • 示例:
## wildcard返回当前目录下所有以.c的文件名,patsubst再将其替换以.o结尾的文件名
$(patsubst %.c,%.o,$(wildcard *.c))

4.9 realpath 返回文件的绝对路径

  • 语法形式:$(realpath names...)
  • 功能:返回文件的绝对路径,绝对路径是不含. .. 等符号的文件路径,如果文件路径不存在,则返回空
  • 返回:返回文件的相对路径
  • 示例:
## 假设当前makefile在 /home/xx/test目录下
$(realpath ./)
## result /home/xx/test

4.10 abspath 返回文件的绝对路径

  • 语法形式:$(realpath names...)
  • 功能:返回文件的绝对路径,绝对路径是不含. .. 等符号的文件路径,如果文件路径不存在,也会返回绝对路径,这是与 realpath 的区别
  • 返回:返回文件的绝对路径
  • 示例:
## 假设当前makefile在 /home/xx/test目录下
$(abspath ./)
## result /home/xx/test

5 条件函数

5.1 if

  • 语法形式:$(if condition,then-part[,else-part])
  • 功能:如果 condition 是一个非空字符(即条件未真),执行 then-part 部分,否则执行 else-part 部分
  • 返回:不返回数据,只执行条件对应的操作
  • 示例:
## 由于var非空,条件为真,执行echo "true"
var:=1
all:
        $(if $(var),echo "true",echo "false")
## result 执行echo "true"

5.2 or

  • 语法形式:$(or condition1[,condition2[,condition3…]])
  • 功能:判断是否有一个条件为真
  • 返回:从左往右判断条件是否为真,当有一个条件为真时,返回这个条件真的字符串;当所有条件都为假时,返回空字符
  • 示例:
## 由于var非空,条件为真,执行echo "true"
## var1空字符,var2非空,返回第一个真的条件var2
var1:=
var2:=2
var3:=3
$(or $(var1),$(var2),$(var3))
## result 2

5.3 and

  • 语法形式:$(and condition1[,condition2[,condition3…]])
  • 功能:判断所有条件是否为真
  • 返回:从左往右判断条件是否为真,当有所有条件为真时,最后一个条件真的字符串;当有一个条件为假时,返回空字符
  • 示例:
## 由于var非空,条件为真,执行echo "true"
## var1空字符,var2非空,返回第一个假的条件var1
var1:=
var2:=2
var3:=3
$(or $(var1),$(var2),$(var3))
## result 空字符

6 foreach

  • 语法形式:$(foreach var,list,text)
  • 功能:遍历 list,放入 var 中,再执行 text 并返回
  • 返回:返回 test 内容
  • 示例:
dirs := a b c d
files := $(foreach dir,$(dirs),$(wildcard $(dir)/*))
#等价于
files := $(wildcard a/* b/* c/* d/*)

7 file 读写文件

  • 语法形式:$(file op filename[,text])
  • 功能:读写文件
  • $(file > filename [test]) 覆盖写
  • $(file >> filename [test]) 追加写
  • $(file < filename) 读取文件,并返回文件内容
  • 返回:当都文件时,返回文件内容,写文件,返回空
  • 示例:
program: $(OBJECTS)
$(file >$@.in,$^)

8 call 调用参数化函数 (自定义函数)

  • 语法形式:$(value variable)
  • 功能:调用参数化函数,param 会被函数中 $(1)、$ (2)...$(n) 接收
  • 返回:返回什么取决于 variable 所对应的参数化函数
  • 示例:
## 交换参数值
reverse = $(2) $(1)
foo = $(call reverse,a,b)
## result foo=b a

9 value 取变量值

  • 语法形式:$(value variable)
  • 功能:当 variable 也是引用一个变量时,$(variable) 不能正确得到结果,但 value 函数能避免这个问题
  • 返回:返回 variable 引用的值
  • 示例:第一个 echo 会把$P 当作变量,从而生成 ATH,第二个 echo 才能正确解析到环境变量值
FOO = $PATH

all:
        @echo $(FOO)
        @echo $(value FOO)

10 eval

  • 参考
  • 语法形式:$(eval $(call ...))
  • 功能:eval 通常用于当 call 一个自定义函数时,这个函数里是生成 makefile 代码,这时执行 eval,这段 makefile 代码才能生效。
  • 返回:返回值是空
  • 示例:
## eval将PROGRAM_template中定义的
PROGRAMS = server client
server_OBJS = server.o server_priv.o server_access.o
server_LIBS = priv protocol
client_OBJS = client.o client_api.o client_mem.o
client_LIBS = protocol
## Everything after this is generic
.PHONY: all
all: $(PROGRAMS)
define PROGRAM_template =
$(1): $$($(1)_OBJS) $$($(1)_LIBS:%=-l%)
ALL_OBJS += $$($(1)_OBJS)
endef
$(foreach prog,$(PROGRAMS),$(eval $(call PROGRAM_template,$(prog))))
$(PROGRAMS):
$(LINK.o) $^ $(LDLIBS) -o $@
clean:
rm -f $(ALL_OBJS) $(PROGRAMS)

11 orign 显示变量来源

  • 语法形式:$(origin variable)
  • 功能:显示指定变量的来源,是否是环境变量,还是 makefie 定义的,还是未定义的等等
  • 返回:返回值是变量来源,有以下几种
  • undefined :没有定义的变量
  • default :默认定义的变量,比如 CC 定义成 cc,AR 定义成 ar
  • environment :来自系统环境变量
  • environment override :来自系统环境变量,且 make 时带有-e 参数
  • file :makefile 定义的变量,包括如 MAKEFILE_LIST 这类变量
  • command line :命令行传过来的变量,比如执行 make TEST=123,TEST 就是这个
  • override :变量被 override 修饰的
  • automatic :自动化变量,如 $@、$<
  • 示例:
FOO=123
override AA=123
all:
        echo $(origin @)
        echo $(origin AA)
        echo $(origin FOO)
        echo $(origin MAKEFILE_LIST)
        echo $(origin TEST)
        echo $(value FOO)
        echo $(origin PATH)
        echo $(origin CC)
  • 结果
## 执行make
$ make
echo automatic
automatic
echo override
override
echo file
file
echo file
file
echo undefined
undefined
echo 123
123
echo environment
environment
echo default
default

12 flavor 显示变量简单信息

  • 语法形式:$(flavor variable)
  • 功能:显示指定变量是否定义,是否是重复扩展类型(=或 define 定义的变量),简单扩展类型(由:=定义的)
  • 返回:返回值是变量来源,有以下几种
  • undefined :没有定义的变量
  • recursive :由 =define 定义的变量
  • simple :由:=定义的变量
  • 示例:
bar = $(ugh)
ugh := Huh?
FOO=123
override AA=123
all:
        echo $(flavor bar)
        echo $(flavor ugh)
        echo $(flavor xxx)
  • 结果
## 执行make
$ make
echo recursive
recursive
echo simple
simple
echo undefined
undefined

13 提示类型函数

13.1 error

  • 语法形式:$(error text...)
  • 功能:终止 makefile 执行,打印 text
  • 返回:返回值为空
  • 示例:
ifdef ERROR1
$(error error is $(ERROR1))
endif

13.2 warning

  • 语法形式:$(warning text...)
  • 功能:不终止 makefile 执行,但打印 text 到标准输出
  • 返回:返回值为空
  • 示例:
all:
    $(warning warning...)

13.3 info

  • 语法形式:$(info text...)
  • 功能:打印 text 到标准输出
  • 返回:返回值为空
  • 示例:
all:
    $(info info...)

14 shell 函数执行 shell 指令

  • 语法形式:$(shell shell-command)
  • 功能:执行 shell-command
  • 返回:返回值是执行 shell 指令后得到的值
  • 示例:
## 将foo文件内容赋给contents变量
contents := $(shell cat foo)