| 導購 | 订阅 | 在线投稿
分享
 
 
 

makefile規則

來源:互聯網  2008-06-01 02:08:24  評論

目錄

1.簡介 3

1.1.預備工作 3

1.2.Makefile介紹 3

1.3.規則簡介 4

1.4.make工作原理 4

1.5.使用變量 5

1.6.簡化命令 6

1.7.另一種風格 6

1.8.清理 7

2.Makefile 7

2.1.makefile名字 7

2.2.包含 8

2.3.『MAKEFILE』變量 8

2.4.如何重新生成makefile 8

2.5.重載makefile 9

3.規則 9

3.1.例子 9

3.2.規則的語法 9

3.3.通配符 10

3.3.1.通配符的缺陷 10

3.3.2.wildcard函數 11

3.4.目錄搜索 11

3.4.1.『VPATH』 11

3.4.2.選擇性搜索 12

3.4.3.使用自動變量 12

3.4.4.目錄搜索和隱含規則 12

3.5.PHONY目標 13

3.6.FORCE目標 14

3.7.空目標 14

3.8.內建的非凡目標 14

3.9.一個規則多個目標 15

3.10.一個目標多條規則 15

3.11.靜態模式規則 16

3.11.1.語法 16

3.11.2.靜態模式規則和隱式規則 17

3.12.雙冒號規則 17

3.13.自動生成依靠關系 17

4.編寫命令 18

4.1.回顯 18

4.2.執行 19

4.3.並行執行 19

4.4.錯誤 19

4.5.中斷make 20

4.6.遞歸使用 20

4.6.1.『MAKE』變量 20

4.6.2.傳遞變量到子make 21

5.命令行參數 21

6.參考 25

6.1.指令 25

6.2.函數 26

6.3.自動變量 27

6.4.非凡變量 29

GNU Make使用

Make 程序最初設計是爲了維護C程序文件防止不必要的重新編譯。在使用命令行編譯器的時候,修改了一個工程中的頭文件,如何確保包含這個頭文件的所有文件都得到編譯?現在10機的版本生成是使用批處理程序,編譯那些文件依靠于程序的維護者,在模塊之間相互引用頭文件的情況下,要將所有需要重新編譯的文件找出來是一件痛苦的事情;在找到這些文件之後,修改批處理進行編譯。實際上這些工作可以讓make程序來自動完成,make工具對于維護一些具有相互依靠關系的文件非凡有用,它對文件和命令的聯系(在文件改變時調用來更新其它文件的程序)提供一套編碼方法。Make工具的基本概念類似于Proglog語言,你告訴make需要做什麽,提供一些規則,make來完成剩下的工作。

1.簡介

make工作自動確定工程的哪部分需要重新編譯,執行命令去編譯它們。雖然make多用于C程序,然而只要提供命令行的編譯器,你可以將其用于任何語言。實際上,make工具的應用範圍不僅于編程,你可以描述任和一些文件改變需要自動更新另一些文件的任務來使用它。

1.1.預備工作

假如要使用make,你必須寫一個叫做「makefile」的文件,這個文件描述工程中文件之間的關系,提供更新每個文件的命令。典型的工程是這樣的:可執行文件靠目標文件來更新,目標文件靠編譯源文件來更新。

Makefile寫好之後,每次更改了源文件後,只要執行make就足夠了,所有必要的重新編譯將執行。Make程序利用makefile中的數據庫和文件的最後修改時間來確定那個文件需要更新;對于需要更新的文件,make執行數據庫中記錄的命令。

可以提供命令行參數給make來控制那個文件需要重新編譯。

1.2.Makefile介紹

Makefile文件告訴make做什麽,多數情況是怎樣編譯和鏈接一個程序。

這裏有一個簡單的makefile,描述如何編譯鏈接由8個C文件和3個頭文件組成的一個編輯器:

edit : main.o kbd.o command.o display.o

insert.o serach.o files.o utils.o

cc –o edit main.o kbd.o command.o display.o

insert.o search.o files.o utils.o

main.o : main.c defs.h

cc –c main.c

kdb.o : kbd.c defs.h command.h

cc –c kbd.c

command.o : command.c defs.h command.h

cc -c command.c

display.o : display.c defs.h buffer.h

cc -c display.c

insert.o : insert.c defs.h buffer.h

cc -c insert.c

search.o : search.c defs.h buffer.h

cc -c search.c

files.o : files.c defs.h buffer.h command.h

cc -c files.c

utils.o : utils.c defs.h

cc -c utils.c

clean :

rm edit main.o kbd.o command.o display.o

insert.o search.o files.o utils.o

將長行用分開便于閱讀,這和使用一個長行的作用是一樣的。使用這個makefile創建可執行文件「edit」時運行make就可以了;假如要將可執行文件和目標文件刪除,執行make clean

make重新編譯這個編輯器時,每個更改的C文件必須重新編譯;假如頭文件更改了,每個包含頭文件的C文件必須重新編譯;每次編譯産生一個對應于原文件的目標文件。最終,目標文件鏈接在一起産生新的可執行文件。

1.3.規則簡介

makefile中的規則是這樣的:

TARGET … : DEPENDENCIES …

COMMAND

目標(TARGET)程序産生的文件,如可執行文件和目標文件;目標也可以是要執行的動作,如「clean」。

依靠(DEPENDENCIES)是用來産生目標的輸入文件,一個目標通常依靠于多個文件。

命令(COMMAND)是make執行的動作,一個可以有多個命令,每個占一行。注重:每個命令行的起始字符必須爲TAB字符!

有依靠關系規則中的命令通常在依靠文件變化時負責産生target文件,make執行這些命令更新或産生target。規則可以沒有依靠關系,如包含target 「clean」的規則。

規則解釋如何和何時重做該規則中的文件,make根據依靠關系執行産生或更新目標;規則也說明如何和何時執行動作。有的規則看起來很複雜,但都符合上述模式。

1.4.make工作原理

缺省make從第一個target開始(第一個非 』.』 開始的target),這稱作缺省目標。在上述的makefile中,缺省目標是更新執行程序』edit』,將這個目標置于最前面。當執行make的時候,make程序從當前目錄讀入makefile開始處理第一個規則;在例子中,這個規則是重新鏈接』edit』;在make處理這個規則之前,必須處理』edit』所依靠的那些文件的規則,例子中是目標文件。這些文件按照他們自己的規則處理:通過編譯源文件來更新每個』.o』文件;當依靠關系中的源文件或頭文件比目標文件新,或目標文件不存在時,必須重新編譯。

其它的規則被處理是因爲他們的target是目標的依靠,和目標沒有依靠關系的規則不會被處理,除非指定make處理(如make clean)。

在重新編譯目標文件之前,make會試圖更新它的依靠:源文件和頭文件。例子中的makefile對源文件和頭文件未指定任何操作:』.c』和』.h』文件不是任何規則的目標。確認所有的目標文件都是最新的之後,make決定是否重新鏈接』edit』:假如』edit』不存在,或者任何一個目標文件都比它新,則鏈接工作將進行。

這樣,假如我們改變insert.c運行make,make會編譯這個文件來更新』insert.o』,然後鏈接』edit』;假如修改了』command.h』運行make,』kbd.o』,』command.o』,』files.o』會重新生成,鏈接』edit』。

1.5.使用變量

在例子中,在規則』edit』中,目標文件被列出來兩次:

edit : main.o kbd.o command.o display.o

insert.o search.o files.o utils.o

cc -o edit main.o kbd.o command.o display.o

insert.o search.o files.o utils.o

這樣的重複輕易出錯:假設工程中加入了一個新的目標文件,可能只將其加入了一個列表中;通過使用變量可以消除這種風險:變量答應一個預定義的字符串在多個地方被替換。

在makefile中,可以寫這樣一行來定義』object』變量:

objects = main.o kbd.o command.o display.o

insert.o search.o files.o utils.o

于是在需要目標文件名列表的地方,使用$(object) 來代替變量的值。以下是使用了變量以後的makefile:

objects = main.o kbd.o command.o display.o

insert.o search.o files.o utils.o

edit : $(objects)

cc -o edit $(objects)

main.o : main.c defs.h

cc -c main.c

kbd.o : kbd.c defs.h command.h

cc -c kbd.c

command.o : command.c defs.h command.h

cc -c command.c

display.o : display.c defs.h buffer.h

cc -c display.c

insert.o : insert.c defs.h buffer.h

cc -c insert.c

search.o : search.c defs.h buffer.h

cc -c search.c

files.o : files.c defs.h buffer.h command.h

cc -c files.c

utils.o : utils.c defs.h

cc -c utils.c

clean :

rm edit $(objects)

1.6.簡化命令

爲每個文件寫出編譯命令不是必要的,因爲make可以自己來做;以』.c』文件更新』.o』文件有一個隱含的規則,使用』cc -c』命令。Make將利用』cc –c main.c –o main.o』來將main.c編譯爲main.o,因此在生成目標文件的規則中,可以省略命令。

當』.c』文件以這樣的方式使用時,將自動加入到依靠關系中;由是在省略命令的前提下,可以將』.c』文件從依靠關系中省略。以下是簡化過的makefile:

objects = main.o kbd.o command.o display.o

insert.o search.o files.o utils.o

edit : $(objects)

cc -o edit $(objects)

main.o : defs.h

kbd.o : defs.h command.h

command.o : defs.h command.h

display.o : defs.h buffer.h

insert.o : defs.h buffer.h

search.o : defs.h buffer.h

files.o : defs.h buffer.h command.h

utils.o : defs.h

.PHONY : clean

clean :

-rm edit $(objects)

1.7.另一種風格

假如makefile中的目標都是以隱含規則生成,可以將規則按照依靠關系分組:

objects = main.o kbd.o command.o display.o

insert.o search.o files.o utils.o

edit : $(objects)

cc -o edit $(objects)

$(objects) : defs.h

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

display.o insert.o search.o files.o : buffer.h

這裏』defs.h』作爲所有目標文件的依靠。這種風格是好是壞取決于個人喜好,它非常緊湊,但是將每個目標的依靠信息放在一起看起來更清楚一些。

1.8.清理

編寫規則不至于編譯程序。Makefile通常描述如何做其它事情:比如刪除目錄中的目標文件和可執行文件來清理目錄。例子中是這樣寫的:

clean:

rm edit $(objects)

實際情況是,我們需要處理一些意外事件:存在一個叫做』clean』的文件;假如rm出錯,並不希望make過程停止下來,修改過的版本如下:

.PHONY : clean

clean :

-rm edit $(objects)

這樣的規則當然不能放在makefile的開始,因爲這並不是我們缺省要做的工作。由于』clean』並不是』edit』的依靠,在運行make時沒有參數時,這條規則不會執行;要執行這個規則,必須運行』make clean』。

2.Makefile

Makefile中包含五種內容:顯式規則,隱式規則,變量定義,指令(directive)和注釋。

1.顯式規則描述如何生成規則的目標,它列出了目標依靠的文件,指定了産生或更新目標的命令

2.隱式規則描述如何生成基于文件名的一類文件,說明目標可能依靠于和其文件名類似的文件,指定了相應的命令。

3.指令類似與編譯器的僞指令,包含:

4.指示make讀入另一個makefile

5.決定是否忽略makefile中的一部分

6.定義一個變量

7.一行中『#』開始是注釋,直到行末,除非碰到續行符號。在』define』和命令中不能有注釋,其它情況下注釋可出現在任何地方。

2.1.makefile名字

缺省情況下,make以下列名字查找makefile:』GNUmakefile』,』makefile』和』Makefile』(注重大小寫)。通常你的makefile應叫做』makefile』或』Makefile』。』GNUmakefile』不推薦,除非你的makefile是爲GNU的make定制的,其它的make不認爲該名字是一個makefile的名字。

假如你使用非標准命名的makefile,必須用命令開關』-f 』 或 』—file』。參數』 –f NAME』或』—file NAME』告訴make讀入NAME作爲makefile。假如使用多個該開關,所有的文件將按順序連接起來。假如使用該選項,標准的makefile名字不會自動檢測。

2.2.包含

『include』指令告訴make暫停處理余下的內容,讀入其它makefile。語法如下:

include FILENAMES …

這一行起始可以有空格,但TAB字符不答應。假如文件名包含變量或函數,這些將被擴展。

2.3.『MAKEFILE』變量

假如環境變量』MAKEFILE』已定義,make認爲它的值是一系列空格隔開的文件名,這些文件在處理其它makefile前被make程序讀入。這類似于include指令;這些文件中的目標不會影響缺省目標,而且假如文件未找到的話,make並不認爲是錯誤。

這個變量的主要用途是遞歸引用make程序時通訊

2.4.如何重新生成makefile

有時候makefile是從其它文件生成的,比如RCS或SCCS文件。假如makefile是由其它文件生成的,需要make讀入最新版本的makefile。

在讀入所有makefile之後,make認爲每個makefile是一個目標,試圖去更新它;假如makefile中有一條如何更新它的規則,或者有適用的隱式規則,需要的更新會進行。所有的makefile檢查完之後,假如有的改變了,make重新開始再讀入(make會試圖再做更新,但通常不會再改變了,因爲已經是最新的了)。

假如一個文件使用雙冒號規則,提供了命令但沒有依靠關系,文件始終會被更新。在makefile的情況下,假如makefile雙冒號規則,提供了命令但沒有依靠關系,這樣makefile始終會重新生成,這會導致循環:make只是在不斷更新makefile,卻不幹活。爲避免這種情況,make不會重新生成那些只有命令沒有依靠關系的雙冒號規則的makefile。

假如沒有使用』-f』或』--file』選項,make會嘗試缺省的makefile文件名。和指明』-f』或』--file』選項不同,make不能確定這些文件是否應當存在。然而,假如缺省makefile不存在但可以通過運行make規則生成,你可能希望這些規則被運行使得makefile可以使用。

