日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

GNU make中文手冊-第三章:Makefile 總述

 todaytomo 2006-12-30
GNU make中文手冊-第三章:Makefile 總述 作者: hew  發(fā)布日期: 2006-3-21    查看數(shù): 151   出自: http://www.
第三章:Makefile 總述

3.1 Makefile的內(nèi)容
在一個(gè)完整的Makefile中,包含了5個(gè)東西:顯式規(guī)則、隱含規(guī)則、變量的定義、指示符和注釋。關(guān)于“規(guī)則”、“變量”和“Makefile指示符”將在后續(xù)的章節(jié)進(jìn)行詳細(xì)的討論。本章討論的是一些基本概念。

² 顯式規(guī)則:它描述了在何種情況下如何更新一個(gè)或者多個(gè)被稱為目標(biāo)的文件(Makefile的目標(biāo)文件)。在書寫Makefile是需要明確地給出目標(biāo)文件、目標(biāo)的依賴文件列表以及更新目標(biāo)文件所需要的命令。

² 隱含規(guī)則:它是make根據(jù)此類目標(biāo)文件的命名(典型的是文件名的后綴)而自動推導(dǎo)出來的規(guī)則。make根據(jù)目標(biāo)文件的名字,自動產(chǎn)生目標(biāo)的依賴文件并使用默認(rèn)的命令來對目標(biāo)進(jìn)行更新。

² 變量定義:就是使用一個(gè)字符串代表一段文本串,當(dāng)定義了變量以后,Makefile后續(xù)在需要使用此文本串的地方,通過引用這個(gè)變量來實(shí)現(xiàn)對文本串的使 用。第一章的的例子中,我們就定義了一個(gè)變量“objects”來表示一個(gè).o文件列表。關(guān)于變量的詳細(xì)討論可參考 第五章 Makefile中的變量

² Makefile指示符:指示符指明在make程序讀取makefile文件過程中所要執(zhí)行的一個(gè)動作。其中包括:

² 讀取一個(gè)文件,讀取給定文件名的文件。參考 2.3 包含其它makefile文件一節(jié)

² 決定(通常是根據(jù)一個(gè)變量的得值)處理或者忽略Makefile中的某一特定部分。參考 第六章Makefile的條件執(zhí)行

² 定義一個(gè)多行變量。參考 5.8 多行定義 一節(jié)

² 注釋:Makefile中“#”字符后的內(nèi)容被作為是注釋內(nèi)容(和shell腳本一樣)處理。如果此行的第一個(gè)非空字符為“#”,那么此行為注釋行。注釋 行的結(jié)尾如果存在反斜線(\),那么下一行也被作為注釋行。一般在書寫Makefile時(shí)推薦將注釋作為一個(gè)獨(dú)立的行,而不要和Makefile的有效行 放在一行中書寫。當(dāng)在Makefile中需要使用字符“#”時(shí),可以使用反斜線加“#”(\#)來實(shí)現(xiàn),其表示將“#”作為一字符而不是注釋的開始標(biāo)志。

需要注意的地方:

Makefile中第一個(gè)規(guī)則之后的所有以[Tab]字符開始的的行,make程序都會將其給系統(tǒng)的shell程序去解釋執(zhí)行。因此以[Tab]字符開始 的注釋行也會被交給shell來處理,此命令行是否需要被執(zhí)行(shell執(zhí)行或者忽略)是由系統(tǒng)shell程序來判決的。

另外,在使用指示符“define”定義一個(gè)多行的變量或者命令包時(shí),其定義體(“define”和“endef”之間的內(nèi)容)會被完整的展開到 Makefile中引用此變量的地方(包含定義體中的注釋行);make在引用此變量的地方對所有的定義體進(jìn)行處理,決定是注釋還是有效內(nèi)容。 Makefile中的變量可以和C語言中的宏(實(shí)質(zhì)一樣)一樣來理解。對一個(gè)變量引用的地方make所做的就是將這個(gè)變量根據(jù)定義進(jìn)行基于文本的展開,展 開變量的過程不涉及到任何變量的具體含義和功能分析。



