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

分享

GNU make中文手冊(cè)-第五章:規(guī)則的命令

 todaytomo 2006-12-30
GNU make中文手冊(cè)-第五章:規(guī)則的命令 作者: hew  發(fā)布日期: 2006-3-21    查看數(shù): 142   出自: http://www.
第五章:規(guī)則的命令

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

規(guī)則的命令由一些shell命令行組成,他們被一條一條的執(zhí)行。規(guī)則中除了第一條緊跟在依賴列表之后使用分號(hào)隔開(kāi)的命令以外,其它的每一行命令行必需一 [Tab]字符開(kāi)始。多個(gè)命令行之間可以有空行和注釋行(所謂空行,就是沒(méi)有包含任何字符的一行。如果以[Tab]鍵開(kāi)始而其后沒(méi)有命令的行,此行不是空 行。是空命令行),在執(zhí)行規(guī)則時(shí)他們將被忽略。

可能用戶使用了多個(gè)不同的shell。但是在make處理Makefile過(guò)程是,如果沒(méi)有明確指定,那么對(duì)所有規(guī)則中命令行的解析使用“/bin/sh”來(lái)完成。

使用的shell決定了規(guī)則中的命令的語(yǔ)法和處理機(jī)制。當(dāng)使用默認(rèn)的“/bin/sh”時(shí),命令中字符“#”到行末的內(nèi)容被認(rèn)為是注釋。當(dāng)然了“#”可以不在此行的行首,此時(shí)“#”之前的內(nèi)容不會(huì)被作為注視處理。

另外在make解析makefile文件時(shí),對(duì)待注釋也是采用同樣的處理方式。我們的shell腳本也一樣。

5.1 命令回顯
通常,make在執(zhí)行命令行之前會(huì)把要執(zhí)行的命令行進(jìn)行輸出。我們稱之為“回顯”,就好像我們輸入命令執(zhí)行一樣。

如果要執(zhí)行的命令行以字符“@”開(kāi)始,則make在執(zhí)行時(shí)這個(gè)命令就不會(huì)被回顯。典型的用法是我們?cè)谑褂?#8220;echo”命令輸出一些信息時(shí)。如:



@echo 開(kāi)始編譯XXX模塊......



當(dāng)make執(zhí)行時(shí),將輸出“開(kāi)始編譯XXX模塊......”這個(gè)信息。如果在命令行之前沒(méi)有字符“@”,那么,make的輸出就是:



echo編譯XXX模塊......

編譯XXX模塊......



另外,如果使用make的命令行參數(shù)“-n”或“--just-print”,那么make執(zhí)行時(shí)只顯示所要執(zhí)行的命令,但不會(huì)真正的去執(zhí)行這些命令。只 有在這種情況下make才會(huì)打印出所有make需要執(zhí)行的命令,其中也包括了使用“@”字符開(kāi)始的命令。這個(gè)選項(xiàng)對(duì)于我們調(diào)試Makefile非常有用, 使用這個(gè)選項(xiàng)我們可以按執(zhí)行順序打印出Makefile中所有需要執(zhí)行的命令。

而make參數(shù)“-s”或“--slient”則是禁止所有執(zhí)行命令的顯示,就好像所有的命令行均使用“@”開(kāi)始一樣。在Makefile中使用沒(méi)有依賴 的特殊目標(biāo)“.SILENT”也可以禁止命令的回顯,但是它的缺點(diǎn)是不如“@”靈活。因此我們?cè)跁鴮慚akefile時(shí),推薦使用“@”來(lái)控制命令的回 顯。

5.2 命令的執(zhí)行
規(guī)則中,當(dāng)目標(biāo)需要被重建時(shí)。此規(guī)則所定義的命令將會(huì)被執(zhí)行,如果是多行命令,那么make就為每一行命令使用一個(gè)獨(dú)立的子shell去執(zhí)行。因此,多行命令之間的執(zhí)行是相互獨(dú)立的,相互之間不存在依賴。

而在Makefile中書寫在同一行中的多個(gè)命令屬于一個(gè)完整的shell命令行,書寫在獨(dú)立行的一條命令是一個(gè)獨(dú)立的shell命令行。所以需要注意: 在一個(gè)規(guī)則的命令中,命令行“cd”改變目錄不會(huì)對(duì)其后的命令的執(zhí)行產(chǎn)生影響。就是說(shuō)其后的命令執(zhí)行的工作目錄不會(huì)是之前使用“cd”進(jìn)入的那個(gè)目錄。如 果要實(shí)現(xiàn)這個(gè)目的,就不能把“cd”和其后的命令放在兩行來(lái)書寫。而應(yīng)該把這兩條命令寫在一行上,用分號(hào)分隔。這樣它們才是一個(gè)完整的shell命令行。 如:



foo : bar/lose

cd bar; gobble lose > ../foo



如果希望把一個(gè)完整的shell命令行書寫在多行上,需要使用反斜杠(\)來(lái)對(duì)處于多行的命令進(jìn)行連接,表示他們是一個(gè)完整的shell命令行。例如上例我們以也可以這樣書寫:



foo : bar/lose

cd bar; \

gobble lose > ../foo



make對(duì)所有規(guī)則命令的解析使用環(huán)境變量“SHELL”所指定的那個(gè)程序,在GNU make中,默認(rèn)的程序是“/bin/sh”。

不像其他絕大多數(shù)變量,它們的值可以直接從同名的系統(tǒng)環(huán)境變量那里獲得。make的環(huán)境變量“SHELL”沒(méi)有使用系統(tǒng)環(huán)境變量的定義。因?yàn)橄到y(tǒng)環(huán)境變量 “SHELL”指定那個(gè)程序被用來(lái)作為用戶和系統(tǒng)交互的接口程序,它對(duì)于不存在直接交互過(guò)程的make顯然不合適。在make的環(huán)境變量中“SHELL” 會(huì)被重新賦值;它作為一個(gè)變量我們也可以在Makefile中明確地給它賦值(指出解釋程序的名字,當(dāng)明確指定時(shí)需要使用完整的路徑名。如 “/bin/sh”),變量“SHELL”其值默認(rèn)為“/bin/sh”。

(在MS-DOS下有些不同, MS-DOS不存在SHELL環(huán)境變量。在MS-DOS下make的方法省略了,有興趣地可以自行參考info make)

5.3 并發(fā)執(zhí)行命令
GUN make可以同時(shí)執(zhí)行多條命令。通常情況下,一個(gè)時(shí)刻只有一個(gè)命令在執(zhí)行,下一個(gè)命令在當(dāng)前命令執(zhí)行完成之后才能夠被執(zhí)行。不過(guò)可以通過(guò)make的命令行 選項(xiàng)“-j”或者“--job”來(lái)告訴make在同一時(shí)刻可以允許多條命令同時(shí)被執(zhí)行(注意,在MS-DOS中此選項(xiàng)無(wú)效,因?yàn)樗菃稳蝿?wù)操作系統(tǒng))。

