Makefile文件(三)_書寫規則

參考原文http://blog.csdn.net/liang13664759/article/details/1771246/bash

Makefile書寫規則包含兩部分,一個是依賴關係,一個是生成目標。在Makefile中,規則的順序很重要,由於Makefile中只有一個最終目標。通常,定義在Makefile中的目標可能會有不少,可是第一條規則中的目標將被確立爲最終目標。若是第一條規則中的目標有多個,那麼第一個目標會成爲最終目標,也就是make所完成的目標。函數

1、規則舉例

foo.o:foo.c defs.h  #foo模塊ui

  cc -c -g foo.cspa

這個規則告訴咱們:文件的依賴關係,還有若是要生成或更新foo.o文件,則cc命令說明如何生成。.net

2、規則的語法

target:prerequisites命令行

  commandcode

...blog

或者:文檔

targets: prerequisites;commandget

  command

...

targets是文件名,空格分開,可使用通配符。通常,咱們的目標基本上是一個文件,但也多是多個文件。

command是命令行,若是其不與「target:prerequisites」在一行上,那麼必須以Tab鍵開頭。若是和prerequisites在一行可用分好做爲分隔。

prerequisites即爲目標所依賴的文件或依賴目標。若是其中的某個文件要比目標文件新,則從新生成。

‘/’表示換行符。make會以UNIX的標準Shell,也就是/bin/sh來執行命令。

3、在規則中設置通配符

make支持三種通配符:‘*’,「?」和「[...]」

"~"字符在文件名中也比較特殊,「~/test」表示當前用戶的$HOME目錄下的test目錄

而「~hchen/test」則表示用戶hchen的宿主目錄下的test目錄

例子:

objects = *.o   表示objects就是「*.o」,並不會展開。

若是要讓通配符在變量中展開,讓objects的值是全部[.o]的文件名的集合,

能夠這樣:objects:=$(wildcard *.o)主要是由關鍵字wildcard控制。

4、文件搜索

當make尋找文件的依賴關係時,能夠在文件前加上路徑,但最好的方法是把一個路徑告訴make,讓make自動尋找。

一、VPATH變量

Makefile文件中的特殊變量「VPATH」就是完成這個功能的,若是沒有指明這個變量,make只會在當前的目錄中去尋找依賴文件和目標。若是定義了VPATH,那麼make會在當前目錄找不到的狀況下,到所指定的目錄中去尋找文件。

VPATH=src:../headers