因此,假如沒有缺省makefile,make試圖按照makefile名查找的順序生成它,直到成功或名字用完。注重假如make 不能找到或生成makefile,這並不是錯誤;makefile不總是必需的。

當使用』-t』或』--toUCh』選項時,不希望使用過時的makefile來決定那個目標來touch。所以』-t』選項對makefile更新不起作用;類似』-q』(or 『—question』)和』-n』(or 』—just-print』)不阻止makefile的更新,因爲過時的makefile會産生錯誤的輸出。這樣』make –f mfile –n foo』會更新』mfile』,讀入它,打印出更新』foo』需要執行的命令但不運行這些命令。與』foo』有關的命令是更新過的』mfile』中的內容。

但是有時不希望更新makefile,可以將makefile作爲命令行的目標,當makefile被顯式指定爲目標時,』-t』選項也適用于它們。

這樣』make –f mfile –n mfile foo』會讀入』mfile』,打印出更新執行的命令,』foo』的命令是當前的』mfile』中的內容。

2.5.重載makefile

可以使用』include』指令來包含其它makefile,增加目標的變量定義。然而,make不答應同一個目標有不同的命令,有其它的途徑可以達到目的。

假設有』makefile』 和』mfile』,』makfile』要包含』mfile』,但都有對于目標』foo』的規則。這是可以在』makefile』中寫一條匹配任意模式的規則,指明當make在』makefile』中未找到目標時,搜索』mfile』:

foo:

frobnicate > foo

%: force

@$(MAKE) -f mfile $@

force: ;

當執行』make foo』時,make找到』makefile』,執行命令』 frobnicate > foo』;執行』make bar』時,在』makefile』中未找到相應的規則,這時模式規則適用,執行命令』make –f mfile bar』,』makefile』中未提及的其它目標也是類似的。

這種方法之所有工作是因爲模式規則的模式是』%』,可以匹配任何的目標;這條規則的依靠是』force』,保證即使目標存在命令也會執行;』force』規則的命令爲空防止』make』爲其搜索隱式規則-這樣會導致依靠循環。

3.規則

makefile中的規則描述如何生成特定的文件,即規則的目標。規則列出了目標的依靠文件,指定生成或更新目標的命令。

規則的次序是不重要的,除非是確定缺省目標:缺省目標是第一個makefile中的第一個規則;假如第一個規則有多個目標,第一個目標是缺省的。有兩個例外:以』.』開頭的目標不是缺省目標;模式規則對缺省目標沒有影響。

通常我們所寫的地一個規則是編譯整個或makefile中指定的所有程序。

3.1.例子

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

cc -c -g foo.c

它的目標是』foo.o』,依靠于』foo.c』和』defs.h』,有一個命令』cc –c –g foo.c』。命令行以TAB字符開始標識它是一個命令。

這條規則說明兩件事:

8.如何決定』foo.o』是舊的:假如它不存在,或者』foo.c』或者』defs.h』比它新。

9.如何更新』foo.o』文件:通過運行』cc』程序。命令未提及』defs.h』,擔可以猜想』foo.c』包含了它,這是』defs.h』被置于依靠關系中的理由。

3.2.規則的語法

語法如下:

TARGETS : DEPENDENCIES

COMMAND

...

或者

TARGETS : DEPENDENCIES ; COMMAND

COMMAND

...

TARGETS是以空格隔開的文件名,統配符可以使用。通常一個規則只有一個目標,偶然也有多個。

命令行以TAB鍵開始。第一條命令可在依靠關系的下一行;或者在同一行,在分號後面;兩種方式效果相同。

因爲』$』符號被用做變量引用,假如要在規則中使用』$』符號,必須寫兩個:』$$』。可以用』』符號來分割一個長行,這不是必須的,因爲make對行的長度沒有限制。

3.3.通配符

規則中的文件名可以包含統配符,如』*』,』?』。

文件名前的字符』~』有非凡的含義。單獨使用,或跟隨一個』/』,代表用戶的home目錄,比如』~/bin』擴展爲/home/you/bin』;假如』~』跟隨一個單詞,表示單詞指示的那個用戶的home目錄,如』~john/bin』擴展爲』/home/john/bin』。

通配符在目標,依靠關系,命令中自動擴展,其它情況下,統配符的擴展除非顯式使用』wildcard』函數。通配符的非凡意義可以使用』』符號關閉。

例子:

clean:

rm -f *.o

print: *.c

lpr -p $?

touch print

通配符在定義變量時並不擴展,例如:

objects = *.o

則objects的值是字符串』*.o』;但是假如你將objects用于目標,依靠或命令中,擴展會進行。要將objects設置成擴展過的內容,使用:

objects := $(wildcard *.o)

3.3.1.通配符的缺陷

這是一個使用通配符的例子,但結果不是你所期望的。假設可執行文件』foo』是從當前目錄中的所有』.o』文件生成的:

objects = *.o

foo : $(objects)

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

objects變量的值是字符串』*.o』。通配符擴展在規則』foo』中進行,于是所有存在的』.o』文件成爲』foo』的依靠而且在需要時重新編譯。

但假如刪除了所有的』.o』文件呢?當通配符不匹配任何文件時,一切都保持原樣:則』foo』依靠于一個叫做』*.o』的文件;由于這個文件不大可能存在,』make』程序會報告一個無法生成』*.o』文件的錯誤,這不是期待的結果。

實際上可以用通配符獲得期望結果,但是需要複雜的技術,包括』wildcard』函數和字符串替換函數。

3.3.2.wildcard函數

通配符自動在規則中進行。但是在變量賦值的和函數的參數中通配符不會擴展,假如在這些情況下需要通配符擴展,必須使用』wildcard』函數。語法如下:

$(wildcard PATTERN...)

這個在makefile任何地方出現的字符串,會被匹配任何一個文件名格式的以空格隔開的現有文件列表替換。假如沒有任何文件匹配一個模式,這個模式從』wildcard』的輸出中忽略,注重,這和上述的通配符的處理是不一樣的。

『wildcard』函數的一個功能是找出目錄中所有的』.c』文件:

$(wildcard *.c)

可以通過替換後綴』.c』爲』.o』從C文件列表得到目標文件的列表:

$(patsubst %.c,%.o,$(wildcard *.c))

這樣,上節中的makefile改寫爲:

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

foo : $(objects)

cc -o foo $(objects)

這個makefile利用了編譯C程序的隱含規則,所以不需要對編譯寫出顯式的規則。(』:=』是』=』的一個變體)

注重:』PATTERN』是大小寫敏感的。

3.4.目錄搜索

對于大的系統,通常將源文件和目標文件放在不同的目錄中。目錄搜索功能可以讓make自動在多個目錄中搜尋依靠文件,當你將文件重新分布是,不需要改變規則,更改搜索路徑即可。

3.4.1.『VPATH』

make變量』VPATH』列出make應當搜索的目錄列表。很多情況下,當前目錄不包含依靠文件,』VPATH』描述一個對所有文件的搜索列表,包含那些是規則的目標的文件。

假如一個目標或者依靠文件在當前目錄沒找到的話,』make』在』VPATH』中列出的目錄中查找同名的文件。假如找到的話,那個文件成爲依靠文件;規則可以象這些文件在當前目錄中一樣來使用他們。

在』VPATH』變量中,目錄名以冒號或空格隔開;目錄列出的順序決定make查找的順序。(注:在pSOSystem 2.5移植到Win32的GNU make目錄名必須使用分號隔開,以下均簡稱Win32 GNU make)。舉例說明:

VPATH = src:../headers 則規則

foo.o : foo.c

被解釋爲

foo.o : src/foo.c

假設』foo.c』在當前目錄不存在,在』src』目錄中可以找到。

3.4.2.選擇性搜索

與』VPATH』變量相似但更具選擇性的是』vpath』指令(注重是小寫),可以指定對于符合特定模式文件的查找路徑。這樣可以爲不同類型的文件指定不同的搜索路徑。

『vpath』指令共有三中形式:

10.『vpath PATTERN DirectorIES』

爲匹配PATTERN的文件名指定搜索路徑DIRECTORIES,目錄的分隔和』VPATH』的相同

11.『vpath PATTERN』

清除爲匹配PATTERN的文件名指定的搜索路徑

12.『vpath』

清除所有以前用』vpath』指定的搜索路徑

『vpath』的模式是包含』%』的字符串:這個字符串必須匹配需要搜索的依靠文件名,』%』字符匹配0個或多個任意字符。例如:』%.h』匹配任何以』.h』結尾的文件(假如沒有%,則PATTERN必須和依靠文件完全一致,這種用法不太多)。

當當前目錄中不存在依靠文件時,假如』vpath』中的PATTERN匹配依靠文件名,則指令中DIRECTORIES列出的目錄和』VPATH』中同樣處理。舉例:

vpath %.h ../headers

告訴make在當前目錄中未找到的』.h』文件在../headers目錄中查找。

假如多個』vapth』的模式匹配依靠文件名,make將逐一處理,在所有指定的目錄中搜索。Make按照』vapth』在makefile中的次序;來處理它們,多個相同模式的』vapth』是相互獨立的。

vpath %.c foo

vpath % blish

vpath %.c bar

將按照』foo』,『blish』,』bar』的次序查找』.c』文件。而

vpath %.c foo:bar

vpath % blish

按照』foo』,』bar』,』blish』的順序搜索。

3.4.3.使用自動變量

目錄搜索的結果並不改變規則中的命令:命令按原樣被執行。因此,必須寫出與目錄搜索功相適應的命令。這可以通過使用』$^』這樣的自動變量來完成。』$^』表示規則中的所有依靠文件,包含它們所在的目錄名(參見目錄搜索);』$@』表示目標。例如:

foo.o : foo.c

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

通常情況下,依靠文件也包含頭文件,但命令中並不提及這些文件:變量』$<』表示第一個依靠文件:

VPATH = src:../headers

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

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

3.4.4.目錄搜索和隱含規則

使用』VPATH』和』vpath』指定目錄搜索也會影響隱含規則。例如:文件』foo.o』沒有顯式規則,make會考慮隱式規則:假如』foo.c』存在則編譯它;假如這個文件不存在,則在相應的目錄中查找;假如』foo.c』在任一的目錄中存在,則C編譯的隱式規則被應用。

隱式規則的命令使用自動變量通常是必要的,這樣無需其它努力即可以使用目錄搜索得到的文件名。

3.5.PHONY目標

Phony目標並非實際的文件名:只是在顯式請求時執行命令的名字。有兩種理由需要使用phony目標:避免和同名文件沖突,改善性能。

假如編寫一個規則,並不産生目標文件,則其命令在每次make該目標時都執行。例如:

clean:

rm *.o temp

因爲』rm』命令並不産生』clean』文件,則每次執行』make clean』的時候,該命令都會執行。假如目錄中出現了』clean』文件,則規則失效了:沒有依靠文件,文件』clean』始終是最新的,命令永遠不會執行;爲避免這個問題,可使用』.PHONY』指明該目標。如:

.PHONY : clean

這樣執行』make clean』會無視』clean』文件存在與否。

已知phony目標並非是由其它文件生成的實際文件,make會跳過隱含規則搜索。這就是聲明phony目標會改善性能的原因,即使你並不擔心實際文件存在與否。完整的例子如下:

.PHONY : clean

clean :

rm *.o temp

phony目標不應是真正目標文件的依靠。假如這樣,每次make在更新此文件時,命令都會執行。只要phony目標不是真正目標的依靠,規則的命令只有在指定此目標時才執行。

Phony目標可以有依靠關系。當一個目錄中有多個程序是,將其放在一個makefile中會更方便。因爲缺省目標是makefile中的第一個目標,通常將這個phony目標叫做』all』,其依靠文件爲各個程序:

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』將可以將三個程序都生成了。

當一個phony目標是另一個的依靠,其作用相當于子程序,例如:

.PHONY: cleanall cleanobj cleandiff

cleanall : cleanobj cleandiff

rm program

cleanobj :

rm *.o

cleandiff :

rm *.diff

3.6.FORCE目標

當規則沒有依靠關系也沒有命令,而且其目標不是存在的文件名,make認爲此規則運行時這個目標總是被更新。這意味著假如規則依靠于此目標,其命令總是被執行。

clean: FORCE

rm $(objects)

FORCE:

例中目標』FORCE』滿足這種非凡條件,這樣依靠于它的目標』clean』被強制執行其命令。名字』FORCE』沒有非凡含義,只不過通常這樣用而已。這種方式使用』FORCE』和』.PHONY : clean』效果相同。使用』.PHONY』更加明確高效,擔不是所有的』make』都支持;這樣許多makefile中使用了』FORCE』。

3.7.空目標

空目標(empty target)是phony目標的變種:用來執行顯式請求的一個動作。和phony目標不同的是:這個目標文件可以真實存在,擔文件的內容無關緊要,通常是空的。空目標文件的目的是利用其最後修改時間來記錄命令最近一次執行的時間,這是通過使用』touch』命令更新目標文件來達到的。

print: foo.c bar.c

lpr -p $?

touch print

利用這條規則,執行』make print』時假如自上次』make print』之後任一文件改變了,』lpr』命令會執行。自動變量』$?』是爲了只打印出那些變化了的文件。

3.8.內建的非凡目標

某些名字作爲目標存在時有非凡含義。

13..PHONY 該目標的依靠被認爲是phony目標,處理這些目標時,命令無條件被執行,不管文件名是否存在及其最後修改時間

14..SUFFIXES 該目標的依靠被認爲是一個後綴列表,在檢查後綴規則時使用

15..DEFAULT 該目標的規則被使用在沒有規則(顯式的或隱含的)的目標上。假如』DEFAULT』命令定義了,則對所有不是規則目標的依靠文件都會執行該組命令

