欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
GNU make中文手冊-第四章:Makefile的規則
GNU make中文手冊-第四章:Makefile的規則作者: hew  發(fā)布日期:2006-3-21   查看數:149  出自: http://www.linuxsky.net
第四章:Makefile的規則

--------------------------------------------------------------------------------

本章我們開(kāi)始討論Makefile的一個(gè)重要內容,Makefile的規則。

Makefile中,規則描述了何種情況下使用什么命令來(lái)重建一個(gè)特定的文件,此文件被稱(chēng)為規則“目標”(通常規則中的目標只有一個(gè))。規則所羅列的其他文件稱(chēng)為“目標”的依賴(lài),而規則中的命令是用來(lái)更新或者創(chuàng )建此規則的目標。

除了makefile的“終極目標”所在的規則以外,其他規則的順序在makefile文件中沒(méi)有意義。“終極目標”就是當沒(méi)有使用make 命令行指定具體目標時(shí),make默認的哪一個(gè)目標。它是makefile文件中第一個(gè)規則的目標。如果在makefile中第一個(gè)規則有多個(gè)目標的話(huà),那 么多個(gè)目標中的第一個(gè)將會(huì )被作為make的“終極目標”。有兩種情況的例外:1. 目標名是以點(diǎn)號“.”開(kāi)始的其后不存在斜線(xiàn)“/”(“./”被認為是當前目錄;“../”被認為是上一級目錄);2. 作為模式規則的目標。此兩種情況的Makefile的第一個(gè)目標都不會(huì )被作為“終極目標”來(lái)對待。

“終極目標”是執行make的唯一目的,其所在的規則作為第一個(gè)規則。而其他的規則是在完成重建“終極目標”的過(guò)程中被連帶出來(lái)的。所以這些目標所在規則在Makefile中的順序無(wú)關(guān)緊要。

因此,我們書(shū)寫(xiě)的makefile的第一個(gè)規則應該就是重建整個(gè)程序或者多個(gè)程序的依賴(lài)關(guān)系和執行命令的描述。

4.1 一個(gè)例子
我們來(lái)看一個(gè)規則的例子:



foo.o : foo.c defs.h # module for twiddling the frobs

cc -c -g foo.c



這是一個(gè)典型的規則??吹竭@個(gè)例子,大家也許能夠說(shuō)出這個(gè)規則的各個(gè)部分之間的關(guān)系。不過(guò)我們還是要把這個(gè)例子拿出來(lái)討論。目的是讓我們更加明確的理解 Makefile的規則。本例第一行中,文件“foo.o”是規則需要重建的文件,而“foo.c”和“defs.h”是重建“foo.o”所要使用的文 件。我們把規則所需要重建的文件稱(chēng)為規則的“目標”(foo.o),而把重新目標所需要的文件稱(chēng)為“目標”的“依賴(lài)”。規則中的第二行“cc -c -g foo.c”就是規則的“命令”。它描述了如何使用規則中的依賴(lài)文件重建目標。

而且,上面的規則告訴我們了兩件事:

1. 如何確定目標文件是否過(guò)期(需要重建目標),過(guò)期是指目標文件不存在或者目標文件“foo.o”在時(shí)間戳上比依賴(lài)文件中的任何一個(gè)“foo.c”或者“defs.h”“老”。

2. 如何重建目標文件“foo.o”。這個(gè)規則中使用cc編譯器。在命令中沒(méi)有明確的使用到依賴(lài)文件“defs.h”。我們假設在源文件“foo.c”中已經(jīng)包含了此頭文件。這也是為什么它作為目標依賴(lài)出現的原因。

4.2 規則語(yǔ)法
通常規則的語(yǔ)法格式如下:



TARGETS : PREREQUISITES

COMMAND

...



或者是這樣:



TARGETS : PREREQUISITES ; COMMAND

COMMAND

...



規則中“TARGETS”可以是空格分開(kāi)的多個(gè)文件名,也可以是一個(gè)標簽(執行清空的“clean”)。“TARGETS”的文件名可以使用通配符,格式 “A(M)”表示檔案文件(Linux下的靜態(tài)庫.a文件)的成員“M”(關(guān)于靜態(tài)庫的重建可參考 第十章 使用make更新靜態(tài)庫文件)。通常規則只有一個(gè)目標文件(建議這么做),偶爾會(huì )在一個(gè)規則中需要多個(gè)目標。

書(shū)寫(xiě)規則是我們需要注意的幾點(diǎn):

1. 規則的命令部分有兩種書(shū)寫(xiě)方式:a. 命令可以和目標:依賴(lài)描述放在同一行。命令在依賴(lài)文件列表后并使用分號(;)和依賴(lài)文件列表分開(kāi)。b. 命令在目標:依賴(lài)的描述的下一行,作為獨立的命令行。當作為獨立的命令行時(shí)此行必須以[Tab]字符開(kāi)始。在Makefile中,在第一個(gè)規則之后出現的 所有以[Tab]字符開(kāi)始的行都會(huì )被當作命令來(lái)處理。

2. Makefile中對“$”有特殊的含義(表示變量或者函數的引用),如果我們的規則如果需要“$”,需要書(shū)寫(xiě)兩個(gè)連續的(“$$”)。

3. 在前邊我們也提到過(guò),Makefile一個(gè)較長(cháng)的行,可以使用反斜線(xiàn)“\”將其書(shū)寫(xiě)到幾個(gè)獨立的物理行上。雖然make對Makefile文本行的最大長(cháng) 度是沒(méi)有限制的,但是還是建議這樣做。不僅書(shū)寫(xiě)方便而且更有利于別人的閱讀(這也是一個(gè)程序員修養的體現)。

一個(gè)規則告訴“make”兩件事:1. 目標在什么情況下已經(jīng)過(guò)期; 2. 在需要重建目標的時(shí)候,怎么樣去重建這個(gè)目標。目標是否過(guò)期是由那些使用空格分開(kāi)的規則的依賴(lài)文件所決定的。當目標文件不存在或者目標文件的最后修改時(shí)間 比依賴(lài)文件中的任何一個(gè)都晚,則目標就會(huì )被創(chuàng )建或者重建。也就是說(shuō)執行規則命令行的前提條件是:1。 目標文件不存在; 2. 存在一個(gè)依賴(lài)的最后修改時(shí)間比目標的最后修改時(shí)間晚。規則的中心思想就是:目標文件的內容是由依賴(lài)文件文件決定,依賴(lài)文件的任何一處改動(dòng),將導致目前已經(jīng) 存在的目標文件的內容過(guò)期。規則的命令為重建目標提供了方法。這些命令運行在系統shell之上。

4.3 依賴(lài)的類(lèi)型
GNU make的規則中可以使用兩種不同類(lèi)型的依賴(lài):1. 在以前章節所提到的規則中使用的是常規依賴(lài),這是我們書(shū)寫(xiě)的Makefile規則中最常用的一種。2. 另外一種在我們書(shū)寫(xiě)Makefile時(shí)不會(huì )經(jīng)常使用,它比較特殊、稱(chēng)之為“order-only”依賴(lài)。一個(gè)規則的常規依賴(lài)(通常是多個(gè)依賴(lài)文件)表明了 兩件事:首先,它決定了重建規則目標所要執行命令的順序;表明在更新這個(gè)規則的目標(執行此規則的命令行)之前必需要按照什么樣的順序、執行那些命令來(lái)重 建這些依賴(lài)文件(對所有依賴(lài)文件的重建,使用明確或者隱含規則。就是說(shuō)對于這樣的規則:A:B C,那么在重建目標A之前,首先需要完成對它的依賴(lài)文件B和C的重建。重建B和C的過(guò)程就是執行Makefile中文件B和C所在的規則)。其次,它確定 了一個(gè)依存關(guān)系;規則中如果依賴(lài)文件的任何一個(gè)比目標文件新,則被認為規則的目標已經(jīng)過(guò)期同時(shí)需要重建目標。

通常,如果規則中依賴(lài)文件中的任何一個(gè)被更新,則規則的目標相應地也應該被更新。

有時(shí),我們需要定義一個(gè)這樣的規則,在更新目標(目標文件已經(jīng)存在)時(shí)只需要根據依賴(lài)文件中的部分來(lái)決定目標是否需要被重建,而不是在依賴(lài)文件的任何一個(gè) 被修改后都重建目標。為了實(shí)現這個(gè)目的,我們需要對依賴(lài)進(jìn)行分類(lèi),一類(lèi)是這些依賴(lài)文件的更新需要對應更新目標文件,另一類(lèi)是這些依賴(lài)的更新不會(huì )導致目標被 重建。第二類(lèi)的依賴(lài)我們就稱(chēng)他為:“order-only”依賴(lài)。在書(shū)寫(xiě)規則時(shí),“order-only”依賴(lài)使用管道符號“|”開(kāi)始,作為目標的一個(gè)依 賴(lài)文件。規則的依賴(lài)列表中管道符號“|”左邊的是常規依賴(lài)文件,所有出現在管道符號右邊的就是“order-only”依賴(lài)。這樣的規則書(shū)寫(xiě)格式如下:



TARGETS : NORMAL-PREREQUISITES | ORDER-ONLY-PREREQUISITES



規則中常規依賴(lài)文件可以是空。允許對一個(gè)目標聲明多行按正確順序依次追加的依賴(lài)。需要注意:規則依賴(lài)文件中如果一個(gè)文件被同時(shí)聲明為常規依賴(lài)和 “order-only”依賴(lài),那么此文件被作為常規依賴(lài)處理(因為常規依賴(lài)所實(shí)現的動(dòng)作是“order-only”依賴(lài)所實(shí)現的動(dòng)作的一個(gè)超集)。