如果選項(xiàng)“-j”之后存在一個(gè)整數(shù),其含義是告訴make在同一時(shí)刻可允許同時(shí)執(zhí)行命令的數(shù)目。這個(gè)數(shù)字被稱為“job slots”。當(dāng)“-j”選項(xiàng)之后沒(méi)有出現(xiàn)一個(gè)數(shù)字時(shí),那么同一時(shí)刻執(zhí)行的命令數(shù)目沒(méi)有要求。使用默認(rèn)的“job slots”,其值為1。表示make將串行的執(zhí)行規(guī)則的命令(同一時(shí)刻只能有一條命令被執(zhí)行)。

并行執(zhí)行命令所帶來(lái)的問(wèn)題是顯而易見(jiàn):

1. 同一時(shí)刻的多個(gè)被執(zhí)行的命令同時(shí)輸出,造成輸出到終端的信息的交替,顯得凌亂。當(dāng)出現(xiàn)問(wèn)題是很難命令執(zhí)行失敗時(shí)很難根據(jù)命令的輸出信息來(lái)定位錯(cuò)誤。

2. 在同一時(shí)刻可能會(huì)存在多個(gè)命令執(zhí)行進(jìn)程讀取標(biāo)準(zhǔn)輸入,但是對(duì)于標(biāo)注輸入來(lái)設(shè)備來(lái)說(shuō),在同一時(shí)刻只能有一個(gè)進(jìn)程訪問(wèn)輸入設(shè)備。就是說(shuō)在某個(gè)時(shí)間點(diǎn),make 只能保證這個(gè)時(shí)刻正在執(zhí)行的進(jìn)程中的一個(gè)進(jìn)程讀取標(biāo)準(zhǔn)輸入流,而其它的進(jìn)程的標(biāo)準(zhǔn)輸入流將變得無(wú)效。因此當(dāng)同一時(shí)刻存在多個(gè)執(zhí)行命令的進(jìn)程需要讀取標(biāo)準(zhǔn)輸 入流時(shí)其它的將會(huì)出輸入流無(wú)效導(dǎo)致致命錯(cuò)誤(通常此進(jìn)程會(huì)得到操作系統(tǒng)的管道破裂信號(hào)而被終止)。



這是因?yàn)椋簣?zhí)行中的命令在什么時(shí)候會(huì)讀取標(biāo)準(zhǔn)輸入流(終端輸入或重定向的標(biāo)準(zhǔn)輸入)是不可預(yù)測(cè)的。而得到標(biāo)準(zhǔn)輸入的順序總是按照先來(lái)先獲得的原則。那個(gè)命 令首先被執(zhí)行,那么它就可以首先得到標(biāo)準(zhǔn)輸入設(shè)備。而其它后續(xù)需要獲取標(biāo)準(zhǔn)輸入設(shè)備的命令執(zhí)行進(jìn)程,由于不能得到標(biāo)準(zhǔn)輸入而產(chǎn)生致命錯(cuò)誤。再 Makefile規(guī)則中如果存在很多命令需要讀取標(biāo)準(zhǔn)輸入設(shè)備,而它們又被允許并行執(zhí)行時(shí),就會(huì)出現(xiàn)這樣的錯(cuò)誤。



對(duì)這個(gè)問(wèn)題的解決。我們可以修改Makefile的規(guī)則命令使之在執(zhí)行過(guò)程中不使用標(biāo)準(zhǔn)輸入設(shè)備。當(dāng)然也可以實(shí)現(xiàn)在只存在一個(gè)命令在執(zhí)行時(shí)會(huì)訪問(wèn)標(biāo)準(zhǔn)輸入流的Makefile。

3. 會(huì)導(dǎo)致make的遞歸調(diào)用出現(xiàn)問(wèn)題??蓞⒖?5.6 make的遞歸執(zhí)行 一節(jié)。

Make在執(zhí)行一個(gè)命令時(shí),如果某一條命令執(zhí)行失敗(被一個(gè)信號(hào)中止,或非零退出),且該條命令產(chǎn)生的錯(cuò)誤不可忽略(,那么其它的用于重建同一目標(biāo)的命令 執(zhí)行將會(huì)被終止。此種情況下,如果make沒(méi)有使用“-k”或“--keep-going”選項(xiàng),make將停止繼續(xù)執(zhí)行直接退出。另外:如果make在 執(zhí)行時(shí),由某種原因(包括信號(hào))被中止,此時(shí)它的子進(jìn)程(那些執(zhí)行規(guī)則命令行的shell子進(jìn)程)正在運(yùn)行,那么make將等到所有這些子進(jìn)程結(jié)束之后才 真正退出。

在執(zhí)行make時(shí),如果系統(tǒng)運(yùn)行于重負(fù)荷狀態(tài)下,我們需要控制(減輕)系統(tǒng)在執(zhí)行make時(shí)的負(fù)荷。可以使用“-l”選項(xiàng)告訴make限制當(dāng)前運(yùn)行的任務(wù) 的數(shù)量(make所限制的只是它本身所需要占用的系統(tǒng)負(fù)載,而不能通過(guò)它去控制其它的任務(wù)所占用的系統(tǒng)負(fù)載)。“-l”或“--max-load”選項(xiàng)一 般后邊需要跟一個(gè)浮點(diǎn)數(shù)。例如:

-l 2.5



它的意思是告訴make當(dāng)系統(tǒng)平均負(fù)荷高于2.5時(shí),不再啟動(dòng)任何執(zhí)行命令的子任務(wù)。不帶浮點(diǎn)數(shù)的“-l”選項(xiàng)用于取消前面通“-l”給定的負(fù)荷限制。

更為準(zhǔn)確一點(diǎn)就是:每一次,make在啟動(dòng)一項(xiàng)任務(wù)之前,當(dāng)前系統(tǒng)至少一項(xiàng)make的子任務(wù)正在運(yùn)行。首先make會(huì)檢查當(dāng)前系統(tǒng)的負(fù)荷;如果當(dāng)前系統(tǒng)的負(fù)荷高于通過(guò)“-l”選項(xiàng)指定的值,那么make就不會(huì)在其他任務(wù)完成之前啟動(dòng)任何任務(wù)。缺省情況下沒(méi)有負(fù)荷限制。

5.4 命令執(zhí)行的錯(cuò)誤
通常;規(guī)則中的命令在運(yùn)行結(jié)束后,make會(huì)檢測(cè)命令執(zhí)行的返回狀態(tài),如果返回成功,那么就在另外一個(gè)子shell下執(zhí)行下一條命令。規(guī)則中的所有命令執(zhí) 行完成之后,這個(gè)規(guī)則就執(zhí)行完成了。如果一個(gè)規(guī)則中的某一個(gè)命令出錯(cuò)(返回狀態(tài)非0),make就會(huì)放棄對(duì)當(dāng)前規(guī)則的執(zhí)行,也有可能會(huì)終止所有規(guī)則的執(zhí) 行。

在一些情況下,規(guī)則中的一個(gè)命令的執(zhí)行失敗并不代表規(guī)則執(zhí)行的錯(cuò)誤。例如我們使用“mkdir”命令來(lái)確保存在一個(gè)目錄。當(dāng)此目錄不存在使我們就建立這個(gè) 目錄,當(dāng)目錄存在時(shí)那么“mkdir”就會(huì)執(zhí)行失敗。其實(shí)我們并不希望mkdir在執(zhí)行失敗后終止規(guī)則的執(zhí)行。為了忽略一些無(wú)關(guān)命令執(zhí)行失敗的情況,我們 可以在命令之前加一個(gè)減號(hào)“-”(在[Tab]字符之后),來(lái)告訴make忽略此命令的執(zhí)行失敗。命令中的“-”號(hào)會(huì)在在shell解析并執(zhí)行此命令之前 被去掉,shell所解釋的只是純粹的命令,“-”字符是由make來(lái)處理的。例如對(duì)于“clean”目標(biāo)我們就可以這么寫:



clean:

-rm *.o



其含義是:即使執(zhí)行“rm”刪除文件失敗,make也繼續(xù)執(zhí)行。

在執(zhí)行make時(shí),如果使用命令行選項(xiàng)“-i”或者“—ignore-errors”, make將會(huì)忽略所有規(guī)則中命令執(zhí)行執(zhí)行的錯(cuò)誤。沒(méi)有依賴的特殊目標(biāo)“.IGNORE”在Makefile中有同樣的效果。但是“.IGNORE”的方式 已經(jīng)很少使用,因?yàn)樗鼪](méi)有在命令行之前使用“-”字符方式靈活。