3.2 makefile文件的命名
默認(rèn)的情況下,make會在工作目錄(執(zhí)行make的目錄)下按照文件名順序?qū)ふ襪akefile文件讀取并執(zhí)行,查找的文件名順序?yàn)椋?#8220;GNUmakefile”、“makefile”、“Makefile”。

通常應(yīng)該使用“makefile”或者“Makefile”作為一個(gè)makefile的文件名(我們推薦使用“Makefile”,首字母大寫而比較顯 著,一般在一個(gè)目錄中和當(dāng)前目錄的一些重要文件(README,Chagelist等)靠近,在尋找時(shí)會比較容易的發(fā)現(xiàn)它)。而 “GNUmakefile”是我們不推薦使用的文件名,因?yàn)橐源嗣奈募挥?#8220;GNU make”才可以識別,而其他版本的make程序只會在工作目錄下“makefile”和“Makefile”這兩個(gè)文件。

如果make程序在工作目錄下無法找到以上三個(gè)文件中的任何一個(gè),它將不讀取任何其他文件作為解析對象。但是根據(jù)make隱含規(guī)則的特性,我們可以通過命 令行指定一個(gè)目標(biāo),如果當(dāng)前目錄下存在符合此目標(biāo)的依賴文件,那么這個(gè)命令行所指定的目標(biāo)將會被創(chuàng)建或者更新,參見注釋。

當(dāng)makefile文件的命名不是這三個(gè)任何一個(gè)時(shí),需要通過make的“-f”或者“--file”選項(xiàng)來指定make讀取的makefile文件。給 make指定makefile文件的格式為:“-f NAME”或者“—file=NAME”,它指定文件“NAME”作為執(zhí)行make時(shí)讀取的makefile文件。也可以通過多個(gè)“-f”或者“-- file”選項(xiàng)來指定多個(gè)需要讀取的makefile文件,多個(gè)makefile文件將會被按照指定的順序進(jìn)行連接并被make解析執(zhí)行。當(dāng)通過“-f” 或者“--file”指定make讀取makefile的文件時(shí),make就不再自動查找這三個(gè)標(biāo)準(zhǔn)命名的makefile文件。



注釋:通過命令指定目標(biāo)使用make的隱含規(guī)則:

當(dāng)前目錄下不存在以“GNUmakefile”、“makefile”、“Makefile”命名的任何文件,

1. 當(dāng)前目錄下存在一個(gè)源文件foo.c的,我們可以使用“make foo.o”來使用make的隱含規(guī)則自動生成foo.o。當(dāng)執(zhí)行“make foo.o”時(shí)。我們可以看到其執(zhí)行的命令為:

cc –c –o foo.o foo.c

之后,foo.o將會被創(chuàng)建或者更新。

2. 如果當(dāng)前目錄下沒有foo.c文件時(shí),就是make對.o文件目標(biāo)的隱含規(guī)則中依賴文件不存在。如果使用命令“make foo.o”時(shí),將回到到如下提示:

make: *** No rule to make target ‘foo.o’. Stop.

3. 如果直接使用命令“make”時(shí),得到的提示信息如下:

make: *** No targets specified and no makefile found. Stop.



3.3 包含其它makefile文件
本節(jié)我們討論如何在一個(gè)Makefile中包含其它的makefile文件。Makefile中包含其它文件的關(guān)鍵字是“include”,和C語言對頭文件的包含方式一致。

“include”指示符告訴make暫停讀取當(dāng)前的Makefile,而轉(zhuǎn)去讀取“include”指定的一個(gè)或者多個(gè)文件,完成以后再繼續(xù)當(dāng)前Makefile的讀取。Makefile中指示符“include”書寫在獨(dú)立的一行,其形式如下:



include FILENAMES...



FILENAMES是shell所支持的文件名(可以使用通配符)。

