makefile 經常使用函數

Linux下編譯c/c++源碼須要編寫makefile文件,文章參看 
http://blog.sina.com.cn/s/blog_4c4d6e74010009jr.htmlhtml

 

 

在Makefile中可使用函數來處理變量,從而讓咱們的命令或是規則更爲的靈活和具備智能。make所支持的函數也不算不少,不過已經足夠咱們的操做了。函數調用後,函數的返回值能夠當作變量來使用。c++

1、函數的調用語法

函數調用,很像變量的使用,也是以「$」來標識的,其語法以下: 
$(<function> <arguments>) 
或是 
${<function> <arguments>}shell

這裏 function 就是函數名,make支持的函數很少。* arguments*是函數的參數,參數間以逗號「,」分隔,而函數名和參數之間以「空格」分隔。函數調用以「$」開頭,以圓括號或花括號把函數名和參數括起。感受很像一個變量,是否是?函數中的參數可使用變量,爲了風格的統一,函數和變量的括號最好同樣,如使用"$(subst a,b,$(x))"這樣的形式,而不是"$(subst a,b,${x})"的形式。由於統一會更清楚,也會減小一些沒必要要的麻煩。 
仍是來看一個示例:api

comma:= ,
    empty:=
    space:= $(empty) $(empty)
    foo:= a b c
    bar:= $(subst $(space),$(comma),$(foo))
  • 1
  • 2
  • 3
  • 4
  • 5

在這個示例中,$(comma)的值是一個逗號。$(space)使用了$(empty)定義了一個空格,$(foo)的值是"abc"$(bar)的定義用,調用了函數"subst",這是一個替換函數,這個函數有三個參數,第一個參數是被替換字串,第二個參數是替換字串,第三個參數是替換操做做用的字串。這個函數也就是把$(foo)中的空格替換成逗號,因此$(bar)的值是"a,b,c"ssh

2、字符串處理函數

$(subst <from>,<to>,<text>)

名稱:字符串替換函數——subst。
功能:把字串<text>中的<from>字符串替換成<to>。
返回:函數返回被替換事後的字符串。
  • 1
  • 2
  • 3
  • 4
$(subst ee,EE,feet on the street),
  • 1

feet on the street中的「ee」替換成「EE」,返回結果是「fEEt on the strEEt」ide

$(patsubst <pattern>,<replacement>,<text>)

名稱:模式字符串替換函數——patsubst。
功能:查找<text>中的單詞(單詞以「空格」、「Tab」或「回車」「換行」分隔)是否符合模式<pattern>,若是匹配的話,則以<replacement>替換。這裏,<pattern>能夠包括通配符「%」,表示任意長度的字串。若是 <replacement>中也包含「%」,那麼,<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))」是同樣的。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

$(strip <string>)

名稱:去空格函數——strip。
功能:去掉<string>字串中開頭和結尾的空字符。
返回:返回被去掉空格的字符串值。
示例:

    $(strip a b c )
    把字串「a b c 」去到開頭和結尾的空格,結果是「a b c」。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

$(findstring <find>,<in>)

名稱:查找字符串函數——findstring。
功能:在字串<in>中查找<find>字串。
返回:若是找到,那麼返回<find>,不然返回空字符串。
示例:
    $(findstring a,a b c)
    $(findstring a,b c)
    第一個函數返回「a」字符串,第二個返回「」字符串(空字符串)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

$(filter <pattern...>,<text>)

名稱:過濾函數——filter。
功能:以<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」。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

$(filter-out <pattern...>,<text>)

名稱:反過濾函數——filter-out。
功能:以<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」。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

$(sort <list>)

名稱:排序函數——sort。
功能:給字符串<list>中的單詞排序(升序)。
返回:返回排序後的字符串。
示例:$(sort foo bar lose)返回「bar foo lose」 。
備註:sort函數會去掉<list>中相同的單詞。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

$(word <n>,<text>)

名稱:取單詞函數——word。
功能:取字符串<text>中第<n>個單詞。(從一開始)
返回:返回字符串<text>中第<n>個單詞。若是<n>比<text>中的單詞數要大,那麼返回空字符串。
示例:$(word 2, foo bar baz)返回值是「bar」。
  • 1
  • 2
  • 3
  • 4
  • 5

$(wordlist <s>,<e>,<text>)

名稱:取單詞串函數——wordlist。
功能:從字符串<text>中取從<s>開始到<e>的單詞串。<s>和<e>是一個數字。
返回:返回字符串<text>中從<s>到<e>的單詞字串。若是<s>比<text>中的單詞數要大,那麼返回空字符串。若是<e>大於<text>的單詞數,那麼返回從<s>開始,到< text>結束的單詞串。
示例: $(wordlist 2, 3, foo bar baz)返回值是「bar baz」。
  • 1
  • 2
  • 3
  • 4
  • 5