當(dāng)使用make的“-i”選項(xiàng)或者使用“-”字符來(lái)忽略命令執(zhí)行錯(cuò)誤時(shí),make始終會(huì)把命令的執(zhí)行結(jié)果作為成功來(lái)對(duì)待。但會(huì)提示錯(cuò)誤信息,同時(shí)提示這個(gè)錯(cuò)誤被忽略。

當(dāng)沒(méi)有使用這種方式來(lái)通知make忽略命令的執(zhí)行錯(cuò)誤時(shí),而在錯(cuò)誤發(fā)生時(shí),就意味著定義這個(gè)命令的規(guī)則的目標(biāo)不能被正確重建,同樣,和此目標(biāo)相關(guān)的其它目標(biāo)也不會(huì)被正確重建。因此,由于先決條件不能建立,后續(xù)的命令將不會(huì)執(zhí)行。

在發(fā)生這樣情況時(shí),一般make會(huì)立刻退出并返回一個(gè)非0狀態(tài),表示執(zhí)行失敗。像對(duì)待命令執(zhí)行的錯(cuò)誤一樣,我們可以使用make的命令行選項(xiàng)“-k”或者 “--keep-going”來(lái)通知make,當(dāng)出現(xiàn)錯(cuò)誤時(shí)不立即退出,而是繼續(xù)后續(xù)命令的執(zhí)行。直到無(wú)法繼續(xù)執(zhí)行命令時(shí)才異常退出。例如:使用“-k” 參數(shù),在重建一個(gè).o文件目標(biāo)時(shí)出現(xiàn)錯(cuò)誤,make不會(huì)立即退出。雖然make已經(jīng)知道因?yàn)檫@個(gè)錯(cuò)誤而無(wú)法完成終極目標(biāo)的重建,但還是繼續(xù)完成其它后續(xù)的 依賴文件的重建。直到執(zhí)行最后鏈接時(shí)才錯(cuò)誤退出。

一般“-k”參數(shù)在實(shí)際中應(yīng)用。它的用途主要在:當(dāng)同時(shí)修改了工程中的多個(gè)文件后,“-k”參數(shù)可以幫助我們確認(rèn)對(duì)那些文件的修改是正確的(可以被編 譯),那些文件的修改是不不正確的(不能正確編譯)。例如我們修改了工程中的20個(gè)源文件,修改完成之后使用“-k”參數(shù)來(lái)進(jìn)行make,它可以一次性找 出修改的20個(gè)文件中哪些是不能被編譯的。

通常情況下,執(zhí)行失敗的命令一旦改變了它所在規(guī)則的目標(biāo)文件,則這個(gè)改變了的目標(biāo)可能不是一個(gè)被正確重建的文件。但是這個(gè)文件的時(shí)間戳已經(jīng)被更新過(guò)了(這 種情況也會(huì)發(fā)生在使用一個(gè)信號(hào)來(lái)強(qiáng)制中止命令執(zhí)行的時(shí)候)。因此在下一次執(zhí)行make時(shí),由于時(shí)間戳更新它不會(huì)被再次重建。因此終極目標(biāo)的重建很難保證是 正確的。為了避免這種錯(cuò)誤的出現(xiàn),應(yīng)該在一次make執(zhí)行失敗之后使用“make clean”來(lái)清除已經(jīng)重建的所有目標(biāo),之后再執(zhí)行make。我們也可以讓make自動(dòng)完成這個(gè)動(dòng)作,實(shí)現(xiàn)這個(gè)目的我們只需要Makefile中定義特殊 目標(biāo)“.DELETE_ON_ERROR”。但是這個(gè)做法存在不兼容。推薦的做法是:在make執(zhí)行失敗時(shí),修改錯(cuò)誤之后執(zhí)行make之前,使用 “make clean”明確的刪除第一次錯(cuò)誤重建的所有目標(biāo)。

本節(jié)的最后,需要說(shuō)明的是:雖然make提供了命令行選項(xiàng)來(lái)忽略命令執(zhí)行的錯(cuò)誤。建議對(duì)于此選項(xiàng)謹(jǐn)慎使用。因?yàn)樵谝粋€(gè)大型的工程中,可能需要對(duì)成千個(gè)源文 件進(jìn)行編譯。編譯過(guò)程中的任何一個(gè)文件的編譯錯(cuò)誤都不能被忽略。否則有可能最后完成的終極目標(biāo)可能就是一個(gè)讓你感到迷惑的東西,或者在運(yùn)行時(shí)會(huì)產(chǎn)生一些莫 名奇妙的現(xiàn)象。這需要程序員來(lái)保證其書寫的Makefile的規(guī)則中的命令在執(zhí)行時(shí)不會(huì)發(fā)生錯(cuò)誤。特別需要注意哪些實(shí)現(xiàn)特殊目的規(guī)則的命令書寫。當(dāng)所有命 令都可以被正確執(zhí)行時(shí),我們就沒(méi)有必要為了避免一些討厭的錯(cuò)誤而使用“-i”選項(xiàng),可以使用其它的方式來(lái)實(shí)現(xiàn)。例如刪除命令我們可以這樣寫: “$(RM)”或者“rm -f”,創(chuàng)建目錄的命令可以這樣寫:“mkdir –p ”等等。