“order-only”依賴(lài)的使用舉例:

LIBS = libtest.a

foo : foo.c | $(LIBS)

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

make在執行這個(gè)規則時(shí),如果目標文件“foo”已經(jīng)存在。當“foo.c”被修改以后,目標“foo”將會(huì )被重建,但是當“libtest.a”被修改以后。將不執行規則的命令來(lái)重建目標“foo”。

就是說(shuō),規則中依賴(lài)文件$(LIBS)只有在目標文件不存在的情況下,才會(huì )參與規則的執行。當目標文件存在時(shí)此依賴(lài)不會(huì )參與規則的執行過(guò)程。

4.4 文件名使用通配符
Maekfile中表示一個(gè)單一的文件名時(shí)可使用通配符??墒褂玫耐ㄅ浞校?#8220;*”、“?”和“[…]”。在Makefile中通配符的用法和含義和 Linux(unix)的Bourne shell完全相同。例如,“*.c”代表了當前工作目錄下所有的以“.c”結尾的文件等。但是在Makefile中這些統配符并不是可以用在任何地方, Makefile中統配符可以出現在以下兩種場(chǎng)合:

1. 可以用在規則的目標、依賴(lài)中,此時(shí)make會(huì )自動(dòng)將其展開(kāi);

2. 可出現在規則的命令中,其展開(kāi)是在shell在執行此命令時(shí)完成。

除這兩種情況之外的其它上下文中,不能直接使用通配符。二是需要通過(guò)函數“wildcard”(可參考 7.3 文件名處理函數 一節)來(lái)實(shí)現。

如果規則中的某一個(gè)文件的文件名包含作為統配符的字符(“*”、“.”字符),在使用文件時(shí)需要對文件名中的統配字符進(jìn)行轉義處理,使用反斜線(xiàn)(\)來(lái)進(jìn) 行通配符的轉義。例如“foo\*bar”,在Makefile中它表示了文件“foo*bar”。Makefile中對一些特殊字符的轉移和B- SHELL以及C語(yǔ)言中的基本上相同。

另外需要注意:在Linux(unix)中,以波浪線(xiàn)“~”開(kāi)始的文件名有特殊含義。

單獨使用它或者其后跟一個(gè)斜線(xiàn)(~/),代表了當前用戶(hù)的宿主目錄。(在shell下可以通過(guò)命令“echo ~(~\)”來(lái)查看)。例如“~/bin”代表“/home/username/bin/”(當前用戶(hù)宿主目錄下的bin目錄)

波浪線(xiàn)之后跟一個(gè)單詞(~word),其代表由這個(gè)“word”所指定的用戶(hù)的宿主目錄。例如“~john/bin”就是代表用戶(hù)john的宿主目錄下的bin目錄。

在一些系統中(像MS-DOS和MS-Windows),用戶(hù)沒(méi)有各自的宿主目錄,此情況下可通過(guò)設置環(huán)境變量“HOME”來(lái)模擬。

4.4.1 統配符使用舉例
本節開(kāi)始已經(jīng)提到過(guò),通配符可被用在規則的命令中,它是在命令被執行時(shí)由shell進(jìn)行處理的。例如Makefile的清空過(guò)程文件規則:



clean:

rm -f *.o



通配符也可以用在規則的依賴(lài)文件名中??纯聪旅孢@個(gè)例子。執行“make print”,執行的結果是打印當前工作目錄下所有的在上一次打印以后被修改過(guò)的“.c”文件。



print: *.c

lpr -p $?

touch print



兩點(diǎn)說(shuō)明:1. 上述的規則中目標“print”時(shí)一個(gè)空目標文件。(不存在一個(gè)這樣的文件,此目標不代表一個(gè)文件,它只是記錄了一個(gè)所要執行的動(dòng)作或者命令。參考 4.8 空目標文件 一節)。2. 自動(dòng)環(huán)變量“$?”用在這里表示依賴(lài)文件列表中被改變過(guò)的所有文件。

變量定義中使用的通配符不會(huì )被展開(kāi)(因此在定義變量不能按照這這種方式,下一小節將會(huì )詳細討論)。如果Makefile有這樣一句:“objects = *.o”。那么變量“objects”的值就是“*.o”,而不是使用空格分開(kāi)的所有.o文件列表。如果需要變量“objects”代表所有的.o文件, 則需要是用函數“wildcard”來(lái)實(shí)現(objects = $(wildcar *.o))。

4.4.2 通配符存在的缺陷
上一小節已經(jīng)提到過(guò)在變量定義時(shí)使用通配符可能會(huì )導致意外的結果。本小節將此詳細地分析和討論。在書(shū)寫(xiě)Makefile時(shí),可能存在這種不正確使用通配符 的方法。這種看似正確的方式產(chǎn)生的結果可能并非你所期望得到的。假如在你的makefile中,期望能夠根據所有的.o文件生成可執行文件“foo”。實(shí) 現如下:



objects = *.o



foo : $(objects)

cc -o foo $(CFLAGS) $(objects)



這里變量“objects”的值是一個(gè)字符串“*.o”。在重建“foo”的規則中對變量“objects”進(jìn)行展開(kāi),目標“foo”的依賴(lài)就是 “*.o”,即所有的.o文件的列表。如果工作目錄下已經(jīng)存在必需的.o文件,那么這些.o文件將成為目標的依賴(lài)文件,目標“foo”將根據規則被重建。