指示符“include”所在的行可以一個(gè)或者多個(gè)空格(make程序在處理時(shí)將忽略這些空格)開始,切忌不能以[Tab]字符開始(如果一行以 [Tab]字符開始make程序?qū)⒋诵凶鳛橐粋€(gè)命令行來處理)。指示符“include”和文件名之間、多個(gè)文件之間使用空格或者[Tab]鍵隔開。行尾 的空白字符在處理時(shí)被忽略。使用指示符包含進(jìn)來的Makefile中,如果存在變量或者函數(shù)的引用。它們將會在包含它們的Makefile中被展開。

來看一個(gè)例子,存在三個(gè).mk文件,“$(bar)”被擴(kuò)展為“bish bash”。則

include foo *.mk $(bar)



等價(jià)于

include foo a.mk b.mk c.mk bish bash



make程序在處理指示符include時(shí),將暫停對當(dāng)前使用指示符“include”的makefile文件的讀取,而轉(zhuǎn)去依此讀取由 “include”指示符指定的文件列表。直到完成所有這些文件以后再回過頭繼續(xù)讀取指示符“include”所在的makefile文件。

通常指示符“include”用在以下場合:

1. 有多個(gè)不同的程序,由不同目錄下的幾個(gè)獨(dú)立的Makefile來描述其創(chuàng)建或者更新規(guī)則。它們需要使用一組通用的變量定義或者模式規(guī)則。通用的做法是將這 些共同使用的變量或者模式規(guī)則定義在一個(gè)文件中(沒有具體的文件命名限制),在需要使用的Makefile中使用指示符“include”來包含此文件。

2. 當(dāng)根據(jù)源文件自動產(chǎn)生依賴文件時(shí);我們可以將自動產(chǎn)生的依賴關(guān)系保存在另外一個(gè)文件中,主Makefile使用指示符“include”包含這些文件。這 樣的做法比直接在主Makefile中追加依賴文件的方法要明智的多。其它版本的make已經(jīng)使用這種方式來處理。

如果指示符“include”指定的文件不是以斜線開始(絕對路徑,如/usr/src/Makefile...),而且當(dāng)前目錄下也不存在此文件; make將根據(jù)文件名試圖在以下幾個(gè)目錄下查找:首先,查找使用命令行選項(xiàng)“-I”或者“--include-dir”指定的目錄,如果找到指定的文件, 則使用這個(gè)文件;否則依此搜索以下幾個(gè)目錄(如果其存在):“/usr/gnu/include”、“/usr/local/include”和 “/usr/include”。

當(dāng)在這些目錄下都沒有找到“include”指定的文件時(shí),make將會提示一個(gè)包含文件未找到的告警提示,但是不會立刻退出。而是繼續(xù)處理 Makefile的內(nèi)容。當(dāng)完成讀取所有的makefile文件后,make將試圖使用規(guī)則來創(chuàng)建通過指示符“include”指定的但未找到的文件,當(dāng) 不能創(chuàng)建它時(shí)(沒有創(chuàng)建這個(gè)文件的規(guī)則),make將提示致命錯(cuò)誤并退出。會輸出類似如下錯(cuò)誤提示:



Makefile:錯(cuò)誤的行數(shù):未找到文件名:提示信息(No such file or directory)

Make: *** No rule to make target ‘’. Stop



我們可使用“-include”來代替“include”,忽略由于包含文件不存在或者無法創(chuàng)建時(shí)的錯(cuò)誤提示(“-”的意思是告訴make,忽略此操作的錯(cuò)誤。make繼續(xù)執(zhí)行)。像下邊那樣:



-include FILENAMES...



使用這種方式時(shí),當(dāng)所要包含的文件不存在時(shí)不會有錯(cuò)誤提示、make也不會退出;除此之外,和第一種方式效果相同。以下是這兩種方式的比較:

使用“include FILENAMES...”,make程序處理時(shí),如果“FILENAMES”列表中的任何一個(gè)文件不能正常讀取而且不存在一個(gè)創(chuàng)建此文件的規(guī)則時(shí)make程序?qū)崾惧e(cuò)誤并退出。

使用“-include FILENAMES...”的情況是,當(dāng)所包含的文件不存在或者不存在一個(gè)規(guī)則去創(chuàng)建它,make程序會繼續(xù)執(zhí)行,只有在因?yàn)閙akefile的目標(biāo)的規(guī)則不存在時(shí),才會提示致命錯(cuò)誤并退出。