5.5 中斷make的執(zhí)行
make在執(zhí)行命令時(shí)如果收到一個(gè)致命信號(hào)(結(jié)束make),make將會(huì)刪除命令重建的規(guī)則目標(biāo)文件。其依據(jù)是此目標(biāo)文件的當(dāng)前時(shí)間戳是否和make開(kāi)始時(shí)的時(shí)間戳相同。

刪除這個(gè)目標(biāo)文件的目的是為了確保下一次make時(shí)目標(biāo)文件能夠被正確重建。其原因我們上一節(jié)已經(jīng)有所討論。假設(shè)正在編譯文件是鍵入“Ctrl-c”,在 這時(shí)編譯器已經(jīng)開(kāi)始寫文件“foo.o”,但是“Ctrl-c”產(chǎn)生的信號(hào)關(guān)閉了編譯器。這種情況時(shí)文件“foo.o”可能是不完整的,但這個(gè)內(nèi)容不完整 的“foo.o”文件的時(shí)間戳比源程序‘foo.c’的時(shí)間戳新。如果在make收到終止信號(hào)后不刪除文件“foo.o”而直接退出,那么下次執(zhí)行 make時(shí)make將認(rèn)為該文件已是最新而不會(huì)去重建文件它。最后在鏈接程序生成終極目標(biāo)時(shí)可能由于某一個(gè).o文件的不完整,導(dǎo)致出現(xiàn)一些奇怪的令人難以 理解的錯(cuò)誤信息。

同時(shí),我們可以在Makefile中將一個(gè)目標(biāo)文件作為特殊目標(biāo)“.PRECIOUS”的依賴,這樣可以防止make在重建這個(gè)目標(biāo)時(shí)異常終止時(shí)對(duì)這個(gè)目 標(biāo)文件的刪除動(dòng)作。每次make在重建一個(gè)目標(biāo)之前,首先判斷該目標(biāo)文件是否出現(xiàn)在特殊目標(biāo)“.PRECIOUS”的依賴列表中,決定在終止信號(hào)發(fā)生時(shí)需 不需要?jiǎng)h除這個(gè)目標(biāo)文件。不刪除這種目標(biāo)文件的原因可能是:1. 目標(biāo)的重建動(dòng)作是一個(gè)原子的不可被中斷的過(guò)程;2. 目標(biāo)文件的存在僅僅為了記錄其重建時(shí)間(不關(guān)心其內(nèi)容無(wú));3. 這個(gè)目標(biāo)文件必須一直存在來(lái)防止其它麻煩。

5.6 make的遞歸執(zhí)行
make的遞歸調(diào)用指的是:在Makefile中使用“make”作為一個(gè)命令來(lái)執(zhí)行本身或者其它makefile文件。遞歸調(diào)用在一個(gè)村在有多級(jí)子目錄 的項(xiàng)目中非常有用。例如,當(dāng)前目錄下存在一個(gè)“subdir”子目錄,這個(gè)子目錄中有描述這個(gè)目錄編譯規(guī)則的makefile文件,在執(zhí)行make時(shí)需要 從上層目錄(當(dāng)前目錄)開(kāi)始并完成它所有子目錄的編譯。那么在當(dāng)前目錄下可以使用這樣一個(gè)規(guī)則來(lái)實(shí)現(xiàn)對(duì)它的子目錄的編譯:



subsystem:

cd subdir && $(MAKE)



其等價(jià)于規(guī)則:



subsystem:

$(MAKE) -C subdir



我們對(duì)這兩個(gè)規(guī)則的命令進(jìn)行簡(jiǎn)單說(shuō)明,規(guī)則中“$(MAKE)”是對(duì)變量“MAKE”(下一小節(jié)將詳細(xì)討論)的引用(關(guān)于變量可參考 第六章 Makefile中的變量 )。第一個(gè)規(guī)則命令的意思是:進(jìn)入子目錄,然后在子目錄下執(zhí)行make。第二個(gè)規(guī)則時(shí)用了make的“-C”選項(xiàng),同樣是首先進(jìn)入子目錄而后再執(zhí)行 make。

書寫這樣的規(guī)則應(yīng)該來(lái)說(shuō)對(duì)于我們不是什么大問(wèn)題,但是其中有一些需要我們深入了解的東西。首先需要了解它如何工作、上層make(在當(dāng)前目錄下運(yùn)行的 make進(jìn)程)和下層make(subdir目錄下運(yùn)行的make進(jìn)程)之間存在的聯(lián)系。也許會(huì)發(fā)現(xiàn)這兩個(gè)規(guī)則的實(shí)現(xiàn),使用偽目標(biāo)更能提高效率。

在make的遞歸調(diào)用中,需要了解變量“CURDIR”,此變量代表了make當(dāng)前的工作路徑。如果使用“-C”選項(xiàng)進(jìn)入一個(gè)子目錄后,此變量將被重新賦 值。總之,如果在Makefile中沒(méi)有對(duì)此變量進(jìn)行顯式的賦值操作,那么它代表make的當(dāng)前工作目錄。我們也可以在Makefile為這個(gè)變量賦一個(gè) 新的值。此時(shí)這變量將不再代表make的工作目錄。

5.6.1 變量MAKE
在使用make的遞歸調(diào)用時(shí),在Makefile中規(guī)則的命令行中應(yīng)該使用變量“MAKE”來(lái)代替直接使用“make”。像上一小節(jié)的例子:



subsystem:

cd subdir && $(MAKE)



變量“MAKE”的值是“make”程序的文件名。如果其值為“/bin/make”那么上邊規(guī)則的命令就為“cd subdir && /bin/make”。這樣做的好處是:當(dāng)我們使用一個(gè)其它版本的make程序時(shí),可以保證最上層使用的make程序和其子目錄下執(zhí)行的make保持一 致。

另外使用此變量的另外一個(gè)特點(diǎn)是:當(dāng)規(guī)則命令行中變量MAKE是,它可以改變make的“-t”(“--touch”),“-n”(“--just- print”)和“-q”(“--question”)命令行選項(xiàng)的效果。它所實(shí)現(xiàn)的功能和在規(guī)則中命令行首使用字符“+”的效果相同(可參考 9.3 替代命令的執(zhí)行 一節(jié))。