但是如果我們將工作目錄下所有的.o文件刪除,在執行規則時(shí)將會(huì )得到一個(gè)類(lèi)似于“沒(méi)有創(chuàng )建*.o文件的規則” 的錯誤提示。這當然不是我們所期望的結果(可能在出現這個(gè)錯誤時(shí)會(huì )令你感到萬(wàn)分迷惑?。?。為了實(shí)現們的初衷,在對變量進(jìn)行定義的時(shí)需要使用一些高級的技 巧,包括使用“wildcard”函數和實(shí)現字符串的置換。關(guān)于如何實(shí)現字符串的置換,我們將在后續進(jìn)行詳細地討論。

4.4.3 函數wildcard
前邊提到過(guò),在規則中,通配符會(huì )被自動(dòng)展開(kāi)。但在變量的定義和使用函數是,通配符不會(huì )被自動(dòng)的展開(kāi)。這種情況下需要通配符有效,要用到函數 “wildcard”,其用法:$(wildcard PATTERN...) ;在Makefile中,它被展開(kāi)未已經(jīng)存在的、空格分割的、匹配此模式的所有文件列表。如果不存在符合此模式的文件,那么函數會(huì )忽略模式并返回空。需要 注意的是:這種情況下規則中通配符的展開(kāi)和上一小節匹配通配符的區別。

一般我們可以使用“$(wildcard *.c)”來(lái)獲取工作目錄下的所有的.c文件列表。復雜一些用法;可以使用“$(patsubst %.c,%.o,$(wildcard *.c))”,首先使用“wildcard”函數獲取工作目錄下的.c文件列表;之后將列表中所有文件名的后綴.c替換為.o。這樣我們就可以得到在當前 目錄可生成的.o文件列表。因此在一個(gè)目錄下可以使用如下內容的Makefile來(lái)將工作目錄下的所有的.c文件進(jìn)行編譯并最后連接成為一個(gè)可執行文件:



#sample Makefile

objects := $(patsubst %.c,%.o,$(wildcard *.c))



foo : $(objects)

cc -o foo $(objects)



這里我們使用了make的隱含規則來(lái)編譯.c的源文件。對變量的賦值也用到了一個(gè)特殊的符號(:=)。關(guān)于變量定義可參考 5.2 兩種變量定義 一節。函數“patsubst”可參考 7.2 文本處理函數 一節



4.5 目錄搜尋
在一個(gè)較大的工程中,一般會(huì )將源代碼和二進(jìn)制文件(.o文件和可執行文件)安排在不同的目錄來(lái)進(jìn)行區分管理。這種情況下,我們需要使用make提供的目錄 自動(dòng)搜索依賴(lài)文件功能(在指定的若干個(gè)目錄下搜索依賴(lài)文件)。書(shū)寫(xiě)makefile時(shí),指定依賴(lài)文件的搜索目錄。當工程的目錄結構發(fā)生變化時(shí),我們就可以 不更改Makefile的規則,而只更改依賴(lài)文件的搜索目錄。

本節我們將詳細討論在書(shū)寫(xiě)Makefile時(shí)如何使用這一特性。在自己的工程中靈活運用這一特性,將會(huì )起到事半功倍的效果。

4.5.1 一般搜索(變量VPATH)
make可識別一個(gè)特殊變量“VPATH”。通過(guò)變量“VPATH”可以指定依賴(lài)文件的搜索路徑,在規則的依賴(lài)文件在當前目錄不存在時(shí),make會(huì )在此變 量所指定的目錄下去尋找這些依賴(lài)文件。一般我們都是用此變量來(lái)說(shuō)明規則中的依賴(lài)文件的搜索路徑。其實(shí)“VPATH”變量所指定的是Makefile中所有 文件的搜索路徑,包括依賴(lài)文件和目標文件。

變量“VPATH”的定義中,使用空格或者冒號(:)將多個(gè)目錄分開(kāi)。make搜索的目錄順序按照變量“VPATH”定義中順序進(jìn)行(當前目錄永遠是第一搜索目錄)。例如對變量的定義如下:



VPATH = src:../headers



它指定了兩個(gè)搜索目錄,“src”和“../headers”。對于規則“foo:foo.c”如果“foo.c”在“src”目錄下,此時(shí)此規則等價(jià)于“foo:src:/foo.c”。

通過(guò)“VPATH”變量指定的路徑在Makefile中對所有文件有效。當需要為不類(lèi)型的文件指定不同的搜索目錄時(shí),需要使用另外一種方式。下一小節我們將會(huì )討論這種更高級的方式。

4.5.2 選擇性搜索(關(guān)鍵字vpath)
另一個(gè)設置文件搜索路徑的方法是使用make的“vpath”關(guān)鍵字(全小寫(xiě)的)。它不是一個(gè)變量,是一個(gè)make的關(guān)鍵字,它所實(shí)現的功能和上一小節提 到的“VPATH”變量很類(lèi)似,但是它更為靈活。它可以為不同類(lèi)型的文件(由文件名區分)指定不同的搜索目錄。它的使用方法有三種:

1、vpath PATTERN DIRECTORIES

為符合模式“PATTERN”的文件指定搜索目錄“DIRECTORIES”。多個(gè)目錄使用空格或者冒號(:)分開(kāi)。類(lèi)似上一小節的“VPATH”

2、vpath PATTERN

清除之前為符合模式“PATTERN”的文件設置的搜索路徑。

3、vpath

清除所有已被設置的文件搜索路徑。



vapth使用方法中的“PATTERN”需要包含模式字符“%”。“%”意思是匹配一個(gè)或者多個(gè)字符,例如,“%.h”表示所有以“.h”結尾的文件。 如果在“PATTERN”中沒(méi)有包含模式字符“%”而是一個(gè)明確的文件名,就是指出了此文件所在的目錄,我們很少使用這種方式來(lái)為單獨的一個(gè)文件指定搜索 路徑。在“vpath”所指定的模式中我們可以使用反斜杠來(lái)對字符“%”的引用(和其他的特使字符的引用一樣)。

“PATTERN”表示了具有相同特征的一類(lèi)文件,而“DIRECTORIES”則指定了搜索此類(lèi)文件目錄。當規則的依賴(lài)文件列表中出現的文件不能在當前目錄下找到時(shí),make程序將依次在“DIRECTORIES”所描述的目錄下尋找此文件。例如:



vpath %.h ../headers



其含義是:Makefile中出現的.h文件;如果不能在當前目錄下找到,則到目錄“../headers”下尋找。注意:這里指定的路徑僅限于在 Makefile文件內容中出現的.h文件。 并不能指定源文件中包含的頭文件所在的路徑(在.c源文件中所包含的頭文件需要使用GCC的命令行來(lái)說(shuō)明)。

在Makefile中如果連續的多個(gè)vpath語(yǔ)句中使用了相同的“PATTERN”,make就對這些vpath語(yǔ)句一個(gè)一個(gè)進(jìn)行處理,搜索某種模式文 件的目錄將是所有的通過(guò)vpath指定的符合此模式的目錄,其搜索目錄的順序由vpath語(yǔ)句在Makefile出現的先后次序來(lái)決定。多個(gè)具有相同 “PATTERN”的vpath語(yǔ)句之間相互獨立。下邊是兩種方式下,所有的.c文件的查找目錄的順序(不包含工作目錄,對工作目錄的搜索永遠處于最優(yōu)先 地位)比較:

vpath %.c foo

vpath % blish

vpath %.c bar



表示對所有的.c文件,make依次查找目錄:“foo”、blish”、“bar”。

而:

vpath %.c foo:bar

vpath % blish



對于所有的.c文件make將依次查找目錄:“foo”、“bar”、“blish”

4.5.3 目錄搜索的機制
規則中一個(gè)依賴(lài)文件可以通過(guò)目錄搜尋找到(使用前邊提到的一般搜索或者是選擇性搜索任一種),但是有可能此文件的完整路徑名(文件的相對路徑或者絕對路 徑,如:/home/Stallman/foo.c)卻并不是規則中列出的依賴(lài)(規則“foo : foo.c”,在執行搜索后可能得到的依賴(lài)文件為:“../src/foo.c”。目錄“../src”是使用“VPATH”或“vpath”指定的); 因此使用目錄搜索所到的完整的文件路徑名可能需要廢棄。make在解析Makefile文件執行規則時(shí)對文件路徑保存或廢棄所依據的算法如下:

1. 首先,如果規則的目標文件在Makefile文件所在的目錄(工作目錄)下不存在,那么就執行目錄搜尋。

2. 如果目錄搜尋成功,在指定的目錄下存在此規則的目標。那么搜索到的完整的路徑名就被作為臨時(shí)的目標文件被保存。

3. 對于規則中的所有依賴(lài)文件使用相同的方法處理。

4. 完成第三步的依賴(lài)處理后,make程序就可以決定規則的目標是否需要重建,兩種情況時(shí)后續處理如下:

a) 規則的目標不需要重建:那么通過(guò)目錄搜索得到的所有完整的依賴(lài)文件路徑名有效,同樣,規則的目標文件的完整的路徑名同樣有效。就是說(shuō),當規則的目標不需要被重建時(shí),規則中的所有的文件完整的路徑名有效。已經(jīng)存在的目標文件所在的目錄不會(huì )被改變。

b) 規則的目標需要重建:那么通過(guò)目錄搜索所得到的目標文件的完整的路徑名無(wú)效,規則中的目標文件將會(huì )被在工作目錄下重建。就是說(shuō),當規則的目標需要重建時(shí), 規則的目標文件會(huì )在工作目錄下被重建,而不是在目錄搜尋時(shí)所得到的目錄。這里,必須明確:此種情況只有目標文件的完整路徑名失效,依賴(lài)文件的完整路徑名是 不會(huì )失效的。否則將無(wú)法重建目標。

該算法看起來(lái)比較法雜,但它確實(shí)使make實(shí)現了我們所需要的東西。此算法使用純粹的語(yǔ)言描述可能顯得晦澀。本小節后續將使用一個(gè)例子來(lái)說(shuō)明。使大家能夠 對此算法有明確的理解。對于其他版本的make則使用了一種比較簡(jiǎn)單的算法:如果規則的目標文件的完整路徑名存在(通過(guò)目錄搜索可以定位到目標文件),無(wú) 論該目標是否需要重建,都使用搜索到的目標文件完整路徑名。

實(shí)際上,GNU make也可以實(shí)現這種功能。如果需要make在執行時(shí),將目標文件在已存在的目錄存下進(jìn)行重建,我們可以使用“GPATH”變量來(lái)指定這些目標所在的目 錄。“GPATH”變量和“VPATH”變量具有相同的語(yǔ)法格式。make在執行時(shí),如果通過(guò)目錄搜尋得到一個(gè)過(guò)時(shí)的完整的目標文件路徑名,而目標存在的 目錄又出現在“GPATH”變量的定義列表中,則該目標的完整路徑將不廢棄,目標將在該路徑下被重建。

為了更清楚地描述此算法,我們使用一個(gè)例子來(lái)說(shuō)明。存在一個(gè)目錄“prom”,“prom”的子目錄“src”下存在“sum.c”和“memcp.c”兩個(gè)源文件。在“prom”目錄下的Makefile部分內容如下:



LIBS = libtest.a

VPATH = src



libtest.a : sum.o memcp.o

$(AR) $(ARFLAGS) $@ $^



首先,如果在兩個(gè)目錄(“prom”和“src”)都不存在目標“libtest.a”,執行make時(shí)將會(huì )在當前目錄下創(chuàng )建目標文件“libtest.a”。另外;如果“src”目錄下已經(jīng)存在“libtest.a”,以下兩種不同的執行結果:

1) 當它的兩個(gè)依賴(lài)文件“sum.c”和“memcp.c”沒(méi)有被更新的情況下我們執行make,首先make程序會(huì )搜索到目錄“src”下的已經(jīng)存在的目標 “libtest.a”。由于目標“libtest.a”的依賴(lài)文件沒(méi)有發(fā)生變化,所以不會(huì )重建目標。并且目標所在的目錄不會(huì )發(fā)生變化。

2) 當我們修改了文件“sum.c”或者“memcp.c”以后執行make。“libtest.a”和“sum.o”或者“memcp.o”文件將會(huì )被在當 前目錄下創(chuàng )建(目標完整路徑名被廢棄),而不是在“src”目錄下更新這些已經(jīng)存在的文件。此時(shí)在兩個(gè)目錄下(“prom”和“src”)同時(shí)存在文件 “libtest.a”。但只有“prom/libtest.a”是最新的庫文件。

當在上邊的Makefile文件中使用“GPATH”指定目錄時(shí),情況就不一樣了。首先看看怎么使用“GPATH”,改變后的Makefile內容如下:

LIBS = libtest.a

GPATH = src

VPATH = src

LDFLAGS += -L ./. –ltest

…….

……



同樣;當兩個(gè)目錄都不存在目標文件“libtest.a”時(shí),目標將會(huì )在當前目錄(“prom”目錄)下創(chuàng )建。如果“src”目錄下已經(jīng)存在目標文件 “libtest.a”。當其依賴(lài)文件任何一個(gè)被改變以后執行make,目標“libtest.a”將會(huì )被在“src”目錄下被更新(目標完整路徑名不會(huì ) 被廢棄)。

4.5.4 命令行和搜索目錄
make在執行時(shí),通過(guò)目錄搜索得到的目標的依賴(lài)文件可能會(huì )在其它目錄(此時(shí)依賴(lài)文件為文件的完整路徑名),但是已經(jīng)存在的規則命令卻不能發(fā)生變化。因此,書(shū)寫(xiě)命令時(shí)我們必須保證當依賴(lài)文件在其它目錄下被發(fā)現時(shí)規則的命令能夠正確執行。