為了和其它的make程序進(jìn)行兼容。也可以使用“sinclude”來代替“-include”(GNU所支持的方式)。



1.4 變量 MAKEFILES
如果當(dāng)前環(huán)境定義了一個(gè)“MAKEFILES”的環(huán)境變量,make執(zhí)行時(shí)首先將此變量的值作為需要讀入的Makefile文件,多個(gè)文件之間使用空格分 開。類似使用指示符“include”包含其它Makefile文件一樣,如果文件名非絕對路徑而且當(dāng)前目錄也不存在此文件,make會在一些默認(rèn)的目錄 去尋找。此情況和使用“include”的區(qū)別:

1. 環(huán)境變量指定的makefile文件中的“目標(biāo)”不會被作為make執(zhí)行的“終極目標(biāo)”。就是說,這些文件中所定義規(guī)則的目標(biāo),make不會將其作為“終 極目標(biāo)”來看待。如果在make的工作目錄下沒有一個(gè)名為“Makefile”、“makefile”或者“GNUmakefile”的文件,make同 樣會提示“make: *** No targets specified and no makefile found. Stop.”;而在make的工作目錄下存在這樣一個(gè)文件(“Makefile”、“makefile”或者“GNUmakefile”),那么make 執(zhí)行時(shí)的“終極目標(biāo)”就是當(dāng)前目錄下這個(gè)文件中所定義的“終極目標(biāo)”。

2. 環(huán)境變量所定義的文件列表,在執(zhí)行make時(shí),如果不能找到其中某一個(gè)文件(不存在或者無法創(chuàng)建)。make不會提示錯(cuò)誤,也不退出。就是說環(huán)境變量“MAKEFILES”定義的包含文件是否存在不會導(dǎo)致make錯(cuò)誤(這是比較隱蔽的地方)。

3. make在執(zhí)行時(shí),首先讀取的是環(huán)境變量“MAKEFILES”所指定的文件列表,之后才是工作目錄下的makefile文件,“include”所指定 的文件是在make發(fā)現(xiàn)此關(guān)鍵字的時(shí)、暫停正在讀取的文件而轉(zhuǎn)去讀取“include”所指定的文件。

變量“MAKEFILES”主要用在“make”的遞歸調(diào)用過程中的的通信。實(shí)際應(yīng)用中很少設(shè)置此變量。一旦設(shè)置了此變量,在多層make調(diào)用時(shí);由于每 一級make都會讀取“MAKEFILES”變量所指定的文件,這樣可能導(dǎo)致執(zhí)行的混亂(可能不是你想看到的執(zhí)行結(jié)果)。不過,我們可以使用此環(huán)境變量來 指定一個(gè)定義通用的“隱含規(guī)則”和用的變量的文件,比如設(shè)置默認(rèn)搜索路徑;通過這種方式設(shè)置的“隱含規(guī)則”和定義的變量可以被任何make進(jìn)程使用(有點(diǎn) 象C語言中的全局變量)。

也有人想讓login程序自動的在自己的工作環(huán)境中設(shè)置此環(huán)境變量,編寫的Makefile建立在此環(huán)境變量的基礎(chǔ)上。此想法可以肯定地說不是一個(gè)好主 意。規(guī)勸大家千萬不要這么干,否則你所編寫的Makefile在其人的工作環(huán)境中肯定不能正常工作。因?yàn)閯e人的工作環(huán)境中可能沒有設(shè)置相同的環(huán)境變量 “MAKEFILES”。

推薦的做法實(shí):在需要包含其它makefile文件時(shí)使用指示符“include”來實(shí)現(xiàn)。



3.5 變量 MAKEFILE_LIST
make程序在讀取多個(gè)makefile文件時(shí),包括由環(huán)境變量“MAKEFILES”指定、命令行指、當(dāng)前工作下的默認(rèn)的以及使用指示符 “include”指定包含的,在對這些文件進(jìn)行解析執(zhí)行之前make讀取的文件名將會被自動的追加到變量“MAKEFILE_LIST”的定義域中。