在規(guī)則的命令行中使用“make”代替了“$(MAKE)”以后,上例子規(guī)則的命令行為:“cd subdir && make”。在我們執(zhí)行“make -t”(“-t”選項(xiàng)用來(lái)更新所有目標(biāo)的時(shí)間戳,而不執(zhí)行任何規(guī)則的命令,參考 9.7 make的命令行選項(xiàng) 一節(jié)),結(jié)果是僅僅創(chuàng)建一個(gè)名為“subsystem”的文件,不會(huì)進(jìn)入到目錄“subdir”去更新此目錄下文件的時(shí)間戳。我們使用“-t”命令行參數(shù) 的初衷是對(duì)規(guī)則中的目標(biāo)文件的時(shí)間戳進(jìn)行更新。而如果使“cd subdir && $(MAKE)”作為規(guī)則的命令行,執(zhí)行“make -t”就可以實(shí)現(xiàn)我們的初衷。

變量“MAKE”的這個(gè)特點(diǎn)是:在規(guī)則的命令行中如果使用變量“MAKE”,標(biāo)志“-t”、“-n”和“-q”在這個(gè)命令的執(zhí)行中不起作用。盡管這些選項(xiàng) 是告訴make不執(zhí)行規(guī)則的命令行,但包含變量“MAKE”的命令行除外,它們會(huì)被正常執(zhí)行。同時(shí),執(zhí)行make時(shí)的命令行選項(xiàng)參數(shù)被通過(guò)一個(gè)變量 “MAKEFLAGS”傳遞給子目錄下的make程序。

例如,當(dāng)使用make的命令行選項(xiàng)“-t”來(lái)更新目標(biāo)的時(shí)間戳或者“-n”選項(xiàng)打印命令時(shí),這些選項(xiàng)將會(huì)被賦值給變量“MAKEFLAGS”被傳遞到下一 級(jí)的make程序中。在下一級(jí)子目錄中執(zhí)行的make,這些選項(xiàng)會(huì)被附加作為make的命令行參數(shù)來(lái)執(zhí)行,和在此目錄下使用“make -t”或者“make -n”有相同的效果。

5.6.2 變量和遞歸
在make的遞歸執(zhí)行過(guò)程中,上層make可以明確指定將一些變量的定義通過(guò)環(huán)境變量的方式傳遞給子make過(guò)程。沒(méi)有明確指定需要傳遞的變量,上層 make不會(huì)將其所執(zhí)行的Makefile中定義的變量傳遞給子make過(guò)程。使用環(huán)境變量傳遞上層所定義的變量時(shí),上層所傳遞給子make過(guò)程的變量定 義不會(huì)覆蓋子make過(guò)程所執(zhí)行makefile文件中的同名變量定義。

如果子make過(guò)程所執(zhí)行Makefile中存在同名變量定義,則上層傳遞的變量定義不會(huì)覆蓋子Makefile中定義的值。就是說(shuō)如果上層make傳遞 的變量和子make所執(zhí)行的Makefile中存在重復(fù)的變量定義,則以子Makefile中的變量定義為準(zhǔn)。除非使用make的“-e”選項(xiàng)。

我們?cè)诒緦玫牡谝欢沃刑岬?,?dāng)上層make過(guò)程要將所執(zhí)行的Makefile中的變量傳遞給子make過(guò)程時(shí),需要明確地指出。在GNU make中,實(shí)現(xiàn)此功能的指示符是“export”。當(dāng)一個(gè)變量使用“export”進(jìn)行聲明后,變量和變量的值將被加入到當(dāng)前工作的環(huán)境變量中,以后 make所執(zhí)行的所有規(guī)則的命令都可以使用這個(gè)變量。而當(dāng)沒(méi)有使用指示符“export”對(duì)任何變量進(jìn)行聲明的情況下,上層make只將那些已經(jīng)初始化的 環(huán)境變量(在執(zhí)行make之前已經(jīng)存在的環(huán)境變量)和使用命令行指定的變量(如命令“make CFLAGS +=-g”或者“make –e CFLAGS +=-g”)傳遞給子make程序,通常這些變量由字符、數(shù)字和下劃線組成。需要注意的是:有些shell不能處理那些名字中包含(除字母、數(shù)字、下劃線 以外)其他字符的變量。

兩個(gè)特殊的變量“SHELL”和“MAKEFLAGS”除非使用指示符“unexport”對(duì)它們進(jìn)行聲明,否則在整個(gè)make的執(zhí)行過(guò)程中它們會(huì)始終被 自動(dòng)的傳遞給子make。另外一個(gè)變量“MAKEFILES”,如果此變量有值(不為空)那么同樣他會(huì)被自動(dòng)的傳遞給子make。在沒(méi)有使用關(guān)鍵字 “export”聲明的變量,make執(zhí)行時(shí)不會(huì)被自動(dòng)傳遞給子make過(guò)程,因此下層Makefile中可以定義和上層同名的變量,這樣不會(huì)引起變量定 義沖突。

上層Makefile中定義的某一個(gè)變量需要傳遞給子make時(shí),應(yīng)該在上層Makefile中使用指示符“export”對(duì)此變量進(jìn)行聲明。格式如下:



export VARIABLE ...



當(dāng)不希望將一個(gè)變量傳遞給子make時(shí),可以使用指示符“unexport”來(lái)聲明這個(gè)變量。格式如下:



unexport VARIABLE ...



在以上的兩種格式,指示符“export”或者“unexport”的參數(shù)(變量部分),如果它是對(duì)一個(gè)變量或者函數(shù)的引用,這些變量或者函數(shù)將會(huì)被立即展開(kāi)。并賦值給export或者unexport的變量。例如:



Y = Z

export X=$(Y)”



等價(jià)于“export X=Z”。在這里進(jìn)行展開(kāi)是為了保證傳遞給子make的此變量的值有效。

“export”更方便的用法是在定義此變量時(shí)同時(shí)對(duì)它進(jìn)行聲明。如下的幾個(gè)例子:

1.

export VARIABLE = value



等效于:



VARIABLE = value

export VARIABLE



2.



export VARIABLE := value

等效于:



VARIABLE := value

export VARIABLE



3.

export VARIABLE += value



等效于:



VARIABLE += value

export VARIABLE



其實(shí)在Makefile中指示符“export”和“unexport”的功能和在shell下功能相同。

另外一個(gè)不帶任何參數(shù)的指示符“export”指示符:



export



含義是將此Makefile中定義的所有變量傳遞給子make過(guò)程。如果不需要傳遞其中一個(gè)變量,可以使用指示符“unexport”來(lái)聲明這個(gè)變量,這 個(gè)被聲明的變量就不會(huì)被傳遞給子make。使用“export”將所有定義的變量傳遞給子Makefile時(shí),那些名字中包含其它字符(除字母、數(shù)字和下 劃線以外的字符)的變量可能不會(huì)被傳遞給子make,對(duì)這類特殊命名的變量傳遞需要明確的使用“export”指示符對(duì)它進(jìn)行聲明。

