GUN make (3) Makefile的規則

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文件執行規則時對文件路徑保存或廢棄所依據的算法如下:

  1. 如果規則的 目標文件 在makefile文件所在的目錄下不存在,那麼執行目錄搜索。
  2. 如果目錄搜索成功,在指定的目錄下存在此目標的 規則,那麼搜索到的完整的路徑名就被作爲臨時目標文件被保存。
  3. 對於規則中所有的 依賴文件 使用相同的方法處理。
  4. 完成第三步依賴處理後,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

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章