這樣我們就可以通過測試此變量的最后一個(gè)字來得知當(dāng)前make程序正在處理的是具體的那個(gè)makefile文件。具體地說就是一個(gè)makefile文件中 當(dāng)使用指示符“include”包含另外一個(gè)文件之后,變量“MAKEFILE_LIST”的最后一個(gè)只可能是指示符“include”指定所要包含的那 個(gè)文件的名字。如果一個(gè)makefile的內(nèi)容如下:

name1 := $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))



include inc.mk



name2 := $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))



all:

@echo name1 = $(name1)

@echo name2 = $(name2)

執(zhí)行make,則看到的將是如下的結(jié)果:

name1 = Makefile

name2 = inc.mk

此例子中涉及到了make的函數(shù)的和變量定義的方式,這些將在后續(xù)的章節(jié)中有詳細(xì)的講述。



3.6 其他特殊變量
GNU make支持一個(gè)特殊的變量,此變量不能通過任何途經(jīng)給它賦值。此變量展開以后是一個(gè)特定的值。第一個(gè)重要的特殊的變量是“.VARIABLES”。它被 展開以后是此引用點(diǎn)之前、makefile文件中所定義的所有全局變量列表。包括:空變量(未賦值的變量)和make的內(nèi)嵌變量,但不包含目標(biāo)指定的變 量,目標(biāo)指定變量值在特定目標(biāo)的上下文有效。

3.7 makefile文件的重建
有時(shí),Makefile可由其它文件生成,比如RCS或SCCS文件。如果Makefile由其它文件重建,那么在make開始解析Makefile時(shí)需要讀取的是更新后的Makefile、而不是那個(gè)沒有更新的Makefile。make的處理過程是這樣的:

make在讀入所有makefile文件之后,首先將所讀取的每個(gè)makefile作為一個(gè)目標(biāo),試著去更新它。如果存在一個(gè)更新特定makefile文 件明確規(guī)則或者隱含規(guī)則,則去更新這個(gè)makefile文件。在完成對所有的makefile文件的更新檢查動作之后,如果之前所讀取的makefile 文件已經(jīng)被更新,那么make就清除本次執(zhí)行的狀態(tài)重新讀取一遍所有的makefile文件(此過程中,同樣在讀取完成以后也會去試圖更新所有的已經(jīng)讀取 的makefile文件,但是一般這些文件不會再次被重建,因?yàn)樗鼈冊跁r(shí)間戳上已經(jīng)是最新的)。

實(shí)際應(yīng)用中,我們會很明確的了解我們的那些makefile文件不需要重建。出于make效率的考慮,我們可以采用一些辦法來避免make在執(zhí)行過程時(shí)查找重建makefile的隱含規(guī)則。例如我們可以書寫一個(gè)明確的規(guī)則,將makefile文件作為目標(biāo),命令為空。

Makefile規(guī)則中,如果使用一個(gè)沒有依賴只有命令行的雙冒號規(guī)則去更新一個(gè)文件,那么每次執(zhí)行make時(shí),此規(guī)則的目標(biāo)文件將會被無條件的更新。而 假如此規(guī)則的目標(biāo)文件是一個(gè)makefile文件,那么在執(zhí)行make時(shí),將會導(dǎo)致這個(gè)makefile文件被無條件更新,時(shí)make的執(zhí)行陷入到一個(gè)死 循環(huán)中(此makefile文件被不斷的更新、重新讀取、更新再重新讀取的過程)。為了防止進(jìn)入此循環(huán),make在遇到一個(gè)目標(biāo)是makefile文件的 雙冒號規(guī)則時(shí),將忽略對這個(gè)規(guī)則的執(zhí)行(其中包括了使用“MAKEFILES”指定、命令行選項(xiàng)指定、指示符“include”指定的需要make讀取的 所有makefile文件中定義的這一類雙冒號規(guī)則)。