需要說(shuō)明的是:?jiǎn)为?dú)使用“export”來(lái)導(dǎo)出所有變量的行為是老版本GNU make所默認(rèn)的。但是在新版本的GNU make中取消了這一默認(rèn)的行為。因此在編寫和老版本GNU make兼容的Makefile時(shí),需要使用特殊目標(biāo)“.EXPORT_ALL_VARIABLES”來(lái)代替“export”,此特殊目標(biāo)的功和不帶參數(shù) 的“export”相同。它會(huì)被老版本的make忽略,只有新版本的make能夠識(shí)別這個(gè)特殊目標(biāo)。

因?yàn)?,如果在老版本的GNU make中使用指示符“export”,將會(huì)出現(xiàn)語(yǔ)法錯(cuò)誤。例如為了和老版本兼容可以這樣來(lái)聲明一些變量:



.EXPORT_ALL_VARIABLES:

VARIABLE1=var1

VARIABLE2=var2



這樣對(duì)于不同版本的make來(lái)說(shuō)都是兼容的,其含義是將特殊目標(biāo)“.EXPORT_ALL_VARIABLES”的依賴中的所有變量全部傳遞給子make。

和指示符“export”相似,也可以使用單獨(dú)的“unexport”指示符來(lái)禁止一個(gè)變量的向下傳遞。這一動(dòng)作也是現(xiàn)行版本make所默認(rèn)的,因此我們 就沒(méi)有必要在上層的Makefile中使用它。在多級(jí)的make遞歸調(diào)用中,我么可以在中間的Makefile中使用它來(lái)限制上層傳遞來(lái)的變量再向下傳 遞。需要明確的是,不能使用“export”或者“unexport”來(lái)實(shí)現(xiàn)命令中使用的變量控制功能。就是說(shuō),不能做到用這兩個(gè)指示符來(lái)限制某個(gè)(些) 變量在執(zhí)行特定命令時(shí)有效,而對(duì)于其它的命令則無(wú)效。在Makefile中,最后一個(gè)出現(xiàn)的指示符“export”或者“unexport”決定整個(gè) make運(yùn)行過(guò)程中變量是否進(jìn)行傳遞。

在多級(jí)遞歸調(diào)用的make執(zhí)行過(guò)程中。變量“MAKELEVEL”代表了調(diào)用的深度。在make一級(jí)級(jí)的執(zhí)行過(guò)程中變量“MAKELEVEL”的值不斷的 發(fā)生變化,通過(guò)它的值我們可以了解當(dāng)前make遞歸調(diào)用的深度。最上一級(jí)時(shí)“MAKELEVEL”的值為“0”、下一級(jí)時(shí)為“1”、再下一級(jí)為 “2”.......例如:

Main目錄下的Makefile清單如下:

#maindir Makefile

………

………

.PHONY :test

test:

@echo “main makelevel = $(MAKELEVEL)”

@$(MAKE) –C subdir dislevel



#subdir Makefile

………..

………..

.PHONY : test

test :

@echo “subdir makelevel = $(MAKELEVEL)”



在maindir 目錄下執(zhí)行“make test”。將顯式如下信息:

main makelevel = 0

make[1]: Entering directory `/…../ subdir ‘

subdir makelevel = 1

make[1]: Leaving directory `/…../ subdir ‘



在主控的Makefile中MAKELEVEL 為“0”,而在subdir的Makefile中,MAKELEVEL為“1”。

這個(gè)變量主要用在條件測(cè)試指令中。例如:我們可以通過(guò)測(cè)試此變量的值來(lái)決定是否執(zhí)行遞歸方式的make調(diào)用或者其他方式的make調(diào)用。我們希望一個(gè)子目 錄必須被上層make進(jìn)行調(diào)用才能可以執(zhí)行此目錄下的Makefile,而不允許直接在其所在的目錄下執(zhí)行make。我們可以這樣實(shí)現(xiàn):



.......

$(ifeq $(MAKELEVEL),0)

all : msg

else

all : other

endif



……

…...



msg:

@echo ”Can not make in this directory!”

……

……



當(dāng)在包含次條件判斷的Makefile所在的目錄下執(zhí)行make時(shí),將會(huì)得到提示“Can not make in this directory!”。

5.6.3 命令行選項(xiàng)和遞歸
在make的遞歸執(zhí)行過(guò)程中。最上層(可以稱之為主控)make的命令行選項(xiàng)“-k”、“-s”等被自動(dòng)的通過(guò)環(huán)境變量“MAKEFLAGS”傳遞給子 make進(jìn)程。變量“MAKEFLAGS”的值會(huì)被主控make自動(dòng)的設(shè)置為包含執(zhí)行make時(shí)的命令行選項(xiàng)的字符串。在主控執(zhí)行make時(shí)使用“-k” 和“-s”選項(xiàng),那么“MAKEFLAGS”的值就為“ks”。子make進(jìn)程處理時(shí),會(huì)把此環(huán)境變量的值作為執(zhí)行的命令行選項(xiàng),因此子make進(jìn)程就使 用“-k”和“-s”這兩個(gè)命令行選項(xiàng)。

同樣,在執(zhí)行make時(shí)命令行中給定了一個(gè)變量的定義(如“make CFLAGS+=-g”),此變量和它的值(CFLAGS+=-g)也會(huì)借助環(huán)境變量“MAKEFLAGS”傳遞給子make進(jìn)程??梢越柚鷐ake的環(huán) 境變量“MAKEFLAGS” 傳遞我們?cè)谥骺豰ake所使用的命令行選項(xiàng)給子make進(jìn)程。需要注意的是有幾個(gè)特殊的命令行選項(xiàng)例外,分別是:“-C”、“-f”、“-o”和“- W”。這些命令行選項(xiàng)不會(huì)被賦值給變量“MAKEFLAGS”。

Make命令行選項(xiàng)中一個(gè)比較特殊的是“-j”選項(xiàng)。在支持這個(gè)選項(xiàng)的操作系統(tǒng)上,如果給它指定了一個(gè)數(shù)值“N”(多任務(wù)的系統(tǒng)unix、Linux支 持,MS-DOS不支持),那么主控make和子make進(jìn)程會(huì)在執(zhí)行過(guò)程使用通信機(jī)制來(lái)限制系統(tǒng)在同一時(shí)刻(包括所有的遞歸調(diào)用的make進(jìn)程,否則, 將會(huì)導(dǎo)致make任務(wù)的數(shù)目數(shù)目無(wú)法控制而使別的任務(wù)無(wú)法到的執(zhí)行)的任務(wù)的執(zhí)行數(shù)目不大于“N”。另外,當(dāng)使用的操作系統(tǒng)不能支持make執(zhí)行過(guò)程中的 父子間通信,那么無(wú)論在執(zhí)行主控make時(shí)指定的任務(wù)數(shù)目“N”是多少,變量“MAKEFLAGS”中選項(xiàng)“-j”的數(shù)目會(huì)都被設(shè)置為“1”,這樣可以確 保系統(tǒng)正常運(yùn)轉(zhuǎn)。