處理這種問(wèn)題的方式就是使用“自動(dòng)化變量”(可參考 9.5.3 自動(dòng)化變量 一小節),諸如“$^”等。規則命令行中的自動(dòng)化變量“$^”代表所有的是的通過(guò)目錄搜索得到的依賴(lài)文件的完整路徑名(目錄+一般文件名)列表。“$@” 代表規則的目標。所以對于一個(gè)規則我們可以進(jìn)行如下的描述:



foo.o : foo.c

cc -c $(CFLAGS) $^ -o $@



變量“CFLAGS”是編譯.c文件時(shí)GCC的命令行選項,可以在Makefile中給它指定明確的值、也可以使用隱含的定義值。

規則的依賴(lài)文件列表中可以包含頭文件,而在命令行不需要使用這些頭文件(這些頭文件的作用只有在make程序決定目標是否需要重建時(shí)才有意義)。我們可以使用另外一個(gè)變量來(lái)書(shū)代替“$^”,例如:



VPATH = src:../headers

foo.o : foo.c defs.h hack.h

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



自動(dòng)化變量“$<”代表規則中通過(guò)目錄搜索得到的依賴(lài)文件列表的第一個(gè)依賴(lài)文件。關(guān)于自動(dòng)化變量我們在后續有專(zhuān)門(mén)的討論。

4.5.5 隱含規則和搜索目錄
隱含規則同樣會(huì )為依賴(lài)文件搜索通過(guò)變量“VPATH”、或者關(guān)鍵字“vpath”指定的搜索目錄。例如:一個(gè)目標文件“foo.o”在Makefile中 沒(méi)有重建它的明確規則,make會(huì )使用隱含規則來(lái)由已經(jīng)存在的“foo.c”來(lái)重建它。當“foo.c”在當前目錄下不存在時(shí),make將會(huì )進(jìn)行目錄搜 索。如果能夠在一個(gè)可以搜索的目錄中找到此文件,同樣make會(huì )使用隱含規則根據搜索到的文件完整的路徑名去重建目標,編譯這個(gè).c源文件。

隱含規則中的命令行中就是使用自動(dòng)化變量來(lái)解決目錄搜索可能帶來(lái)的問(wèn)題;相應的命令中的文件名都是使用目錄搜索得到的完整的路徑名。(可參考上一小節)

4.5.6 庫文件和搜索目錄
Makefile中程序鏈接的靜態(tài)庫、共享庫同樣也可以有目錄搜索得到。這一特性需要我們在書(shū)規則的依賴(lài)是指定一個(gè)類(lèi)似“-lNNAM”的依賴(lài)文件名(一 個(gè)奇怪的依賴(lài)文件名!一般依賴(lài)文件名應該是一個(gè)普通文件的名字。庫文件的命名也應該是“libNAME.a”而不是所寫(xiě)的“-lNAME”。這是為什么, 熟悉GNU ld的話(huà)我想這就不難理解了,“-lNAME”的表示方式和ld的對庫的引用方式完全一樣,只是我們在書(shū)寫(xiě)Makefile的規則時(shí)使用了這種書(shū)寫(xiě)方式。 因此你不應該感到奇怪)。下邊我們就來(lái)看看這種奇怪的依賴(lài)文件到底是什么。

當規則中依賴(lài)文件列表中存在一個(gè)“-lNAME”形式的文件時(shí)。make將根據“NAME”首先搜索當前系統可提供的共享庫,如果當前系統不能提供這個(gè)共 享庫,則搜索它的靜態(tài)庫(當然你可以在命令行中指定編譯或者連接選項來(lái)指定動(dòng)態(tài)連接還是靜態(tài)連接,這里我們不討論)。來(lái)看一下詳細的過(guò)程。1. make在執行規則時(shí)會(huì )在當前目錄下搜索一個(gè)名字為“libNAME.so”的文件;2. 如果當前工作目錄下不存在這樣一個(gè)文件,則make程序會(huì )繼續搜索使用“VPATH”或者“vpath”指定的搜索目錄。3. 還是不存在,make程序將搜索系統默認目錄,順序是:“/lib”、“/usr/lib”和“PREFIX/lib”(在Linux系統中為 “/usr/local/lib”,其他的系統可能不同)。

如果“libNAME.so”通過(guò)以上的途徑最后還是沒(méi)有找到的話(huà),那么make程序將會(huì )按照以上的搜索順序查找名字為“libNAME.a”的文件。

假設你的系統中存在“/usr/lib/libcurses.a”(不存在“/usr/lib/libcurses.so”)這個(gè)庫文件??匆粋€(gè)例子:



foo : foo.c -lcurses

cc $^ -o $@



上例中,如果文件“foo.c”被修改或者“/usr/lib/libcurses.a”被更新,執行規則時(shí)將使用命令“cc foo.c /usr/lib/libcurses.a -o foo”來(lái)完成目標文件的重建。需要注意的是:如果“/usr/lib/libcurses.a”需要在執行make的時(shí)生成,那么就不能這樣寫(xiě),因為 “-lNAME”只是告訴了鏈接器在生成目標時(shí)需要鏈接那個(gè)庫文件。上例的中的“-lcurses”并沒(méi)有告訴make程序其依賴(lài)的庫文件應該如何重建。 當搜索的所有目錄中不存在庫“libcurses”時(shí)。Make將提示“沒(méi)有規則可以創(chuàng )建目標“foo”需要的目標“-lcurses”。如果在執行 make時(shí),出現這樣的提示信息,你應該明確發(fā)生了什么錯誤,而不要因為錯誤而不知所措。

當規則的依賴(lài)列表中出現了“-lNAME”格式的依賴(lài),默認搜索的文件名為“libNAME.so”和“libNAME.a”,這是由變量 “.LIBPATTERNS”來(lái)指定的。“.LIBPATTERNS”的值一般是多個(gè)包含模式字符(%)的字(一個(gè)不包含空格的字符串),多個(gè)字之間使用 空格分開(kāi)。在規則中出現“-lNAME”格式的的依賴(lài)時(shí),首先使用這里的“NAME”代替變量“.LIBPATTERNS”的第一個(gè)字的模式字符(%)而 得到第一個(gè)庫文件名,根據這個(gè)文件名在搜索目錄下查找,如果能夠找到、就是用這個(gè)文件,否則使用“NAME”代替第二個(gè)字的模式字符,進(jìn)行同樣的查找。默 認情況時(shí),“.LIBPATTERNS”的值為:“lib%.so lib%.a”。這也是默認情況下在規則存在“-lNAME”格式的依賴(lài)時(shí),鏈接生成目標時(shí)使用“libNAME.so”和“libNAME.a”的原 因。

變量“.LIBPATTERNS”就是告訴鏈接器在執行鏈接過(guò)程中對于出現“-LNAME”的文件如何展開(kāi)。當然我們也可以將此變量制空,取消鏈接器對“-lNAME”格式進(jìn)行展開(kāi)。



4.6 Makefile偽目標
本節我們討論一個(gè)Makefile中的一個(gè)重要的特殊目標:偽目標。

偽目標是這樣一個(gè)目標:它不代表一個(gè)真正的文件名,在執行make時(shí)可以指定這個(gè)目標來(lái)執行其所在規則定義的命令,有時(shí)我們也可以將一個(gè)偽目標稱(chēng)為標簽。 使用偽目標有兩點(diǎn)原因:1. 避免在我們的Makefile中定義的只執行命令的的目標(此目標的目的為了執行執行一些列命令,而不需要創(chuàng )建這個(gè)目標)和工作目錄下的實(shí)際文件出現名字 沖突。2. 提高執行make時(shí)的效率,特別是對于一個(gè)大型的工程來(lái)說(shuō),編譯的效率也許你同樣關(guān)心。以下就這兩個(gè)問(wèn)題我們進(jìn)行分析討論:

1. 如果我們需要書(shū)寫(xiě)這樣一個(gè)規則:規則所定義的命令不是去創(chuàng )建目標文件,而是使用make指定具體的目標來(lái)執一些特定的命令。像下邊那樣:

clean:

rm *.o temp



規則中“rm”不是創(chuàng )建文件“clean”的命令,只是刪除當前目錄下的所有.o文件和temp文件。在工作目錄下不存在“clean”這個(gè)文件時(shí),我們輸入“make clean”后,“rm *.o temp”總會(huì )被執行。這是我們的初衷。

但當前工作目錄下存在文件“clean”時(shí)情況就不一樣了,在我們輸入“make clean”時(shí)。規則沒(méi)有依賴(lài)文件,所以目標被認為是最新的而不去執行規則作定義的命令,命令“rm”將不會(huì )被執行。這并不是我們的初衷。為了避免這個(gè)問(wèn) 題,我們可以將目標“clean”明確的聲明為偽目標。將一個(gè)目標聲明為偽目標需要將它作為特殊目標.PHONY”的依賴(lài)。如下:

.PHONY : clean



這樣目標“clean”就是一個(gè)偽目標,無(wú)論當前目錄下是否存在“clean”這個(gè)文件。我們輸入“make clean”之后。“rm”命令都會(huì )被執行。而且,當一個(gè)目標被聲明為偽目標后,make在執行此規則時(shí)不會(huì )試圖去查找隱含規則來(lái)創(chuàng )建這個(gè)目標。這樣也提 高了make的執行效率,同時(shí)我們也不用擔心由于目標和文件名重名而使我們的期望失敗。在書(shū)寫(xiě)偽目標規則時(shí),首先需要聲明目標是一個(gè)偽目標,之后才是偽目 標的規則定義。目標“clean”書(shū)寫(xiě)格式應該如下:



