翻譯:于鳳昌
make
Version 3.79Richard M. Stallman and Roland McGrath
1 make概述
1.1 怎樣閱讀本手冊
1.2 問題和BUG
2 Makefile文件介紹
2.1 規則的格式
2.2一個簡單的Makefile文件
2.3make處理Makefile文件的過程
2.4使用變量簡化Makefile文件
2.5讓make推斷命令
2.6另一種風格的Makefile文件
2.7在目錄中刪除文件的規則
3ant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;"> 編寫Makefile文件
3.1Makefile文件的內容
3.2Makefile文件的命名
3.3包含其它的Makefile文件
3.4變量MAKEFILES
3.5Makefile文件重新生成的過程
3.6重載其它Makefile文件
3.7make讀取Makefile文件的過程
4 編寫規則
4.1規則的語法
4.2在文件名中使用通配符
4.2.1通配符例子
4.2.2使用通配符的常見錯誤
4.2.3函數wildcard
4.3在目錄中搜尋依賴
4.3.1VPATH:所有依賴的搜尋路徑
4.3.2vpath指令
4.3.3目錄搜尋過程
4.3.4編寫搜尋目錄的shell命令
4.3.5目錄搜尋和隱含規則
4.3.6連接庫的搜尋目錄
4.4假想目標
4.5沒有命令或依賴的規則
4.6使用空目錄文件記錄事件
4.7內建的特殊目標名
4.8具有多個目標的規則
4.9具有多條規則的目標
4.10靜態格式規則
4.10.1靜態格式規則的語法
4.10.2靜態格式規則和隱含規則
4.11雙冒號規則
4.12自動生成依賴
5 在規則中使用命令
5.1命令回顯
5.2執行命令
5.3并行執行
5.4命令錯誤
5.5中斷或關閉make
5.6遞歸調用make
5.6.1變量MAKE的工作方式
5.6.2與子make通訊的變量
5.6.3與子make通訊的選項
5.6.4`--print-directory'選項
5.7定義固定次序命令
5.8使用空命令
6 使用變量
6.1變量引用基礎
6.2變量的兩個特色
6.3變量高級引用技術
6.3.1替換引用
6.3.2嵌套變量引用
6.4變量取值
6.5設置變量
6.6為變量值追加文本
6.7override指令
6.8定義多行變量
6.9環境變量
6.10特定目標變量的值
6.11特定格式變量的值
7 Makefile文件的條件語句
7.1條件語句的例子
7.2條件語句的語法
7.3測試標志的條件語句
8 文本轉換函數
8.1函數調用語法
8.2字符串替換和分析函數
8.3文件名函數
8.4函數foreach
8.5函數if
8.6函數call
8.7函數origin
8.8函數shell
8.9控制Make的函數
9 運行make
9.1指定Makefile文件的參數
9.2指定最終目標的參數
9.3代替執行命令
9.4避免重新編譯文件
9.5變量重載
9.6測試編譯程序
9.7選項概要
10 使用隱含規則
10.1使用隱含規則
10.2隱含規則目錄
10.3隱含規則使用的變量
10.4隱含規則鏈
10.5定義與重新定義格式規則
10.5.1格式規則簡介
10.5.2格式規則的例子
10.5.3自動變量
10.5.4格式匹配
10.5.5萬用規則
10.5.6刪除隱含規則
10.6定義最新類型的缺省規則
10.7過時的后綴規則
10.8隱含規則搜尋算法
11 使用make更新檔案文件
11.1檔案成員目標
11.2檔案成員目標的隱含規則
11.2.1更新檔案成員的符號索引表
11.3使用檔案的危險
11.4檔案文件的后綴規則
12 GNU make的特點
13 不兼容性和失去的特點
14 Makefile文件慣例
14.1makefile文件的通用慣例
14.2makefile文件的工具
14.3指定命令的變量
14.4安裝路徑變量
14.5用戶標準目標
14.6安裝命令分類
15快速參考
16make產生的錯誤
17復雜的Makefile文件例子
附錄 名詞翻譯對照表
Make 可自動決定一個大程序中哪些文件需要重新編譯,并發布重新編譯它們的命令。本版本GNU Make使用手冊由RichardM. Stallman and Roland McGrath編著,是從Paul D. Smith撰寫的V3.76版本發展過來的。
GNU Make符合IEEE Standard 1003.2-1992(POSIX.2) 6.2章節的規定。
因為C語言程序更具有代表性,所以我們的例子基于C語言程序,但Make并不是僅僅能夠處理C語言程序,它可以處理那些編譯器能夠在Shell命令下運行的的各種語言的程序。事實上,GNUMake不僅僅限于程序,它可以適用于任何如果一些文件變化導致另外一些文件必須更新的任務。
如果要使用Make,必須先寫一個稱為Makefile的文件,該文件描述程序中各個文件之間的相互關系,并且提供每一個文件的更新命令。在一個程序中,可執行程序文件的更新依靠OBJ文件,而OBJ文件是由源文件編譯得來的。
一旦合適的Makefile文件存在,每次更改一些源文件,在shell命令下簡單的鍵入:
make
就能執行所有的必要的重新編譯任務。Make程序根據Makefile文件中的數據和每個文件更改的時間戳決定哪些文件需要更新。對于這些需要更新的文件,Make基于Makefile文件發布命令進行更新,進行更新的方式由提供的命令行參數控制。具體操作請看運行Make章節。
如果您現在對Make一無所知或者您僅需要了解對make 的普通性介紹,請查閱前幾章內容,略過后面的章節。前幾章節是普通介紹性內容,后面的章節是具體的專業、技術內容。
如果您對其它Make程序十分熟悉,請參閱GNU Make的特點和不兼容性和失去的特點部分,GNU Make的特點這一章列出了GNU Make對make程序的擴展,不兼容和失去的特點一章解釋了其它Make程序有的特征而GNU Make缺乏的原因。
對于快速瀏覽者,請參閱選項概要、快速參考和內建的特殊目標名部分。
如果您有關于GNUMake的問題或者您認為您發現了一個BUG,請向開發者報告;我們不能許諾我們能干什么,但我們會盡力修正它。在報告BUG之前,請確定您是否真正發現了BUG,仔細研究文檔后確認它是否真的按您的指令運行。如果文檔不能清楚的告訴您怎么做,也要報告它,這是文檔的一個BUG。
在您報告或者自己親自修正BUG之前,請把它分離出來,即在使問題暴露的前提下盡可能的縮小Makefile文件。然后把這個Makefile文件和Make給出的精確結果發給我們。同時請說明您希望得到什么,這可以幫助我們確定問題是否出在文檔上。
一旦您找到一個精確的問題,請給我們發E-mail,我們的E-mail地址是:
bug-make@gnu.org
在郵件中請包含您使用的GNU Make的版本號。您可以利用命令‘make--version’得到版本號。同時希望您提供您的機器型號和操作系統類型,如有可能的話,希望同時提供config.h文件(該文件有配置過程產生)。
Make程序需要一個所謂的Makefile文件來告訴它干什么。在大多數情況下,Makefile文件告訴Make怎樣編譯和連接成一個程序。
本章我們將討論一個簡單的Makefile文件,該文件描述怎樣將8個C源程序文件和3個頭文件編譯和連接成為一個文本編輯器。Makefile文件可以同時告訴Make怎樣運行所需要的雜亂無章的命令(例如,清除操作時刪除特定的文件)。如果要看更詳細、復雜的Makefile文件例子,請參閱復雜的Makefile文件例子一章。
當Make重新編譯這個編輯器時,所有改動的C語言源文件必須重新編譯。如果一個頭文件改變,每一個包含該頭文件的C語言源文件必須重新編譯,這樣才能保證生成的編輯器是所有源文件更新后的編輯器。每一個C語言源文件編譯后產生一個對應的OBJ文件,如果一個源文件重新編譯,所有的OBJ文件無論是剛剛編譯得到的或原來編譯得到的必須從新連接,形成一個新的可執行文件。
一個簡單的Makefile文件包含一系列的“規則”,其樣式如下:
目標(target)…: 依賴(prerequiries)…
<tab>命令(command)
…
…
目標(target)通常是要產生的文件的名稱,目標的例子是可執行文件或OBJ文件。目標也可是一個執行的動作名稱,諸如‘clean’(詳細內容請參閱假想目標一節)。
依賴是用來輸入從而產生目標的文件,一個目標經常有幾個依賴。
命令是Make執行的動作,一個規則可以含有幾個命令,每個命令占一行。注意:每個命令行前面必須是一個Tab字符,即命令行第一個字符是Tab。這是不小心容易出錯的地方。
通常,如果一個依賴發生變化,則需要規則調用命令對相應依賴和服務進行處理從而更新或創建目標。但是,指定命令更新目標的規則并不都需要依賴,例如,包含和目標‘clern’相聯系的刪除命令的規則就沒有依賴。
規則一般是用于解釋怎樣和何時重建特定文件的,這些特定文件是這個詳盡規則的目標。Make需首先調用命令對依賴進行處理,進而才能創建或更新目標。當然,一個規則也可以是用于解釋怎樣和何時執行一個動作,詳見編寫規則一章。
一個Makefile文件可以包含規則以外的其它文本,但一個簡單的Makefile文件僅僅需要包含規則。雖然真正的規則比這里展示的例子復雜,但格式卻是完全一樣。
一個簡單的Makefile文件,該文件描述了一個稱為文本編輯器(edit)的可執行文件生成方法,該文件依靠8個OBJ文件(.o文件),它們又依靠8個C源程序文件和3個頭文件。
在這個例子中,所有的C語言源文件都包含‘defs.h’ 頭文件,但僅僅定義編輯命令的源文件包含‘command.h’頭文件,僅僅改變編輯器緩沖區的低層文件包含‘buffer.h’頭文件。
edit : main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
clearcase/" target="_blank" >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
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 main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
我們把每一個長行使用反斜杠-新行法分裂為兩行或多行,實際上它們相當于一行,這樣做的意圖僅僅是為了閱讀方便。
使用Makefile文件創建可執行的稱為‘edit’的文件,鍵入:make
使用Makefile文件從目錄中刪除可執行文件和目標,鍵入:make clean
在這個Makefile文件例子中,目標包括可執行文件‘edit’和OBJ文件‘main.o’及‘kdb.o’。依賴是C語言源文件和C語言頭文件如‘main.c’和‘def.h’等。事實上,每一個OBJ文件即是目標也是依賴。所以命令行包括‘cc-c main.c’和‘cc -c kbd.c’。
當目標是一個文件時,如果它的任一個依賴發生變化,目標必須重新編譯和連接。任何命令行的第一個字符必須是‘Tab’字符,這樣可以把Makefile文件中的命令行與其它行分別開來。(一定要牢記:Make并不知道命令是如何工作的,它僅僅能向您提供保證目標的合適更新的命令。Make的全部工作是當目標需要更新時,按照您制定的具體規則執行命令。)
目標‘clean’不是一個文件,僅僅是一個動作的名稱。正常情況下,在規則中‘clean’這個動作并不執行,目標‘clean’也不需要任何依賴。一般情況下,除非特意告訴make執行‘clean’命令,否則‘clean’命令永遠不會執行。注意這樣的規則不需要任何依賴,它們存在的目的僅僅是執行一些特殊的命令。象這些不需要依賴僅僅表達動作的目標稱為假想目標。詳細內容參見假想目標;參閱命令錯誤可以了解rm或其它命令是怎樣導致make忽略錯誤的。
缺省情況下,make開始于第一個目標(假想目標的名稱前帶‘.’)。這個目標稱為缺省最終目標(即make最終更新的目標,具體內容請看指定最終目標的參數一節)。
在上節的簡單例子中,缺省最終目標是更新可執行文件‘edit’,所以我們將該規則設為第一規則。這樣,一旦您給出命令:
make
make就會讀當前目錄下的makefile文件,并開始處理第一條規則。在本例中,第一條規則是連接生成‘edit’,但在make全部完成本規則工作之前,必須先處理‘edit’所依靠的OBJ文件。這些OBJ文件按照各自的規則被處理更新,每個OBJ文件的更新規則是編譯其源文件。重新編譯根據其依靠的源文件或頭文件是否比現存的OBJ文件更‘新’,或者OBJ文件是否存在來判斷。
其它規則的處理根據它們的目標是否和缺省最終目標的依賴相關聯來判斷。如果一些規則和缺省最終目標無任何關聯則這些規則不會被執行,除非告訴Make強制執行(如輸入執行makeclean命令)。
在OBJ文件重新編譯之前,Make首先檢查它的依賴C語言源文件和C語言頭文件是否需要更新。如果這些C語言源文件和C語言頭文件不是任何規則的目標,make將不會對它們做任何事情。Make也可以自動產生C語言源程序,這需要特定的規則,如可以根據Bison或Yacc產生C語言源程序。
在OBJ文件重新編譯(如果需要的話)之后,make決定是否重新連接生成edit可執行文件。如果edit可執行文件不存在或任何一個OBJ文件比存在的edit可執行文件‘新’,則make重新連接生成edit可執行文件。
這樣,如果我們修改了‘insert.c’文件,然后運行make,make將會編譯‘insert.c’文件更新‘insert.o’文件,然后重新連接生成edit可執行文件。如果我們修改了‘command.h’文件,然后運行make,make將會重新編譯‘kbd.o’和‘command.o’文件,然后重新連接生成edit可執行文件。
在我們的例子中,我們在‘edit’的生成規則中把所有的OBJ文件列舉了兩次,這里再重復一遍:
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
這樣的兩次列舉有出錯的可能,例如在系統中加入一個新的OBJ文件,我們很有可能在一個需要列舉的地方加入了,而在另外一個地方卻忘記了。我們使用變量可以簡化makefile文件并且排除這種出錯的可能。變量是定義一個字符串一次,而能在多處替代該字符串使用(具體內容請閱讀使用變量一節)。
在makefile文件中使用名為objects
, OBJECTS
,objs
,OBJS
,obj
,或 OBJ的變量代表所有OBJ文件已是約定成俗。
在這個makefile文件我們定義了名為objects的變量,其定義格式如下:
objects = main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
然后,在每一個需要列舉OBJ文件的地方,我們使用寫為
`$(objects)'形式的變量代替(具體內容請閱讀使用變量一節)。下面是使用變量后的完整的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 :
rmedit $(objects)
編譯單獨的C語言源程序并不需要寫出命令,因為make可以把它推斷出來:make有一個使用‘CC –c’命令的把C語言源程序編譯更新為相同文件名的OBJ文件的隱含規則。例如make可以自動使用‘cc -c main.c -o main.o’命令把‘main.c’編譯 ‘main.o’。因此,我們可以省略OBJ文件的更新規則。詳細內容請看使用隱含規則一節。
如果C語言源程序能夠這樣自動編譯,則它同樣能夠自動加入到依賴中。所以我們可在依賴中省略C語言源程序,進而可以省略命令。下面是使用隱含規則和變量objects的完整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)