執(zhí)行多級(jí)的make調(diào)用時(shí),如果不希望“MAKEFLAGS”的值傳遞給子make,就需要在執(zhí)行子make時(shí)對(duì)它重新進(jìn)行賦值。例如:



subsystem:

cd subdir && $(MAKE) MAKEFLAGS=



此規(guī)則取消了子make執(zhí)行式的命令行選項(xiàng)(將變量的值賦為空)。

在執(zhí)行make的同時(shí)可以通過(guò)命令行來(lái)定義一個(gè)變量,像上例中的那樣;前邊已經(jīng)提到過(guò),這種變量是借助環(huán)境“MAKEFLAGS”來(lái)傳遞給多級(jí)調(diào)用的子 make進(jìn)程的。其實(shí)真正的命令行中的 變量定義 是通過(guò)另外一個(gè)變量“MAKEOVRRIDES”來(lái)記錄的,變量“MAKEFLAGS”引用此變量,因而命令行中的變量定義就可以被記錄在環(huán)境變量 “MAKEFLAGS”中被傳遞下去。當(dāng)不希望將上層make在命令行中定義的變量傳遞給子make時(shí),就可以在上層Makefile中把 “MAKEOVERRIDES”賦空來(lái)實(shí)現(xiàn)(MAKEOVERRIDES=)。這種方式一般很少使用,建議非萬(wàn)不得已您還是最好不使用這種方式(為了和 POSIX2.0兼容,當(dāng)Makefile中出現(xiàn)“.POSIX”這個(gè)特殊的目標(biāo)時(shí),在上層Makefile中修改變量“MAKEOVERRIDES”對(duì) 子make不會(huì)產(chǎn)生任何影響)。另外一些系統(tǒng)中對(duì)環(huán)境變量的長(zhǎng)度存在一個(gè)上限,因此當(dāng)“MAKEFLAGS”的值超過(guò)一定的數(shù)目時(shí),執(zhí)行過(guò)程出現(xiàn)了類似 “Arg list too long”的錯(cuò)誤提示。

歷史原因,在make中存在另外一個(gè)和“MAKEFLAGS”相類似的變量“MFLAGS”?,F(xiàn)行版本中此變量保留的原因是和老版本的兼容需要。和 “MAKEFLAGS”不同點(diǎn)是:1. 此變量在make的遞歸調(diào)用時(shí)不包含命令行選項(xiàng)中的變量定義部分(就是說(shuō)此變量的定義沒(méi)有包含對(duì)“MAKEOVERRIDES”的引用);2. 此變量的值(除為空的情況)是以“-”開(kāi)始的,而“MAKEFLAGS”的值只有在長(zhǎng)命令選項(xiàng)格式(如:“--warn-undefined- variables”)時(shí)才以“-”開(kāi)頭。傳統(tǒng)得此變量一般被明確的使用在make遞歸調(diào)用命令中。像下邊那樣:



subsystem:

cd subdir && $(MAKE) $(MFLAGS)



在現(xiàn)行的make版本中,變量“MFLAGS”已經(jīng)成為一個(gè)多余部分。在書寫和老版本make兼容的Makefile時(shí)可能需要這個(gè)變量。當(dāng)然它在目前的版本上也能夠正常的工作。

在某些特殊的場(chǎng)合,可能需要為所有的make進(jìn)程指定一個(gè)統(tǒng)一的命令行選項(xiàng)。比如說(shuō)需要給所有的運(yùn)行的make指定“-k”選項(xiàng)。實(shí)現(xiàn)這個(gè)目的,我們可以 在執(zhí)行make之前設(shè)置一個(gè)系統(tǒng)環(huán)境變量(存在于當(dāng)前系統(tǒng)的環(huán)境中)“MAKEFLAGS=k”,或者在主控Makefile中將它的值賦為“k”。需要 注意的是:不能通過(guò)變量“MFLAGS”來(lái)實(shí)現(xiàn)。

make在執(zhí)行時(shí),首先將會(huì)對(duì)變量“MAKEFLAGS”的值(系統(tǒng)環(huán)境中或者在Makefile中設(shè)置的)進(jìn)行分析。當(dāng)變量的值不是以連字符(“-”) 開(kāi)始時(shí),將變量的值按字分開(kāi),字之間使用空格分開(kāi)。將這些字作為命令行的選項(xiàng)對(duì)待(除了選項(xiàng)“-C”、“-f”、“-h”、“-o”和“-W”以及他們的 長(zhǎng)格式,如果其中包含無(wú)效的選項(xiàng)也不會(huì)提示錯(cuò)誤)。

最后需要強(qiáng)調(diào)的是:當(dāng)把“MAKEFLAGS”設(shè)置到你的系統(tǒng)環(huán)境變量中時(shí),要小心謹(jǐn)慎!將一些調(diào)試選項(xiàng)或者特殊選項(xiàng)設(shè)置為此變量值的一部分,在執(zhí)行 make時(shí),會(huì)對(duì)make的正常執(zhí)行產(chǎn)生影響,甚至是破壞性的影響。例如變量“MAKEFLAGS”中包含選項(xiàng)“t”、“n”、“q”這三個(gè)的任何一個(gè), 你在執(zhí)行make時(shí)產(chǎn)生的結(jié)果可能并不是你所要達(dá)到的目的。建議大家最好不要隨便更改“MAKEFLAGS”的值,更不要把它設(shè)置為系統(tǒng)的環(huán)境變量來(lái)使 用。否則可能會(huì)產(chǎn)生一些奇怪甚至讓你感到不解的現(xiàn)象。

1.6.4 -w選項(xiàng)
在多級(jí)make遞歸調(diào)用過(guò)程中,選項(xiàng)“-w”或者“--print-directory”可以讓make在開(kāi)始編譯一個(gè)目錄之前和完成此目錄的編譯之后給 出相應(yīng)的提示信息,方便開(kāi)發(fā)人員能夠跟蹤make的執(zhí)行過(guò)程。例如,在目錄“/u/gnu/make”目錄下執(zhí)行“make -w”,將會(huì)看到如下的一些信息:

在開(kāi)始執(zhí)行之前我們將看到:



make: Entering directory `/u/gnu/make‘.



而在完成之后我們同樣將會(huì)看到:



make: Leaving directory `/u/gnu/make‘.



