2012年12月3日 星期一

Makefile 語法筆記

自動化變數


$@  工作目標檔名
$<    第一個必要條件的檔名.
$^    所有必要條件的檔名, 並以空格隔開這些檔名. (這份清單已經拿掉重複的檔名)
$*    工作目標的主檔名.


萬用字元

makefile 中所用的萬用字元是 % ,代表所有可能的字串,前後可以接指定的字串來表示某些固定樣式的字串。例如%.c 表示結尾是 .c 的所有字串。因此我們改寫 makefile 如下
CC = gcc
OBJS = a.o b.o c.o

all: test

%.o: %.c
  $(CC) -c -o $@ $<

test: $(OBJS)
  $(CC) -o test &^

特別字元:

@    不要顯示執行的指令。
-      表示即使該行指令出錯,也不會中斷執行。

例:
.PHONY: clean
clean:
    @echo "Clean..."
    -rm *.o 

因為 make 會一行一行將正在執行的 Commands 顯示在螢幕上,但您可以利用 @ 來暫時關閉這個功能。而 make 只要遇到任何錯誤就會中斷執行。但像是在進行 clean 時,也許根本沒有任何檔案可以 clean,因而 rm 會傳回錯誤值,因而導致 make 中斷執行。我們可以利用 - 來關閉錯誤中斷功能,讓 make 不會因而中斷。


目標

這個項目所要建立的檔案,必須以 : 結尾。例:

foo.o: common.h
    gcc -c foo.c 

其中,foo.o 是這個項目要建立的檔案;common.h 是相依性的項目/檔案;而 gcc -c foo.c 則為要產生這個項目所要執行的指令。
make 在編譯時,若發現 target 比較新,也就是 dependencies 都比 target 舊,那麼將不會重新建立 target,如此可以避免不必要的編譯動作。
若該項目並非檔案,則為 fake 項目。如此一來將不會建立 target 檔案。但為了避免 make 有時會無去判斷 target 是否為檔案或 fake 項目,建議利用 .PHONY 來指定該項目為 fake 項目。例:

.PHONY: clean
clean:
    rm *.o

在上例中,若不使用 .PHONY 來指定 clean 為 fake 項目的話,若目錄中同時存在了一個名為 clean 的檔案,則 clean 這個項目將被視為要建立 clean 這個檔案,但 clean 這個項目卻又沒有任何的 dependencies,也因此,clean 項目將永遠被視為 up-to-date,永遠不會被執行。
因為利用了 .PHONY 來指定 clean 為 fake 項目,所以 make 不會去檢查目錄中是否存在了一個名為 clean 的檔案。如此也可以提昇 make 的執行效率。


函數

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

名稱:模式字元串替換函數。
功能:查找<text>中的單詞(單詞以「空格」、「Tab」或「回車」「換行」分隔)是否符合模式< pattern>,如果匹配的話,則以<replacement>替換。這裏,<pattern>可以包括通配符 「%」,表示任意長度的字串。如果<replacement>中也包含「%」,那麼,<replacement>中的這個 「%」將是<pattern>中的那個「%」所代表的字串。(可以用「\」來轉義,以「\%」來表示真實含義的「%」字元)
返回:函數返回被替換過後的字元串。
示例:

filelist = x.c.c bar.c
$(patsubst %.c,%.o,$(filelist))
等於
$(filelist:%.c=%.o)

把字串「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))」是一樣的。


#List all .c file in current directory
filelist = $(wildcard *.c)

    wildcard 使用方法如下,注意的是wildcard裡面的參數就跟我們在命令列用的一樣,用*.c 表示所有.c結尾的檔名,請看上面範例,filelist 等於所有 .c 結尾的檔名,例如 "a.c b.c c.c"。

    VPATH: 設定文件蒐尋目錄

    在一些大的工程中,有大量的源文件,我們通常的做法是把這許多的源文件分類,並存放在不同的目錄中。所以,當 make 需要去找尋文件的依賴關係時,你可以在文件前加上路徑,但最好的方法是把一個路徑告訴 make,讓 make 自動去找。

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

    VPATH=src:../headers

    上面的的定義指定兩個目錄,“src” 和 “../headers”,make 會按照這個順序進行搜索。目錄由“冒號”分隔。(當然,當前目錄永遠是最高優先搜索的地方)

    另一個設置文件搜索路徑的方法是使用 make 的 “vpath” 關鍵字(注意,它是全小寫的),這不是變量,這是一個 make 的關鍵字,這和上面提到的那個 VPATH 變量很類似,但是它更為靈活。它可以指定不同的文件在不同的搜索目錄中。這是一個很靈活的功能。它的使用方法有三種:

    1、vpath <pattern> <directories>
    為符合模式 <pattern> 的文件指定搜索目錄 <directories>。

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

    3、vpath
    清除所有已被設置好了的文件搜索目錄。

    vapth 使用方法中的 <pattern> 需要包含 “%” 字符。“%” 的意思是匹配零或若干字符,(需引用 “%”,使用 “\%")例如,“%.h” 表示所有以 “.h” 結尾的文件。<pattern> 指定了要搜索的文件集,而 <directories> 則指定了 < pattern> 的文件集的搜索的目錄。例如:

    vpath %h ../headers

    該語句表示,要求 make 在 “../headers” 目錄下搜索所有以 “.h” 結尾的文件。(如果某文件在當前目錄沒有找到的話)

    我們可以連續地使用 vpath 語句,以指定不同搜索策略。如果連續的 vpath 語句中出現了相同的 <pattern>,或是被重複了的 <pattern>,那麼,make 會按照 vpath 語句的先後順序來執行搜索。如:

    vpath %.c foo
    vpath %.c blish
    vpath %.c bar

    其表示 “.c” 結尾的文件,先在 “foo” 目錄,然後是 “blish”,最後是 “bar” 目錄。

    vpath %.c foo:bar vpath %.c blish

    而上面的語句則表示 “.c” 結尾的文件,先在 “foo” 目錄,然後是 “bar” 目錄,最後才是 “blish” 目錄。


    參考網址:
    Makefile語法簡介


    沒有留言:

    張貼留言