.PHONY: clean

clean:

rm *.o temp



2. 偽目標的另外一使用場(chǎng)合在make的并行和遞歸執行過(guò)程中。此情況下一般存在一個(gè)變量,其定義為所有需要make的子目錄。對多個(gè)目錄進(jìn)行make的實(shí)現方式可以在一個(gè)規則中可以使用shell的循環(huán)來(lái)完成。如下:



SUBDIRS = foo bar baz



subdirs:

for dir in $(SUBDIRS); do \

$(MAKE) -C $$dir; \

done



但這種實(shí)現方法存在以下幾個(gè)問(wèn)題。1. 當子目錄執行make出現錯誤時(shí),make不會(huì )退出。就是說(shuō),在對某一個(gè)目錄執行make失敗以后,會(huì )繼續對其他的目錄進(jìn)行make。在最終執行失敗的情 況下,我們很難根據錯誤的提示定位出具體是是那個(gè)目錄下的Makefile出現錯誤。這給問(wèn)題定位造成了很大的困難。為了避免這樣的問(wèn)題,我們可以在命令 行部分加入錯誤的監測,在命令執行錯誤后make退出。不幸的是,如果在執行make時(shí)使用了“-k”選項,此方式將失效。2. 另外一個(gè)問(wèn)題就是使用這種shell的循環(huán)方式時(shí),沒(méi)有用到make對目錄的并行處理功能,因為規則的命令是一條完整的shell命令,不能被并行的執 行。

我們可以通過(guò)偽目標方式來(lái)克服以上實(shí)現方式所存在的兩個(gè)問(wèn)題。



SUBDIRS = foo bar baz



.PHONY: subdirs $(SUBDIRS)



subdirs: $(SUBDIRS)

$(SUBDIRS):

$(MAKE) -C $@

foo: baz



上邊的實(shí)現中使用了一個(gè)沒(méi)有命令行的規則“foo: baz”,用來(lái)限制子目錄的make順序。此規則的含義時(shí)在處理“foo”目錄之前,需要等待“baz”目錄處理完成。在書(shū)寫(xiě)一個(gè)并行執行make的Makefile時(shí),目錄的處理順序是需要特別注意的。

一般情況下,一個(gè)偽目標不作為一個(gè)另外一個(gè)目標文件的依賴(lài)。這是因為當一個(gè)目標文件的依賴(lài)包含偽目標時(shí),每一次在執行這個(gè)規則時(shí)偽目標所定義的命令都會(huì )被 執行(因為它是規則的依賴(lài),重建規則目標文件時(shí)需要首先重建它的依賴(lài))。當偽目標沒(méi)有作為任何目標(此目標是一個(gè)可被創(chuàng )建或者已存在的文件)的依賴(lài)時(shí),我 們只能通過(guò)make的命令行選項明確指定這個(gè)偽目標,來(lái)執行它所定義的命令。例如我們的“make clean”。

Makefile中,偽目標可以有自己的依賴(lài)。在一個(gè)目錄下如果需要創(chuàng )建多個(gè)可執行程序,我們可以將所有程序的重建規則在一個(gè)Makefile中描述。因 為Makefile中第一個(gè)目標是“終極目標”,約定的做法是使用一個(gè)稱(chēng)為“all”的偽目標來(lái)作為終極目標,它的依賴(lài)文件就是那些需要創(chuàng )建的程序。下邊 就是一個(gè)例子:



#sample 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



執行make時(shí),目標“all”被作為終極目標。為了完成對它的更新,make會(huì )創(chuàng )建(不存在)或者重建(已存在)目標“all”的所有依賴(lài)文件 (prog1、prog2和prog3)。當需要單獨更新某一個(gè)程序時(shí),我們可以通過(guò)make的命令行選項來(lái)明確指定需要重建的程序。(例如: “make prog1”)。

當一個(gè)偽目標作為另外一個(gè)偽目標依賴(lài)時(shí),make將其作為另外一個(gè)偽目標的子例程來(lái)處理(可以這樣理解:其作為另外一個(gè)偽目標的必須執行的部分,就行C語(yǔ)言中的函數調用一樣)。下邊的例子就是這種用法:



.PHONY: cleanall cleanobj cleandiff

cleanall : cleanobj cleandiff

rm program



cleanobj :

rm *.o



cleandiff :

rm *.diff



“cleanobj”和“cleandiff”這兩個(gè)偽目標有點(diǎn)像“子程序”的意思(執行目標“clearall時(shí)會(huì )觸發(fā)它們所定義的命令被執行”)。我 們可以輸入“make cleanall”和“make cleanobj”和“make cleandiff”命令來(lái)達到清除不同種類(lèi)文件的目的。例子首先通過(guò)特殊目標“.PHONY”聲明了多個(gè)偽目標,它們之間使用空各分割,之后才是各個(gè)偽 目標的規則定義。

說(shuō)明:

通常在清除文件的偽目標所定義的命令中“rm”使用選項“–f”(--force)來(lái)防止在缺少刪除文件時(shí)出錯并退出,使“make clean”過(guò)程失敗。也可以在“rm”之前加上“-”來(lái)防止“rm”錯誤退出,這種方式時(shí)make會(huì )提示錯誤信息但不會(huì )退出。為了不看到這些討厭的信 息,需要使用上述的第一種方式。

另外make存在一個(gè)內嵌隱含變量“RM”,它被定義為:“RM = rm –f”。因此在書(shū)寫(xiě)“clean”規則的命令行時(shí)可以使用變量“$(RM)”來(lái)代替“rm”,這樣可以免出現一些不必要的麻煩!這是我們推薦的用法。

4.7 強制目標(沒(méi)有命令或依賴(lài)的規則)
如果一個(gè)規則沒(méi)有命令或者依賴(lài),而且它的目標不是一個(gè)存在的文件名。在執行此規則時(shí),目標總會(huì )被認為是最新的。就是說(shuō):這個(gè)規則一旦被執行,make就認 為它的目標已經(jīng)被更新過(guò)。這樣的目標在作為一個(gè)規則的依賴(lài)時(shí),因為依賴(lài)總被認為被更新過(guò),因此作為依賴(lài)所在的規則定義的命令總會(huì )被執行??匆粋€(gè)例子:



clean: FORCE

rm $(objects)

FORCE:



這個(gè)例子中,目標“FORCE”符合上邊的條件。它作為目標“clean”的依賴(lài)出現,在執行make時(shí),它總被認為被更新過(guò)。所以“clean”所在的規則在被執行時(shí)規則所定義的命令總會(huì )被執行。這樣的一個(gè)目標通常我們將其命名為“FORCE”。

上邊的例子中使用“FORCE”目標的效果和我們指定“clean”為偽目標效果相同。兩種方式相比較,使用“.PHONY”方式更加直觀(guān)高效。這種方式主要用在非GNU版本的make中。

在使用GNU make,盡量避免使用這種方式。在GNU make中我們推薦使用偽目標方式。關(guān)于偽目標可參考3.6 Makefile偽目標 一節

4.8 空目標文件
空目標是偽目標的一個(gè)變種;此目標所在規則執行的目的和偽目標相同——通過(guò)make命令行指定終極目標來(lái)執行規則所定義的命令。和偽目標不同的是:這個(gè)目標可以是一個(gè)存在的文件,一般文件的具體內容我們并不關(guān)心,通常此文件是一個(gè)空文件。

空目標文件只是用來(lái)記錄上一次執行此規則定義命令的時(shí)間。一般在這樣的規則中,命令部分都會(huì )使用“touch”在完成所有命令之后來(lái)更新目標文件的時(shí)間 戳,記錄此規則命令的最后執行時(shí)間。make時(shí)通過(guò)命令行將此目標作為終極目標,當前目錄下如果不存在這個(gè)文件,“touch”會(huì )在第一次執行時(shí)創(chuàng )建一個(gè) 空的文件(命名為空目標文件名)。

通常,一個(gè)空目標文件應該存在一個(gè)或者多個(gè)依賴(lài)文件。將這個(gè)目標作為終極目標,在它所依賴(lài)的文件比它新時(shí),此目標所在規則的命令行將被執行。就是說(shuō),如果空目標的依賴(lài)文件被改變之后,空目標所在規則中定義的命令會(huì )被執行??匆粋€(gè)例子:



print: foo.c bar.c

lpr -p $?

touch print



執行“make print”,當目標“print”的依賴(lài)文件任何一個(gè)被修改之后,命令“lpr –p $?”都會(huì )被執行,打印這個(gè)被修改的文件。關(guān)于自動(dòng)化變量“$?”可參考 9.5.3 自動(dòng)化變量 一小節。

4.9 Makefile的特殊目標
在Makefile中,有一些名字,當它們作為規則的目標出現時(shí),具有特殊含義。它們是一些特殊的目標,GNU make所支持的特殊的目標有:

.PHONY:

目標“.PHONY”的所有的依賴(lài)被作為偽目標。偽目標時(shí)這樣一個(gè)目標:當使用make命令行指定此目標時(shí),這個(gè)目標所在規則定義的命令、無(wú)論目標文件是否存在都會(huì )被無(wú)條件執行。參考 3.6 Makefile偽目標 一節

.SUFFIXES:

特殊目標“SUFFIXES”的所有依賴(lài)指出了一系列在后綴規則中需要檢查的后綴名(就是當前make需要處理的后綴)。參考 9.7 后綴規則 一節

.DEFAULT

Makefile中,目標“.DEFAULT”所在規則定義的命令,被用在重建那些沒(méi)有具體規則的目標(明確規則和隱含規則)。就是說(shuō)一個(gè)文件作為某個(gè)規 則的依賴(lài),但卻不是另外一個(gè)規則的目標時(shí)。Make程序無(wú)法找到重建此文件的規則,此種情況時(shí)就執行“.DEFAULT”所指定的命令。

