轉自 http://blog.csdn.net/todd911/article/details/42750233shell
當你有一長串文件要制定時,爲了簡化此過程,make提供了通配符(wildcard),此功能也被稱爲文件名模式匹配。makewindows
的通配符如同Bourne shell的~、*、?、[...]和[^...]。舉例來講,*.*會被擴展成文件名中包含點號的全部文件,一個問號表明佈局
任何單一字符,而[...]表明一個字符集。若要取得字符集的補集,則可使用[^...]。測試
此外,「~」符號能夠用來表明當前用戶的主目錄,一個「~」符號以後若跟着用戶的名稱則表明該用戶的主目錄。this
以工做目標充當標籤來表明命令腳本,一般會有些用處。任何不表明文件的工做目標就叫作假想工做目標(phony target)。spa
另外一個標準的假想工做目標稱爲clean:.net
clean:blog
rm -f *.o get
一般,make老是會執行假想工做目標,由於對應於該規則的命令並不會建立以該工做目標爲名稱的文件。io
切記,make沒法區分文件形式的工做目標和假想工做目標,若是當前目錄中恰好出現於假想工做目標同名的文件,make
將會在它的相依圖中創建該文件與假想工做目標的關係。例如,運行make clean時,工做目錄中恰好存在clean這個文件,
那麼將會產生使人困惑的信息:
make clean
make:‘clean’ is up to date.
由於大多數的假想工做目標並未指定必要條件,clean工做目標老是被視爲已經更新,全部相應的命令不會被執行。
爲了不這個問題,GNU make提供了一個特殊的工做目標-----.PHONY,用來告訴make,該工做目標不是一個真正的
文件。當你要聲明假想工做目標時,只要將該工做目標指定成.PHONY的一個必要條件便可:
.PHONY:clean
clean:
rm -f *.o
如今,即便當前目錄中存在名爲clean的文件,make仍是會執行對應於clean的命令。
許多makefile多少都會包含一組標準的假想工做目標,下面列出了這些標準的假想工做目標。
工做目標 功能
all 執行編譯應用程序的全部工做。
install 從已編譯的二進制文件進行應用程序的安裝
clean 將產生自源代碼的二進制文件刪除
distclean 刪除編譯過程當中所產生的任何文件。
TAGS 創建可供編輯其使用的標記表。
info 從Texinfo源代碼來建立GNU info文件。
check 執行與應用程序相關的任何測試。
最簡答的變量具備以下的語法:
${variale-name}
這表明咱們想要擴展名爲variable-name的變量。任何文字均可以包含在變量之中,並且大多數字符均可以用在變量名稱
上。通常來講,必須$()或${}將變量名稱括住,這樣make纔會認得。
一般makefile文件都會定義許多變量,不過其中有許多特殊變量是make自動定義的。這些變量中若干可控制make
的行爲,其他變量則是供make用來跟用戶的makefile文件溝通。
當規則相符時,make會設定自動變量。經過它們,你能夠取用工做目標以及必要條件中的元素,因此你沒必要指明任何文件
名稱。要避免重複,自動變量就至關有用,它們也是定義較通常模式規則中不可少的項目。
下面是7個核心的自動變量:
$@ 工做目標的文件名。 //針對每個目標都適用
$% 檔案文件成員結構中的文件名元素。
$< 第一個必要條件的文件名。
$? 時間戳在工做目標(時間戳)以後的全部必要條件,並以空格隔開這些必要條件。
$^ 全部必要條件的文件名,並以空格隔開這些文件名。這份列表已經刪除重複的文件名,由於對大多數的應用而言,好比
編譯、複製等,並不會用到重複的文件名。
$+ 如同$^,表明全部必要條件的文件名,並以空格隔開這些文件,它包含重複的文件名。此變量會在特殊的情況下被建立,
好比將自動變量傳遞給鏈接器時重複的值是有意義的。
$* 工做目標的主文件名。一個文件名稱是由兩個部分組成:主文件名和擴展名。請不要在模式規則之外使用此變量。
以前的makefile文件:
main:main.o myutil.o
gcc main.o myutil.o -o main
main.o:main.c myutil.h
gcc -c main.c myutil.h
myutil.o:myutil.c myutil.h
gcc -c myutil.c
替換成適當的自動變量後:
main:main.o myutil.o
gcc $^ -o $@
main.o:main.c myutil.h
gcc -c $^
myutil.o:myutil.c myutil.h
gcc -c $^
到目前爲止的例子都很簡單:makefile與全部的源文件都存放在同一目錄下。真實的項目中可能會比較複雜。按源代碼
樹的布局慣例,頭文件會被放到include目錄中,而源文件會被放到src目錄裏,並把makefile放到它們的上層目錄,佈局
以下:
根目錄
|---makefile
|----|include|
| |___myutil.h
|___|src|
|----myutil.c
|__main.c
各文件內容以下:
main.c:
#include <stdio.h>
#include "myutil.h"
int main(void) {
myprint();
return 0;
}
myutil.h:
void myprint();
myutil.c:
#include <stdio.h>
void myprint(void) {
printf("this is myprint function.\n");
}
makefile:
main:main.o myutil.o
gcc $^ -o $@
main.o:main.c myutil.h
gcc -c $^
myutil.o:myutil.c myutil.h
gcc -c $^
執行make的結果以下:
make: *** No rule to make target `main.c', needed by `main.o'. Stop.
由於main.c不在當前目錄,因此make找不到這個源文件,咱們可使用VPATH和vpath來告訴make到不一樣的目錄去查找
源文件,能夠再makefile文件中對VPATH進行以下賦值動做:
VPATH=src include
執行make,依然不行:
gcc -c src/main.c include/myutil.h
src/main.c:2:20: fatal error: myutil.h: No such file or directory
compilation terminated.
make: *** [main.o] Error 1
由於gcc沒法找到引入文件,咱們只要使用正確的-I選項來自定義隱含編譯規則就能夠解決這個問題了:
VPATH=src include
CPPFLAGS=-I include
main:main.o myutil.o
gcc $(CPPFLAGS) $^ -o $@
main.o:main.c myutil.h
gcc $(CPPFLAGS) -c $^
myutil.o:myutil.c myutil.h
gcc $(CPPFLAGS) -c $^
執行make:
gcc -I include -c src/main.c include/myutil.h
gcc -I include -c src/myutil.c
gcc -I include main.o myutil.o -o main
成功編譯。
VPATH變量的內容是一份目錄列表,可供make搜索其所須要的文件。這份目錄列表可用來搜索工做目標以及必要條件,
但不包含腳本中說起的文件。這份目錄列表的分割符在Unix上能夠是空格或冒號,在windows上可使空格或分號。
雖然VPATH變臉能夠解決以上的搜索問題,可是也有限制。make將會爲它所須要的任何文件搜索VPATH列表中的每一個目錄,
若是多個目錄出現同名的文件,則make只會獲取第一個被找到的文件,這可能會形成問題。
此時可使用vpath指令,這個指令的語法以下:
vpath pattern directory-list
全部以前的VPATH變量能夠改寫成:
vpath %.c src
vpath %.h include
如今咱們告訴了make應該在src目錄中搜索.c文件,在include目錄中搜索.h文件。