1. 依賴的類型
GUN make中存在兩種類型的依賴:
常規依賴:依賴文件中任何一個比目標文件新,則認爲規則的目標過期需要重建。
order-only依賴:當order-only依賴中的文件更新時,若目標不存在,則生成目標; 若目標存在,則不更新目標。
常規、order-only依賴書寫規則:
TARGETS:NORMAL-PREREQUISITES | ORDER-ONLY-PREREQUISITES
使用 “ | ”分隔常規依賴和order-only依賴,如果有文件同時出現在兩邊,則算爲常規依賴。
2. 文件名通配符
2.1 通配符類型
makefile中文件名可以使用通配符,有 * , ? , [...]
通配符可以使用以下場合:
- 使用在規則的目標,依賴中, make在讀取makefile時自動對其進行匹配處理(通配符展開)。
- 可出現在規則的命令中,通配處理是在shell執行此命令時完成的。
- 除上述兩種情況之外的其他上下文中,不能直接使用通配符。
2.2 wildcard函數
在規則中,通配符會被自動展開,但在變量定義和函數引用時,通配符將失效。
若此時需要通配符生效,使用wildcard函數:
$(wildcard PATTERN)
在makefile中,它被展開爲已存在的,使用空格分開的,匹配模式的所有文件列表。
比如:
$(wildcard *.c)來獲取工作目錄下的所有.c文件列表。
3. 目錄搜索
3.1 一般搜索(VPATH)
通過變量VPATH可以指定依賴文件的搜索路徑,使用 空格 或在 冒號: 將多個需要搜索的目錄文件分開,搜索順序是按照目錄排列順序進行。
當規則的依賴文件在當前目錄不存在時,make會在此變量所指定的目錄下尋找這些依賴文件。
比如:
VPATH = src:../headers
指定了src 和../headers兩個搜索目錄,對於foo:foo.c ,如果foo.c存在於src目錄下,此規則等價於foo:src:/foo.c
3.2選擇性搜索(vpath)
選擇性搜索可以爲不同的類型文件指定不同的搜索目錄。
vpath中的PATTERN需要包含模式字符%, 其表示匹配一個或多個字符。表示具有相同特徵的一類文件。
DIRECTORIES指定了搜索此類文件目錄。
三種使用方法:
- vpath PATTERN DIRECTORIES
爲所有符合模式PATTERN的文件指定搜索目錄DIRECTORIES,多個目錄使用空格 或者 冒號: 分隔。
- vpath PATTERN
清除之前爲符合模式PATTERN 的文件文件設置的搜索路徑。
- vpath 清除所有已被設置的文件搜索路徑。
比如:
vpath %.h ../headers
表示makefile中出現的.h文件,如果不能在當前目錄下找到,則到目錄../headers 下尋找。
注意,這裏的指定路徑僅限於在makefile文件內容中出現的.h文件,並不能指定源文件中包含的頭文件所在的路徑。在.c源文件中包含的頭文件路徑需要使用gcc的 -I 來指定。
3.3 目錄搜索的機制
make在解析Makefile文件執行規則時對文件路徑保存或廢棄所依據的算法如下:
- 如果規則的 目標文件 在makefile文件所在的目錄下不存在,那麼執行目錄搜索。
- 如果目錄搜索成功,在指定的目錄下存在此目標的 規則,那麼搜索到的完整的路徑名就被作爲臨時目標文件被保存。
- 對於規則中所有的 依賴文件 使用相同的方法處理。
- 完成第三步依賴處理後,make程序就可以決定規則的目標是否需要重建,存在兩種情況:
- 規則的目標不需要重建,規則中的所有文件的完整路徑名有效,已經存在的目標文件所在的目錄不會被改變。
- 規則的目標需要重建,則規則的目標文件會在工作目錄下被重建,而不是在目錄搜索時所得到的目錄。
- 若使用GPATH而不是VPATH指定搜索目錄,則目標在重建時,會在目錄搜索時所得到的目錄中進行重建。
3.4 庫文件和搜索目錄
makefile可以使用 -INAME 對靜態庫.a和動態庫.so進行目錄搜索。
搜索的依賴庫文件名由 .LIBPATTERNS指定,其一般是多個包含模式字符%的字,多個字之間使用空格分開。
按照 .LIBPATTERNS出現的字順序,用NAME逐個代替字的模式字符,得到庫文件名,根據這個庫文件名在搜索目錄下搜索。
默認情況下, .LIBPATTERNS值爲 lib%.so lib%.a ,所以一般先搜索libNAME.so庫,再搜索libNAME.a庫。
4. Makefile中的目標
4.1 僞目標
僞目標使用:
.PHONY:clean //使用.PHONY聲明僞目標clean
clean:
rm *.o temp
僞目標優點:
- 當工作目錄下不存在clean這個文件的時候,輸出make clean時,對應規則一定會執行。但是如果當前工作目錄下存在clean這個文件時,當輸入make clean,由於這個規則沒有依賴文件,所以目標被認爲是最新的而不去執行規則所定義的命令。
- 當一個目標被聲明爲僞目標的時候,make在執行此規則時不會試圖去查找隱含規則來創建它。
4.2 強制目標
強制目標的目標是一個不存在的文件名,並且沒有命令和依賴。
在執行該強制目標時,目標總是被認爲是最新的。因此,如果強制目標作爲依賴,導致該規則一定會執行。
比如:
clean:FORCE //強制目標作爲依賴
rm $(objects)
FORCE: //強制目標(沒有依賴和命令)
4.3 多目標
多目標規則意味着所有的目標具有相同的依賴文件。
多目標使用情況:
aaa bbb:text.g
generate text.g -$(subst output,$@) > $@
等價於:
aaa:text.g
generate text.g -$(subst output,$@) > aaa
bbb:text.g
generate text.g -$(subst output,$@) > bbb
4.4 多規則目標
對於一個多規則的目標,重建此目標的命令只能出現在一個規則中。
如果多個規則同時給出重建此目標的命令,make將使用最後一個規則中所定義的命令。
4.5 靜態模式
靜態模式規則:
規則存在多個目標,並且不同的目標可以根據目標文件的名字來自動構造出依賴文件。並且依賴文件必須是類似的而不是完全相同的。
4.5.1 語法:
TARGETS...:TARGET-PATTERN:PREREQ-PATTERN...
COMMANDS
...
TARGETS列出了此規則的一系列目標文件。
TARGET-PATTERN和PREREQ-PATTERNS說明了如何爲每一個目標文件生成的依賴文件。從目標模式TARGET-PATTERN的目標名字中抽取一部分字符串(稱爲 莖),使用莖代替依賴模式PREREQ-PATTERNS中相應部分來產生對應目標的依賴文件。
比如:
objects=foo.o bar.o
all:$(objects)
$(objects):%o:%c
$(CC) -c $(CFLAGS) $< -o $@
規則中 %o:%c 描述了所有的 .o 文件的依賴文件爲對應的 .c 文件。
對目標foo.o取其莖 foo 代替對應的依賴模式%.c中的模式字符%之後可得到目標的依賴文件foo.c。
上邊的規則描述了以下兩個具體的規則:
foo.o:foo.c
$(CC) -c $(CFLAGS) foo.c -o foo.o
bar.o:bar.c
$(CC) -c $(CFLAGS) bar.c -o bar.o
4.5.2 靜態模式和隱含規則區別
- 隱含規則可以被用在 任何 和它相匹配的目標上。當存在多個隱含規則和目標模式相匹配時,只執行其中一個規則,具體執行哪個取決於定義規則的順序。
- 靜態模式規則只能用在規則中 明確 指出的那些文件的重建過程中。如果一個目標存在兩個規則,則make執行會提示錯誤。
4.6 自動產生依賴
gcc 通過 -M 選項自動尋找源文件中包含的頭文件,並生成文件的依賴。
當不需要依賴關係中考慮標準庫頭文件時,使用 -MM 參數。
比如,main.c中只包含了頭文件def.h,則:
gcc -M main.c
其輸出是:
main.o:main.c def.h