16..PRECIOUS 該目標的依靠文件會受到非凡對待:假如make被kill或命令的執行被中止,這些目標並不刪除;而且假如該目標是中間文件,在不需要時不會被刪除。可以將隱含規則的目標模式(如%.o)做爲』.PRECIOUS』的依靠文件,這樣可以保存這些規則産生的中間文件。

17..INTERMEDIATE 該目標的依靠文件被當作中間文件;假如該目標沒有依靠文件,則makefile中所有的目標文件均被認爲是中間文件。

18..IGNORE 在執行該目標的依靠規則的命令時,make會忽略錯誤,此規則本身的命令沒有意義。假如該規則沒有依靠關系,表示忽略所有命令執行的錯誤,這種用法只是爲了向後兼容;由于會影響到所有的命令,所以不是非凡有用,推薦使用其它更有選擇性忽略錯誤的方法。

19..SILENT 在執行該目標的依靠規則的命令時,make並不打印命令本身。該規則的命令沒有意義。在』.SILIENT』沒有依靠關系時,表示執行makefile中的所有命令都不會打印,該規則只是爲了向後兼容提供的。

20..EXPORT_ALL_VARIABLES 只是作爲一個目標存在,指示make將所有變量輸出到子進程中。

定義的隱含規則的後綴作爲目標時,也認爲它是非凡目標;兩個後綴的連接也是一樣,比如』.c.o』。這些目標是後綴規則,一中定義隱式規則的過時方法(但仍然廣泛使用)。後綴通常以』.』開始,所以非凡目標也以』.』開始。

3.9.一個規則多個目標

一條有多個目標的規則和寫多條規則,每條一個目標作用是等同的。同樣的命令應用于所有目標,但其效用會因將實際目標以』$@』代替而不同。規則中所有目標的依靠關系是一樣的。

這在兩種情況下有用:

★只有依靠關系,不需要命令。例如:

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

21.所有的目標同樣的命令。命令不需要完全相同,因爲在命令中可以使用』$@』:

bigoutput littleoutput : text.g

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

bigoutput : text.g

generate text.g -big > bigoutput

littleoutput : text.g

generate text.g -little > littleoutput

等同。這裏假設程序』generate』産生兩種輸出:一種使用』-big』選項,一種使用』-little』選項。假如想象使用』$@』變化命令那樣來變化依靠關系,不能通過多目標的普通規則實現,但是可以通過模式規則來實現。

3.10.一個目標多條規則

一個文件可以是多條規則的目標,所有規則的依靠關系被合並。假如目標比任一個依靠文件舊,命令被執行。

一個文件只能有一組命令執行。假如多個規則對于同一個文件都給出了命令,make使用最後一組並打印錯誤信息(非凡情況:假如文件名以』.』開始,並不打印錯誤信息,這一點是爲了和其它make兼容)。沒有任何理由需要將makefile寫成這樣,這是make給出錯誤信息的理由。

一條只有依靠關系的附加規則可以一次給出許多文件的附加依靠文件。例如』objects』變量表示系統中編譯器的所有輸出.,說明當』config.h』更改時所有文件必須重做的簡單方法如下:

objects = foo.o bar.o

foo.o : defs.h

bar.o : defs.h test.h

$(objects) : config.h

不用改變實際目標文件生成的規則,這條規則可以在需要增刪附加的依靠關系時插入或提出。另一個訣竅是附加的依靠關系可以用變量表示,在make執行時,可以給變量賦值:

extradeps=

$(objects) : $(extradeps)

當命令`make extradeps=foo.h'執行時會認爲』foo.h』是每個目標文件的依靠文件,但簡單的』make』命令不是這樣。

3.11.靜態模式規則

靜態模式規則(static pattern rules)可以指定多個目標,並且使用目標名字來建議依靠文件的名字;比普通多目標規則更通用因爲不需要依靠關系是相同的:依靠關系必須類似但不需要相同。

3.11.1.語法

TARGETS ...: TARGET-PATTERN: DEP-PATTERNS ...

COMMANDS

...

TARGETS列表指出規則應用的目標,可以包含通配符,于普通規則的目標相同。TARGET-PATTERN和DEP-PATTERNS來表明目標的依靠關系如何計算:匹配TARGET-PATTERN的目標從名字中抽出一部分,叫做詞幹(stem),詞幹被替換到DEP-PATTERNS來形成依靠文件名。

每個模式通常包含一個』%』字符。當TARGET-PATTERN匹配一個目標時,』%』字符可以匹配目標名中的任何部分;這部分即是詞幹,模式的其余部分必須完全匹配。例如』foo.o』匹配』%.o』,』foo』是詞幹;目標』foo.c』和』foo.out』並不匹配這個模式。

目標的依靠文件名通過將DEP-PATTERNS中的』%』替換爲詞幹形成:假如依靠模式爲』%.c』,在替換詞幹』foo』可以得到』foo.c』。依靠模式中不包含』%』也是合法的,此依靠文件對所有的目標均有效。

假如需要在模式規則中使用』%』字符,必須在其前面加』』字符,假如』%』前的』』字符是有實際意義的,必須在其前面加』』,其它的』』不必如此處理。如』the\%weird\%pattern』在有效的』%』前是』the%weird』,其後是』pattern』。最後的』』保持原樣是因爲其並不影響』%』字符。

以下例子從相應的』.c』文件編譯』foo.o』和』bar.o』:

objects = foo.o bar.o

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

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

每個目標必須匹配目標模式,對于不匹配的目標會給出警告。假如列表中只有部分文件匹配模式,可以使用filter函數移去不匹配的文件名:

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 %.elc,$(files))' 的結果是`foo.elc'。以下例子說明』$*』的使用:

bigoutput littleoutput : %output : text.g

generate text.g -$* > $@