執(zhí)行make時(shí),如果沒有使用“-f(--file)”選項(xiàng)指定一個(gè)文件,make程序?qū)⒆x取缺省的文件。和使用“-f(--file)”選項(xiàng)不同, make無法確定工作目錄下是否存在缺省名稱的makefile文件。如果缺省makefile文件不存在,但可以通過一個(gè)規(guī)則來創(chuàng)建它(此規(guī)則是隱含規(guī) 則),則會自動創(chuàng)建缺省makefile文件,之后重新讀取它并開始執(zhí)行。

因此,如果不存在缺省makefile文件,make將按照搜索makefile文件的名稱順序去創(chuàng)建它,直到創(chuàng)建成功或者超越其缺省的命名順序。需要明 確的一點(diǎn)是:執(zhí)行make時(shí),如果不能成功地創(chuàng)建其缺省的makefile文件,并不一定會導(dǎo)致錯(cuò)誤。運(yùn)行make時(shí)一個(gè)makefile文件并不是必需 的。(關(guān)于這一點(diǎn)大家會在后續(xù)的閱讀過程中體會到)

當(dāng)使用“-t(--touch)”選項(xiàng)來對Makefile目標(biāo)文件進(jìn)行時(shí)間戳更新時(shí),對于哪些makefile文件的目標(biāo)是無效的。就是說即使執(zhí)行 make時(shí)使用了選項(xiàng)“-t”,那些目標(biāo)是makefile文件的規(guī)則同樣也會被make執(zhí)行(而其它的規(guī)則不會被執(zhí)行,make只是簡單的更新規(guī)則目標(biāo) 文件的時(shí)間戳);類似還有選項(xiàng)“-q(—question)”和“-n(—just-print) ”,這主要是因?yàn)橐粋€(gè)過時(shí)的makefile文件對其它目標(biāo)的重建規(guī)則在當(dāng)前看來可能是錯(cuò)誤的。正因?yàn)槿绱?,?zhí)行命令“make –f mfile –n foo”首先會試圖重建“mfile文件”、并重新讀取它,之后會打印出更新目標(biāo)“foo”規(guī)則中所定義的命令但不執(zhí)行此命令。

在這種情況下,如果我們不希望重建makefile文件。那么我們就需要在執(zhí)行make時(shí),在命令行中將這個(gè)makefile文件中為一個(gè)最終目的,這樣 “–t”和其它的選項(xiàng)就對這個(gè)makefile文件的目標(biāo)有效,防止執(zhí)行這個(gè)makefile作為目標(biāo)的規(guī)則。同樣,命令“make –f mfile –n mfile foo”會讀取文件“mfile”,打印出重建文件“mfile”的命令、重建“foo”的命令而實(shí)際不去執(zhí)行此命令。并且所打印的用于更新“foo”目 標(biāo)的命令是選項(xiàng)“-f”指定的、沒有被重建的“mfile”文件中所定義的命令。

3.8 重載另外一個(gè)makefile
有些情況下存在兩個(gè)比較類似的makefile文件。其中一個(gè)(makefile-A)需要使用另外一個(gè)文件(makefile-B)中所定義的變量和規(guī) 則。我們可以在“makefile-A”中使用指示符“include”來包含“mkaefile-B”來達(dá)到目的,這種情況下,如果兩個(gè) makefile文件中存在相同目標(biāo),而其描述規(guī)則中使用不同的命令。相同目標(biāo)有兩個(gè)不同的規(guī)則命令,這是makefile所不允許的。遇到這種情況,使 用指示符“include”顯然是行不通的。GNU make提供另外一種途徑來達(dá)到此目的。具體的做法如下:

在需要包含的makefile文件(makefile-A)中,我們可以使用一個(gè)稱之為“所有匹配模式”的規(guī)則來描述在“makefile-A”中沒有明確定義的目標(biāo),make將會在給定的makefile文件中尋找沒有在當(dāng)前Makefile中給出的目標(biāo)更新規(guī)則。

看一個(gè)例子,如果存在一個(gè)命名為“Makefile”的makefile文件,其中描述目標(biāo)“foo”的規(guī)則和其他的一些規(guī),我們也可以書寫一個(gè)內(nèi)容如下命名為“GNUmakefile”的文件。



