函數
GNUmake支持內置函數和用戶自定義函數。函數調用看起來像是變量引用,只不過多了用逗號隔開的參數而已。所有的函數都具有相同的形式:$(function-name
arg1[, argn]
)
$之後是函數的名稱,接着是函數的參數,參數之間以逗號隔開。
內置函數
內置函數是內嵌於make程序內的函數,可以直接使用。
字符串函數
$(filter
pattern ..., text
)
filter
函數將text
視爲一系列以空格隔開的單詞,與pattern
比較之後,返回符合的單詞(模式必須與單詞相匹配,而不能只匹配一部分)。模式可以有多個,只要符合其中一個就會被匹配。模式中採用%
作爲通配符,當有多個%
出現在一個模式中,只有第一個作爲通配符,其他的作爲字面值。
$(filter-out
pattern ..., text
)
filter-out
函數剛好與filter
相反,用來選出與模式不相符的每個單詞。
text = apple pear banana watermelon orange pineapple
filtered = $(filter %apple pear %ge,$(text))
not_filtered = $(filter-out %apple pear %.ge, $(text))
all :
@echo $(filtered)
@echo $(not_filtered)
$ make
apple pear orange pineapple
banana watermelon orange
$(findstring
string...,text
)
此函數將會從text
裏搜索string
。如果找到了就返回該字符串,否則返回空string
沒有模式匹配功能。
$(subst
search-string,replace-string,text
)
這是一個不具有模式匹配的搜索替換函數。search-string
和replace-string
不必是整個單詞。
$(patsubst
search-string,replace-string,text
)
這個替換函數具有模式匹配功能。同樣的,只能用一個%
。
sources = hello.c lib.c main.c tom_hello.c tom_lib.c
objects = $(subst .c,.o, $(sources))
has_main.c = $(findstring main.c, $(sources))
has_main = $(findstring main, $(sources))
no_domain = $(findstring domain, $(sources))
patsubsted = $(patsubst tom%,jerry%, $(sources))
all:
@echo $(objects)
@echo $(has_main.c)
@echo $(has_main)
@echo $(no_domain)
@echo $(patsubsted)
$ make
hello.o lib.o main.o tom_hello.o tom_lib.o
main.c
main
hello.c lib.c main.c jerry_hello.c jerry_lib.c
$(words
text
)
此函數返回text
中單詞的數量。
$(word
n,text
)
此函數返回text
中的第n
個單詞。第一個單詞編號爲1,如果n
的值大於單詞的總數,返回空值。
$(firstword
text
)
返回text
中的第一個單詞。等效與$(word 1,text)
。
$(wordlist
start,end,text
)
此函數返回text
中範圍從start
(含)到end
(含)的單詞。
$(sort
list
)
sort
函數會排序它的list
參數並且移除重複的單詞。此函數會返回按照字典順序的不重複的單詞列表,以空格分隔。而且,sort
還會刪除前導和結尾的空格。這裏的sort
是make
內部實現的函數,不是shell
裏的程序。
$(shell
command
)
shell
的參數會被擴展(就像所有其他參數)並且傳遞給subshell
執行。然後make
讀取command
的標準輸出,並將之作爲函數的返回值。輸出中所出現的一系列換行符會被縮減成單一的空格,任何末尾的換行被刪除。標準錯誤並不會被返回。
$(wildcard
pattern...
)
wildcard
的參數是一個模式列表,他會對每個模式進行擴展。如果擴展的模式找不到符合的文件,返回空字符串。該模式爲shell的glob匹配。
如果想要判斷某個文件是否存在,就可以使用wildcard
:
dot-emacs-exists := $(wildcard ~/.emacs)
$(dir
list...
)
dir
函數返回list
中每個單詞的目錄部分。
$(notdir
name...
)
返回每個單詞的文件名部分。
$(suffix
name...
)
返回由每個單詞的擴展名構成的單詞列表
$(basename
name...
)
返回由每個單詞的非擴展名部分組成的單詞列表
$(addsuffix,
suffix,name...
)
返回由name
單詞列表中的每個單詞前加上suffix
前綴構成的新的單詞表。
$(addprefix,
prefix,name...
)
$(join
prefix-list,suffix-list
)
join
函數把prefix-list
的第i個單詞與suffix-list
的第i個單詞連在一起構成新序列的第i個單詞。
流程控制函數
$(if
condition,then-part,else-part
)
if
函數(可不是條件指令ifne,ifeq,ifdef
等)會根據條件表達式的求值結果,從兩個宏中選擇一個進行擴展。
如果condition
擴展之後包含任何字符(包括空格),求值結果爲真,會對then-part
進行擴展;否則,如果condition
擴展之後爲空,會對else-part
進行擴展。
make
對condition
求值時,首先會移除前導及末尾的空格。
$(error
text
)
error
函數會使make
輸出text
錯誤信息和當前makefile
的名稱行號之後以2
這個狀態結束運行。
$(warn
text
)
與error
類似,輸出text
的內容,但並不退出。擴展結果爲空串。$(foreach
variable,list,body
)
當foreach
函數執行的時候,它將list
中的每個單詞作爲body
中的variable
進行操作,返回操作的結果。
sources = fat32.c format.c alloca.c main.c
dirs = src bin inc
objects = $(foreach var,$(sources), $(subst .c,.o, $(var)))
full_path = $(foreach var, $(sources), $(addprefix src/, $(var)))
do_mkdirs = $(foreach var, $(dirs), $(shell mkdir -p $(var)))
all:
@echo $(objects)
@echo $(full_path)
@echo $(do_mkdirs)
$ make
fat32.o format.o alloca.o main.o
src/fat32.c src/format.c src/alloca.c src/main.c
#產生了三個文件夾
eval函數
$(eval
contents
)
這個函數很重要。它用來將它後面的文本直接放入make解析器。
首先make會掃描eval的參數並對其中的變量進行擴展,然後make會解析文本進行求值的動作(這裏也包含了一次擴展動作,因爲普通的在makefile中的文本也會擴展一次),就好像它是輸入的文本一樣。
eval函數經常用與含有多行文本的宏的展開。一個解析器頂層的宏被擴展成多行文本是不合法的,但是用eval函數可以將展開後的宏直接當做輸入的文本,再展開一次之後就放入數據庫中了。而eval函數本身的展開結果爲空。
注意:定義複雜的宏時要考慮二次展開的問題,然後用eval函數引用這個宏。
用戶自定義函數
可以用define定義一個自定義的宏:
define macor-name
contents
endef
用戶自定義函數是帶有參數的宏,宏定義中的$1
、$2...
是函數的形參,宏的定義就是函數的定義。
調用一個自定義函數的形式是:
$(call
macro-name[,param1 ...]
)
。
call
是一個內置函數,call
擴展它的第一個參數並把其他參數依次替換到宏定義中的$1
、$2...
的地方。macro-name
之後是宏的參數,以逗號隔開。在函數的內部可以使用$0
來訪問函數名。
call
的參數傳遞機制很簡單。調用時可以爲call
指定任意個參數。如果宏定義內引用了$n
,但是調用時並未指定相應的參數,那麼該變量就爲空值。如果call
的參數比宏的$n
引用還多,則被忽略。
注意使用函數是不要隨意加前導空格,否則可能回產生難以排查的錯誤。(但降低了可讀性)