通常,選項(xiàng)“-w”會(huì)被自動(dòng)打開(kāi)。在主控Makefile中當(dāng)如果使用“-C”參數(shù)來(lái)為make指定一個(gè)目錄或者使用“cd”進(jìn)入一個(gè)目錄時(shí),“-w”選 項(xiàng)會(huì)被自動(dòng)打開(kāi)。主控make可以使用選項(xiàng)“-s”(“--slient”)來(lái)禁止此選項(xiàng)的自動(dòng)打開(kāi)。另外,make的命令行選項(xiàng)“--no-print -directory”,將禁止所有關(guān)于目錄信息的打印。

5.7 定義命令包
在書寫Makefile時(shí),可能有多個(gè)規(guī)則會(huì)使用相同的一組命令。就像c語(yǔ)言程序中需要經(jīng)常使用到函數(shù)“printf”。這時(shí)我們就會(huì)想能不能將這樣一組 命令進(jìn)行類似c語(yǔ)言函數(shù)一樣的封裝,以后在我們需要用到的地方可以通過(guò)它的名字(c語(yǔ)言中的函數(shù)名)來(lái)對(duì)這一組命令進(jìn)行引用。這樣就可減少重復(fù)工作,提高 了效率。在GNU make中,可以使用指示符“define”來(lái)完成這個(gè)功能。通過(guò)“define”來(lái)定義這樣一組命令,同時(shí)用一個(gè)變量(作為一個(gè)變量,不能和 Makefile中其它常規(guī)的變量命名出現(xiàn)沖突)來(lái)代表這一組命令。通常我們把使用“define”定義的一組命令稱為一個(gè)命令包。定義一個(gè)命令包的語(yǔ)法 以“define”開(kāi)始,以“endef”結(jié)束,例如:



define run-yacc

yacc $(firstword $^)

mv y.tab.c $@

endef



這里,“run-yacc”是這個(gè)命令包的名字。在“define”和“endef”之間的命令就是命令包的主體。需要說(shuō)明的是:使用“define”定 義的命令包中,命令體中變量和函數(shù)的引用不會(huì)展開(kāi)。命令體中所有的內(nèi)容包括“$”、“(”、“)”等都是變量“run-yacc”的定義。它和c語(yǔ)言中宏 的使用方式一樣。

例子中,命令包中第一個(gè)命令是對(duì)引用它所在規(guī)則中的第一個(gè)依賴文件(函數(shù)“firstword”,可參考 8.2 文本處理函數(shù) 一節(jié))運(yùn)行yacc程序。yacc程序總是生成一個(gè)命名為“y.tab.c”的文件。第二行的命令就是把這個(gè)文件名改為規(guī)則目標(biāo)的名字。

定義了這樣一個(gè)命令包后,后續(xù)應(yīng)該如何使用它?前面已經(jīng)提到,命令包是使用一個(gè)變量來(lái)表示的。因此我們就可以按使用變量的方式來(lái)使用它。當(dāng)在規(guī)則的命令行 中使用這個(gè)變量時(shí),命令包所定義的命令體就會(huì)對(duì)它進(jìn)行替代。由于使用“define”定義的變量屬于遞歸展開(kāi)式變量,因此,命令包中所有命令中對(duì)其它變量 的引用,在規(guī)則被執(zhí)行時(shí)會(huì)被完全展開(kāi)。例如這樣一個(gè)規(guī)則:



foo.c : foo.y

$(run-yacc)



此規(guī)則在執(zhí)行時(shí),我們來(lái)看一下命令包中的變量的替換過(guò)程:1. 命令包重中的“$^”會(huì)被“foo.y”替換;2. “$@”被“foo.c”替換。大家應(yīng)該對(duì)“$<”和“$@”不陌生吧,如果陌生可以 參考 自動(dòng)化變量 一小節(jié)。

當(dāng)在一個(gè)規(guī)則中引用一個(gè)已定義的命令包時(shí),命令包中的命令體會(huì)被原封不動(dòng)的展開(kāi)在引用它的地方(和 c語(yǔ)言中的宏一樣)。這些命令就成為規(guī)則的命令。因此我們也可在定義命令包時(shí)使用前綴來(lái)控制單獨(dú)的一個(gè)命令行(例如“@”,“-”和“+”)。例如:



define frobnicate

@echo "frobnicating target $@"

frob-step-1 $< -o $@-step-1

frob-step-2 $@-step-1 -o $@

endef



此命令包的第一行命令執(zhí)行前不會(huì)被回顯,其它的命令在執(zhí)行前都被回顯。

另一方面,如果一個(gè)規(guī)則在引用此命令包之前使用了命令的前綴字符。那么這個(gè)前綴字符將會(huì)被添加到命令包定義的所有命令行之中。例如:



frob.out: frob.in

@$(frobnicate)



這個(gè)規(guī)則執(zhí)行時(shí)不會(huì)回顯任何將要執(zhí)行的命令。

5.8 空命令
有時(shí)可能存在這樣的一個(gè)需求,需要定義一個(gè)什么也不做的規(guī)則(沒(méi)有命令行)。前面我們已經(jīng)看到過(guò)這樣的用法。這樣的規(guī)則,只有目標(biāo)文件(可以存在依賴文件)而沒(méi)有命令行??梢韵襁@樣定義:



target: ;



這就是一個(gè)空命令的規(guī)則,為目標(biāo)“target”定義了一個(gè)空命令。也可以命令行的格式來(lái)定義空命令,需要注意的是命令行必須以[Tab]字符開(kāi)始。一般在定義空命令時(shí),建議不使用命令行的方式,因?yàn)榭雌饋?lái)空命令行和空行在感覺(jué)上沒(méi)有區(qū)別。

大家會(huì)奇怪為什么要定義一個(gè)沒(méi)有命令的規(guī)則。其唯一的原因是,使用空命令行可以防止make在執(zhí)行時(shí)圖重建這個(gè)目標(biāo)而查找隱含命令(包括了使用隱含規(guī)則中 的命令和“.DEFAULT”指定的命令。關(guān)于隱含規(guī)則可參考 第10章 使用隱含規(guī)則)。這一點(diǎn)和偽目標(biāo)有相同之處。在使用空命令的目標(biāo)時(shí),需要說(shuō)明的是:實(shí)現(xiàn)一個(gè)沒(méi)有實(shí)際文件的目標(biāo),這個(gè)目標(biāo)只是作為一個(gè)標(biāo)簽,來(lái)完成它的依 賴文件的重建動(dòng)作。實(shí)現(xiàn)這個(gè)目的,首先應(yīng)該想到偽目標(biāo)而不是空命令目標(biāo)。因?yàn)橐粋€(gè)實(shí)際不存在的目標(biāo)文件的依賴文件,可能不會(huì)被正確的重建。

所以,對(duì)于空命令規(guī)則,最好不要給它指定依賴文件。避免特殊情況下產(chǎn)生錯(cuò)誤的情況。定義一個(gè)空命令規(guī)則,建議使用上例的格式。

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

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多