#sample GNUmakefile

foo:

frobnicate > foo



%: force

@$(MAKE) -f Makefile $@

force: ;



執(zhí)行命令“make foo”,make將使用工作目錄下命名為“GNUmakefile”的文件并執(zhí)行目標(biāo)“foo”所在的規(guī)則,創(chuàng)建它的命令是:“frobnicate > foo”。如果我們執(zhí)行另外一個(gè)命令“make bar”, “GUNmakefile”中沒有此目標(biāo)的更新規(guī)則。那么,make將會使用“所有匹配模式”規(guī)則,執(zhí)行命令“$(MAKE) -f Makefile bar”。如果文件“Makefile”中存在此目標(biāo)更新規(guī)則的定義,那么這個(gè)規(guī)則會被執(zhí)行。此過程同樣適用于其它 “GNUmakefile”中沒有給出的目標(biāo)更新規(guī)則。此方式的靈活之處在于:如果在“Makefile”文件中存在同樣一一個(gè)目標(biāo)“foo”的重建規(guī) 則,由于make執(zhí)行時(shí)首先讀取文件“GUNmakefile”并在其中能夠找到目標(biāo)“foo”的重建規(guī)則,所以make就不會去執(zhí)行這個(gè)“所有模式匹配 規(guī)則”(上例中的目標(biāo)是“%”的規(guī)則)。這樣就避免了使用指示符“include”包含一個(gè)makefile文件時(shí)所帶來的目標(biāo)規(guī)則的重復(fù)定義問題。

此種方式,模式規(guī)則的模式只使用了單獨(dú)的“%”(我們才稱他為“所有模式匹配規(guī)則”),它可以匹配任何一個(gè)目標(biāo);它的依賴是“force”,保證了即使目 標(biāo)文件已經(jīng)存在也會執(zhí)行這個(gè)規(guī)則(文件已存在時(shí),需要根據(jù)它的依賴文件的修改情況決定是否需要重建這個(gè)目標(biāo)文件);“force”規(guī)則中使用空命令是為了 防止make程序試圖尋找一個(gè)規(guī)則去創(chuàng)建目標(biāo)“force”時(shí),又使用了模式規(guī)則“%: force”而陷入無限循環(huán)。

3.9 make如何解析makefile文件
GUN make的執(zhí)行過程分為兩個(gè)階段。

第一階段:讀取所有的makefile文件(包括“MAKIFILES”變量指定的、指示符“include”指定的、以及命令行選項(xiàng)“-f(-- file)”指定的makefile文件),內(nèi)建所有的變量、明確規(guī)則和隱含規(guī)則,并建立所有目標(biāo)和依賴之間的依賴關(guān)系結(jié)構(gòu)鏈表。

在第二階段:根據(jù)第一階段已經(jīng)建立的依賴關(guān)系結(jié)構(gòu)鏈表決定哪些目標(biāo)需要更新,并使用對應(yīng)的規(guī)則來重建這些目標(biāo)。

理解make執(zhí)行過程的兩個(gè)階段是很重要的。它能幫助我們更深入的了解執(zhí)行過程中變量以及函數(shù)是如何被展開的。變量和函數(shù)的展開問題是書寫 Makefile時(shí)容易犯錯(cuò)和引起大家迷惑的地方之一。本節(jié)將對這些不同的結(jié)構(gòu)的展開階段進(jìn)行簡單的總結(jié)(明確變量和函數(shù)的展開階段,對正確的使用變量非 常有幫助)。首先,明確以下基本的概念;在make執(zhí)行的第一階段中如果變量和函數(shù)被展開,那么稱此展開是“立即”的,此時(shí)所有的變量和函數(shù)被展開在需要 構(gòu)建的結(jié)構(gòu)鏈表的對應(yīng)規(guī)則中(此規(guī)則在建立鏈表是需要使用)。其他的展開稱之為“延后”的。這些變量和函數(shù)不會被“立即”展開,而是直到后續(xù)某些規(guī)則須要 使用時(shí)或者在make處理的第二階段它們才會被展開。

