Posted on 2009-09-03 12:57
ggh 閱讀(397)
評(píng)論(0) 編輯 收藏 引用
makefile文件是win32匯編程序中不可少的一部分,類(lèi)似于dos匯編下的bat文件
它一般需要包含以下內(nèi)容
1.注釋
2.宏定義
3.顯示規(guī)則
4.隱含規(guī)則
為了方便使用,一般都把描述文件的文件名取為默認(rèn)文件名:makefile。這個(gè)例子的makefile文件如下(注意前面括號(hào)里的是行號(hào),不是文件的真正內(nèi)容):
(001) # nmake工具的描述文件例子
(002) EXE = Test.exe #指定輸出文件
(003) OBJS = x.obj \
(004) y.obj #需要的目標(biāo)文件
(005) RES = x.res #需要的資源文件
(006)
(007) LINK_FLAG = /subsystem:windows #鏈接選項(xiàng)
(008) ML_FLAG = /c /coff #編譯選項(xiàng)
(009)
(010) #定義依賴關(guān)系和執(zhí)行命令
(011) $(EXE): $(OBJS) $(RES)
(012) Link $(LINK_FLAG) /out:$(EXE) $(OBJS) $(RES)
(013) $(OBJS): Common.inc
(014) y.obj: y.inc
(015)
(016) #定義匯編編譯和資源編譯的默認(rèn)規(guī)則
(017) .asm.obj:
(018) ml $(ML_FLAG) $<
(019) .rc.res:
(020) rc $<
(021)
(022) #清除臨時(shí)文件
(023) clean:
(024) del *.obj
(025) del *.res
1. 注釋和換行
makefile中的注釋是以#號(hào)開(kāi)頭一直到行尾的字符,當(dāng)nmake工具處理到這些字符的時(shí)候,它會(huì)完全忽略#號(hào)及全部注釋字符。
當(dāng)一行的內(nèi)容過(guò)長(zhǎng)的時(shí)候,可以用換行符來(lái)繼續(xù),makefile的換行符是\,如例子中的第三行和第四行可以合并為:
OBJS = x.obj y.obj #需要的目標(biāo)文件
在使用換行符的時(shí)候要注意在“\”后面不能再加上其他字符,包括注釋和空格,否則nmake檢測(cè)到“\”不在一行的最后,就不會(huì)把它當(dāng)成換行符解釋,就會(huì)出現(xiàn)錯(cuò)誤。
2. 宏定義
makefile中允許使用簡(jiǎn)單的宏定義指代源文件及其相關(guān)編譯信息,可以把宏稱為變量,在整個(gè)描述文件中,只要符合下面語(yǔ)法的行就是宏定義:
變量名=變量?jī)?nèi)容
如上面例子文件中的2到8就是宏定義,在引用宏時(shí)只需在變量前加$符號(hào),但是要注意的是,如果變量名的長(zhǎng)度超過(guò)一個(gè)字符,在引用時(shí)就必須加圓括號(hào)(),下面都是有效的宏引用:
$(LINK_FLAG)
$(EXE)
$A
$(A)
其中最后兩個(gè)引用是完全一致的。
宏定義的使用可以使makefile的使用更靈活:首先可以使文件便于修改,比如把第8行和第18行中ml的選項(xiàng)部分寫(xiě)成宏定義,以后要改變編譯選項(xiàng)的時(shí)候,只要直接在makefile文件頭部改變宏定義就可以了,不必重新閱讀整個(gè)makefile文件;其次,當(dāng)不止一個(gè)地方用到同一個(gè)文件的時(shí)候,把文件名定義為宏定義可以減少錯(cuò)誤,增加可讀性,同時(shí)也可以便于修改;最大的好處是可以直接在命令行中用新的宏定義覆蓋,比如在命令行中鍵入:
nmake ML_FLAG="/c /coff /Fl"
那么這時(shí)就會(huì)以新的/c /coff /Fl定義代替makefile中定義的/c /coff,在這種使用中要注意兩個(gè)問(wèn)題,一是宏名稱要區(qū)分大小寫(xiě),ML_FLAG和ml_flag是不一樣的;二是定義值中有空格的時(shí)候要用雙引號(hào)引起來(lái),沒(méi)有空格時(shí)可以不用雙引號(hào),如ML_FLAG=/c,這使臨時(shí)使用不同的參數(shù)編譯文件時(shí)可以不必修改makefile。
3. 顯式規(guī)則
makefile中包含有一些規(guī)則,這些規(guī)則定義了文件之間的依賴關(guān)系和產(chǎn)生命令,一個(gè)規(guī)則的格式是這樣的:
目標(biāo)文件:依賴文件;命令 (方法1)
或
目標(biāo)文件:依賴文件 (方法2)
命令
在規(guī)則定義和命令行中,不能包含注釋,例子中的第11和12行把宏定義展開(kāi)后就是:
test.exe:x.obj y.obj x.res
Link /subsystem:windows /out:test.exe x.obj y.obj x.res
這里的目標(biāo)文件就是test.exe,它依賴于3個(gè)文件x.obj,y.obj和x.res,如果有必要,產(chǎn)生目標(biāo)文件的命令就是下面的Link命令,整個(gè)規(guī)則可以用兩種方法,用第二種方法的時(shí)候,命令可以從第二行開(kāi)始,第一行的“;”省略,但是這時(shí)命令前面必須有一個(gè)Tab字符,否則nmake無(wú)法區(qū)分這究竟是命令還是別的定義。目標(biāo)文件可以有多個(gè),依賴文件也可以有多個(gè),同時(shí)命令也可以由多個(gè)命令行組成,當(dāng)然這時(shí)候就必須用第二種方法定義了。
我們也可以用test.exe生成的規(guī)則定義其他文件,如x.obj或x.res的生成方法,但nmake如何知道哪個(gè)是最終要make的文件呢?實(shí)際上nmake默認(rèn)將整個(gè)描述文件的第一條規(guī)則中的目標(biāo)文件認(rèn)為是最終文件,如果我們把11,12行放到第13行后面,那么x.obj和y.obj的建立規(guī)則就成了第一條規(guī)則,nmake建立了x.obj和x.obj之后就不理會(huì)test.exe的建立了,所以我們必須把最終需要生成的文件放在第一條規(guī)則定義。當(dāng)然,在nmake的命令行參數(shù)中可以指定要make的目標(biāo),如我們要生成x.res文件,那么不必修改makefile將x.res的描述規(guī)則移動(dòng)到最前面,而是直接在命令行鍵入以下命令即可:
nmake x.res
參數(shù)中也可以同時(shí)帶好幾個(gè)目標(biāo)文件名,nmake會(huì)一一處理,如果指定的目標(biāo)文件沒(méi)有對(duì)應(yīng)的規(guī)則,nmake會(huì)返回一個(gè)出錯(cuò)信息:
fatal error U1073: don't know how to make 'xxx文件'
當(dāng)用戶要求nmake去建造一個(gè)目標(biāo)時(shí),make會(huì)去找到這個(gè)目標(biāo)的依賴規(guī)則,這時(shí)第二行中的命令并不會(huì)立刻就執(zhí)行,而是首先要做一些事情:nmake先去檢查依賴文件是否是另一條規(guī)則的目標(biāo)文件,如果是則先處理這一條規(guī)則,否則不是,nmake再檢查各個(gè)依賴文件的時(shí)間,看這些文件有沒(méi)有比目標(biāo)文件更新的,如果沒(méi)有,nmake會(huì)決定不再重新建造目標(biāo)文件,并給出提示:'xxx文件' is up-to-date,如果依賴文件有比目標(biāo)文件更新的,才執(zhí)行命令。
所以一個(gè)順序下來(lái),所有的目標(biāo)文件以及它們的依賴文件,以及依賴文件的依賴文件都會(huì)被檢查并更新,總而言之,一個(gè)目標(biāo)文件的建立包含了順序正確的指令鏈接,這個(gè)鏈接結(jié)構(gòu)是樹(shù)狀的,目標(biāo)文件是根,一級(jí)級(jí)擴(kuò)展到多個(gè)文件,我們要求的是nmake去建立鏈接中處于根部的那個(gè)文件,nmake會(huì)根據(jù)鏈接結(jié)構(gòu)從目標(biāo)開(kāi)始向初始狀態(tài)前進(jìn),最后慢慢回來(lái),在這個(gè)過(guò)程中執(zhí)行建立每個(gè)文件所必須的命令,一直到最終目標(biāo)建立完成。
目標(biāo)也可以沒(méi)有依賴文件,而且目標(biāo)也可以不是一個(gè)真正存在的文件,如例子第23行到第25行中的clean是一個(gè)目標(biāo),但我們并不是要生成一個(gè)clean文件,而是希望在文件調(diào)試完畢后用nmake來(lái)清除臨時(shí)文件,當(dāng)我們鍵入nmake clean的時(shí)候,工作目錄下并沒(méi)有clean這個(gè)文件,那么nmake就會(huì)去執(zhí)行clean定義中的命令,因?yàn)閚make把每一個(gè)不存在的目標(biāo)當(dāng)做是一個(gè)過(guò)時(shí)的目標(biāo),如此一來(lái),就會(huì)刪除中間過(guò)程中的文件*.obj和*.res。
指出了目標(biāo)文件全名的規(guī)則稱為顯式規(guī)則,但有些類(lèi)別的文件的編譯方法可以是雷同 的,如從asm文件產(chǎn)生obj文件的命令總是用ml,從rc文件產(chǎn)生res文件的命令總是用rc,對(duì)于每個(gè)文件都寫(xiě)一條規(guī)則有些多余,這時(shí)候就要用到隱含規(guī)則。
4. 隱含規(guī)則
隱含規(guī)則可以為某一類(lèi)的文件指出建立的命令,它具體定義了如何將帶一個(gè)特定擴(kuò)展名的文件轉(zhuǎn)換成具有另一種擴(kuò)展名的文件,定義的格式是:
.源擴(kuò)展名.目標(biāo)擴(kuò)展名:;命令 (方法1)
或
.源擴(kuò)展名.目標(biāo)擴(kuò)展名: (方法2)
命令
隱含規(guī)則的語(yǔ)法和顯式規(guī)則相似,也是用“:”隔開(kāi),在“;”下面書(shū)寫(xiě)命令,也可以不用“;”而將命令寫(xiě)在第二行,同理,這時(shí)命令之前要加一個(gè)Tab字符。
隱含規(guī)則不能有依賴文件,所以“:”下面沒(méi)有內(nèi)容,例子中的第17、18行定義了從asm文件建立obj文件的隱含規(guī)則,第19和20行定義了從rc文件建立res文件的隱含規(guī)則,隱含規(guī)則中無(wú)法指定確定的輸入文件名,因?yàn)檩斎胛募欠褐傅挠邢嗤瑪U(kuò)展名的一整類(lèi)文 件,這時(shí)候就要用到幾個(gè)特殊的內(nèi)定宏來(lái)指定文件名,這些宏是$@,$*,$?和$<,它們的含義如下:
● $@ —— 全路徑的目標(biāo)文件。
● $* —— 除去擴(kuò)展名的全路徑的目標(biāo)文件。
● $? —— 所有源文件名。
● $< —— 源文件名(只能用在隱含規(guī)則中)。
所以第19、20行中的rc $< 用于x.rc的時(shí)候就是rc x.rc。
讀者可以注意到一些顯式規(guī)則沒(méi)有命令行,如第13行的“$(OBJS): Common.inc”指出了所有的obj文件全部依賴于Common.inc文件,第14行的“y.obj: y.inc”則指出了y.obj同時(shí)也依賴于y.inc和第13行的規(guī)則合并,y.obj依賴于Common.inc也依賴于y.inc,但是這兩條規(guī)則都沒(méi)有指出產(chǎn)生這些obj文件的命令,所以nmake處理的時(shí)候會(huì)到隱含規(guī)則中去找命令行,最后會(huì)用第18行的“ml $(ML_FLAG) $<”命令去產(chǎn)生這些obj文件。
本文來(lái)自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/hust_chen/archive/2008/04/25/2329368.aspx