Posted on 2010-11-19 14:03
幻海藍夢 閱讀(18525)
評論(0) 編輯 收藏 所屬分類:
Linux 、
版本管理
原文: http://www.chinaunix.net/jh/7/16880.html
Make 程序最初設(shè)計是為了維護C程序文件防止不必要的重新編譯。在使用命令行編譯器的時
候,修改了一個工程中的頭文件,如何確保包含這個頭文件的所有文件都得到編譯?現(xiàn)在10機的版本生成是使用批處理程序,編譯那些文件依賴于程序的維護者,
在模塊之間相互引用頭文件的情況下,要將所有需要重新編譯的文件找出來是一件痛苦的事情;在找到這些文件之后,修改批處理進行編譯。實際上這些工作可以讓
make程序來自動完成,make工具對于維護一些具有相互依賴關(guān)系的文件特別有用,它對文件和命令的聯(lián)系(在文件改變時調(diào)用來更新其它文件的程序)提供
一套編碼方法。Make工具的基本概念類似于Proglog語言,你告訴make需要做什么,提供一些規(guī)則,make來完成剩下的工作。
1簡介
make
工作自動確定工程的哪部分需要重新編譯,執(zhí)行命令去編譯它們。雖然make多用于C程序,然而只要提供命令行的編譯器,你可以將其用于任何語言。實際
上,make工具的應(yīng)用范圍不僅于編程,你可以描述任和一些文件改變需要自動更新另一些文件的任務(wù)來使用它。
1.1準備工作
如果要使用
make,你必須寫一個叫做“makefile”的文件,這個文件描述工程中文件之間的關(guān)系,提供更新每個文件的命令。典型的工程是這樣的:可執(zhí)行文件靠
目標文件來更新,目標文件靠編譯源文件來更新。
Makefile寫好之后,每次更改了源文件后,只要執(zhí)行make就足夠了,所有必要的重新編譯將
執(zhí)行。Make程序利用makefile中的數(shù)據(jù)庫和文件的最后修改時間來確定那個文件需要更新;對于需要更新的文件,make執(zhí)行數(shù)據(jù)庫中記錄的命令。
可
以提供命令行參數(shù)給make來控制那個文件需要重新編譯。
1.2Makefile介紹
Makefile文件告訴make做什么,多數(shù)情況
是怎樣編譯和鏈接一個程序。
這里有一個簡單的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創(chuàng)建可執(zhí)行文件“edit”時運行make就可以了;如果要將可執(zhí)行文
件和目標文件刪除,執(zhí)行make clean
make重新編譯這個編輯器時,每個更改的C文件必須重新編譯;如果頭文件更改了,每個包含頭文件的
C文件必須重新編譯;每次編譯產(chǎn)生一個對應(yīng)于原文件的目標文件。最終,目標文件鏈接在一起產(chǎn)生新的可執(zhí)行文件。
1.3規(guī)則簡介
makefile
中的規(guī)則是這樣的:
TARGET … : DEPENDENCIES …
COMMAND
…
目標(TARGET)程序產(chǎn)
生的文件,如可執(zhí)行文件和目標文件;目標也可以是要執(zhí)行的動作,如“clean”。
依賴(DEPENDENCIES)是用來產(chǎn)生目標的輸入文件,
一個目標通常依賴于多個文件。
命令(COMMAND)是make執(zhí)行的動作,一個可以有多個命令,每個占一行。注意:每個命令行的起始字符必須為
TAB字符!
有依賴關(guān)系規(guī)則中的命令通常在依賴文件變化時負責產(chǎn)生target文件,make執(zhí)行這些命令更新或產(chǎn)生target。規(guī)則可以沒有
依賴關(guān)系,如包含target “clean”的規(guī)則。
規(guī)則解釋如何和何時重做該規(guī)則中的文件,make根據(jù)依賴關(guān)系執(zhí)行產(chǎn)生或更新目標;規(guī)則也
說明如何和何時執(zhí)行動作。有的規(guī)則看起來很復(fù)雜,但都符合上述模式。
1.4make工作原理
缺省make從第一個target開始(第一
個非 ’.’ 開始的target),這稱作缺省目標。在上述的makefile中,缺省目標是更新執(zhí)行程序’edit’,將這個目標置于最前面。當執(zhí)行
make的時候,make程序從當前目錄讀入makefile開始處理第一個規(guī)則;在例子中,這個規(guī)則是重新鏈接’edit’;在make處理這個規(guī)則之
前,必須處理’edit’所依賴的那些文件的規(guī)則,例子中是目標文件。這些文件按照他們自己的規(guī)則處理:通過編譯源文件來更新每個’.o’文件;當依賴關(guān)
系中的源文件或頭文件比目標文件新,或目標文件不存在時,必須重新編譯。
其它的規(guī)則被處理是因為他們的target是目標的依賴,和目標沒有依賴
關(guān)系的規(guī)則不會被處理,除非指定make處理(如make clean)。
在重新編譯目標文件之前,make會試圖更新它的依賴:源文件和頭文
件。例子中的makefile對源文件和頭文件未指定任何操作:’.c’和’.h’文件不是任何規(guī)則的目標。確認所有的目標文件都是最新的之后,make
決定是否重新鏈接’edit’:如果’edit’不存在,或者任何一個目標文件都比它新,則鏈接工作將進行。
這樣,如果我們改變insert.c
運行make,make會編譯這個文件來更新’insert.o’,然后鏈接’edit’;如果修改了’command.h’運行
make,’kbd.o’,’command.o’,’files.o’會重新生成,鏈接’edit’。
1.5使用變量
在例子中,在規(guī)
則’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
這
樣的重復(fù)容易出錯:假設(shè)工程中加入了一個新的目標文件,可能只將其加入了一個列表中;通過使用變量可以消除這種風險:變量允許一個預(yù)定義的字符串在多個地
方被替換。
在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’文件有一個隱含的規(guī)則,使用’cc -c’命
令。Make將利用’cc –c main.c –o main.o’來將main.c編譯為main.o,因此在生成目標文件的規(guī)則中,可以省略命令。
當’.c’
文件以這樣的方式使用時,將自動加入到依賴關(guān)系中;由是在省略命令的前提下,可以將’.c’文件從依賴關(guān)系中省略。以下是簡化過的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中的目標都是以隱含規(guī)則生成,可以將規(guī)則按照依賴關(guān)系分組:
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
清理
編寫規(guī)則不至于編譯程序。Makefile通常描述如何做其它事情:比如刪除目錄中的目標文件和可執(zhí)行文件來清理目錄。例子中是這樣寫的:
clean:
rm edit $(objects)
實
際情況是,我們需要處理一些意外事件:存在一個叫做’clean’的文件;如果rm出錯,并不希望make過程停止下來,修改過的版本如下:
.PHONY : clean
clean :
-rm edit $(objects)
這
樣的規(guī)則當然不能放在makefile的開始,因為這并不是我們?nèi)笔∫龅墓ぷ鳌S捎?#8217;clean’并不是’edit’的依賴,在運行make時沒有參數(shù)
時,這條規(guī)則不會執(zhí)行;要執(zhí)行這個規(guī)則,必須運行’make clean’。
2Makefile
Makefile中包含五種內(nèi)容:顯式規(guī)
則,隱式規(guī)則,變量定義,指令(directive)和注釋。
;顯式規(guī)則描述如何生成規(guī)則的目標,它列出
了目標依賴的文件,指定了產(chǎn)生或更新目標的命令
;隱式規(guī)則描述如何生成基于文件名的一類文件,說明目標可
能依賴于和其文件名類似的文件,指定了相應(yīng)的命令。
;指令類似與編譯器的偽指令,包含:
;
指示make讀入另一個makefile
;決定是否忽略makefile中的一部分
;
定義一個變量
;一行中‘#’開始是注釋,直到行末,除非遇到續(xù)行符號。在’define’和命令中不能有
注釋,其它情況下注釋可出現(xiàn)在任何地方。
2.1makefile名字
缺省情況下,make以下列名字查找
makefile:’GNUmakefile’,’makefile’和’Makefile’(注意大小寫)。通常你的makefile應(yīng)叫
做’makefile’或’Makefile’。’GNUmakefile’不推薦,除非你的makefile是為GNU的make定制的,其它的
make不認為該名字是一個makefile的名字。
如果你使用非標準命名的makefile,必須用命令開關(guān)’-f ’ 或 ’—file’。
參數(shù)’ –f NAME’或’—file NAME’告訴make讀入NAME作為makefile。如果使用多個該開關(guān),所有的文件將按順序連接起來。
如果使用該選項,標準的makefile名字不會自動檢測。
2.2包含
‘include’指令告訴make暫停處理余下的內(nèi)容,讀入其它
makefile。語法如下:
include FILENAMES …
這一行起始可以有空格,但TAB字符不允許。如果文件名包含變量或
函數(shù),這些將被擴展。
2.3‘MAKEFILE’變量
如果環(huán)境變量’MAKEFILE’已定義,make認為它的值是一系列空格隔開的文
件名,這些文件在處理其它makefile前被make程序讀入。這類似于include指令;這些文件中的目標不會影響缺省目標,而且如果文件未找到的
話,make并不認為是錯誤。
這個變量的主要用途是遞歸引用make程序時通訊
2.4如何重新生成makefile
有時候
makefile是從其它文件生成的,比如RCS或SCCS文件。如果makefile是由其它文件生成的,需要make讀入最新版本的
makefile。
在讀入所有makefile之后,make認為每個makefile是一個目標,試圖去更新它;如果makefile中有一條
如何更新它的規(guī)則,或者有適用的隱式規(guī)則,需要的更新會進行。所有的makefile檢查完之后,如果有的改變了,make重新開始再讀入(make會試
圖再做更新,但通常不會再改變了,因為已經(jīng)是最新的了)。
如果一個文件使用雙冒號規(guī)則,提供了命令但沒有依賴關(guān)系,文件始終會被更新。在
makefile的情況下,如果makefile雙冒號規(guī)則,提供了命令但沒有依賴關(guān)系,這樣makefile始終會重新生成,這會導(dǎo)致循環(huán):make只
是在不斷更新makefile,卻不干活。為避免這種情況,make不會重新生成那些只有命令沒有依賴關(guān)系的雙冒號規(guī)則的makefile。
如果
沒有使用’-f’或’--file’選項,make會嘗試缺省的makefile文件名。和指明’-f’或’--file’選項不同,make不能確定這
些文件是否應(yīng)當存在。然而,如果缺省makefile不存在但可以通過運行make規(guī)則生成,你可能希望這些規(guī)則被運行使得makefile可以使用。
因
此,如果沒有缺省makefile,make試圖按照makefile名查找的順序生成它,直到成功或名字用完。注意如果make 不能找到或生成
makefile,這并不是錯誤;makefile不總是必需的。
當使用’-t’或’--touch’選項時,不希望使用過時的makefile
來決定那個目標來touch。所以’-t’選項對makefile更新不起作用;類似’-q’(or ‘—question’)和’-n’(or ’—
just-print’)不阻止makefile的更新,因為過時的makefile會產(chǎn)生錯誤的輸出。這
樣’make –f mfile –n foo’會更新’mfile’,讀入它,打印出更新’foo’需要執(zhí)行的命令但不運行這些命令。與’foo’有關(guān)
的命令是更新過的’mfile’中的內(nèi)容。
但是有時不希望更新makefile,可以將makefile作為命令行的目標,當makefile被
顯式指定為目標時,’-t’選項也適用于它們。
這樣’make –f mfile –n mfile foo’會讀入’mfile’,打印出更新
執(zhí)行的命令,’foo’的命令是當前的’mfile’中的內(nèi)容。
2.5重載makefile
可以使用’include’指令來包含其它
makefile,增加目標的變量定義。然而,make不允許同一個目標有不同的命令,有其它的途徑可以達到目的。
假設(shè)
有’makefile’ 和’mfile’,’makfile’要包含’mfile’,但都有對于目標’foo’的規(guī)則。這是可以在’makefile’
中寫一條匹配任意模式的規(guī)則,指明當make在’makefile’中未找到目標時,搜索’mfile’:
foo:
frobnicate >; foo
%: force
@$(MAKE) -f mfile $@
force: ;
當
執(zhí)行’make foo’時,make找到’makefile’,執(zhí)行命令’ frobnicate >; foo’;執(zhí)行’make bar’
時,在’makefile’中未找到相應(yīng)的規(guī)則,這時模式規(guī)則適用,執(zhí)行命令’make –f mfile bar’,’makefile’中未提及的其
它目標也是類似的。
這種方法之所有工作是因為模式規(guī)則的模式是’%’,可以匹配任何的目標;這條規(guī)則的依賴是’force’,保證即使目標存在命
令也會執(zhí)行;’force’規(guī)則的命令為空防止’make’為其搜索隱式規(guī)則-這樣會導(dǎo)致依賴循環(huán)。
3規(guī)則
makefile中的規(guī)則描述
如何生成特定的文件,即規(guī)則的目標。規(guī)則列出了目標的依賴文件,指定生成或更新目標的命令。
規(guī)則的次序是不重要的,除非是確定缺省目標:缺省目標
是第一個makefile中的第一個規(guī)則;如果第一個規(guī)則有多個目標,第一個目標是缺省的。有兩個例外:以’.’開頭的目標不是缺省目標;模式規(guī)則對缺省
目標沒有影響。
通常我們所寫的地一個規(guī)則是編譯整個或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字符開始標識它是一個命
令。
這條規(guī)則說明兩件事:
;如何決定’foo.o’是舊的:如果它不存在,或者’foo.c’或
者’defs.h’比它新。
;如何更新’foo.o’文件:通過運行’cc’程序。命令未提
及’defs.h’,擔可以猜想’foo.c’包含了它,這是’defs.h’被置于依賴關(guān)系中的理由。
3.2規(guī)則的語法
語法如下:
TARGETS : DEPENDENCIES
COMMAND
...
或
者
TARGETS : DEPENDENCIES ; COMMAND
COMMAND
...
TARGETS
是以空格隔開的文件名,統(tǒng)配符可以使用。通常一個規(guī)則只有一個目標,偶爾也有多個。
命令行以TAB鍵開始。第一條命令可在依賴關(guān)系的下一行;或者
在同一行,在分號后面;兩種方式效果相同。
因為’$’符號被用做變量引用,如果要在規(guī)則中使用’$’符號,必須寫兩個:’$$’。可以用’\’符
號來分割一個長行,這不是必須的,因為make對行的長度沒有限制。
3.3通配符
規(guī)則中的文件名可以包含統(tǒng)配符,如’*’,’?’。
文
件名前的字符’~’有特殊的含義。單獨使用,或跟隨一個’/’,代表用戶的home目錄,比如’~/bin’擴展為/home/you/bin’;如
果’~’跟隨一個單詞,表示單詞指示的那個用戶的home目錄,如’~john/bin’擴展為’/home/john/bin’。
通配符在目
標,依賴關(guān)系,命令中自動擴展,其它情況下,統(tǒng)配符的擴展除非顯式使用’wildcard’函數(shù)。通配符的特殊意義可以使用’\’符號關(guān)閉。
例
子:
clean:
rm -f *.o
和
print: *.c
lpr -p $?
touch print
通
配符在定義變量時并不擴展,例如:
objects = *.o
則objects的值是字符串’*.o’;但是如果你將objects用于
目標,依賴或命令中,擴展會進行。要將objects設(shè)置成擴展過的內(nèi)容,使用:
objects := $(wildcard *.o)
3.3.1
通配符的缺陷
這是一個使用通配符的例子,但結(jié)果不是你所期望的。假設(shè)可執(zhí)行文件’foo’是從當前目錄中的所有’.o’文件生成的:
objects = *.o
foo : $(objects)
cc -o foo $(CFLAGS) $(objects)
objects
變量的值是字符串’*.o’。通配符擴展在規(guī)則’foo’中進行,于是所有存在的’.o’文件成為’foo’的依賴而且在需要時重新編譯。
但如果
刪除了所有的’.o’文件呢?當通配符不匹配任何文件時,一切都保持原樣:則’foo’依賴于一個叫做’*.o’的文件;由于這個文件不大可能存
在,’make’程序會報告一個無法生成’*.o’文件的錯誤,這不是期待的結(jié)果。
實際上可以用通配符獲得期望結(jié)果,但是需要復(fù)雜的技術(shù),包
括’wildcard’函數(shù)和字符串替換函數(shù)。
3.3.2wildcard函數(shù)
通配符自動在規(guī)則中進行。但是在變量賦值的和函數(shù)的參數(shù)中
通配符不會擴展,如果在這些情況下需要通配符擴展,必須使用’wildcard’函數(shù)。語法如下:
$(wildcard PATTERN...)
這
個在makefile任何地方出現(xiàn)的字符串,會被匹配任何一個文件名格式的以空格隔開的現(xiàn)有文件列表替換。如果沒有任何文件匹配一個模式,這個模式
從’wildcard’的輸出中忽略,注意,這和上述的通配符的處理是不一樣的。
‘wildcard’函數(shù)的一個功能是找出目錄中所有的’.c’
文件:
$(wildcard *.c)
可以通過替換后綴’.c’為’.o’從C文件列表得到目標文件的列表:
$(patsubst %.c,%.o,$(wildcard *.c))
這
樣,上節(jié)中的makefile改寫為:
objects := $(patsubst %.c,%.o,$(wildcard *.c))
foo : $(objects)
cc -o foo $(objects)
這
個makefile利用了編譯C程序的隱含規(guī)則,所以不需要對編譯寫出顯式的規(guī)則。(’:=’是’=’的一個變體)
注意:’PATTERN’是大
小寫敏感的。
3.4目錄搜索
對于大的系統(tǒng),通常將源文件和目標文件放在不同的目錄中。目錄搜索功能可以讓make自動在多個目錄中搜尋依
賴文件,當你將文件重新分布是,不需要改變規(guī)則,更改搜索路徑即可。
3.4.1‘VPATH’
make變量’VPATH’列出make應(yīng)
當搜索的目錄列表。很多情況下,當前目錄不包含依賴文件,’VPATH’描述一個對所有文件的搜索列表,包含那些是規(guī)則的目標的文件。
如果一個目
標或者依賴文件在當前目錄沒找到的話,’make’在’VPATH’中列出的目錄中查找同名的文件。如果找到的話,那個文件成為依賴文件;規(guī)則可以象這些
文件在當前目錄中一樣來使用他們。
在’VPATH’變量中,目錄名以冒號或空格隔開;目錄列出的順序決定make查找的順序。(注:在
pSOSystem 2.5移植到Win32的GNU make目錄名必須使用分號隔開,以下均簡稱Win32 GNU make)。舉例說明:
VPATH = src:../headers 則
規(guī)則
foo.o : foo.c
被解釋為
foo.o : src/foo.c
假設(shè)’foo.c’在當前目錄不存在,
在’src’目錄中可以找到。
3.4.2選擇性搜索
與’VPATH’變量相似但更具選擇性的是’vpath’指令(注意是小寫),可以指
定對于符合特定模式文件的查找路徑。這樣可以為不同類型的文件指定不同的搜索路徑。
‘vpath’指令共有三中形式:
;‘vpath PATTERN DIRECTORIES’
為
匹配PATTERN的文件名指定搜索路徑DIRECTORIES,目錄的分隔和’VPATH’的相同
;‘vpath PATTERN’
清
除為匹配PATTERN的文件名指定的搜索路徑
;‘vpath’
清除所有以前用’vpath’指
定的搜索路徑
‘vpath’的模式是包含’%’的字符串:這個字符串必須匹配需要搜索的依賴文件名,’%’字符匹配0個或多個任意字符。例
如:’%.h’匹配任何以’.h’結(jié)尾的文件(如果沒有%,則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使用自動變量
目錄搜索的結(jié)果并不改變規(guī)則中的命令:命令按原樣被執(zhí)行。
因此,必須寫出與目錄搜索功相適應(yīng)的命令。這可以通過使用’$^’這樣的自動變量來完成。’$^’表示規(guī)則中的所有依賴文件,包含它們所在的目錄名(參見
目錄搜索);’$@’表示目標。例如:
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
目錄搜索和隱含規(guī)則
使用’VPATH’和’vpath’指定目錄搜索也會影響隱含規(guī)則。例如:文件’foo.o’沒有顯式規(guī)則,make會考慮隱
式規(guī)則:如果’foo.c’存在則編譯它;如果這個文件不存在,則在相應(yīng)的目錄中查找;如果’foo.c’在任一的目錄中存在,則C編譯的隱式規(guī)則被應(yīng)
用。
隱式規(guī)則的命令使用自動變量通常是必要的,這樣無需其它努力即可以使用目錄搜索得到的文件名。
3.5PHONY目標
Phony
目標并非實際的文件名:只是在顯式請求時執(zhí)行命令的名字。有兩種理由需要使用phony目標:避免和同名文件沖突,改善性能。
如果編寫一個規(guī)則,
并不產(chǎn)生目標文件,則其命令在每次make該目標時都執(zhí)行。例如:
clean:
rm *.o temp
因為’rm’命令并不
產(chǎn)生’clean’文件,則每次執(zhí)行’make clean’的時候,該命令都會執(zhí)行。如果目錄中出現(xiàn)了’clean’文件,則規(guī)則失效了:沒有依賴文
件,文件’clean’始終是最新的,命令永遠不會執(zhí)行;為避免這個問題,可使用’.PHONY’指明該目標。如:
.PHONY : clean
這
樣執(zhí)行’make clean’會無視’clean’文件存在與否。
已知phony目標并非是由其它文件生成的實際文件,make會跳過隱含規(guī)則
搜索。這就是聲明phony目標會改善性能的原因,即使你并不擔心實際文件存在與否。完整的例子如下:
.PHONY : clean
clean :
rm *.o temp
phony
目標不應(yīng)是真正目標文件的依賴。如果這樣,每次make在更新此文件時,命令都會執(zhí)行。只要phony目標不是真正目標的依賴,規(guī)則的命令只有在指定此目
標時才執(zhí)行。
Phony目標可以有依賴關(guān)系。當一個目錄中有多個程序是,將其放在一個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.6FORCE
目標
當規(guī)則沒有依賴關(guān)系也沒有命令,而且其目標不是存在的文件名,make認為此規(guī)則運行時這個目標總是被更新。這意味著如果規(guī)則依賴于此目標,
其命令總是被執(zhí)行。
clean: FORCE
rm $(objects)
FORCE:
例中目
標’FORCE’滿足這種特殊條件,這樣依賴于它的目標’clean’被強制執(zhí)行其命令。名字’FORCE’沒有特殊含義,只不過通常這樣用而已。這種方
式使用’FORCE’和’.PHONY : clean’效果相同。使用’.PHONY’更加明確高效,擔不是所有的’make’都支持;這樣許多
makefile中使用了’FORCE’。
3.7空目標
空目標(empty target)是phony目標的變種:用來執(zhí)行顯式請求的
一個動作。和phony目標不同的是:這個目標文件可以真實存在,擔文件的內(nèi)容無關(guān)緊要,通常是空的。空目標文件的目的是利用其最后修改時間來記錄命令最
近一次執(zhí)行的時間,這是通過使用’touch’命令更新目標文件來達到的。
print: foo.c bar.c
lpr -p $?
touch print
利
用這條規(guī)則,執(zhí)行’make print’時如果自上次’make print’之后任一文件改變了,’lpr’命令會執(zhí)行。自動變量’$?’是為了只打
印出那些變化了的文件。
3.8內(nèi)建的特殊目標
某些名字作為目標存在時有特殊含義。
★.PHONY該目標的依賴被認為是phony
目標,處理這些目標時,命令無條件被執(zhí)行,不管文件名是否存在及其最后修改時間
★.SUFFIXES該目標的依賴被認為是一個后綴列表,在檢查后
綴規(guī)則時使用
★.DEFAULT該目標的規(guī)則被使用在沒有規(guī)則(顯式的或隱含的)的目標上。如果’DEFAULT’命令定義了,則對所有不是規(guī)則
目標的依賴文件都會執(zhí)行該組命令
★.PRECIOUS該目標的依賴文件會受到特別對待:如果make被kill或命令的執(zhí)行被中止,這些目標并不
刪除;而且如果該目標是中間文件,在不需要時不會被刪除。可以將隱含規(guī)則的目標模式(如%.o)做為’.PRECIOUS’的依賴文件,這樣可以保存這些
規(guī)則產(chǎn)生的中間文件。
★.INTERMEDIATE該目標的依賴文件被當作中間文件;如果該目標沒有依賴文件,則makefile中所有的目標文
件均被認為是中間文件。
★.IGNORE在執(zhí)行該目標的依賴規(guī)則的命令時,make會忽略錯誤,此規(guī)則本身的命令沒有意義。如果該規(guī)則沒有依賴關(guān)
系,表示忽略所有命令執(zhí)行的錯誤,這種用法只是為了向后兼容;由于會影響到所有的命令,所以不是特別有用,推薦使用其它更有選擇性忽略錯誤的方法。
★.SILENT
在執(zhí)行該目標的依賴規(guī)則的命令時,make并不打印命令本身。該規(guī)則的命令沒有意義。在’.SILIENT’沒有依賴關(guān)系時,表示執(zhí)行makefile中
的所有命令都不會打印,該規(guī)則只是為了向后兼容提供的。
★.EXPORT_ALL_VARIABLES只是作為一個目標存在,指示make將所有
變量輸出到子進程中。
定義的隱含規(guī)則的后綴作為目標時,也認為它是特殊目標;兩個后綴的連接也是一樣,比如’.c.o’。這些目標是后綴規(guī)則,一
中定義隱式規(guī)則的過時方法(但仍然廣泛使用)。后綴通常以’.’開始,所以特殊目標也以’.’開始。
3.9一個規(guī)則多個目標
一條有多個目
標的規(guī)則和寫多條規(guī)則,每條一個目標作用是等同的。同樣的命令應(yīng)用于所有目標,但其效用會因?qū)嶋H目標以’$@’代替而不同。規(guī)則中所有目標的依賴關(guān)系是
一樣的。
這在兩種情況下有用:
★只有依賴關(guān)系,不需要命令。例如:
kbd.o command.o files.o: command.h
★
所有的目標同樣的命令。命令不需要完全相同,因為在命令中可以使用’$@’:
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
等
同。這里假設(shè)程序’generate’產(chǎn)生兩種輸出:一種使用’-big’選項,一種使用’-little’選項。如果想象使用’$@’變化命令那樣來變
化依賴關(guān)系,不能通過多目標的普通規(guī)則實現(xiàn),但是可以通過模式規(guī)則來實現(xiàn)。
3.10一個目標多條規(guī)則
一個文件可以是多條規(guī)則的目標,所有
規(guī)則的依賴關(guān)系被合并。如果目標比任一個依賴文件舊,命令被執(zhí)行。
一個文件只能有一組命令執(zhí)行。如果多個規(guī)則對于同一個文件都給出了命
令,make使用最后一組并打印錯誤信息(特殊情況:如果文件名以’.’開始,并不打印錯誤信息,這一點是為了和其它make兼容)。沒有任何理由需要將
makefile寫成這樣,這是make給出錯誤信息的理由。
一條只有依賴關(guān)系的附加規(guī)則可以一次給出許多文件的附加依賴文件。例
如’objects’變量表示系統(tǒng)中編譯器的所有輸出.,說明當’config.h’更改時所有文件必須重做的簡單方法如下:
objects = foo.o bar.o
foo.o : defs.h
bar.o : defs.h test.h
$(objects) : config.h
不
用改變實際目標文件生成的規(guī)則,這條規(guī)則可以在需要增刪附加的依賴關(guān)系時插入或提出。另一個訣竅是附加的依賴關(guān)系可以用變量表示,在make執(zhí)行時,可以
給變量賦值:
extradeps=
$(objects) : $(extradeps)
當命令
`make extradeps=foo.h'執(zhí)行時會認為’foo.h’是每個目標文件的依賴文件,但簡單的’make’命令不是這樣。
3.11
靜態(tài)模式規(guī)則
靜態(tài)模式規(guī)則(static pattern rules)可以指定多個目標,并且使用目標名字來建議依賴文件的名字;比普通多目標
規(guī)則更通用因為不需要依賴關(guān)系是相同的:依賴關(guān)系必須類似但不需要相同。
3.11.1語法
TARGETS ...: TARGET-PATTERN: DEP-PATTERNS ...
COMMANDS
...
TARGETS
列表指出規(guī)則應(yīng)用的目標,可以包含通配符,于普通規(guī)則的目標相同。TARGET-PATTERN和DEP-PATTERNS來表明目標的依賴關(guān)系如何計
算:匹配TARGET-PATTERN的目標從名字中抽出一部分,叫做詞干(stem),詞干被替換到DEP-PATTERNS來形成依賴文件名。
每
個模式通常包含一個’%’字符。當TARGET-PATTERN匹配一個目標時,’%’字符可以匹配目標名中的任何部分;這部分即是詞干,模式的其余部分
必須完全匹配。例如’foo.o’匹配’%.o’,’foo’是詞干;目標’foo.c’和’foo.out’并不匹配這個模式。
目標的依賴文件
名通過將DEP-PATTERNS中的’%’替換為詞干形成:如果依賴模式為’%.c’,在替換詞干’foo’可以得到’foo.c’。依賴模式中不包
含’%’也是合法的,此依賴文件對所有的目標均有效。
如果需要在模式規(guī)則中使用’%’字符,必須在其前面加’\’字符,如果’%’前的’\’字符
是有實際意義的,必須在其前面加’\’,其它的’\’不必如此處理。如’the\%weird\\%pattern\\’在有效的’%’前
是’the%weird\’,其后是’pattern\\’。最后的’\\’保持原樣是因為其并不影響’%’字符。
以下例子從相應(yīng)的’.c’文件
編譯’foo.o’和’bar.o’:
objects = foo.o bar.o
$(objects): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
每
個目標必須匹配目標模式,對于不匹配的目標會給出警告。如果列表中只有部分文件匹配模式,可以使用filter函數(shù)移去不匹配的文件名:
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))' 結(jié)果是
`bar.o lose.o’; `$(filter %.elc,$(files))' 的結(jié)果是`foo.elc'。以下例子說明’$*’的使用:
bigoutput littleoutput : %output : text.g
generate text.g -$* >; $@
命
令`generate'執(zhí)行時,’$*’擴展為詞干’big’或’little’。
3.11.2靜態(tài)模式規(guī)則和隱式規(guī)則
靜態(tài)模式規(guī)則和隱
式規(guī)則在作為模式規(guī)則是具有很多共同點,都有目標模式和構(gòu)造依賴文件名的模式,不同之處在于make決定何時應(yīng)用規(guī)則的方法。
隱式規(guī)則可應(yīng)用于匹
配其模式的任何目標,但只限于沒有指定命令的目標,如果有多條可應(yīng)用的隱式規(guī)則,只有一條被使用,取決于規(guī)則的順序。
反之,靜態(tài)模式規(guī)則適用于規(guī)
則中明確目標列表,不適用于其它目標且總是適用于指定的每個目標。如果有兩條沖突的規(guī)則,且都有命令,這是一個錯誤。
靜態(tài)模式規(guī)則比隱式規(guī)則優(yōu)越
之處如下:
★可為一些不能按句法分類,但可以顯式列出的文件重載隱式規(guī)則
★不能判定目錄中的精確內(nèi)容,一些無關(guān)的文件可能導(dǎo)致make適
用錯誤的隱式規(guī)則;最終結(jié)果可能依賴于隱式規(guī)則的次序。適用靜態(tài)模式規(guī)則時,這種不確定性是不存在的:規(guī)則適用于明確指定的目標。
3.12雙冒號
規(guī)則
雙冒號規(guī)則(Double-colon rules)的目標后是’::’而不是’:’,當一個目標出現(xiàn)在多條規(guī)則中時,其處理和普通規(guī)則的處
理不同。
當一個目標出現(xiàn)在多條規(guī)則中時,所有規(guī)則必須是相同類型的:都是普通的或者都是雙冒號的。如果是雙冒號,規(guī)則之間相互獨立;如果目標需要
更新,則規(guī)則的命令被執(zhí)行;結(jié)果可能是沒有執(zhí)行,或者執(zhí)行了其中一些,或者所有的規(guī)則都執(zhí)行了。
同一目標的雙冒號規(guī)則事實是完全孤立的,每條規(guī)則
被被單獨處理,就象不同目標的規(guī)則一樣;規(guī)則按照在makefile中出現(xiàn)的次序被處理,此類規(guī)則真正有意義的是那些于命令執(zhí)行次序無關(guān)的。
這種
規(guī)則有時比較晦澀不是特別有用;它提供了一種機制:通過不同依賴文件的更新來對目標進行不同的處理,這種情形很罕見。每個這種規(guī)則應(yīng)當提供命令,如果沒
有,適用的隱式規(guī)則將使用。
3.13自動生成依賴關(guān)系
在makefile中,許多規(guī)則都是一些目標文件依賴于一些頭文件。例
如:’main.c’ 通過’#include’使用’defs.h’,這樣規(guī)則:
main.o: defs.h
告訴make
在’defs.h’變化時更新’main.o’。在程序比較大時,需要寫許多這樣的規(guī)則;而且當每次增刪’#include’時,必須小心的更新
makefile。許多現(xiàn)代的編譯器可以幫你寫這些規(guī)則,通常這是通過編譯器的’-M’選項,例如命令:
cc –M main.c
輸出以
下內(nèi)容:
main.o : main.c defs.h
這樣就不必寫這些規(guī)則,有編譯器代勞了。
注意這樣的依賴關(guān)系中提
及’main.o’,不會被隱式規(guī)則認為是中間文件,這意味這make在使用過它之后不會將其刪除。使用老的’make’程序時,習慣做法是使
用’make depend’命令利用編譯器的功能產(chǎn)生依賴關(guān)系,該命令會產(chǎn)生一個’depend’文件包含所有自動產(chǎn)生的依賴關(guān)系,然后在
makefile中使用’include’將其讀入。
使用GNU的make時,重新生成makefile的功能使得這種做法變得過時:從不需要顯
式請求更新依賴關(guān)系,因為它總是重新生成任何過時的makefile。
自動依賴關(guān)系生成推薦的做法是對每個源文件做一個makefile。對每個
源文件’NAME.c’,有一個makefile ’NAME.d’,其中列出了目標文件’NAME.o’依賴的所有文件,這樣在源文件更新時,需要掃描
來產(chǎn)生新的依賴關(guān)系。例子是一個從’NAME.c’產(chǎn)生依賴關(guān)系文件’NAME.d’的模式規(guī)則:
%.d: %.c
$(SHELL) -ec '$(CC) -M $(CPPFLAGS) $< \
| sed '\''s/\($*\)\.o[ :]*/\1 $@/g'\'' >; $@'
-e
選項是當$(CC)命令失敗時(exit狀態(tài)非0),shell立刻退出。通常shell的返回值是管道中最后一條命令(sed)的返回值,這樣make
不會注意到編譯器出錯。
使用GNU的C編譯器時(gcc),可以用’-MM’選項來代替’-M’選項,這樣省略系統(tǒng)頭文件的依賴關(guān)系。’sed’
命令的目的是將
main.o : main.c defs.h
轉(zhuǎn)換為
main.o main.d : main.c defs.h
這
樣使得每個’.d’文件依賴于’.o’文件相應(yīng)源文件和頭文件,make則可以在原文間或頭文件變化時更新依賴關(guān)系文件。
如果定義了生成’.d’
文件的規(guī)則,可以使用’include’指令來讀入所有的文件:
sources = foo.c bar.c
include $(sources:.c=.d)
例
中使用替換變量來將源文件列表’ foo.c bar.c’轉(zhuǎn)換為依賴關(guān)系文件的列表。因為’.d’文件和其它文件一樣,不需要更多工作,make會在需
要時重新生成它們。
4編寫命令
規(guī)則的命令是由一一執(zhí)行的shell命令組成。除了以分號隔開寫在依賴關(guān)系后的命令,每個命令行必須以
tab字符開始空行和注釋行可以出現(xiàn)在命令行中,處理時被忽略(注意:以tab字符開始的空行不是’空’行,是一條空命令)。
可以在命令中使用任
何程序,但這些程序是由$(SHELL)來執(zhí)行的。
4.1回顯
通常make打印出要執(zhí)行的命令,稱之為回顯,這和親自敲命令的現(xiàn)象是一樣
的。當行之前有’@’字符時,命令不再回顯,字符’@’在傳遞給shell前丟棄。典型的用法是只對打印命令有效,比如’echo’命令:
@echo About to make distribution files
當
make使用’-n’或’—just-print’選項時,顯示要發(fā)生的一切,但不執(zhí)行命令。只有在這種情況下,即使命令以’@’開始,命令行仍然顯示出
來。這個選項對查看make實際要執(zhí)行的動作很有用。
‘-s’或’—silent’選項阻止make所有回顯,就象所有命令以’@’開始一樣;一
條沒有依賴關(guān)系的’.SILENT’規(guī)則有相同的作用,但是’@’更加靈活。
4.2執(zhí)行
在需要執(zhí)行命令更新目標時,make為每一行創(chuàng)建
一個子shell來執(zhí)行。這意味著諸如為進程設(shè)置局部變量的shell命令’cd’(改變進程的當前目錄)不會影響以后的命令。如果需要’cd’影響下一
個命令,將它們放在一行上用分號隔開,這樣make認為是一條命令傳遞給shell程序(注意:這需要shell支持):
foo : bar/lose
cd bar; gobble lose >; ../foo
另
一個形式使用續(xù)行符:
foo : bar/lose
cd bar; \
gobble lose >; ../foo
shell
程序的名字是通過’SHELL’變量來取得的。
(*UNIX)不象大多數(shù)變量,’SHELL’變量不是通過環(huán)境來設(shè)置的(即需要在
makefile中設(shè)置),因為’SHELL’環(huán)境是個人選擇的,如果不同人的選擇會影響makefile的功能的話,這樣很糟糕。
4.3并行執(zhí)
行
GNU make可以一次執(zhí)行幾條命令。通常make一次執(zhí)行一條命令,等待其返回,再執(zhí)行下一條。使用’-j’或’—jobs’可以同時執(zhí)行
多條命令。如果’-j’后梗一個正數(shù),表示一次可以執(zhí)行的命令條數(shù);如果’-j’之后沒有參數(shù),則不限制可執(zhí)行的命令數(shù)。缺省的數(shù)量是一。
一個討
厭的問題是如果同時執(zhí)行多條命令,它們的輸出會混在一起;另一個問題是兩個進程不能從同一個設(shè)備獲得輸入。
4.4錯誤
每條shell命令
返回時,make會檢查其返回狀態(tài)。如果命令執(zhí)行成功,則下一條命令被執(zhí)行,最后一條命令執(zhí)行完后,規(guī)則執(zhí)行結(jié)束。
如果有錯誤(返回非0狀
態(tài)),make放棄當前規(guī)則,也可能是所有規(guī)則。
有時候命令執(zhí)行錯誤并不是問題,比如使用’mkdir’命令確保目錄存在:如果目錄一存在,
則’mkdir’會報告錯誤,但仍希望make繼續(xù)。
要忽略命令的錯誤,在命令之前使用’-‘字符,’-‘字符在傳遞給shell之前被丟棄:
clean:
-rm -f *.o
如
果使用’-i’或’—ignore-errors’選項,make會忽略所有命令產(chǎn)生的錯誤;一條沒有依賴關(guān)系的’.IGNORE’規(guī)則有相同的作用,
但’-‘更靈活。
在忽略錯誤時,make將錯誤也認為是成功,只是通知你命令的退出狀態(tài)和和錯誤被忽略。如果make并未告知忽略錯誤,在錯誤發(fā)
生時,表明該目標不能成功更新,直接或間接依賴于此的目標當然也不能成功;這些目標的命令不會被執(zhí)行,因為其先決條件不滿足。
通常make會立即
以非0狀態(tài)退出。然而,如果給定’-k’或’—keep-going’選項,make在退出前會處理其它的依賴關(guān)系,進行必要的更新。例如,在編譯一個目
標文件遇到錯誤,’make -k’會繼續(xù)編譯其它的目標文件。
通常認為你的目的是更新指定的目標,當make知道這是不可能時,會立即報告失
敗;’-k’選項指示真正目的是測試更新程序的更多可能性:在編譯之前找出更多不相關(guān)的問題。
如果命令失敗了,假設(shè)它更新的目標文件,這個文件是
不完整的不能使用-至少不是完全更新的。但文件的最后修改時間表明停已經(jīng)是最新的,下一次make運行時,不會再更新這個文件。這種情況和命令被kill
相同;則通常情況下在命令失敗時將目標刪除是正確的;當’.DELETE_ON_ERROR’是目標時make幫你做這件事。雖然你總是希望make這么
做,但這不是過去的習慣;所以必須顯式要求make這樣做(其它的make自動這樣做)。
4.5中斷make
如果make執(zhí)行命令時遇到
錯誤,可能會刪除命令更新的目標文件: make檢查文件的修改時間是否變化。刪除目標的目的是確保make下次執(zhí)行時重新生成它。為什么這樣做?假設(shè)在
編譯器運行時按了’Ctrl-c’,此時編譯器寫生成目標文件’foo.o’。’Ctrl-c’ kill了編譯器,留下一個不完整的文件,但它的修改時
間比源文件’foo.c’新;此時make也受到’Ctrl-c’信號刪除這個不完整的文件,如果make不這樣做,下次make運行時認
為’foo.o’不需要更新,會在鏈接時出現(xiàn)奇怪的錯誤。
可以使用’.PRECIOUS’規(guī)則來防止目標文件被刪除。在make更新目標時,會檢
測其是否為’.PRECIOUS’的依賴,決定在命令出錯或中斷時是否刪除該目標。如果你希望目標的更新是原子操作,或是用來記錄修改時間,或必須一直存
在防止其它類型的錯誤,這些理由使得你必須這樣做。
4.6遞歸使用
遞歸使用make就是在makefile中使用make命令。這種技術(shù)
在你將一個大系統(tǒng)分解為幾個子系統(tǒng),為每個自系統(tǒng)提供一個makefile時有用處。比如有一個子目錄’subdir’中有自己的makefile,希望
make在自目錄中運行,可以這樣做:
subsystem:
cd subdir; $(MAKE)
或
者
subsystem:
$(MAKE) -C subdir
可以照抄這個;例子來遞歸使用make
4.6.1‘MAKE’
變量
遞歸的make必須使用’MAKE’變量,不是顯式的make命令:
subsystem:
cd subdir; $(MAKE)
該
變量的值是被調(diào)用的make的名字。在命令中使用’MAKE’有特殊的功能:它改變了`-t' (`--touch'), `-n' (`--just-
print')和`-q' (`--question')選項的含義。使用上例來考慮’make –t’命令(’-t’選項將目標標記為最新但不運行命
令),更加’-t’選項的功能,該命令將創(chuàng)建一個’subsystem’文件,實際希望的操作是運
行’cd subdir; make –t’;但這會執(zhí)行命令,與’-t’的原意不符。
這個特殊功能做了期望的工作。當命令行包
含變量’MAKE’時,選項’-t’,’-n’和’-q’并不適用。不管這些導(dǎo)致不會執(zhí)行命令的標志,包含’MAKE’變量的命令始終會執(zhí)行。正常
的’MAKEFLAGS’機制將這些標志傳遞到子make,這樣打印命令的請求被傳播到子系統(tǒng)中。
4.6.2傳遞變量到子make
上級
(top-level)make中的變量可以顯式通過環(huán)境傳遞到子make中。在子make中,這些變量被缺省定義,但不會重載子makefile中的定
義除非使用’-e’選項。
為向下傳遞,或輸出變量,make在運行命令時將其加入到環(huán)境變量中;子make,可以使用環(huán)境變量來初始化變量表。除
非顯式要求,make只輸出初始環(huán)境中或命令行設(shè)置的變量而且變量名只由字母,數(shù)字和下劃線組成。一些shell不能處理有其它字符的環(huán)境變量。
特
殊變量’SHELL’,’MAKEFLAGS’總是輸出,如果’MAKEFILE’變量有值,也會輸出。Make自動通過’MAKEFLAGS’來輸出命
令行定義的變量。
如果想要輸出特定變量,使用’export’指令:
export VARIABLE ...
如果要阻止輸出一個
變量,使用’unexport’指令:
unexport VARIABLE ...
為方便起見,可以在定義變量時輸出它:
export VARIABLE = value
和
VARIABLE = value
export VARIABLE
作
用相同。
如果要輸出所有的變量,使用’export’指令本身就可以了。
變量’MAKELEVEL’在一級一級傳遞時會改變,這個變量的
值是表示嵌套層數(shù)的字符串,頂級’make’是,變量的值為’0’;子make的值為’1’;子子make的值為’2’,依此類推。
‘MAKELEVEL’
的用途是在條件指令中測試它,這樣寫出在遞歸運行時和直接運行時表現(xiàn)不同的makefile。