可能現(xiàn)在講述的這些還不能完全理解。不過沒有關(guān)系,通過后續(xù)章節(jié)內(nèi)容的學(xué)習(xí),我們會一步一步的熟悉make的執(zhí)行過程。學(xué)習(xí)過程中可以回過頭來參考本節(jié)的內(nèi)容。相信在看完本書之后,會對make的整個(gè)過程有全面深入的理解。

3.9.1 變量取值
變量定義解析的規(guī)則如下:



IMMEDIATE = DEFERRED

IMMEDIATE ?= DEFERRED

IMMEDIATE := IMMEDIATE

IMMEDIATE += DEFERRED or IMMEDIATE

define IMMEDIATE

DEFERRED

Endef



當(dāng)變量使用追加符(+=)時(shí),如果此前這個(gè)變量是一個(gè)簡單變量(使用 :=定義的)則認(rèn)為它是立即展開的,其它情況時(shí)都被認(rèn)為是“延后”展開的變量。

3.9.2 條件語句
所有使用到條件語句在產(chǎn)生分支的地方,make程序會根據(jù)預(yù)設(shè)條件將正確地分支展開。就是說條件分支的展開是“立即”的。其中包括:“ifdef”、“ifeq”、“ifndef”和“ifneq”所確定的所有分支命令。

3.9.3 規(guī)則的定義
所有的規(guī)則在make執(zhí)行時(shí),都按照如下的模式展開:



IMMEDIATE : IMMEDIATE ; DEFERRED

DEFERRED



其中,規(guī)則中目標(biāo)和依賴如果引用其他的變量,則被立即展開。而規(guī)則的命令行中的變量引用會被延后展開。此模板適合所有的規(guī)則,包括明確規(guī)則、模式規(guī)則、后綴規(guī)則、靜態(tài)模式規(guī)則。

3.10 總結(jié)
make的執(zhí)行過程如下:

1. 依次讀取變量“MAKEFILES”定義的makefile文件列表

2. 讀取工作目錄下的makefile文件(根據(jù)命名的查找順序“GNUmakefile”,“makefile”,“Makefile”,首先找到那個(gè)就讀取那個(gè))

3. 依次讀取工作目錄makefile文件中使用指示符“include”包含的文件

4. 查找重建所有已讀取的makefile文件的規(guī)則(如果存在一個(gè)目標(biāo)是當(dāng)前讀取的某一個(gè)makefile文件,則執(zhí)行此規(guī)則重建此makefile文件,完成以后從第一步開始重新執(zhí)行)

5. 初始化變量值并展開那些需要立即展開的變量和函數(shù)并根據(jù)預(yù)設(shè)條件確定執(zhí)行分支

6. 根據(jù)“終極目標(biāo)”以及其他目標(biāo)的依賴關(guān)系建立依賴關(guān)系鏈表

7. 執(zhí)行除“終極目標(biāo)”以外的所有的目標(biāo)的規(guī)則(規(guī)則中如果依賴文件中任一個(gè)文件的時(shí)間戳比目標(biāo)文件新,則使用規(guī)則所定義的命令重建目標(biāo)文件)

8. 執(zhí)行“終極目標(biāo)”所在的規(guī)則



執(zhí)行一個(gè)規(guī)則的過程:

對于一個(gè)存在的規(guī)則(明確規(guī)則和隱含規(guī)則)首先,make比較目標(biāo)文件和所有的依賴文件的時(shí)間戳。如果目標(biāo)的時(shí)間戳比所有依賴文件的時(shí)間戳更新(依賴文件 在上一次執(zhí)行make之后沒有被修改),那么什么也不做。否則(依賴文件中的某一個(gè)或者全部在上一次執(zhí)行make后已經(jīng)被修改過),規(guī)則所定義的重建目標(biāo) 的命令將會被執(zhí)行。這就是make工作的基礎(chǔ),也是其執(zhí)行規(guī)制所定義命令的依據(jù)。(后續(xù)討論規(guī)則時(shí)將會對此詳細(xì)地說明)

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多