.PRECIOUS

目標“.PRECIOUS”的所有依賴(lài)文件在make過(guò)程中會(huì )被特殊處理:當命令在執行過(guò)程中被中斷時(shí),make不會(huì )刪除它們(可參考 4.5 中斷make的執行 一節)。而且如果目標的依賴(lài)文件是中間過(guò)程文件,同樣這些文件不會(huì )被刪除。這一點(diǎn)目標“.PRECIOUS”和目標“.SECONDAY”實(shí)現的功能相 同。參考 9.4 make隱含規則鏈 一節

另外,目標“.PRECIOUS”的依賴(lài)文件也可以是一個(gè)模式,例如“%.o”。這樣可以保留有規則創(chuàng )建的中間過(guò)程文件。

.INTERMEDIATE

目標“.INTERMEDIATE”的依賴(lài)文件在make時(shí)被作為中間過(guò)程文件對待。沒(méi)有任何依賴(lài)文件的目標“.INTERMEDIATE”沒(méi)有意義。參考 9.4 make隱含規則鏈 一節

.SECONDARY

目標“.SECONDARY”的依賴(lài)文件被作為中間過(guò)程文件對待。但這些文件不會(huì )被自動(dòng)刪除(可參考 9.4 make隱含規則鏈 一節)

沒(méi)有任何依賴(lài)文件的目標“.SECONDARY”的含義是:將所有的文件作為中間過(guò)程文件(不會(huì )自動(dòng)刪除任何文件)。

.DELETE_ON_ERROR

如果在Makefile中存在特殊目標“.DELETE_ON_ERROR”,make在執行過(guò)程中,如果規則的命令執行錯誤,將刪除已經(jīng)被修改的目標文件。參考 4.4 命令執行的錯誤 一節

.IGNORE

如果給目標“.IGNORE”指定依賴(lài)文件,則忽略創(chuàng )建這個(gè)文件所執行命令的錯誤。給此目標指定命令是沒(méi)有意義的。當此目標沒(méi)有依賴(lài)文件時(shí),將忽略所有命令執行的錯誤。參考 4.4 命令執行的錯誤 一節

.LOW_RESOLUTION_TIME

目標“.LOW_RESOLUTION_TIME”的依賴(lài)文件被make認為是低分辨率時(shí)間戳文件。給目標“.LOW_RESOLUTION_TIME”指定命令是沒(méi)有意義的。

通常文件的時(shí)間輟都是高分辨率的,make在處理依賴(lài)關(guān)系時(shí)、對規則目標-依賴(lài)文件的高分辨率的時(shí)間戳進(jìn)行比較,判斷目標是否過(guò)期。但是在系統中并沒(méi)有提 供一個(gè)修改文件高分辨率時(shí)間輟的機制(方式),因此類(lèi)似“cp -p”這樣的命令在根據源文件創(chuàng )建目的文件時(shí),所產(chǎn)生的目的文件的高分辨率時(shí)間輟的細粒度部分被丟棄(來(lái)源于源文件)??赡軙?huì )造成目的文件的時(shí)間戳和源文 件的相等甚至不及源文件新。處理此類(lèi)命令創(chuàng )建的文件時(shí),需要將命令創(chuàng )建的文件作為目標“.LOW_RESOLUTION_TIME”的依賴(lài),聲明這個(gè)文件 是一個(gè)低分辨率時(shí)間輟的文件。例如:



.LOW_RESOLUTION_TIME: dst

dst: src

cp -p src dst



首先規則的命令“cp –p src dst”,所創(chuàng )建的文件“dst”在時(shí)間戳上稍稍比“src”晚(因為命令不能更新文件“dst”的細粒度時(shí)間)。因此make在判斷文件依賴(lài)關(guān)系時(shí)會(huì )出 現誤判,將文件作為目標“.LOW_RESOLUTION_TIME”的依賴(lài)后,只要規則中目標和依賴(lài)文件的時(shí)間戳中的初始時(shí)間相等,就認為目標已經(jīng)過(guò) 期。這個(gè)特殊的目標主要作用是,彌補系統在沒(méi)有提供修改文件高分辨率時(shí)間戳機制的情況下,某些命令在make中的一些缺陷。

對于靜態(tài)庫文件(文檔文件)成員的更新也存在這個(gè)問(wèn)題。make在創(chuàng )建或者更新靜態(tài)庫時(shí),會(huì )自動(dòng)將靜態(tài)庫的所有成員作為目標“.LOW_RESOLUTION_TIME”的依賴(lài)。

.SILENT

出現在目標“.SILENT”的依賴(lài)列表中的文件,make在創(chuàng )建這些文件時(shí),不打印出重建此文件所執行的命令。同樣,給目標“.SILENT”指定命令行是沒(méi)有意義的。

沒(méi)有任何依賴(lài)文件的目標“.SILENT”告訴make在執行過(guò)程中不打印任何執行的命令?,F行版本make支持目標“.SILENT”的這種功能和用法 是為了和舊版本的兼容。在當前版本中如果需要禁命令執行過(guò)程的打印,可以使用make的命令行參數“-s”或者“--silent”。參考 8.7 make的命令行選項 一節



.EXPORT_ALL_VARIABLES

此目標應該作為一個(gè)簡(jiǎn)單的沒(méi)有依賴(lài)的目標,它的功能含義是將之后所有的變量傳遞給子make進(jìn)程。參考 4.6 make的遞歸執行 一節

.NOTPARALLEL

Makefile中,如果出現目標“.NOPARALLEL”,則所有命令按照串行方式執行,即使存在make的命令行參數“-j”。但在遞歸調用的字make進(jìn)程中,命令可以并行執行。此目標不應該有依賴(lài)文件,所有出現的依賴(lài)文件將被忽略。

所有定義的隱含規則后綴作為目標出現時(shí),都被視為一個(gè)特殊目標,兩個(gè)后綴串聯(lián)起來(lái)也是如此,例如“.c.o”。這樣的目標被稱(chēng)為后綴規則的目標,這種定義 方式是已經(jīng)過(guò)時(shí)的定義隱含規則的方法(目前,這種方式還被用在很多地方)。原則上,如果將其分為兩個(gè)部分、并將它們加到后綴列表中,任何目標都可采用這種 方式來(lái)表示。實(shí)際中,后綴通常以“.”開(kāi)始,因此,以上的這些特別目標同樣是以“.”開(kāi)始??蓞⒖?9.7 后綴規則 一節



4.10 多目標
一個(gè)規則中可以有多個(gè)目標,規則所定義的命令對所有的目標有效。一個(gè)具有多目標的規則相當于多個(gè)規則。規則中命令對不同的目標的執行效果不同,因為在規則的命令中可能使用自動(dòng)環(huán)變量“$@”。多目標規則意味著(zhù)所有的目標具有相同的依賴(lài)文件。多目標通常用在以下兩種情況:

Ø 僅需要一個(gè)描述依賴(lài)關(guān)系的規則,而不需要在規則中定義命令。例如

kbd.o command.o files.o: command.h



這個(gè)規則實(shí)現了給同時(shí)給三個(gè)目標文件指定一個(gè)依賴(lài)文件。

² 對于多個(gè)具有類(lèi)似重建命令的目標。重建這些目標的命令并不需要是絕對相同,因為我們可以在命令行中使用make的自動(dòng)環(huán)變量“$@”來(lái)引用具體一個(gè)目標,并完成對它的重建(可參考 9.5.3 自動(dòng)化變量 一小節)。例如規則:



bigoutput littleoutput : text.g

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

其等價(jià)于:



bigoutput : text.g

generate text.g -big > bigoutput

littleoutput : text.g

generate text.g -little > littleoutput



例子中的“generate”根據命令行參數來(lái)決定輸出文件的類(lèi)型。使用了make的字符串處理函數“subst”來(lái)根據目標產(chǎn)生對應的命令行選項。

雖然在多目標的規則中,可以根據不同的目標使用不同的命令(在命令行中使用自動(dòng)化變量“$@”)。但是,多目標的規則并不能做到根據目標文件自動(dòng)改變依賴(lài) 文件,就像我們在上邊例子中使用自動(dòng)化變量“$@”來(lái)改變規則的命令一樣。需要實(shí)現這個(gè)目的是,要用到make的靜態(tài)模式。



4.11多規則目標
Makefile中,一個(gè)文件可以作為多個(gè)規則的目標出現。這種情況時(shí),此目標文件的所有依賴(lài)文件將會(huì )被合并成此目標一個(gè)依賴(lài)文件列表,其中任何一個(gè)依賴(lài)文件比目標更新(比較目標文件和依賴(lài)文件的時(shí)間戳)時(shí),make將會(huì )執行特定的命令來(lái)重建這個(gè)目標。

對于一個(gè)多規則的目標,重建此目標的命令只能出現在一個(gè)規則中(可以是多條命令)。如果多個(gè)規則同時(shí)給出重建此目標的命令,make將使用最后一個(gè)規則所 以的命令,同時(shí)提示錯誤信息(一個(gè)特殊的例外是:使用“.”開(kāi)頭的多規則目標文件,可以在多個(gè)規則中給出多個(gè)重建命令。這種方式只是為了和其他版本 make進(jìn)行兼容,一般在GNU make中應該避免使用這個(gè)功能)。某些情況下,需要對相同的目標使用不同的規則中所定義的命令,這種情況我們可使用另外一種方式“雙冒號”規則來(lái)實(shí)現。