$(words <text>)

名稱:單詞個數統計函數——words。
功能:統計<text>中字符串中的單詞個數。
返回:返回<text>中的單詞數。
示例:$(words, foo bar baz)返回值是「3」。
備註:若是咱們要取<text>中最後的一個單詞,咱們能夠這樣:$(word $(words <text>),<text>)。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

$(firstword <text>)

名稱:首單詞函數——firstword。
功能:取字符串<text>中的第一個單詞。
返回:返回字符串<text>的第一個單詞。
示例:$(firstword foo bar)返回值是「foo」。
備註:這個函數能夠用word函數來實現:$(word 1,<text>)。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

以上,是全部的字符串操做函數,若是搭配混合使用,能夠完成比較複雜的功能。這裏,舉一個現實中應用的例子。咱們知道,make使用「VPATH」變量來指定「依賴文件」的搜索路徑。因而,咱們能夠利用這個搜索路徑來指定編譯器對頭文件的搜索路徑參數CFLAGS,如: 
override CFLAGS += (patsubst(patsubst(subst :, ,(VPATH)))(VPATH)))若是咱們的「(VPATH)」值是「src:../headers」,那麼「(patsubst(patsubst(subst :, ,$(VPATH)))」將返回「-Isrc -I../headers」,這正是cc或gcc搜索頭文件路徑的參數。函數

3、文件名操做函數

下面咱們要介紹的函數主要是處理文件名的。每一個函數的參數字符串都會被當作一個或是一系列的文件名來對待。測試

$(dir <names...>)

名稱:取目錄函數——dir。
功能:從文件名序列<names>中取出目錄部分。目錄部分是指最後一個反斜槓(「/」)以前的部分。若是沒有反斜槓,那麼返回「./」。
返回:返回文件名序列<names>的目錄部分。
示例: $(dir src/foo.c hacks)返回值是「src/ ./」。
  • 1
  • 2
  • 3
  • 4
  • 5

$(notdir <names...>)

名稱:取文件函數——notdir。
功能:從文件名序列<names>中取出非目錄部分。非目錄部分是指最後一個反斜槓(「/」)以後的部分。
返回:返回文件名序列<names>的非目錄部分。
示例: $(notdir src/foo.c hacks)返回值是「foo.c hacks」。
  • 1
  • 2
  • 3
  • 4
  • 5

$(suffix <names...>)

名稱:取後綴函數——suffix。
功能:從文件名序列<names>中取出各個文件名的後綴。
返回:返回文件名序列<names>的後綴序列,若是文件沒有後綴,則返回空字串。
示例:$(suffix src/foo.c src-1.0/bar.c hacks)返回值是「.c .c」。
  • 1
  • 2
  • 3
  • 4
  • 5

$(basename <names...>)

名稱:取前綴函數——basename。
功能:從文件名序列<names>中取出各個文件名的前綴部分。
返回:返回文件名序列<names>的前綴序列,若是文件沒有前綴,則返回空字串。
示例:$(basename src/foo.c src-1.0/bar.c hacks)返回值是「src/foo src-1.0/bar hacks」。
  • 1
  • 2
  • 3
  • 4
  • 5

$(addsuffix <suffix>,<names...>)

名稱:加後綴函數——addsuffix。
功能:把後綴<suffix>加到<names>中的每一個單詞後面。
返回:返回加事後綴的文件名序列。
示例:$(addsuffix .c,foo bar)返回值是「foo.c bar.c」。
  • 1
  • 2
  • 3
  • 4
  • 5

$(addprefix <prefix>,<names...>)

名稱:加前綴函數——addprefix。
功能:把前綴<prefix>加到<names>中的每一個單詞後面。
返回:返回加過前綴的文件名序列。
示例:$(addprefix src/,foo bar)返回值是「src/foo src/bar」。
  • 1
  • 2
  • 3
  • 4
  • 5

$(join <list1>,<list2>)

名稱:鏈接函數——join。
功能:把<list2>中的單詞對應地加到<list1>的單詞後面。若是<list1>的單詞個數要比< list2>的多,那麼,<list1>中的多出來的單詞將保持原樣。若是<list2>的單詞個數要比< list1>多,那麼,<list2>多出來的單詞將被複制到<list2>中。
返回:返回鏈接事後的字符串。
示例:$(join aaa bbb , 111 222 333)返回值是「aaa111 bbb222 333」。
  • 1
  • 2
  • 3
  • 4
  • 5

4、foreach 函數

foreach函數和別的函數很是的不同。由於這個函數是用來作循環用的,Makefile中的foreach函數幾乎是仿照於Unix標準Shell(/bin/sh)中的for語句,或是C-Shell(/bin/csh)中的foreach語句而構建的。它的語法是:this

$(foreach ,,)
  • 1
  • 2

這個函數的意思是,把參數中的單詞逐一取出放到參數所指定的變量中,而後再執行所包含的表達式。每一次會返回一個字符串,循環過程當中,的所返回的每一個字符串會以空格分隔,最後當整個循環結束時,所返回的每一個字符串所組成的整個字符串(以空格分隔)將會是foreach函數的返回值。atom

因此,最好是一個變量名,能夠是一個表達式,而中通常會使用這個參數來依次枚舉中的單詞。舉個例子:

names := a b c d
files := $(foreach n,$(names),$(n).o)
  • 1
  • 2
  • 3

上面的例子中,(name)n(name)中的單詞會被挨個取出,並存到變量「n」中,「(n).o」每次根據「(n)foreach(n)」計算出一個值,這些值以空格分隔,最後做爲foreach函數的返回,因此,(files)的值是「a.o b.o c.o d.o」。

注意,foreach中的參數是一個臨時的局部變量,foreach函數執行完後,參數的變量將不在做用,其做用域只在foreach函數當中。

5、if 函數

if函數很像GNU的make所支持的條件語句——ifeq(參見前面所述的章節),if函數的語法是:

$(if ,)
  • 1
  • 2

或是

$(if ,,)
  • 1
  • 2

可見,if函數能夠包含「else」部分,或是不含。即if函數的參數能夠是兩個,也能夠是三個。參數是if的表達式,若是其返回的爲非空字符串,那麼這個表達式就至關於返回真,因而,會被計算,不然會被計算。

而if函數的返回值是,若是爲真(非空字符串),那個會是整個函數的返回值,若是爲假(空字符串),那麼會是整個函數的返回值,此時若是沒有被定義,那麼,整個函數返回空字串。

因此,和只會有一個被計算。

6、call函數

call函數是惟一一個能夠用來建立新的參數化的函數。你能夠寫一個很是複雜的表達式,這個表達式中,你能夠定義許多參數,而後你能夠用call函數來向這個表達式傳遞參數。其語法是:

$(call ,,,...)
  • 1
  • 2

當make執行這個函數時,參數中的變量,如(1)(1),(2),$(3)等,會被參數,,依次取代。而的返回值就是call函數的返回值。例如:

reverse =  $(1) $(2)
foo = $(call reverse,a,b)
  • 1
  • 2
  • 3

那麼,foo的值就是「a b」。固然,參數的次序是能夠自定義的,不必定是順序的,如:

reverse =  $(2) $(1)
foo = $(call reverse,a,b)
  • 1
  • 2
  • 3

此時的foo的值就是「b a」。


Makefile中的wildcard用法

在Makefile規則中,通配符會被自動展開。但在變量的定義和函數引用時,通配符將失效。這種狀況下若是須要通配符有效,就須要使用函數「wildcard」,它的用法是:(wildcardPATTERN)Makefile使使(wildcardPATTERN…)。在Makefile中,它被展開爲已經存在的、使用空格分開的、匹配此模式的全部文件列表。若是不存在任何符合此模式的文件,函數會忽略模式字符並返回空。須要注意的是:這種狀況下規則中通配符的展開和上一小節匹配通配符的區別。通常咱們可使用「(wildcard *.c)」來獲取工做目錄下的全部的.c文件列表。複雜一些用法;可使用「(patsubst(patsubst(wildcard *.c))」,首先使用「wildcard」函數獲取工做目錄下的.c文件列表;以後將列表中全部文件名的後綴.c替換爲.o。這樣咱們就能夠獲得在當前目錄可生成的.o文件列表。所以在一個目錄下可使用以下內容的Makefile來將工做目錄下的全部的.c文件進行編譯並最後鏈接成爲一個可執行文件:

sample Makefile

objects := (patsubst(patsubst(wildcard *.c))

foo : (objects)ccofoo(objects)cc−ofoo(objects)

這裏咱們使用了make的隱含規則來編譯.c的源文件。對變量的賦值也用到了一個特殊的符號(:=)。

一、wildcard : 擴展通配符 
二、notdir : 去除路徑 
三、patsubst :替換通配符 
例子: 
創建一個測試目錄,在測試目錄下創建一個名爲sub的子目錄 
mkdirtestmkdirtest cd test 
mkdirsubtesta.cb.c2subsa.csb.c2Makefilesrc=mkdirsub在test下,創建a.c和b.c2個文件,在sub目錄下,創建sa.c和sb.c2個文件創建一個簡單的Makefilesrc=(wildcard .c ./sub/.c) 
dir=(notdir(notdir(src)) 
obj=(patsubst(patsubst(dir) ) 
all: 
@echo (src)@echo(src)@echo(dir) 
@echo $(obj) 
@echo 「end」

執行結果分析: 
第一行輸出: 
a.c b.c ./sub/sa.c ./sub/sb.c 
wildcard把 指定目錄 ./ 和 ./sub/ 下的全部後綴是c的文件所有展開。 
第二行輸出: 
a.c b.c sa.c sb.c 
notdir把展開的文件去除掉路徑信息 
第三行輸出: 
a.o b.o sa.o sb.o 
(patsubst(patsubst(dir) )中,patsubst把(dir).c.o使obj=(dir)中的變量符合後綴是.c的所有替換成.o,任何輸出。或者可使用obj=(dir:%.c=%.o) 
效果也是同樣的。 
這裏用到makefile裏的替換引用規則,即用您指定的變量替換另外一個變量。 
它的標準格式是 
(var:a=b)(var:a=b)或{var:a=b} 
它的含義是把變量var中的每個值結尾用b替換掉a

今天在研究makefile時在網上看到一篇文章,介紹了使用函數wildcard獲得指定目錄下全部的C語言源程序文件名的方法,這下好了,不用手工一個一個指定須要編譯的.c文件了,方法以下: 
SRC = (wildcard.c).cincwildcardSRC=(wildcard∗.c)等於指定編譯當前目錄下全部.c文件,若是還有子目錄,好比子目錄爲inc,則再增長一個wildcard函數,象這樣:SRC=(wildcard *.c) (wildcardinc/.c)ASRC=(wildcardinc/∗.c)也能夠指定彙編源程序:ASRC=(wildcard *.S)

http://blog.csdn.net/eddy_liu/article/details/8210804

函數功能:函數「eval」是一個比較特殊的函數。使用它咱們能夠在咱們的Makefile中構造一個可變的規則結構關係(依賴關係鏈),其中可使用其它變量和函數。函數「eval」對它的參數進行展開,展開的結果做爲Makefile的一部分,make能夠對展開內容進行語法解析。展開的結果能夠包含一個新變量、目標、隱含規則或者是明確規則等。也就是說此函數的功能主要是:根據其參數的關係、結構,對它們進行替換展開。 
返回值:函數「eval」的返回值時空,也能夠說沒有返回值。 
函數說明:「eval」函數執行時會對它的參數進行兩次展開。 
第一次展開過程是由函數自己完成的, 
第二次是函數展開後的結果被做爲Makefile內容時由make解析時展開的。 
明確這一點對於使用「eval」函數很是重要。 
在理解了函數「eval」二次展開的過程後。 
實際使用時,當函數的展開結果中存在引用(格式爲:(x)使(x))時,那麼在函數的參數中應該使用「」來代替「」。

由於這一點,因此一般它的參數中會使用函數「value」來取一個變量的文本值。

「It’s important to realize that the eval argument is expanded twice; first by the eval function, then the results of that expansion are expanded again when they are parsed as makefile syntax.」

Take the example from GNU Make for example:

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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

How to understand the twice replace for eval: 
In foreach: 
「eval (callPROGRAMtemplate,server)1sttimereplacement,PROGRAMtemplateisexecutedasshell:server:(callPROGRAMtemplate,server)」1sttimereplacement,‘PROGRAMtemplate′isexecutedasshell:「server:(server_OBJS) $(server_LIBS:%=-l%) 
2nd time replacement, execute as makefile:

server: serverOBJSlserverOBJS−lserver_LIBS

References: 
* GNU make manual: http://www.gnu.org/software/make/manual/make.html#Eval-Function 
http://www.cnblogs.com/hnrainll/archive/2011/04/12/2013377.html 
經常使用函數

addprefix函數: 
addprefix: 
@echo $(addprefix aaaaa, xxx yyy zzz) 
結果 
[root@localhost testMake]# make addprefix 
aaaaaxxx aaaaayyy aaaaazzz

foreach函數:(經常使用於前置條件的 多條件展開) 
list1 = aaa bbb ccc 
dst = (foreachv,(foreachv,(list1), (v).txt)testfor:@echo(v).txt)testfor:@echo(dst) 結果 [root@localhost testMake]# make testfor aaa.txt bbb.txt ccc.txt

相關文章
相關標籤/搜索