該定義制定兩個目錄,「src」和「../headers」,make會按照這個順序搜索,目錄由冒號分隔。(當前目錄永遠是最優先搜索的地方

二、vpath關鍵字

另外一個設置是使用make的「vpath」關鍵字(全小寫),這不是變量,是一個make的關鍵字。和上面提到的VPATH相似,但更靈活。能夠制定不一樣的文件在不一樣的目錄中搜索。

使用方法:

①、vpath<pattern><directories> 爲符合模式<patern>的文件制定搜索目錄<directories>

②、vpath<pattern>  清除符合模式<pattern>的文件搜索目錄

③、vpath  清除全部已經設置好的文件搜索目錄

說明:vpath中的<pattern>須要包含「%」,意思是匹配零或若干字符,例如,「%.h」表示全部以「.h」結尾的文件。<pattern>制定了要搜索的文件集,而<directories>則制定了<pattern>的文件集搜索目錄。

例如: vpath %.h  ../headers    表示make在「../headers」目錄下搜索全部以「.h」結尾的文件。

連續使用vpath語句,可制定不一樣搜索策略,若是連續的vpath語句出現了相同的<pattern>,或是被重複了的<pattern>,則make會按照vpath語句的前後順序來執行搜索。

vpath %.c foo

vpath % blish

vpath %.c bar

表示「.c」文件,先在foo目錄,而後是blish,最後是bar目錄。

vpath %.c foo:bar

vpath % blish

上面的語句則表示「.c」文件,先在foo目錄,而後是bar目錄,最後是blish目錄

5、僞目標

如前面的clean文件,並非文件,只是一個標籤。make沒法生成它的依賴關係和決定他是否執行,只能能過顯式指明這個目標纔可以讓其生效。固然,爲目標的取名不能和文件名重名,否則失去僞目標的意義。

聲明.PHONY:clean,表不論是否有「clean」文件,要運行「clean」目標,只有「make clean」。

僞目標通常沒有依賴的文件。可是,也能夠爲僞目標指定所依賴的文件。僞目標一樣能夠做爲「默認目標」。只要將其放在第一個。例如,當Makefile須要一會兒生成若干個可執行文件,可是隻想簡單地一個make命令完事,而且全部的目標文件都寫在一個Makefile中,那麼可使用僞目標這特性:

all: prog1 prog2 prog3

.PHONY : all

prog1:prog1.o utils.o

  cc -o prog1 prog1.o utils.o

prog2:prog2.o 

  cc -o prog2 prog2.o

prog3: prog3.o sort.o utils.o

  cc -o prog3 prog3.o sort.o utils.o

Makefile中的第一個目標會被做爲默認目標。聲明瞭一個「all」僞目標,依賴於其餘三個目標,因爲僞目標的特性是總被執行。因此其依賴於的那三個目標就老是不如all目標新。因此其餘三個目標老是會被執行,也就達到了一會兒生成多個目標的目的。

6、多目標

Makefile的規則中的目標能夠不止一個,支持多目標。有可能咱們的多個目標同時依賴於一個文件,其生成命令大致相似。因而咱們能夠將其合併。自動化變量「$@」,表示目前規則中全部的目標集合

bigoutput littleoutput: text.g

  generate text.g -$(subst output,,$@)>$@

上述規則等價於:

bigoutput: text.g

  generate text.g -big > bigoutput

littleoutput:text.g

  generate text.g -little > littleoutput

其中,-$(subst output,,$@)中的「$」表示執行了一個Makefile的函數,函數名爲subst,後面的爲參數。「$@」表示目標集合,依次取出目標並執行命令。

7、靜態模式

靜態模式能夠更容易地定義多目標的規則,語法:

<target ...>:<target-parttern>:<prereq-patterns ...>

  <command>

...

targets定義了一系列的目標文件,能夠有通配符。

targets-pattern是指明瞭targets的模式,也就是目標集模式

prereq-patterns是目標的依賴模式,對target-pattern造成的模式再進行一次依賴目標的定義。

例子:

objects = foo.o bar.o

all: $(objects)

$(objects) : %.o : %.c

  $(CC) -c $(CFLAGS) $< -o $@

例子,咱們的目標從$object中獲取,「%.o」代表要全部「.o」結尾的目標,也就是「foo.o bar.o」,變量$objects集合的模式,

而依賴模式「%.c」則取模式「%.o」的「%」,也就是「foo bar」,併爲其加上「.c」後綴,因而,依賴目標就是「foo.c bar.c」。

而命令中的「$<」和「$@」自動化變量,「$<」表示全部的依賴目標集(「foo.c bar.c」),「$@」表目標集(「foo.o bar.o」)

因此,上面的規則等價於:

foo.o : foo.c

  $(CC) -c $(CFLAGS) foo.c -o foo.o

bar.o : bar.c

  $(CC) -c $(CFLAGS) bar.c -o bar.o

 

另外一個例子:

files = foo.elc bar.o lose.o

$(filter %.o,$(files)): %.o : %.c

  $(CC) -c $(CFLAGS) $< -o $@

$(filter %.elc,$(files)):%.elc:%el

  emacs -f batch-byte-compile $<

說明:$(filter %.o,$(files))表示調用Makefile的filter函數,過濾「$filter」集,只要其中模式爲「%.o」的內容。

8、自動生成依賴性

cc -M main.c   中的-M選項,自動找尋源文件中包含的頭文件,並生成一個依賴關係。

其輸出是: main.o : main.c defs.h

由於mian.c中包含頭文件defs.h,因而編譯器自動生成依賴關係。若是是GNU的C/C++編譯器,得用「-MM」參數,否則,「-M」參數會把一些標準庫的頭文件也包含進來。

編譯器的功能聯繫進Makefile,GNU建議把編譯器爲每個源文件自動生成的依賴關係放到一個文件中,爲每個「name.c」的文件都生成一個「name.d」的Makefile文件,[.d]文件中就存放對應[.c]文件的依賴關係。因而,能夠寫出[.c]文件和[.d]文件的依賴關係,並讓make自動更新或生成[.d]文件,幷包含在咱們的主Makefile中。

產生[.d]文件的模式規則:

%.d : %.c

  @set -e; rm -f $@;/

  $(CC) -M $(CPFLAGS) $< > $@.;/

  sed 's,/($*/)/.o[ :]*,/1.o $@ : ,g' < $@.> $@; /

  rm -f $@.

@set -e表示告訴bash若是任何語句的執行結果不是true則應該退出。該規則的意思是,全部的[.d]文件依賴於[.c]文件,「rm -f $@」刪除全部目標[.d]文件。下一行是爲每一個依賴文件「$<」,也就是[.c]文件生成依賴文件,「$@」表示模式「%.d」文件,若是有一個C文件是name.c,那麼「%」就是「name」。sed命令,查看文檔。這裏表示整行替換

即把依賴關係mian.o : main.c defs.h  ====>>>轉成: main.o main.d : main.c defs.h

接下來,把自動生成的規則放進主Makefile中,使用Makefile中的「include」引入別的Makefile文件,例如:

sources = foo.c bar.c

include $(sources:.c = .d)

說明:「$(sources:.c=.d)」中的「.c=.d」表示替換,把變量$(sources)全部的[.c]的字串都替換成[.d]。替換也會按照次序來的。

相關文章
相關標籤/搜索