一個(gè)僅僅描述依賴(lài)關(guān)系的描述規則可用來(lái)給出一個(gè)或做多個(gè)目標文件的依賴(lài)文件。例如,Makefile中通常存在一個(gè)變量,就像以前我們提到的 “objects”,它定義為所有的需要編譯生成的.o文件的列表。當這些.o文件在其源文件所包含的頭文件“config.h”發(fā)生變化之后能夠自動(dòng)的 被重建,我們可以使用多目標像下邊那樣來(lái)書(shū)寫(xiě)我們的Makefile:





objects = foo.o bar.o

foo.o : defs.h

bar.o : defs.h test.h

$(objects) : config.h



這樣做的好處是:我們可以在源文件中增加或者刪除了包含的頭文件以后不用修改已經(jīng)存在的Makefile的規則,只需要增加或者刪除某一個(gè).o文件依賴(lài)的 頭文件。這種方式很簡(jiǎn)單也很方便。對于一個(gè)大的工程來(lái)說(shuō),這樣做的好處是顯而易見(jiàn)的。在一個(gè)大的工程中,對于一個(gè)單獨目錄下的.o文件的依賴(lài)規則建議使用 此方式。規則中頭文件的依賴(lài)描述也可以使用GCC自動(dòng)產(chǎn)生??蓞⒖?3.14 自動(dòng)產(chǎn)生依賴(lài) 一節

另外,我們也可以通過(guò)一個(gè)變量來(lái)增加目標的依賴(lài)文件,使用make的命令行來(lái)指定某一個(gè)目標的依賴(lài)頭文件,例如:



extradeps=

$(objects) : $(extradeps)



它的意思是:如果我們執行“make extradeps=foo.h”那么“foo.h”將作為所有的.o文件的依賴(lài)文件。當然我們只執行“make”的話(huà),就沒(méi)有指定任何文件作為.o文件的依賴(lài)文件。

在多規則的目標中,如果目標的任何一個(gè)規則沒(méi)有定義重建此目標的命令,make將會(huì )尋找一個(gè)合適的隱含規則來(lái)重建此目標。關(guān)于隱含規則可參考 第九章 make的隱含規則



4.12 靜態(tài)模式
靜態(tài)模式規則是這樣一個(gè)規則:規則存在多個(gè)目標,并且不同的目標可以根據目標文件的名字來(lái)自動(dòng)構造出依賴(lài)文件。靜態(tài)模式規則比多目標規則更通用,它不需要多個(gè)目標具有相同的依賴(lài)。但是靜態(tài)模式規則中的依賴(lài)文件必須是相類(lèi)似的而不是完全相同的。

4.12.1 靜態(tài)模式規則的語(yǔ)法
首先,我們來(lái)看一下靜態(tài)模式規則的基本語(yǔ)法:





TARGETS ...: TARGET-PATTERN: PREREQ-PATTERNS ...

COMMANDS

...



“TAGETS”列出了此規則的一系列目標文件。像普通規則的目標一樣可以包含通配符。關(guān)于通配符的使用可參考 3.4 文件名使用通配符 一節

“TAGET-PATTERN”和“PREREQ-PATTERNS”說(shuō)明了如何為每一個(gè)目標文件生成依賴(lài)文件。從目標模式(TAGET- PATTERN)的目標名字中抽取一部分字符串(稱(chēng)為“莖”)。使用“莖”替代依賴(lài)模式(PREREQ-PATTERNS)中的相應部分來(lái)產(chǎn)生對應目標的 依賴(lài)文件。下邊詳細說(shuō)明這一替代的過(guò)程。

首先在目標模式和依賴(lài)模式中,一般需要包含模式字符“%”。在目標模式(TAGET-PATTERN)中“%”可以匹配目標文件的任何部分,模式字符 “%”匹配的部分就是“莖”。目標文件和目標模式的其余部分必須精確的匹配??匆粋€(gè)例子:目標“foo.o”符合模式“%.o”,其“莖”為“foo”。 而目標“foo.c”和“foo.out”就不符合此目標模式。

每一個(gè)目標的依賴(lài)文件是使用此目標的“莖”代替依賴(lài)模式(PREREQ-PATTERNS)中的模式字符“%”而得到。例如:上邊的例子中依賴(lài)模式 (PREREQ-PATTERNS)為“%.c”,那么使用“莖”“foo”替代依賴(lài)模式中的“%”得到的依賴(lài)文件就是“foo.c”。需要明確的一點(diǎn) 是:在模式規則的依賴(lài)列表中使用不包含模式字符“%”也是合法的。代表這個(gè)文件是所有目標的依賴(lài)文件。

在模式規則中字符‘%’可以用前面加反斜杠“\”方法引用。引用“%”的反斜杠也可以由更多的反斜杠引用。引用“%”、“\”的反斜杠在和文件名比較或由 “莖”代替它之前會(huì )從模式中被刪除。反斜杠不會(huì )因為引用“%”而混亂。如,模式“the\%weird\\%pattern\\”是“the%weird \”+“%”+“pattern\\”構成。最后的兩個(gè)反斜杠由于沒(méi)有任何轉義引用“%”所以保持不變。

我們來(lái)看一個(gè)例子,它根據相應的.c文件來(lái)編譯生成“foo.o”和“bar.o”文件:

objects = foo.o bar.o



all: $(objects)



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

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



例子中,規則描述了所有的.o文件的依賴(lài)文件為對應的.c文件,對于目標“foo.o”,取其莖“foo”替代對應的依賴(lài)模式“%.c”中的模式字符 “%”之后可得到目標的依賴(lài)文件“foo.c”。這就是目標“foo.o”的依賴(lài)關(guān)系“foo.o: foo.c”,規則的命令行描述了如何完成由“foo.c”編譯生成目標“foo.o”。命令行中“$<”和“$@”是自動(dòng)化變量,“$<” 表示規則中的第一個(gè)依賴(lài)文件,“$@”表示規則中的目標文件(可參考 3.14 自動(dòng)產(chǎn)生依賴(lài) 一節)。以上的規則就是描述了以下兩個(gè)具體的規則:



foo.o : foo.c

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

bar.o : bar.c

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



在使用靜態(tài)模式規則時(shí),指定的目標必須和目標模式相匹配,否則在執行make時(shí)將會(huì )得到一個(gè)錯誤提示。如果存在一個(gè)文件列表,其中一部分符合某一種模式而 另外一部分符合另外一種模式,這種情況下我們可以使用“filter”函數(可參考 第七章 make的內嵌函數)來(lái)對這個(gè)文件列表進(jìn)行分類(lèi),在分類(lèi)之后對確定的某一類(lèi)使用模式規則。例如:



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))的結果為“bar.o lose.o”。“filter”函數過(guò)濾不符合“%.o”模式的文件名而至返回所有符合此模式的文件列表。第一條靜態(tài)模式規則描述了這些目標文件是通過(guò) 編譯對應的.c源文件來(lái)重建的。同樣第二條規則也是使用這種方式。

我們通過(guò)另外一個(gè)例子來(lái)看一下自動(dòng)環(huán)變量“$*”在靜態(tài)模式規則中的使用方法:



bigoutput littleoutput : %output : text.g

generate text.g -$* > $@



當執行此規則的命令時(shí),自動(dòng)環(huán)變量“$*”被展開(kāi)為“莖”。在這里就是“big”和“little”。

靜態(tài)模式規則在一個(gè)較大的工程中非常有用的。它可以對一個(gè)工程中的同類(lèi)文件的重建規則進(jìn)行一次定義,而實(shí)現對整個(gè)工程中此類(lèi)文件指定相同的重建規則。比 如,可以用來(lái)描述整個(gè)工程中所有的.o文件的依賴(lài)規則和編譯命令。通常的做法是將生成同一類(lèi)目標的模式定義在一個(gè)make.rules的文件中。在工程各 個(gè)模塊的Makefile中包含此文件。

4.12.2 靜態(tài)模式和隱含規則
在Makefile中,靜態(tài)模式規則和被定義為隱含規則的模式規則都是我們經(jīng)常使用的兩種方式。兩者相同的地方都是用目標模式和依賴(lài)模式來(lái)構建目標的規則中的文件依賴(lài)關(guān)系,兩者不同的地方是make在執行時(shí)使用它們的時(shí)機。

隱含規則可被用在任何和它相匹配的目標上,在Makefile中沒(méi)有為這個(gè)目標指定具體的規則、存在規則但規則沒(méi)有命令行或者這個(gè)目標的依賴(lài)文件可被搜尋到。當存在多個(gè)隱含規則和目標模式相匹配時(shí),只執行其中的一個(gè)規則。具體執行哪一個(gè)規則取決于定義規則的順序。

相反的,靜態(tài)模式規則只能用在規則中明確指出的那些文件的重建過(guò)程中。不能用在除此之外的任何文件的重建過(guò)程中,并且它對指定的每一個(gè)目標來(lái)說(shuō)是唯一的。如果一個(gè)目標存在于兩個(gè)規則,并且每一個(gè)規則中都定以了命令,make執行時(shí)就會(huì )提示錯誤。

靜態(tài)模式規則相比隱含模式規則由以下兩個(gè)優(yōu)點(diǎn):

² 不能根據文件名通過(guò)詞法分析進(jìn)行分類(lèi)的文件,我們可以明確列出這些文件,并使用靜態(tài)模式規則來(lái)重建其隱含規則。