命令`generate'執行時,』$*』擴展爲詞幹』big』或』little』。

3.11.2.靜態模式規則和隱式規則

靜態模式規則和隱式規則在作爲模式規則是具有很多共同點,都有目標模式和構造依靠文件名的模式,不同之處在于make決定何時應用規則的方法。

隱式規則可應用于匹配其模式的任何目標,但只限于沒有指定命令的目標,假如有多條可應用的隱式規則,只有一條被使用,取決于規則的順序。

反之,靜態模式規則適用于規則中明確目標列表,不適用于其它目標且總是適用于指定的每個目標。假如有兩條沖突的規則,且都有命令,這是一個錯誤。

靜態模式規則比隱式規則優越之處如下:

22.可爲一些不能按句法分類,但可以顯式列出的文件重載隱式規則

23.不能判定目錄中的精確內容,一些無關的文件可能導致make適用錯誤的隱式規則;最終結果可能依靠于隱式規則的次序。適用靜態模式規則時,這種不確定性是不存在的:規則適用于明確指定的目標。

3.12.雙冒號規則

雙冒號規則(Double-colon rules)的目標後是』::』而不是』:』,當一個目標出現在多條規則中時,其處理和普通規則的處理不同。

當一個目標出現在多條規則中時,所有規則必須是相同類型的:都是普通的或者都是雙冒號的。假如是雙冒號,規則之間相互獨立;假如目標需要更新,則規則的命令被執行;結果可能是沒有執行,或者執行了其中一些,或者所有的規則都執行了。

同一目標的雙冒號規則事實是完全孤立的,每條規則被被單獨處理,就象不同目標的規則一樣;規則按照在makefile中出現的次序被處理,此類規則真正有意義的是那些于命令執行次序無關的。

這種規則有時比較晦澀不是非凡有用;它提供了一種機制:通過不同依靠文件的更新來對目標進行不同的處理,這種情形很罕見。每個這種規則應當提供命令,假如沒有,適用的隱式規則將使用。

3.13.自動生成依靠關系

在makefile中,許多規則都是一些目標文件依靠于一些頭文件。例如:』main.c』 通過』#include』使用』defs.h』,這樣規則:

main.o: defs.h

告訴make在』defs.h』變化時更新』main.o』。在程序比較大時,需要寫許多這樣的規則;而且當每次增刪』#include』時,必須小心的更新makefile。許多現代的編譯器可以幫你寫這些規則,通常這是通過編譯器的』-M』選項,例如命令:

cc –M main.c

輸出以下內容:

main.o : main.c defs.h

這樣就不必寫這些規則,有編譯器代勞了。

注重這樣的依靠關系中提及』main.o』,不會被隱式規則認爲是中間文件,這意味這make在使用過它之後不會將其刪除。使用老的』make』程序時,習慣做法是使用』make depend』命令利用編譯器的功能産生依靠關系,該命令會産生一個』depend』文件包含所有自動産生的依靠關系,然後在makefile中使用』include』將其讀入。

使用GNU的make時,重新生成makefile的功能使得這種做法變得過時:從不需要顯式請求更新依靠關系,因爲它總是重新生成任何過時的makefile。

自動依靠關系生成推薦的做法是對每個源文件做一個makefile。對每個源文件』NAME.c』,有一個makefile 』NAME.d』,其中列出了目標文件』NAME.o』依靠的所有文件,這樣在源文件更新時,需要掃描來産生新的依靠關系。例子是一個從』NAME.c』産生依靠關系文件』NAME.d』的模式規則:

%.d: %.c

$(SHELL) -ec '$(CC) -M $(CPPFLAGS) $<

sed '''s/($*).o[ :]*/1 $@/g''' > $@'

-e選項是當$(CC)命令失敗時(exit狀態非0),shell馬上退出。通常shell的返回值是管道中最後一條命令(sed)的返回值,這樣make不會注重到編譯器出錯。

使用GNU的C編譯器時(gcc),可以用』-MM』選項來代替』-M』選項,這樣省略系統頭文件的依靠關系。』sed』命令的目的是將

main.o : main.c defs.h

轉換爲

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

這樣使得每個』.d』文件依靠于』.o』文件相應源文件和頭文件,make則可以在原文間或頭文件變化時更新依靠關系文件。

假如定義了生成』.d』文件的規則,可以使用』include』指令來讀入所有的文件:

sources = foo.c bar.c

include $(sources:.c=.d)

例中使用替換變量來將源文件列表』 foo.c bar.c』轉換爲依靠關系文件的列表。因爲』.d』文件和其它文件一樣,不需要更多工作,make會在需要時重新生成它們。

4.編寫命令

規則的命令是由一一執行的shell命令組成。除了以分號隔開寫在依靠關系後的命令,每個命令行必須以tab字符開始空行和注釋行可以出現在命令行中,處理時被忽略(注重:以tab字符開始的空行不是』空』行,是一條空命令)。

可以在命令中使用任何程序,但這些程序是由$(SHELL)來執行的。

4.1.回顯

通常make打印出要執行的命令,稱之爲回顯,這和親自敲命令的現象是一樣的。當行之前有』@』字符時,命令不再回顯,字符』@』在傳遞給shell前丟棄。典型的用法是只對打印命令有效,比如』echo』命令:

@echo About to make distribution files

當make使用』-n』或』—just-print』選項時,顯示要發生的一切,但不執行命令。只有在這種情況下,即使命令以』@』開始,命令行仍然顯示出來。這個選項對查看make實際要執行的動作很有用。

『-s』或』—silent』選項阻止make所有回顯,就象所有命令以』@』開始一樣;一條沒有依靠關系的』.SILENT』規則有相同的作用,但是』@』更加靈活。

4.2.執行

在需要執行命令更新目標時,make爲每一行創建一個子shell來執行。這意味著諸如爲進程設置局部變量的shell命令』cd』(改變進程的當前目錄)不會影響以後的命令。假如需要』cd』影響下一個命令,將它們放在一行上用分號隔開,這樣make認爲是一條命令傳遞給shell程序(注重:這需要shell支持):

foo : bar/lose

cd bar; gobble lose > ../foo

另一個形式使用續行符:

foo : bar/lose

cd bar;

gobble lose > ../foo

shell程序的名字是通過』SHELL』變量來取得的。

(*UNIX)不象大多數變量,』SHELL』變量不是通過環境來設置的(即需要在makefile中設置),因爲』SHELL』環境是個人選擇的,假如不同人的選擇會影響makefile的功能的話,這樣很糟糕。

4.3.並行執行

GNU make可以一次執行幾條命令。通常make一次執行一條命令,等待其返回,再執行下一條。使用』-j』或』—jobs』可以同時執行多條命令。假如』-j』後梗一個正數,表示一次可以執行的命令條數;假如』-j』之後沒有參數,則不限制可執行的命令數。缺省的數量是一。

一個討厭的問題是假如同時執行多條命令,它們的輸出會混在一起;另一個問題是兩個進程不能從同一個設備獲得輸入。

4.4.錯誤

每條shell命令返回時,make會檢查其返回狀態。假如命令執行成功,則下一條命令被執行,最後一條命令執行完後,規則執行結束。

假如有錯誤(返回非0狀態),make放棄當前規則,也可能是所有規則。

有時候命令執行錯誤並不是問題,比如使用』mkdir』命令確保目錄存在:假如目錄一存在,則』mkdir』會報告錯誤,但仍希望make繼續。

要忽略命令的錯誤,在命令之前使用』-『字符,』-『字符在傳遞給shell之前被丟棄:

clean:

-rm -f *.o

假如使用』-i』或』—ignore-errors』選項,make會忽略所有命令産生的錯誤;一條沒有依靠關系的』.IGNORE』規則有相同的作用,但』-『更靈活。

在忽略錯誤時,make將錯誤也認爲是成功,只是通知你命令的退出狀態和和錯誤被忽略。假如make並未告知忽略錯誤,在錯誤發生時,表明該目標不能成功更新,直接或間接依靠于此的目標當然也不能成功;這些目標的命令不會被執行,因爲其先決條件不滿足。

通常make會立即以非0狀態退出。然而,假如給定』-k』或』—keep-going』選項,make在退出前會處理其它的依靠關系,進行必要的更新。例如,在編譯一個目標文件碰到錯誤,』make -k』會繼續編譯其它的目標文件。

通常認爲你的目的是更新指定的目標,當make知道這是不可能時,會立即報告失敗;』-k』選項指示真正目的是測試更新程序的更多可能性:在編譯之前找出更多不相關的問題。

假如命令失敗了,假設它更新的目標文件,這個文件是不完整的不能使用-至少不是完全更新的。但文件的最後修改時間表明停已經是最新的,下一次make運行時,不會再更新這個文件。這種情況和命令被kill相同;則通常情況下在命令失敗時將目標刪除是正確的;當』.DELETE_ON_ERROR』是目標時make幫你做這件事。雖然你總是希望make這麽做,但這不是過去的習慣;所以必須顯式要求make這樣做(其它的make自動這樣做)。

4.5.中斷make

假如make執行命令時碰到錯誤,可能會刪除命令更新的目標文件: make檢查文件的修改時間是否變化。刪除目標的目的是確保make下次執行時重新生成它。爲什麽這樣做?假設在編譯器運行時按了』Ctrl-c』,此時編譯器寫生成目標文件』foo.o』。』Ctrl-c』 kill了編譯器,留下一個不完整的文件,但它的修改時間比源文件』foo.c』新;此時make也受到』Ctrl-c』信號刪除這個不完整的文件,假如make不這樣做,下次make運行時認爲』foo.o』不需要更新,會在鏈接時出現希奇的錯誤。

可以使用』.PRECIOUS』規則來防止目標文件被刪除。在make更新目標時,會檢測其是否爲』.PRECIOUS』的依靠,決定在命令出錯或中斷時是否刪除該目標。假如你希望目標的更新是原子操作,或是用來記錄修改時間,或必須一直存在防止其它類型的錯誤,這些理由使得你必須這樣做。

4.6.遞歸使用

遞歸使用make就是在makefile中使用make命令。這種技術在你將一個大系統分解爲幾個子系統,爲每個自系統提供一個makefile時有用處。比如有一個子目錄』subdir』中有自己的makefile,希望make在自目錄中運行,可以這樣做:

subsystem:

cd subdir; $(MAKE)

或者

subsystem:

$(MAKE) -C subdir

可以照抄這個;例子來遞歸使用make

4.6.1.『MAKE』變量

遞歸的make必須使用』MAKE』變量,不是顯式的make命令:

subsystem:

cd subdir; $(MAKE)

該變量的值是被調用的make的名字。在命令中使用』MAKE』有非凡的功能:它改變了`-t' (`--touch'), `-n' (`--just-print')和`-q' (`--question')選項的含義。使用上例來考慮』make –t』命令(』-t』選項將目標標記爲最新但不運行命令),更加』-t』選項的功能,該命令將創建一個』subsystem』文件,實際希望的操作是運行』cd subdir; make –t』;但這會執行命令,與』-t』的原意不符。

這個非凡功能做了期望的工作。當命令行包含變量』MAKE』時,選項』-t』,』-n』和』-q』並不適用。不管這些導致不會執行命令的標志,包含』MAKE』變量的命令始終會執行。正常的』MAKEFLAGS』機制將這些標志傳遞到子make,這樣打印命令的請求被傳播到子系統中。

4.6.2.傳遞變量到子make

上級(top-level)make中的變量可以顯式通過環境傳遞到子make中。在子make中,這些變量被缺省定義,但不會重載子makefile中的定義除非使用』-e』選項。

爲向下傳遞,或輸出變量,make在運行命令時將其加入到環境變量中;子make,可以使用環境變量來初始化變量表。除非顯式要求,make只輸出初始環境中或命令行設置的變量而且變量名只由字母,數字和下劃線組成。一些shell不能處理有其它字符的環境變量。

非凡變量』SHELL』,』MAKEFLAGS』總是輸出,假如』MAKEFILE』變量有值,也會輸出。Make自動通過』MAKEFLAGS』來輸出命令行定義的變量。

假如想要輸出特定變量,使用』export』指令:

export VARIABLE ...

假如要阻止輸出一個變量,使用』unexport』指令:

unexport VARIABLE ...

爲方便起見,可以在定義變量時輸出它:

export VARIABLE = value

VARIABLE = value

export VARIABLE

作用相同。

假如要輸出所有的變量,使用』export』指令本身就可以了。

變量』MAKELEVEL』在一級一級傳遞時會改變,這個變量的值是表示嵌套層數的字符串,頂級』make』是,變量的值爲』0』;子make的值爲』1』;子子make的值爲』2』,依此類推。

『MAKELEVEL』的用途是在條件指令中測試它,這樣寫出在遞歸運行時和直接運行時表現不同的makefile。

以下內容拷貝自GNU Make Manual

5.命令行參數

`-b'

`-m'

These options are ignored for compatibility with other versions of

`make'.

`-C DIR'

`--directory=DIR'

Change to directory DIR before reading the makefiles. If multiple

`-C' options are specified, each is interpreted relative to the

previous one: `-C / -C etc' is equivalent to `-C /etc'. This is

typically used with recursive invocations of `make' (*note

Recursive Use of `make': Recursion.).

`-d'

`--debug'

Print debugging information in addition to normal processing. The

debugging information says which files are being considered for

remaking, which file-times are being compared and with what

results, which files actually need to be remade, which implicit

rules are considered and which are applied--everything interesting

about how `make' decides what to do.

`-e'

`--environment-overrides'

Give variables taken from the environment precedence over

variables from makefiles. *Note Variables from the Environment:

Environment.

`-f FILE'

`--file=FILE'

`--makefile=FILE'

Read the file named FILE as a makefile.

`-h'

`--help'

Remind you of the options that `make' understands and then exit.

`-i'

`--ignore-errors'

Ignore all errors in commands executed to remake files.

`-I DIR'

`--include-dir=DIR'

Specifies a directory DIR to search for included makefiles. If several `-I' options are

used to specify several directories, the directories are searched

in the order specified.

`-j [JOBS]'

`--jobs=[JOBS]'

Specifies the number of jobs (commands) to run simultaneously.

With no argument, `make' runs as many jobs simultaneously as

possible. If there is more than one `-j' option, the last one is

effective.

`-k'

`--keep-going'

Continue as much as possible after an error. While the target that

failed, and those that depend on it, cannot be remade, the other

dependencies of these targets can be processed all the same.

`-l [LOAD]'

`--load-average[=LOAD]'

`--max-load[=LOAD]'

Specifies that no new jobs (commands) should be started if there

are other jobs running and the load average is at least LOAD (a

floating-point number). With no argument, removes a previous load

limit. *Note Parallel Execution: Parallel.

`-n'

`--just-print'

`--dry-run'

`--recon'

Print the commands that would be executed, but do not execute them.

`-o FILE'

`--old-file=FILE'

`--assume-old=FILE'

Do not remake the file FILE even if it is older than its

dependencies, and do not remake anything on account of changes in

FILE. Essentially the file is treated as very old and its rules

are ignored.

`-p'

`--print-data-base'

Print the data base (rules and variable values) that results from

reading the makefiles; then execute as usual or as otherwise

specified. This also prints the version information given by the

`-v' switch (see below). To print the data base without trying to

remake any files, use `make -p -f /dev/null'.

`-q'

`--question'

"Question mode". Do not run any commands, or print anything; just

return an exit status that is zero if the specified targets are

already up to date, one if any remaking is required, or two if an

error is encountered.

`-r'

`--no-builtin-rules'

Eliminate use of the built-in implicit rules.You can still define your own by writing

pattern rules. The `-r' option also clears out the default list

of suffixes for suffix rules .But you can still define your own suffixes with a

rule for `.SUFFIXES', and then define your own suffix rules.

`-s'

`--silent'

`--quiet'

Silent operation; do not print the commands as they are executed.

`-S'

`--no-keep-going'

`--stop'

Cancel the effect of the `-k' option. This is never necessary

except in a recursive `make' where `-k' might be inherited from

the top-level `make' via `MAKEFLAGS' or if you set `-k' in `MAKEFLAGS' in your

environment.

`-t'

`--touch'

Touch files (mark them up to date without really changing them)

instead of running their commands. This is used to pretend that

the commands were done, in order to fool future invocations of

`make'.

`-v'

`--version'

Print the version of the `make' program plus a copyright, a list

of authors, and a notice that there is no warranty; then exit.

`-w'

`--print-directory'

Print a message containing the working directory both before and

after executing the makefile. This may be useful for tracking

down errors from complicated nests of recursive `make' commands.

`--no-print-directory'

Disable printing of the working directory under `-w'. This option

is useful when `-w' is turned on automatically, but you do not

want to see the extra messages.

`-W FILE'

`--what-if=FILE'

`--new-file=FILE'

`--assume-new=FILE'

Pretend that the target FILE has just been modified. When used

with the `-n' flag, this shows you what would happen if you were

to modify that file. Without `-n', it is almost the same as

running a `touch' command on the given file before running `make',

except that the modification time is changed only in the

imagination of `make'.

`--warn-undefined-variables'

Issue a warning message whenever `make' sees a reference to an

undefined variable. This can be helpful when you are trying to

debug makefiles which use variables in complex ways.

6.參考

6.1.指令

`define VARIABLE'

`endef'

Define a multi-line, recursively-expanded variable.

*Note Sequences::.

`ifdef VARIABLE'

`ifndef VARIABLE'

`ifeq (A,B)'

`ifeq "A" "B"'

`ifeq 'A' 'B''

`ifneq (A,B)'

`ifneq "A" "B"'

`ifneq 'A' 'B''

`else'

`endif'

Conditionally evaluate part of the makefile.

`include FILE'

Include another makefile.

`override VARIABLE = VALUE'

`override VARIABLE := VALUE'

`override VARIABLE += VALUE'

`override define VARIABLE'

`endef'

Define a variable, overriding any previous definition, even one

from the command line.

`export'

Tell `make' to export all variables to child processes by default.

`export VARIABLE'

`export VARIABLE = VALUE'

`export VARIABLE := VALUE'

`export VARIABLE += VALUE'

`unexport VARIABLE'

Tell `make' whether or not to export a particular variable to child

processes.

`vpath PATTERN PATH'

Specify a search path for files matching a `%' pattern.

*Note The `vpath' Directive: Selective Search.

`vpath PATTERN'

Remove all search paths previously specified for PATTERN.

`vpath'

Remove all search paths previously specified in any `vpath'

directive.

6.2.函數

`$(subst FROM,TO,TEXT)'

Replace FROM with TO in TEXT.

`$(patsubst PATTERN,REPLACEMENT,TEXT)'

Replace Words matching PATTERN with REPLACEMENT in TEXT.

`$(strip STRING)'

Remove excess whitespace characters from STRING.

`$(findstring FIND,TEXT)'

Locate FIND in TEXT.

`$(filter PATTERN...,TEXT)'

Select words in TEXT that match one of the PATTERN words.

`$(filter-out PATTERN...,TEXT)'

Select words in TEXT that *do not* match any of the PATTERN words.

`$(sort LIST)'

Sort the words in LIST lexicographically, removing duplicates.

`$(dir NAMES...)'

Extract the directory part of each file name.

`$(notdir NAMES...)'

Extract the non-directory part of each file name.

`$(suffix NAMES...)'

Extract the suffix (the last `.' and following characters) of each

file name.

`$(basename NAMES...)'

Extract the base name (name without suffix) of each file name.

`$(addsuffix SUFFIX,NAMES...)'

Append SUFFIX to each word in NAMES.

`$(addprefix PREFIX,NAMES...)'

Prepend PREFIX to each word in NAMES.

`$(join LIST1,LIST2)'

Join two parallel lists of words.

`$(word N,TEXT)'

Extract the Nth word (one-origin) of TEXT.

`$(words TEXT)'

Count the number of words in TEXT.

`$(firstword NAMES...)'

Extract the first word of NAMES.

`$(wildcard PATTERN...)'

Find file names matching a shell file name pattern (*not* a `%'

pattern).

`$(shell COMMAND)'

Execute a shell command and return its output.

`$(origin VARIABLE)'

Return a string describing how the `make' variable VARIABLE was

defined.

`$(foreach VAR,WORDS,TEXT)'

Evaluate TEXT with VAR bound to each word in WORDS, and

concatenate the results.

6.3.自動變量

`$@'

The file name of the target.

`$%'

The target member name, when the target is an archive member.

`$<'

The name of the first dependency.

`$?'

The names of all the dependencies that are newer than the target,

with spaces between them. For dependencies which are archive

members, only the member named is used

with spaces between them. For dependencies which are archive

members, only the member named is used

`$^'

`$+'

The names of all the dependencies, with spaces between them. For

dependencies which are archive members, only the member named is

used. The value of `$^' omits duplicate

dependencies, while `$+' retains them and preserves their order.

`$*'

The stem with which an implicit rule matches

`$(@D)'

`$(@F)'

The directory part and the file-within-directory part of `$@'.

`$(*D)'

`$(*F)'

The directory part and the file-within-directory part of `$*'.

`$(%D)'

`$(%F)'

The directory part and the file-within-directory part of `$%'

`$(<D)'

`$(<F)'

The directory part and the file-within-directory part of `$<'

`$(^D)'

`$(^F)'

The directory part and the file-within-directory part of `$^'

`$(+D)'

`$(+F)'

The directory part and the file-within-directory part of `$+'

`$(?D)'

`$(?F)'

The directory part and the file-within-directory part of `$?'

6.4.非凡變量

`MAKEFILES'

Makefiles to be read on every invocation of `make'.

`VPATH'

Directory search path for files not found in the current directory.

`SHELL'

The name of the system default command interpreter, usually

`/bin/sh'. You can set `SHELL' in the makefile to change the

shell used to run commands.

`MAKE'

The name with which `make' was invoked. Using this variable in

commands has special meaning.

`MAKELEVEL'

The number of levels of recursion (sub-`make's).

`MAKEFLAGS'

The flags given to `make'. You can set this in the environment or

a makefile to set flags.

`SUFFIXES'

The default list of suffixes before `make' reads any makefiles.

  目錄 1.簡介 3 1.1.預備工作 3 1.2.Makefile介紹 3 1.3.規則簡介 4 1.4.make工作原理 4 1.5.使用變量 5 1.6.簡化命令 6 1.7.另一種風格 6 1.8.清理 7 2.Makefile 7 2.1.makefile名字 7 2.2.包含 8 2.3.『MAKEFILE』變量 8 2.4.如何重新生成makefile 8 2.5.重載makefile 9 3.規則 9 3.1.例子 9 3.2.規則的語法 9 3.3.通配符 10 3.3.1.通配符的缺陷 10 3.3.2.wildcard函數 11 3.4.目錄搜索 11 3.4.1.『VPATH』 11 3.4.2.選擇性搜索 12 3.4.3.使用自動變量 12 3.4.4.目錄搜索和隱含規則 12 3.5.PHONY目標 13 3.6.FORCE目標 14 3.7.空目標 14 3.8.內建的非凡目標 14 3.9.一個規則多個目標 15 3.10.一個目標多條規則 15 3.11.靜態模式規則 16 3.11.1.語法 16 3.11.2.靜態模式規則和隱式規則 17 3.12.雙冒號規則 17 3.13.自動生成依靠關系 17 4.編寫命令 18 4.1.回顯 18 4.2.執行 19 4.3.並行執行 19 4.4.錯誤 19 4.5.中斷make 20 4.6.遞歸使用 20 4.6.1.『MAKE』變量 20 4.6.2.傳遞變量到子make 21 5.命令行參數 21 6.參考 25 6.1.指令 25 6.2.函數 26 6.3.自動變量 27 6.4.非凡變量 29 GNU Make使用 Make 程序最初設計是爲了維護C程序文件防止不必要的重新編譯。在使用命令行編譯器的時候,修改了一個工程中的頭文件,如何確保包含這個頭文件的所有文件都得到編譯?現在10機的版本生成是使用批處理程序,編譯那些文件依靠于程序的維護者,在模塊之間相互引用頭文件的情況下,要將所有需要重新編譯的文件找出來是一件痛苦的事情;在找到這些文件之後,修改批處理進行編譯。實際上這些工作可以讓make程序來自動完成,make工具對于維護一些具有相互依靠關系的文件非凡有用,它對文件和命令的聯系(在文件改變時調用來更新其它文件的程序)提供一套編碼方法。Make工具的基本概念類似于Proglog語言,你告訴make需要做什麽,提供一些規則,make來完成剩下的工作。 1.簡介 make工作自動確定工程的哪部分需要重新編譯,執行命令去編譯它們。雖然make多用于C程序,然而只要提供命令行的編譯器,你可以將其用于任何語言。實際上,make工具的應用範圍不僅于編程,你可以描述任和一些文件改變需要自動更新另一些文件的任務來使用它。 1.1.預備工作 假如要使用make,你必須寫一個叫做「makefile」的文件,這個文件描述工程中文件之間的關系,提供更新每個文件的命令。典型的工程是這樣的:可執行文件靠目標文件來更新,目標文件靠編譯源文件來更新。 Makefile寫好之後,每次更改了源文件後,只要執行make就足夠了,所有必要的重新編譯將執行。Make程序利用makefile中的數據庫和文件的最後修改時間來確定那個文件需要更新;對于需要更新的文件,make執行數據庫中記錄的命令。 可以提供命令行參數給make來控制那個文件需要重新編譯。 1.2.Makefile介紹 Makefile文件告訴make做什麽,多數情況是怎樣編譯和鏈接一個程序。 這裏有一個簡單的makefile,描述如何編譯鏈接由8個C文件和3個頭文件組成的一個編輯器: edit : main.o kbd.o command.o display.o insert.o serach.o files.o utils.o cc –o edit main.o kbd.o command.o display.o insert.o search.o files.o utils.o main.o : main.c defs.h cc –c main.c kdb.o : kbd.c defs.h command.h cc –c kbd.c command.o : command.c defs.h command.h cc -c command.c display.o : display.c defs.h buffer.h cc -c display.c insert.o : insert.c defs.h buffer.h cc -c insert.c search.o : search.c defs.h buffer.h cc -c search.c files.o : files.c defs.h buffer.h command.h cc -c files.c utils.o : utils.c defs.h cc -c utils.c clean : rm edit main.o kbd.o command.o display.o insert.o search.o files.o utils.o 將長行用分開便于閱讀,這和使用一個長行的作用是一樣的。使用這個makefile創建可執行文件「edit」時運行make就可以了;假如要將可執行文件和目標文件刪除,執行make clean make重新編譯這個編輯器時,每個更改的C文件必須重新編譯;假如頭文件更改了,每個包含頭文件的C文件必須重新編譯;每次編譯産生一個對應于原文件的目標文件。最終,目標文件鏈接在一起産生新的可執行文件。 1.3.規則簡介 makefile中的規則是這樣的: TARGET … : DEPENDENCIES … COMMAND … 目標(TARGET)程序産生的文件,如可執行文件和目標文件;目標也可以是要執行的動作,如「clean」。 依靠(DEPENDENCIES)是用來産生目標的輸入文件,一個目標通常依靠于多個文件。 命令(COMMAND)是make執行的動作,一個可以有多個命令,每個占一行。注重:每個命令行的起始字符必須爲TAB字符! 有依靠關系規則中的命令通常在依靠文件變化時負責産生target文件,make執行這些命令更新或産生target。規則可以沒有依靠關系,如包含target 「clean」的規則。 規則解釋如何和何時重做該規則中的文件,make根據依靠關系執行産生或更新目標;規則也說明如何和何時執行動作。有的規則看起來很複雜,但都符合上述模式。 1.4.make工作原理 缺省make從第一個target開始(第一個非 』.』 開始的target),這稱作缺省目標。在上述的makefile中,缺省目標是更新執行程序』edit』,將這個目標置于最前面。當執行make的時候,make程序從當前目錄讀入makefile開始處理第一個規則;在例子中,這個規則是重新鏈接』edit』;在make處理這個規則之前,必須處理』edit』所依靠的那些文件的規則,例子中是目標文件。這些文件按照他們自己的規則處理:通過編譯源文件來更新每個』.o』文件;當依靠關系中的源文件或頭文件比目標文件新,或目標文件不存在時,必須重新編譯。 其它的規則被處理是因爲他們的target是目標的依靠,和目標沒有依靠關系的規則不會被處理,除非指定make處理(如make clean)。 在重新編譯目標文件之前,make會試圖更新它的依靠:源文件和頭文件。例子中的makefile對源文件和頭文件未指定任何操作:』.c』和』.h』文件不是任何規則的目標。確認所有的目標文件都是最新的之後,make決定是否重新鏈接』edit』:假如』edit』不存在,或者任何一個目標文件都比它新,則鏈接工作將進行。 這樣,假如我們改變insert.c運行make,make會編譯這個文件來更新』insert.o』,然後鏈接』edit』;假如修改了』command.h』運行make,』kbd.o』,』command.o』,』files.o』會重新生成,鏈接』edit』。 1.5.使用變量 在例子中,在規則』edit』中,目標文件被列出來兩次: edit : main.o kbd.o command.o display.o insert.o search.o files.o utils.o cc -o edit main.o kbd.o command.o display.o insert.o search.o files.o utils.o 這樣的重複輕易出錯:假設工程中加入了一個新的目標文件,可能只將其加入了一個列表中;通過使用變量可以消除這種風險:變量答應一個預定義的字符串在多個地方被替換。 在makefile中,可以寫這樣一行來定義』object』變量: objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.o 于是在需要目標文件名列表的地方,使用$(object) 來代替變量的值。以下是使用了變量以後的makefile: objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.o edit : $(objects) cc -o edit $(objects) main.o : main.c defs.h cc -c main.c kbd.o : kbd.c defs.h command.h cc -c kbd.c command.o : command.c defs.h command.h cc -c command.c display.o : display.c defs.h buffer.h cc -c display.c insert.o : insert.c defs.h buffer.h cc -c insert.c search.o : search.c defs.h buffer.h cc -c search.c files.o : files.c defs.h buffer.h command.h cc -c files.c utils.o : utils.c defs.h cc -c utils.c clean : rm edit $(objects) 1.6.簡化命令 爲每個文件寫出編譯命令不是必要的,因爲make可以自己來做;以』.c』文件更新』.o』文件有一個隱含的規則,使用』cc -c』命令。Make將利用』cc –c main.c –o main.o』來將main.c編譯爲main.o,因此在生成目標文件的規則中,可以省略命令。 當』.c』文件以這樣的方式使用時,將自動加入到依靠關系中;由是在省略命令的前提下,可以將』.c』文件從依靠關系中省略。以下是簡化過的makefile: objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.o edit : $(objects) cc -o edit $(objects) main.o : defs.h kbd.o : defs.h command.h command.o : defs.h command.h display.o : defs.h buffer.h insert.o : defs.h buffer.h search.o : defs.h buffer.h files.o : defs.h buffer.h command.h utils.o : defs.h .PHONY : clean clean : -rm edit $(objects) 1.7.另一種風格 假如makefile中的目標都是以隱含規則生成,可以將規則按照依靠關系分組: objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.o edit : $(objects) cc -o edit $(objects) $(objects) : defs.h kbd.o command.o files.o : command.h display.o insert.o search.o files.o : buffer.h 這裏』defs.h』作爲所有目標文件的依靠。這種風格是好是壞取決于個人喜好,它非常緊湊,但是將每個目標的依靠信息放在一起看起來更清楚一些。 1.8.清理 編寫規則不至于編譯程序。Makefile通常描述如何做其它事情:比如刪除目錄中的目標文件和可執行文件來清理目錄。例子中是這樣寫的: clean: rm edit $(objects) 實際情況是,我們需要處理一些意外事件:存在一個叫做』clean』的文件;假如rm出錯,並不希望make過程停止下來,修改過的版本如下: .PHONY : clean clean : -rm edit $(objects) 這樣的規則當然不能放在makefile的開始,因爲這並不是我們缺省要做的工作。由于』clean』並不是』edit』的依靠,在運行make時沒有參數時,這條規則不會執行;要執行這個規則,必須運行』make clean』。 2.Makefile Makefile中包含五種內容:顯式規則,隱式規則,變量定義,指令(directive)和注釋。 1.顯式規則描述如何生成規則的目標,它列出了目標依靠的文件,指定了産生或更新目標的命令 2.隱式規則描述如何生成基于文件名的一類文件,說明目標可能依靠于和其文件名類似的文件,指定了相應的命令。 3.指令類似與編譯器的僞指令,包含: 4.指示make讀入另一個makefile 5.決定是否忽略makefile中的一部分 6.定義一個變量 7.一行中『#』開始是注釋,直到行末,除非碰到續行符號。在』define』和命令中不能有注釋,其它情況下注釋可出現在任何地方。 2.1.makefile名字 缺省情況下,make以下列名字查找makefile:』GNUmakefile』,』makefile』和』Makefile』(注重大小寫)。通常你的makefile應叫做』makefile』或』Makefile』。』GNUmakefile』不推薦,除非你的makefile是爲GNU的make定制的,其它的make不認爲該名字是一個makefile的名字。 假如你使用非標准命名的makefile,必須用命令開關』-f 』 或 』—file』。參數』 –f NAME』或』—file NAME』告訴make讀入NAME作爲makefile。假如使用多個該開關,所有的文件將按順序連接起來。假如使用該選項,標准的makefile名字不會自動檢測。 2.2.包含 『include』指令告訴make暫停處理余下的內容,讀入其它makefile。語法如下: include FILENAMES … 這一行起始可以有空格,但TAB字符不答應。假如文件名包含變量或函數,這些將被擴展。 2.3.『MAKEFILE』變量 假如環境變量』MAKEFILE』已定義,make認爲它的值是一系列空格隔開的文件名,這些文件在處理其它makefile前被make程序讀入。這類似于include指令;這些文件中的目標不會影響缺省目標,而且假如文件未找到的話,make並不認爲是錯誤。 這個變量的主要用途是遞歸引用make程序時通訊 2.4.如何重新生成makefile 有時候makefile是從其它文件生成的,比如RCS或SCCS文件。假如makefile是由其它文件生成的,需要make讀入最新版本的makefile。 在讀入所有makefile之後,make認爲每個makefile是一個目標,試圖去更新它;假如makefile中有一條如何更新它的規則,或者有適用的隱式規則,需要的更新會進行。所有的makefile檢查完之後,假如有的改變了,make重新開始再讀入(make會試圖再做更新,但通常不會再改變了,因爲已經是最新的了)。 假如一個文件使用雙冒號規則,提供了命令但沒有依靠關系,文件始終會被更新。在makefile的情況下,假如makefile雙冒號規則,提供了命令但沒有依靠關系,這樣makefile始終會重新生成,這會導致循環:make只是在不斷更新makefile,卻不幹活。爲避免這種情況,make不會重新生成那些只有命令沒有依靠關系的雙冒號規則的makefile。 假如沒有使用』-f』或』--file』選項,make會嘗試缺省的makefile文件名。和指明』-f』或』--file』選項不同,make不能確定這些文件是否應當存在。然而,假如缺省makefile不存在但可以通過運行make規則生成,你可能希望這些規則被運行使得makefile可以使用。 因此,假如沒有缺省makefile,make試圖按照makefile名查找的順序生成它,直到成功或名字用完。注重假如make 不能找到或生成makefile,這並不是錯誤;makefile不總是必需的。 當使用』-t』或』--toUCh』選項時,不希望使用過時的makefile來決定那個目標來touch。所以』-t』選項對makefile更新不起作用;類似』-q』(or 『—question』)和』-n』(or 』—just-print』)不阻止makefile的更新,因爲過時的makefile會産生錯誤的輸出。這樣』make –f mfile –n foo』會更新』mfile』,讀入它,打印出更新』foo』需要執行的命令但不運行這些命令。與』foo』有關的命令是更新過的』mfile』中的內容。 但是有時不希望更新makefile,可以將makefile作爲命令行的目標,當makefile被顯式指定爲目標時,』-t』選項也適用于它們。 這樣』make –f mfile –n mfile foo』會讀入』mfile』,打印出更新執行的命令,』foo』的命令是當前的』mfile』中的內容。 2.5.重載makefile 可以使用』include』指令來包含其它makefile,增加目標的變量定義。然而,make不答應同一個目標有不同的命令,有其它的途徑可以達到目的。 假設有』makefile』 和』mfile』,』makfile』要包含』mfile』,但都有對于目標』foo』的規則。這是可以在』makefile』中寫一條匹配任意模式的規則,指明當make在』makefile』中未找到目標時,搜索』mfile』: foo: frobnicate > foo %: force @$(MAKE) -f mfile $@ force: ; 當執行』make foo』時,make找到』makefile』,執行命令』 frobnicate > foo』;執行』make bar』時,在』makefile』中未找到相應的規則,這時模式規則適用,執行命令』make –f mfile bar』,』makefile』中未提及的其它目標也是類似的。 這種方法之所有工作是因爲模式規則的模式是』%』,可以匹配任何的目標;這條規則的依靠是』force』,保證即使目標存在命令也會執行;』force』規則的命令爲空防止』make』爲其搜索隱式規則-這樣會導致依靠循環。 3.規則 makefile中的規則描述如何生成特定的文件,即規則的目標。規則列出了目標的依靠文件,指定生成或更新目標的命令。 規則的次序是不重要的,除非是確定缺省目標:缺省目標是第一個makefile中的第一個規則;假如第一個規則有多個目標,第一個目標是缺省的。有兩個例外:以』.』開頭的目標不是缺省目標;模式規則對缺省目標沒有影響。 通常我們所寫的地一個規則是編譯整個或makefile中指定的所有程序。 3.1.例子 foo.o : foo.c defs.h # module for twiddling the frobs cc -c -g foo.c 它的目標是』foo.o』,依靠于』foo.c』和』defs.h』,有一個命令』cc –c –g foo.c』。命令行以TAB字符開始標識它是一個命令。 這條規則說明兩件事: 8.如何決定』foo.o』是舊的:假如它不存在,或者』foo.c』或者』defs.h』比它新。 9.如何更新』foo.o』文件:通過運行』cc』程序。命令未提及』defs.h』,擔可以猜想』foo.c』包含了它,這是』defs.h』被置于依靠關系中的理由。 3.2.規則的語法 語法如下: TARGETS : DEPENDENCIES COMMAND ... 或者 TARGETS : DEPENDENCIES ; COMMAND COMMAND ... TARGETS是以空格隔開的文件名,統配符可以使用。通常一個規則只有一個目標,偶然也有多個。 命令行以TAB鍵開始。第一條命令可在依靠關系的下一行;或者在同一行,在分號後面;兩種方式效果相同。 因爲』$』符號被用做變量引用,假如要在規則中使用』$』符號,必須寫兩個:』$$』。可以用』』符號來分割一個長行,這不是必須的,因爲make對行的長度沒有限制。 3.3.通配符 規則中的文件名可以包含統配符,如』*』,』?』。 文件名前的字符』~』有非凡的含義。單獨使用,或跟隨一個』/』,代表用戶的home目錄,比如』~/bin』擴展爲/home/you/bin』;假如』~』跟隨一個單詞,表示單詞指示的那個用戶的home目錄,如』~john/bin』擴展爲』/home/john/bin』。 通配符在目標,依靠關系,命令中自動擴展,其它情況下,統配符的擴展除非顯式使用』wildcard』函數。通配符的非凡意義可以使用』』符號關閉。 例子: clean: rm -f *.o 和 print: *.c lpr -p $? touch print 通配符在定義變量時並不擴展,例如: objects = *.o 則objects的值是字符串』*.o』;但是假如你將objects用于目標,依靠或命令中,擴展會進行。要將objects設置成擴展過的內容,使用: objects := $(wildcard *.o) 3.3.1.通配符的缺陷 這是一個使用通配符的例子,但結果不是你所期望的。假設可執行文件』foo』是從當前目錄中的所有』.o』文件生成的: objects = *.o foo : $(objects) cc -o foo $(CFLAGS) $(objects) objects變量的值是字符串』*.o』。通配符擴展在規則』foo』中進行,于是所有存在的』.o』文件成爲』foo』的依靠而且在需要時重新編譯。 但假如刪除了所有的』.o』文件呢?當通配符不匹配任何文件時,一切都保持原樣:則』foo』依靠于一個叫做』*.o』的文件;由于這個文件不大可能存在,』make』程序會報告一個無法生成』*.o』文件的錯誤,這不是期待的結果。 實際上可以用通配符獲得期望結果,但是需要複雜的技術,包括』wildcard』函數和字符串替換函數。 3.3.2.wildcard函數 通配符自動在規則中進行。但是在變量賦值的和函數的參數中通配符不會擴展,假如在這些情況下需要通配符擴展,必須使用』wildcard』函數。語法如下: $(wildcard PATTERN...) 這個在makefile任何地方出現的字符串,會被匹配任何一個文件名格式的以空格隔開的現有文件列表替換。假如沒有任何文件匹配一個模式,這個模式從』wildcard』的輸出中忽略,注重,這和上述的通配符的處理是不一樣的。 『wildcard』函數的一個功能是找出目錄中所有的』.c』文件: $(wildcard *.c) 可以通過替換後綴』.c』爲』.o』從C文件列表得到目標文件的列表: $(patsubst %.c,%.o,$(wildcard *.c)) 這樣,上節中的makefile改寫爲: objects := $(patsubst %.c,%.o,$(wildcard *.c)) foo : $(objects) cc -o foo $(objects) 這個makefile利用了編譯C程序的隱含規則,所以不需要對編譯寫出顯式的規則。(』:=』是』=』的一個變體) 注重:』PATTERN』是大小寫敏感的。 3.4.目錄搜索 對于大的系統,通常將源文件和目標文件放在不同的目錄中。目錄搜索功能可以讓make自動在多個目錄中搜尋依靠文件,當你將文件重新分布是,不需要改變規則,更改搜索路徑即可。 3.4.1.『VPATH』 make變量』VPATH』列出make應當搜索的目錄列表。很多情況下,當前目錄不包含依靠文件,』VPATH』描述一個對所有文件的搜索列表,包含那些是規則的目標的文件。 假如一個目標或者依靠文件在當前目錄沒找到的話,』make』在』VPATH』中列出的目錄中查找同名的文件。假如找到的話,那個文件成爲依靠文件;規則可以象這些文件在當前目錄中一樣來使用他們。 在』VPATH』變量中,目錄名以冒號或空格隔開;目錄列出的順序決定make查找的順序。(注:在pSOSystem 2.5移植到Win32的GNU make目錄名必須使用分號隔開,以下均簡稱Win32 GNU make)。舉例說明: VPATH = src:../headers 則規則 foo.o : foo.c 被解釋爲 foo.o : src/foo.c 假設』foo.c』在當前目錄不存在,在』src』目錄中可以找到。 3.4.2.選擇性搜索 與』VPATH』變量相似但更具選擇性的是』vpath』指令(注重是小寫),可以指定對于符合特定模式文件的查找路徑。這樣可以爲不同類型的文件指定不同的搜索路徑。 『vpath』指令共有三中形式: 10.『vpath PATTERN DirectorIES』 爲匹配PATTERN的文件名指定搜索路徑DIRECTORIES,目錄的分隔和』VPATH』的相同 11.『vpath PATTERN』 清除爲匹配PATTERN的文件名指定的搜索路徑 12.『vpath』 清除所有以前用』vpath』指定的搜索路徑 『vpath』的模式是包含』%』的字符串:這個字符串必須匹配需要搜索的依靠文件名,』%』字符匹配0個或多個任意字符。例如:』%.h』匹配任何以』.h』結尾的文件(假如沒有%,則PATTERN必須和依靠文件完全一致,這種用法不太多)。 當當前目錄中不存在依靠文件時,假如』vpath』中的PATTERN匹配依靠文件名,則指令中DIRECTORIES列出的目錄和』VPATH』中同樣處理。舉例: vpath %.h ../headers 告訴make在當前目錄中未找到的』.h』文件在../headers目錄中查找。 假如多個』vapth』的模式匹配依靠文件名,make將逐一處理,在所有指定的目錄中搜索。Make按照』vapth』在makefile中的次序;來處理它們,多個相同模式的』vapth』是相互獨立的。 vpath %.c foo vpath % blish vpath %.c bar 將按照』foo』,『blish』,』bar』的次序查找』.c』文件。而 vpath %.c foo:bar vpath % blish 按照』foo』,』bar』,』blish』的順序搜索。 3.4.3.使用自動變量 目錄搜索的結果並不改變規則中的命令:命令按原樣被執行。因此,必須寫出與目錄搜索功相適應的命令。這可以通過使用』$^』這樣的自動變量來完成。』$^』表示規則中的所有依靠文件,包含它們所在的目錄名(參見目錄搜索);』$@』表示目標。例如: foo.o : foo.c cc -c $(CFLAGS) $^ -o $@ 通常情況下,依靠文件也包含頭文件,但命令中並不提及這些文件:變量』$<』表示第一個依靠文件: VPATH = src:../headers foo.o : foo.c defs.h hack.h cc –c $(CFLAGS) $< -o $@ 3.4.4.目錄搜索和隱含規則 使用』VPATH』和』vpath』指定目錄搜索也會影響隱含規則。例如:文件』foo.o』沒有顯式規則,make會考慮隱式規則:假如』foo.c』存在則編譯它;假如這個文件不存在,則在相應的目錄中查找;假如』foo.c』在任一的目錄中存在,則C編譯的隱式規則被應用。 隱式規則的命令使用自動變量通常是必要的,這樣無需其它努力即可以使用目錄搜索得到的文件名。 3.5.PHONY目標 Phony目標並非實際的文件名:只是在顯式請求時執行命令的名字。有兩種理由需要使用phony目標:避免和同名文件沖突,改善性能。 假如編寫一個規則,並不産生目標文件,則其命令在每次make該目標時都執行。例如: clean: rm *.o temp 因爲』rm』命令並不産生』clean』文件,則每次執行』make clean』的時候,該命令都會執行。假如目錄中出現了』clean』文件,則規則失效了:沒有依靠文件,文件』clean』始終是最新的,命令永遠不會執行;爲避免這個問題,可使用』.PHONY』指明該目標。如: .PHONY : clean 這樣執行』make clean』會無視』clean』文件存在與否。 已知phony目標並非是由其它文件生成的實際文件,make會跳過隱含規則搜索。這就是聲明phony目標會改善性能的原因,即使你並不擔心實際文件存在與否。完整的例子如下: .PHONY : clean clean : rm *.o temp phony目標不應是真正目標文件的依靠。假如這樣,每次make在更新此文件時,命令都會執行。只要phony目標不是真正目標的依靠,規則的命令只有在指定此目標時才執行。 Phony目標可以有依靠關系。當一個目錄中有多個程序是,將其放在一個makefile中會更方便。因爲缺省目標是makefile中的第一個目標,通常將這個phony目標叫做』all』,其依靠文件爲各個程序: 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』將可以將三個程序都生成了。 當一個phony目標是另一個的依靠,其作用相當于子程序,例如: .PHONY: cleanall cleanobj cleandiff cleanall : cleanobj cleandiff rm program cleanobj : rm *.o cleandiff : rm *.diff 3.6.FORCE目標 當規則沒有依靠關系也沒有命令,而且其目標不是存在的文件名,make認爲此規則運行時這個目標總是被更新。這意味著假如規則依靠于此目標,其命令總是被執行。 clean: FORCE rm $(objects) FORCE: 例中目標』FORCE』滿足這種非凡條件,這樣依靠于它的目標』clean』被強制執行其命令。名字』FORCE』沒有非凡含義,只不過通常這樣用而已。這種方式使用』FORCE』和』.PHONY : clean』效果相同。使用』.PHONY』更加明確高效,擔不是所有的』make』都支持;這樣許多makefile中使用了』FORCE』。 3.7.空目標 空目標(empty target)是phony目標的變種:用來執行顯式請求的一個動作。和phony目標不同的是:這個目標文件可以真實存在,擔文件的內容無關緊要,通常是空的。空目標文件的目的是利用其最後修改時間來記錄命令最近一次執行的時間,這是通過使用』touch』命令更新目標文件來達到的。 print: foo.c bar.c lpr -p $? touch print 利用這條規則,執行』make print』時假如自上次』make print』之後任一文件改變了,』lpr』命令會執行。自動變量』$?』是爲了只打印出那些變化了的文件。 3.8.內建的非凡目標 某些名字作爲目標存在時有非凡含義。 13..PHONY 該目標的依靠被認爲是phony目標,處理這些目標時,命令無條件被執行,不管文件名是否存在及其最後修改時間 14..SUFFIXES 該目標的依靠被認爲是一個後綴列表,在檢查後綴規則時使用 15..DEFAULT 該目標的規則被使用在沒有規則(顯式的或隱含的)的目標上。假如』DEFAULT』命令定義了,則對所有不是規則目標的依靠文件都會執行該組命令 16..PRECIOUS 該目標的依靠文件會受到非凡對待:假如make被kill或命令的執行被中止,這些目標並不刪除;而且假如該目標是中間文件,在不需要時不會被刪除。可以將隱含規則的目標模式(如%.o)做爲』.PRECIOUS』的依靠文件,這樣可以保存這些規則産生的中間文件。 17..INTERMEDIATE 該目標的依靠文件被當作中間文件;假如該目標沒有依靠文件,則makefile中所有的目標文件均被認爲是中間文件。 18..IGNORE 在執行該目標的依靠規則的命令時,make會忽略錯誤,此規則本身的命令沒有意義。假如該規則沒有依靠關系,表示忽略所有命令執行的錯誤,這種用法只是爲了向後兼容;由于會影響到所有的命令,所以不是非凡有用,推薦使用其它更有選擇性忽略錯誤的方法。 19..SILENT 在執行該目標的依靠規則的命令時,make並不打印命令本身。該規則的命令沒有意義。在』.SILIENT』沒有依靠關系時,表示執行makefile中的所有命令都不會打印,該規則只是爲了向後兼容提供的。 20..EXPORT_ALL_VARIABLES 只是作爲一個目標存在,指示make將所有變量輸出到子進程中。 定義的隱含規則的後綴作爲目標時,也認爲它是非凡目標;兩個後綴的連接也是一樣,比如』.c.o』。這些目標是後綴規則,一中定義隱式規則的過時方法(但仍然廣泛使用)。後綴通常以』.』開始,所以非凡目標也以』.』開始。 3.9.一個規則多個目標 一條有多個目標的規則和寫多條規則,每條一個目標作用是等同的。同樣的命令應用于所有目標,但其效用會因將實際目標以』$@』代替而不同。規則中所有目標的依靠關系是一樣的。 這在兩種情況下有用: ★只有依靠關系,不需要命令。例如: kbd.o command.o files.o: command.h 21.所有的目標同樣的命令。命令不需要完全相同,因爲在命令中可以使用』$@』: bigoutput littleoutput : text.g generate text.g -$(subst output,,$@) > $@ 和 bigoutput : text.g generate text.g -big > bigoutput littleoutput : text.g generate text.g -little > littleoutput 等同。這裏假設程序』generate』産生兩種輸出:一種使用』-big』選項,一種使用』-little』選項。假如想象使用』$@』變化命令那樣來變化依靠關系,不能通過多目標的普通規則實現,但是可以通過模式規則來實現。 3.10.一個目標多條規則 一個文件可以是多條規則的目標,所有規則的依靠關系被合並。假如目標比任一個依靠文件舊,命令被執行。 一個文件只能有一組命令執行。假如多個規則對于同一個文件都給出了命令,make使用最後一組並打印錯誤信息(非凡情況:假如文件名以』.』開始,並不打印錯誤信息,這一點是爲了和其它make兼容)。沒有任何理由需要將makefile寫成這樣,這是make給出錯誤信息的理由。 一條只有依靠關系的附加規則可以一次給出許多文件的附加依靠文件。例如』objects』變量表示系統中編譯器的所有輸出.,說明當』config.h』更改時所有文件必須重做的簡單方法如下: objects = foo.o bar.o foo.o : defs.h bar.o : defs.h test.h $(objects) : config.h 不用改變實際目標文件生成的規則,這條規則可以在需要增刪附加的依靠關系時插入或提出。另一個訣竅是附加的依靠關系可以用變量表示,在make執行時,可以給變量賦值: extradeps= $(objects) : $(extradeps) 當命令`make extradeps=foo.h'執行時會認爲』foo.h』是每個目標文件的依靠文件,但簡單的』make』命令不是這樣。 3.11.靜態模式規則 靜態模式規則(static pattern rules)可以指定多個目標,並且使用目標名字來建議依靠文件的名字;比普通多目標規則更通用因爲不需要依靠關系是相同的:依靠關系必須類似但不需要相同。 3.11.1.語法 TARGETS ...: TARGET-PATTERN: DEP-PATTERNS ... COMMANDS ... TARGETS列表指出規則應用的目標,可以包含通配符,于普通規則的目標相同。TARGET-PATTERN和DEP-PATTERNS來表明目標的依靠關系如何計算:匹配TARGET-PATTERN的目標從名字中抽出一部分,叫做詞幹(stem),詞幹被替換到DEP-PATTERNS來形成依靠文件名。 每個模式通常包含一個』%』字符。當TARGET-PATTERN匹配一個目標時,』%』字符可以匹配目標名中的任何部分;這部分即是詞幹,模式的其余部分必須完全匹配。例如』foo.o』匹配』%.o』,』foo』是詞幹;目標』foo.c』和』foo.out』並不匹配這個模式。 目標的依靠文件名通過將DEP-PATTERNS中的』%』替換爲詞幹形成:假如依靠模式爲』%.c』,在替換詞幹』foo』可以得到』foo.c』。依靠模式中不包含』%』也是合法的,此依靠文件對所有的目標均有效。 假如需要在模式規則中使用』%』字符,必須在其前面加』』字符,假如』%』前的』』字符是有實際意義的,必須在其前面加』』,其它的』』不必如此處理。如』the\%weird\%pattern』在有效的』%』前是』the%weird』,其後是』pattern』。最後的』』保持原樣是因爲其並不影響』%』字符。 以下例子從相應的』.c』文件編譯』foo.o』和』bar.o』: objects = foo.o bar.o $(objects): %.o: %.c $(CC) -c $(CFLAGS) $< -o $@ 每個目標必須匹配目標模式,對于不匹配的目標會給出警告。假如列表中只有部分文件匹配模式,可以使用filter函數移去不匹配的文件名: 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 %.elc,$(files))' 的結果是`foo.elc'。以下例子說明』$*』的使用: bigoutput littleoutput : %output : text.g generate text.g -$* > $@ 命令`generate'執行時,』$*』擴展爲詞幹』big』或』little』。 3.11.2.靜態模式規則和隱式規則 靜態模式規則和隱式規則在作爲模式規則是具有很多共同點,都有目標模式和構造依靠文件名的模式,不同之處在于make決定何時應用規則的方法。 隱式規則可應用于匹配其模式的任何目標,但只限于沒有指定命令的目標,假如有多條可應用的隱式規則,只有一條被使用,取決于規則的順序。 反之,靜態模式規則適用于規則中明確目標列表,不適用于其它目標且總是適用于指定的每個目標。假如有兩條沖突的規則,且都有命令,這是一個錯誤。 靜態模式規則比隱式規則優越之處如下: 22.可爲一些不能按句法分類,但可以顯式列出的文件重載隱式規則 23.不能判定目錄中的精確內容,一些無關的文件可能導致make適用錯誤的隱式規則;最終結果可能依靠于隱式規則的次序。適用靜態模式規則時,這種不確定性是不存在的:規則適用于明確指定的目標。 3.12.雙冒號規則 雙冒號規則(Double-colon rules)的目標後是』::』而不是』:』,當一個目標出現在多條規則中時,其處理和普通規則的處理不同。 當一個目標出現在多條規則中時,所有規則必須是相同類型的:都是普通的或者都是雙冒號的。假如是雙冒號,規則之間相互獨立;假如目標需要更新,則規則的命令被執行;結果可能是沒有執行,或者執行了其中一些,或者所有的規則都執行了。 同一目標的雙冒號規則事實是完全孤立的,每條規則被被單獨處理,就象不同目標的規則一樣;規則按照在makefile中出現的次序被處理,此類規則真正有意義的是那些于命令執行次序無關的。 這種規則有時比較晦澀不是非凡有用;它提供了一種機制:通過不同依靠文件的更新來對目標進行不同的處理,這種情形很罕見。每個這種規則應當提供命令,假如沒有,適用的隱式規則將使用。 3.13.自動生成依靠關系 在makefile中,許多規則都是一些目標文件依靠于一些頭文件。例如:』main.c』 通過』#include』使用』defs.h』,這樣規則: main.o: defs.h 告訴make在』defs.h』變化時更新』main.o』。在程序比較大時,需要寫許多這樣的規則;而且當每次增刪』#include』時,必須小心的更新makefile。許多現代的編譯器可以幫你寫這些規則,通常這是通過編譯器的』-M』選項,例如命令: cc –M main.c 輸出以下內容: main.o : main.c defs.h 這樣就不必寫這些規則,有編譯器代勞了。 注重這樣的依靠關系中提及』main.o』,不會被隱式規則認爲是中間文件,這意味這make在使用過它之後不會將其刪除。使用老的』make』程序時,習慣做法是使用』make depend』命令利用編譯器的功能産生依靠關系,該命令會産生一個』depend』文件包含所有自動産生的依靠關系,然後在makefile中使用』include』將其讀入。 使用GNU的make時,重新生成makefile的功能使得這種做法變得過時:從不需要顯式請求更新依靠關系,因爲它總是重新生成任何過時的makefile。 自動依靠關系生成推薦的做法是對每個源文件做一個makefile。對每個源文件』NAME.c』,有一個makefile 』NAME.d』,其中列出了目標文件』NAME.o』依靠的所有文件,這樣在源文件更新時,需要掃描來産生新的依靠關系。例子是一個從』NAME.c』産生依靠關系文件』NAME.d』的模式規則: %.d: %.c $(SHELL) -ec '$(CC) -M $(CPPFLAGS) $< sed '''s/($*).o[ :]*/1 $@/g''' > $@' -e選項是當$(CC)命令失敗時(exit狀態非0),shell馬上退出。通常shell的返回值是管道中最後一條命令(sed)的返回值,這樣make不會注重到編譯器出錯。 使用GNU的C編譯器時(gcc),可以用』-MM』選項來代替』-M』選項,這樣省略系統頭文件的依靠關系。』sed』命令的目的是將 main.o : main.c defs.h 轉換爲 main.o main.d : main.c defs.h 這樣使得每個』.d』文件依靠于』.o』文件相應源文件和頭文件,make則可以在原文間或頭文件變化時更新依靠關系文件。 假如定義了生成』.d』文件的規則,可以使用』include』指令來讀入所有的文件: sources = foo.c bar.c include $(sources:.c=.d) 例中使用替換變量來將源文件列表』 foo.c bar.c』轉換爲依靠關系文件的列表。因爲』.d』文件和其它文件一樣,不需要更多工作,make會在需要時重新生成它們。 4.編寫命令 規則的命令是由一一執行的shell命令組成。除了以分號隔開寫在依靠關系後的命令,每個命令行必須以tab字符開始空行和注釋行可以出現在命令行中,處理時被忽略(注重:以tab字符開始的空行不是』空』行,是一條空命令)。 可以在命令中使用任何程序,但這些程序是由$(SHELL)來執行的。 4.1.回顯 通常make打印出要執行的命令,稱之爲回顯,這和親自敲命令的現象是一樣的。當行之前有』@』字符時,命令不再回顯,字符』@』在傳遞給shell前丟棄。典型的用法是只對打印命令有效,比如』echo』命令: @echo About to make distribution files 當make使用』-n』或』—just-print』選項時,顯示要發生的一切,但不執行命令。只有在這種情況下,即使命令以』@』開始,命令行仍然顯示出來。這個選項對查看make實際要執行的動作很有用。 『-s』或』—silent』選項阻止make所有回顯,就象所有命令以』@』開始一樣;一條沒有依靠關系的』.SILENT』規則有相同的作用,但是』@』更加靈活。 4.2.執行 在需要執行命令更新目標時,make爲每一行創建一個子shell來執行。這意味著諸如爲進程設置局部變量的shell命令』cd』(改變進程的當前目錄)不會影響以後的命令。假如需要』cd』影響下一個命令,將它們放在一行上用分號隔開,這樣make認爲是一條命令傳遞給shell程序(注重:這需要shell支持): foo : bar/lose cd bar; gobble lose > ../foo 另一個形式使用續行符: foo : bar/lose cd bar; gobble lose > ../foo shell程序的名字是通過』SHELL』變量來取得的。 (*UNIX)不象大多數變量,』SHELL』變量不是通過環境來設置的(即需要在makefile中設置),因爲』SHELL』環境是個人選擇的,假如不同人的選擇會影響makefile的功能的話,這樣很糟糕。 4.3.並行執行 GNU make可以一次執行幾條命令。通常make一次執行一條命令,等待其返回,再執行下一條。使用』-j』或』—jobs』可以同時執行多條命令。假如』-j』後梗一個正數,表示一次可以執行的命令條數;假如』-j』之後沒有參數,則不限制可執行的命令數。缺省的數量是一。 一個討厭的問題是假如同時執行多條命令,它們的輸出會混在一起;另一個問題是兩個進程不能從同一個設備獲得輸入。 4.4.錯誤 每條shell命令返回時,make會檢查其返回狀態。假如命令執行成功,則下一條命令被執行,最後一條命令執行完後,規則執行結束。 假如有錯誤(返回非0狀態),make放棄當前規則,也可能是所有規則。 有時候命令執行錯誤並不是問題,比如使用』mkdir』命令確保目錄存在:假如目錄一存在,則』mkdir』會報告錯誤,但仍希望make繼續。 要忽略命令的錯誤,在命令之前使用』-『字符,』-『字符在傳遞給shell之前被丟棄: clean: -rm -f *.o 假如使用』-i』或』—ignore-errors』選項,make會忽略所有命令産生的錯誤;一條沒有依靠關系的』.IGNORE』規則有相同的作用,但』-『更靈活。 在忽略錯誤時,make將錯誤也認爲是成功,只是通知你命令的退出狀態和和錯誤被忽略。假如make並未告知忽略錯誤,在錯誤發生時,表明該目標不能成功更新,直接或間接依靠于此的目標當然也不能成功;這些目標的命令不會被執行,因爲其先決條件不滿足。 通常make會立即以非0狀態退出。然而,假如給定』-k』或』—keep-going』選項,make在退出前會處理其它的依靠關系,進行必要的更新。例如,在編譯一個目標文件碰到錯誤,』make -k』會繼續編譯其它的目標文件。 通常認爲你的目的是更新指定的目標,當make知道這是不可能時,會立即報告失敗;』-k』選項指示真正目的是測試更新程序的更多可能性:在編譯之前找出更多不相關的問題。 假如命令失敗了,假設它更新的目標文件,這個文件是不完整的不能使用-至少不是完全更新的。但文件的最後修改時間表明停已經是最新的,下一次make運行時,不會再更新這個文件。這種情況和命令被kill相同;則通常情況下在命令失敗時將目標刪除是正確的;當』.DELETE_ON_ERROR』是目標時make幫你做這件事。雖然你總是希望make這麽做,但這不是過去的習慣;所以必須顯式要求make這樣做(其它的make自動這樣做)。 4.5.中斷make 假如make執行命令時碰到錯誤,可能會刪除命令更新的目標文件: make檢查文件的修改時間是否變化。刪除目標的目的是確保make下次執行時重新生成它。爲什麽這樣做?假設在編譯器運行時按了』Ctrl-c』,此時編譯器寫生成目標文件』foo.o』。』Ctrl-c』 kill了編譯器,留下一個不完整的文件,但它的修改時間比源文件』foo.c』新;此時make也受到』Ctrl-c』信號刪除這個不完整的文件,假如make不這樣做,下次make運行時認爲』foo.o』不需要更新,會在鏈接時出現希奇的錯誤。 可以使用』.PRECIOUS』規則來防止目標文件被刪除。在make更新目標時,會檢測其是否爲』.PRECIOUS』的依靠,決定在命令出錯或中斷時是否刪除該目標。假如你希望目標的更新是原子操作,或是用來記錄修改時間,或必須一直存在防止其它類型的錯誤,這些理由使得你必須這樣做。 4.6.遞歸使用 遞歸使用make就是在makefile中使用make命令。這種技術在你將一個大系統分解爲幾個子系統,爲每個自系統提供一個makefile時有用處。比如有一個子目錄』subdir』中有自己的makefile,希望make在自目錄中運行,可以這樣做: subsystem: cd subdir; $(MAKE) 或者 subsystem: $(MAKE) -C subdir 可以照抄這個;例子來遞歸使用make 4.6.1.『MAKE』變量 遞歸的make必須使用』MAKE』變量,不是顯式的make命令: subsystem: cd subdir; $(MAKE) 該變量的值是被調用的make的名字。在命令中使用』MAKE』有非凡的功能:它改變了`-t' (`--touch'), `-n' (`--just-print')和`-q' (`--question')選項的含義。使用上例來考慮』make –t』命令(』-t』選項將目標標記爲最新但不運行命令),更加』-t』選項的功能,該命令將創建一個』subsystem』文件,實際希望的操作是運行』cd subdir; make –t』;但這會執行命令,與』-t』的原意不符。 這個非凡功能做了期望的工作。當命令行包含變量』MAKE』時,選項』-t』,』-n』和』-q』並不適用。不管這些導致不會執行命令的標志,包含』MAKE』變量的命令始終會執行。正常的』MAKEFLAGS』機制將這些標志傳遞到子make,這樣打印命令的請求被傳播到子系統中。 4.6.2.傳遞變量到子make 上級(top-level)make中的變量可以顯式通過環境傳遞到子make中。在子make中,這些變量被缺省定義,但不會重載子makefile中的定義除非使用』-e』選項。 爲向下傳遞,或輸出變量,make在運行命令時將其加入到環境變量中;子make,可以使用環境變量來初始化變量表。除非顯式要求,make只輸出初始環境中或命令行設置的變量而且變量名只由字母,數字和下劃線組成。一些shell不能處理有其它字符的環境變量。 非凡變量』SHELL』,』MAKEFLAGS』總是輸出,假如』MAKEFILE』變量有值,也會輸出。Make自動通過』MAKEFLAGS』來輸出命令行定義的變量。 假如想要輸出特定變量,使用』export』指令: export VARIABLE ... 假如要阻止輸出一個變量,使用』unexport』指令: unexport VARIABLE ... 爲方便起見,可以在定義變量時輸出它: export VARIABLE = value 和 VARIABLE = value export VARIABLE 作用相同。 假如要輸出所有的變量,使用』export』指令本身就可以了。 變量』MAKELEVEL』在一級一級傳遞時會改變,這個變量的值是表示嵌套層數的字符串,頂級』make』是,變量的值爲』0』;子make的值爲』1』;子子make的值爲』2』,依此類推。 『MAKELEVEL』的用途是在條件指令中測試它,這樣寫出在遞歸運行時和直接運行時表現不同的makefile。 以下內容拷貝自GNU Make Manual 5.命令行參數 `-b' `-m' These options are ignored for compatibility with other versions of `make'. `-C DIR' `--directory=DIR' Change to directory DIR before reading the makefiles. If multiple `-C' options are specified, each is interpreted relative to the previous one: `-C / -C etc' is equivalent to `-C /etc'. This is typically used with recursive invocations of `make' (*note Recursive Use of `make': Recursion.). `-d' `--debug' Print debugging information in addition to normal processing. The debugging information says which files are being considered for remaking, which file-times are being compared and with what results, which files actually need to be remade, which implicit rules are considered and which are applied--everything interesting about how `make' decides what to do. `-e' `--environment-overrides' Give variables taken from the environment precedence over variables from makefiles. *Note Variables from the Environment: Environment. `-f FILE' `--file=FILE' `--makefile=FILE' Read the file named FILE as a makefile. `-h' `--help' Remind you of the options that `make' understands and then exit. `-i' `--ignore-errors' Ignore all errors in commands executed to remake files. `-I DIR' `--include-dir=DIR' Specifies a directory DIR to search for included makefiles. If several `-I' options are used to specify several directories, the directories are searched in the order specified. `-j [JOBS]' `--jobs=[JOBS]' Specifies the number of jobs (commands) to run simultaneously. With no argument, `make' runs as many jobs simultaneously as possible. If there is more than one `-j' option, the last one is effective. `-k' `--keep-going' Continue as much as possible after an error. While the target that failed, and those that depend on it, cannot be remade, the other dependencies of these targets can be processed all the same. `-l [LOAD]' `--load-average[=LOAD]' `--max-load[=LOAD]' Specifies that no new jobs (commands) should be started if there are other jobs running and the load average is at least LOAD (a floating-point number). With no argument, removes a previous load limit. *Note Parallel Execution: Parallel. `-n' `--just-print' `--dry-run' `--recon' Print the commands that would be executed, but do not execute them. `-o FILE' `--old-file=FILE' `--assume-old=FILE' Do not remake the file FILE even if it is older than its dependencies, and do not remake anything on account of changes in FILE. Essentially the file is treated as very old and its rules are ignored. `-p' `--print-data-base' Print the data base (rules and variable values) that results from reading the makefiles; then execute as usual or as otherwise specified. This also prints the version information given by the `-v' switch (see below). To print the data base without trying to remake any files, use `make -p -f /dev/null'. `-q' `--question' "Question mode". Do not run any commands, or print anything; just return an exit status that is zero if the specified targets are already up to date, one if any remaking is required, or two if an error is encountered. `-r' `--no-builtin-rules' Eliminate use of the built-in implicit rules.You can still define your own by writing pattern rules. The `-r' option also clears out the default list of suffixes for suffix rules .But you can still define your own suffixes with a rule for `.SUFFIXES', and then define your own suffix rules. `-s' `--silent' `--quiet' Silent operation; do not print the commands as they are executed. `-S' `--no-keep-going' `--stop' Cancel the effect of the `-k' option. This is never necessary except in a recursive `make' where `-k' might be inherited from the top-level `make' via `MAKEFLAGS' or if you set `-k' in `MAKEFLAGS' in your environment. `-t' `--touch' Touch files (mark them up to date without really changing them) instead of running their commands. This is used to pretend that the commands were done, in order to fool future invocations of `make'. `-v' `--version' Print the version of the `make' program plus a copyright, a list of authors, and a notice that there is no warranty; then exit. `-w' `--print-directory' Print a message containing the working directory both before and after executing the makefile. This may be useful for tracking down errors from complicated nests of recursive `make' commands. `--no-print-directory' Disable printing of the working directory under `-w'. This option is useful when `-w' is turned on automatically, but you do not want to see the extra messages. `-W FILE' `--what-if=FILE' `--new-file=FILE' `--assume-new=FILE' Pretend that the target FILE has just been modified. When used with the `-n' flag, this shows you what would happen if you were to modify that file. Without `-n', it is almost the same as running a `touch' command on the given file before running `make', except that the modification time is changed only in the imagination of `make'. `--warn-undefined-variables' Issue a warning message whenever `make' sees a reference to an undefined variable. This can be helpful when you are trying to debug makefiles which use variables in complex ways. 6.參考 6.1.指令 `define VARIABLE' `endef' Define a multi-line, recursively-expanded variable. *Note Sequences::. `ifdef VARIABLE' `ifndef VARIABLE' `ifeq (A,B)' `ifeq "A" "B"' `ifeq 'A' 'B'' `ifneq (A,B)' `ifneq "A" "B"' `ifneq 'A' 'B'' `else' `endif' Conditionally evaluate part of the makefile. `include FILE' Include another makefile. `override VARIABLE = VALUE' `override VARIABLE := VALUE' `override VARIABLE += VALUE' `override define VARIABLE' `endef' Define a variable, overriding any previous definition, even one from the command line. `export' Tell `make' to export all variables to child processes by default. `export VARIABLE' `export VARIABLE = VALUE' `export VARIABLE := VALUE' `export VARIABLE += VALUE' `unexport VARIABLE' Tell `make' whether or not to export a particular variable to child processes. `vpath PATTERN PATH' Specify a search path for files matching a `%' pattern. *Note The `vpath' Directive: Selective Search. `vpath PATTERN' Remove all search paths previously specified for PATTERN. `vpath' Remove all search paths previously specified in any `vpath' directive. 6.2.函數 `$(subst FROM,TO,TEXT)' Replace FROM with TO in TEXT. `$(patsubst PATTERN,REPLACEMENT,TEXT)' Replace Words matching PATTERN with REPLACEMENT in TEXT. `$(strip STRING)' Remove excess whitespace characters from STRING. `$(findstring FIND,TEXT)' Locate FIND in TEXT. `$(filter PATTERN...,TEXT)' Select words in TEXT that match one of the PATTERN words. `$(filter-out PATTERN...,TEXT)' Select words in TEXT that *do not* match any of the PATTERN words. `$(sort LIST)' Sort the words in LIST lexicographically, removing duplicates. `$(dir NAMES...)' Extract the directory part of each file name. `$(notdir NAMES...)' Extract the non-directory part of each file name. `$(suffix NAMES...)' Extract the suffix (the last `.' and following characters) of each file name. `$(basename NAMES...)' Extract the base name (name without suffix) of each file name. `$(addsuffix SUFFIX,NAMES...)' Append SUFFIX to each word in NAMES. `$(addprefix PREFIX,NAMES...)' Prepend PREFIX to each word in NAMES. `$(join LIST1,LIST2)' Join two parallel lists of words. `$(word N,TEXT)' Extract the Nth word (one-origin) of TEXT. `$(words TEXT)' Count the number of words in TEXT. `$(firstword NAMES...)' Extract the first word of NAMES. `$(wildcard PATTERN...)' Find file names matching a shell file name pattern (*not* a `%' pattern). `$(shell COMMAND)' Execute a shell command and return its output. `$(origin VARIABLE)' Return a string describing how the `make' variable VARIABLE was defined. `$(foreach VAR,WORDS,TEXT)' Evaluate TEXT with VAR bound to each word in WORDS, and concatenate the results. 6.3.自動變量 `$@' The file name of the target. `$%' The target member name, when the target is an archive member. `$<' The name of the first dependency. `$?' The names of all the dependencies that are newer than the target, with spaces between them. For dependencies which are archive members, only the member named is used with spaces between them. For dependencies which are archive members, only the member named is used `$^' `$+' The names of all the dependencies, with spaces between them. For dependencies which are archive members, only the member named is used. The value of `$^' omits duplicate dependencies, while `$+' retains them and preserves their order. `$*' The stem with which an implicit rule matches `$(@D)' `$(@F)' The directory part and the file-within-directory part of `$@'. `$(*D)' `$(*F)' The directory part and the file-within-directory part of `$*'. `$(%D)' `$(%F)' The directory part and the file-within-directory part of `$%' `$(<D)' `$(<F)' The directory part and the file-within-directory part of `$<' `$(^D)' `$(^F)' The directory part and the file-within-directory part of `$^' `$(+D)' `$(+F)' The directory part and the file-within-directory part of `$+' `$(?D)' `$(?F)' The directory part and the file-within-directory part of `$?' 6.4.非凡變量 `MAKEFILES' Makefiles to be read on every invocation of `make'. `VPATH' Directory search path for files not found in the current directory. `SHELL' The name of the system default command interpreter, usually `/bin/sh'. You can set `SHELL' in the makefile to change the shell used to run commands. `MAKE' The name with which `make' was invoked. Using this variable in commands has special meaning. `MAKELEVEL' The number of levels of recursion (sub-`make's). `MAKEFLAGS' The flags given to `make'. You can set this in the environment or a makefile to set flags. `SUFFIXES' The default list of suffixes before `make' reads any makefiles.
󰈣󰈤
王朝萬家燈火計劃
期待原創作者加盟
 
 
 
>>返回首頁<<
 
 
 
 
 熱帖排行
 
王朝網路微信公眾號
微信掃碼關註本站公眾號 wangchaonetcn
 
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有