² 對于無(wú)法確定工作目錄內容,而且不能確定是否此目錄下的無(wú)關(guān)文件會(huì )使用錯誤的隱含規則而導致make失敗的情況。當存在多個(gè)適合此文件的隱含規則時(shí),使用 哪一個(gè)隱含規則取決于其規則的定義順序。這種情況下我們使用靜態(tài)模式規則就可以避免這些不確定因素,因為靜態(tài)模式中,指定的目標文件有特定的規則來(lái)描述其 依賴(lài)關(guān)系和重建命令。

4.13 雙冒號規則
雙冒號規則就是使用“::”代替普通規則的“:”得到的規則。當同一個(gè)文件作為多個(gè)規則的目標時(shí),雙冒號規則的處理和普通規則的處理過(guò)程完全不同(雙冒號規則允許在多個(gè)規則中為同一個(gè)目標指定不同的重建目標的命令)。

首先需要明確的是:Makefile中,一個(gè)目標可以出現在多個(gè)規則中。但是這些規則必須是同一種規則,要么都是普通規則,要么都是雙冒號規則。而不允許一個(gè)目標同時(shí)出現在兩種不同的規則中。雙冒號規則和普通規則的處理的不同點(diǎn)表現在以下幾個(gè)方面:

1. 雙冒號規則中,當依賴(lài)文件比目標更新時(shí)。規則將會(huì )被執行。對于一個(gè)沒(méi)有依賴(lài)而只有命令行的雙冒號規則,當引用此目標時(shí),規則的命令將會(huì )被無(wú)條件執行。而普通規則,當規則的目標文件存在時(shí),此規則的命令永遠不會(huì )被執行(目標文件永遠是最新的)。

2. 當同一個(gè)文件作為多個(gè)雙冒號規則的目標時(shí)。這些不同的規則會(huì )被獨立的處理,而不是像普通規則那樣合并所有的依賴(lài)到一個(gè)目標文件。這就意味著(zhù)對這些規則的處 理就像多個(gè)不同的普通規則一樣。就是說(shuō)多個(gè)雙冒號規則中的每一個(gè)的依賴(lài)文件被改變之后,make只執行此規則定義的命令,而其它的以這個(gè)文件作為目標的雙 冒號規則將不會(huì )被執行。

我們來(lái)看一個(gè)例子,在我們的Makefile中包含以下兩個(gè)規則:



Newprog :: foo.c

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

Newprog :: bar.c

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



如果“foo.c”文件被修改,執行make以后將根據“foo.c”文件重建目標“Newprog”。而如果“bar.c”被修改那么 “Newprog”將根據“bar.c”被重建?;叵胍幌?,如果以上兩個(gè)規則為普通規時(shí)出現的情況是什么?(make將會(huì )出錯并提示錯誤信息)

當同一個(gè)目標出現在多個(gè)雙冒號規則中時(shí),規則的執行順序和普通規則的執行順序一樣,按照其在Makefile中的書(shū)寫(xiě)順序執行。

GNU make的雙冒號規則給我們提供一種根據依賴(lài)的更新情況而執行不同的命令來(lái)重建同一目標的機制。一般這種需要的情況很少,所以雙冒號規則的使用比較罕見(jiàn)。一般雙冒號規則都需要定義命令,如果一個(gè)雙冒號規則沒(méi)有定義命令,在執行規則時(shí)將為其目標自動(dòng)查找隱含規則。

4.14 自動(dòng)產(chǎn)生依賴(lài)
Makefile中,可能需要書(shū)寫(xiě)一些規則來(lái)描述一個(gè).o目標文件和頭文件的依賴(lài)關(guān)系。例如,如果在main.c中使用“#include defs.h”,那么我們可能需要如下那樣的一個(gè)規則來(lái)描述當頭文件“defs.h”被修改以后執行make,目標“main.o”應該被重建。



main.o: defs.h



這樣,在一個(gè)比較大型的工程中。就需要在Makefile中書(shū)寫(xiě)很多條類(lèi)似于這樣的規則。并且,當在源文件中加入或刪除頭文件后,也需要小心地去修改 Makefile。這是一件很費力、也很費時(shí)并且容易出錯誤的工作。為了避免這個(gè)令人討厭的問(wèn)題,現代的c編譯器提供了通過(guò)查找源文件中的 “#include”來(lái)自動(dòng)產(chǎn)生這種依賴(lài)的功能。“GCC”支持一個(gè)“-M”的選項來(lái)實(shí)現此功能。“GCC”將自動(dòng)找尋源文件中包含的頭文件,并生成一個(gè) 依賴(lài)關(guān)系。例如,如果“main.c”只包含了頭文件“defs.h”,那么在Linxu下執行下面的命令:



gcc -M main.c



其輸出是:



main.o : main.c defs.h



既然編譯器已經(jīng)提供了自動(dòng)產(chǎn)生依賴(lài)關(guān)系的功能,那么我們就不需要去動(dòng)手寫(xiě)這些規則的依賴(lài)關(guān)系了。但是需要明確的是:在“main.c”中包含了其他的標準 庫的頭文件,其輸出的依賴(lài)關(guān)系中也包含了標準庫的頭文件。當不需要依賴(lài)關(guān)系中不考慮標準庫頭文件時(shí),需要使用“-MM”參數。

需要注意的是,在使用“GCC”自動(dòng)產(chǎn)生依賴(lài)關(guān)系時(shí),所產(chǎn)生的規則中明確的指明了目標是“main.o”文件。一次在通過(guò).c文件直接產(chǎn)生可執行文件時(shí),作為過(guò)程文件的“main.o”的中間過(guò)程文件在使用完之后將不會(huì )被刪除。

在舊版本的make中,使用編譯器此項功能通常的做法是:在Makefile中書(shū)寫(xiě)一個(gè)偽目標“depend”的規則來(lái)定義自動(dòng)產(chǎn)生依賴(lài)關(guān)系文件的命令。 輸入“make depend”將生成一個(gè)稱(chēng)為“depend”的文件,其中包含了所有源文件的依賴(lài)規則描述。Makefile使用“include”指示符包含這個(gè)文 件。

在新版本的make中,推薦的方式是為每一個(gè)源文件產(chǎn)生一個(gè)描述其依賴(lài)關(guān)系的makefile文件。對于一個(gè)源文件“NAME.c”,對應的這個(gè) makefile文件為“NAME.d”。“NAME.d”中描述了文件“NAME.o”所要依賴(lài)的所有頭文件。采用這種方式,只有源文件在修改之后才會(huì ) 重新使用命令生成新的依賴(lài)關(guān)系描述文件“NAME.o”。

我們可以使用如下的模式規則來(lái)自動(dòng)生成每一個(gè).c文件對應的.d文件:



%.d: %.c

$(CC) -M $(CPPFLAGS) $< > $@.$$$$; \

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

rm -f $@.$$$$



此規則的含義是:所有的.d文件依賴(lài)于同名的.c文件。

第一行;使用c編譯器自自動(dòng)生成依賴(lài)文件($<)的頭文件的依賴(lài)關(guān)系,并輸出成為一個(gè)臨時(shí)文件,“$$$$”表示當前進(jìn)程號。如果$(CC)為 GNU的C編譯工具,產(chǎn)生的依賴(lài)關(guān)系的規則中,依賴(lài)頭文件包括了所有的使用的系統頭文件和用戶(hù)定義的頭文件。如果需要生成的依賴(lài)描述文件不包含系統頭文 件,可使用“-MM”代替“-M”。

第二行;使用sed處理第二行已產(chǎn)生的那個(gè)臨時(shí)文件并生成此規則的目標文件。這里sed完成了如下的轉換過(guò)程。例如對已一個(gè).c源文件。將編譯器產(chǎn)生的依賴(lài)關(guān)系:

main.o : main.c defs.h

轉成:

main.o main.d : main.c defs.h



這樣就將.d加入到了規則的目標中,其和對應的.o文件文件一樣依賴(lài)于對應的.c源文件和源文件所包含的頭文件。當.c源文件或者頭文件被改變之后規則將會(huì )被執行,相應的.d文件同樣會(huì )被更新。

第三行;刪除臨時(shí)文件。

使用上例的規則就可以建立一個(gè)描述目標文件依賴(lài)關(guān)系的.d文件。我們可以在Makefile中使用include指示符將描述將這個(gè)文件包含進(jìn)來(lái)。在執行 make時(shí),Makefile所包含的所有.d文件就會(huì )被自動(dòng)創(chuàng )建或者更新。Makefile中對當前目錄下.d文件處理可以參考如下:



sources = foo.c bar.c

sinclude $(sources:.c=.d)



例子中,變量“sources”定義了當前目錄下的需要編譯的源文件。變量引用變換“$(sources : .c=.d)”的功能是根據需要.c文件自動(dòng)產(chǎn)生對應的.d文件,并在當前Makefile文件中包含這些.d文件。.d文件和其它的makefile文 件一樣,make在執行時(shí)讀取并試圖重建他們。其實(shí)這些.d文件也是一些可被make解析的makefile文件。

需要注意的是include指示符的書(shū)寫(xiě)順序,因為在這些.d文件中已經(jīng)存在規則。當一個(gè)Makefile使用指示符include這些.d文件時(shí),應該 注意它應該出現在終極目標之后,以免.d文件中的規則被是Makefile的終極規則。關(guān)于這個(gè)前面我們已經(jīng)有了比較詳細的討論。
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
Makefile教程: 跟我一起寫(xiě)Makefile -- LearnMakefile
跟我一起寫(xiě)Makefile 3—— 書(shū)寫(xiě)規則
怎樣寫(xiě)Makefile文件(C語(yǔ)言部分)
Makefile VPATH和vpath的使用
Makefile筆記
如何編寫(xiě)Makefile一份由淺入深的Makefile全攻略(make是如何工作的)
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久