程序員如何寫Makefile培訓(xùn)教材_第1頁
程序員如何寫Makefile培訓(xùn)教材_第2頁
程序員如何寫Makefile培訓(xùn)教材_第3頁
程序員如何寫Makefile培訓(xùn)教材_第4頁
程序員如何寫Makefile培訓(xùn)教材_第5頁
已閱讀5頁,還剩56頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

程序員如何寫Makefile培訓(xùn)教材什么是makefile?或許很多WinodwsWindowsIDEprofessional的程序員,makefile還是要懂。HTML的編輯器,但如果你想成為一個(gè)專業(yè)人士,你還是要了解HTMLUnixmakefilemakefile,從一個(gè)側(cè)面說明了一個(gè)人是否具備完成大型工程的能力。因?yàn)?,makefilemakefile譯,哪些文件需要后編譯,哪些文件需要重新編譯,甚至于進(jìn)行更復(fù)雜的功能操作,因?yàn)閙akefileShell腳本一樣,其中也可以執(zhí)行操作系統(tǒng)的命令。akefileakemakemakefileIDEC++nmake,LinuxGNUmake??梢?,makefile都成為了一種在工程方面的編譯方法。Makefile介紹makeMakefilemake命令需要怎么樣的去編譯和鏈接程序。Makefile的書寫規(guī)則。以便給大家一個(gè)感興認(rèn)識(shí)。這個(gè)示例GNUmake8個(gè)C3個(gè)頭文件,Makefilemake命令如何編譯和鏈接這幾個(gè)文件。我們的規(guī)則是:C文件都要編譯并被鏈接。CCC文件Makefilemake需要的文件和鏈接目標(biāo)程序。一、Makefile的規(guī)則在講述這個(gè)Makefile之前,還是讓我們先來粗略地看一看Makefile的規(guī)則。target...:prerequisites...command......targetObjectFile,也可以是執(zhí)行文件。還可以是一個(gè)標(biāo)簽(Labelprerequisites就是,要生成那個(gè)target所需要的文件或是目標(biāo)。command也就是make需要執(zhí)行的命令。(任意的Shell命令)這是一個(gè)文件的依賴關(guān)系,也就是說,target這一個(gè)或多個(gè)的目標(biāo)文件依賴于prerequisitescommandprerequisites中如果有一個(gè)以target文件要新的話,commandMakefile的Makefile中最核心的內(nèi)容。說到底,Makefile的東西就是這樣一點(diǎn),好像我的這篇文檔也該結(jié)束了。呵呵。還不盡然,這是Makefile的主線和核心,但要寫好一個(gè)Makefile還不夠,我會(huì)以后面一點(diǎn)一點(diǎn)地結(jié)合我的工作經(jīng)驗(yàn)給你慢慢到來。內(nèi)容還多著呢。:)二、一個(gè)示例38CMakefile應(yīng)該是下面的這個(gè)樣子的。edit:main.okbd.ocommand.odisplay.o\insert.osearch.ofiles.outils.occ-oeditmain.okbd.ocommand.odisplay.o\insert.osearch.ofiles.outils.omain.o:main.cdefs.hcc-cmain.ckbd.o:kbd.cdefs.hcommand.hcc-ckbd.ccommand.o:command.cdefs.hcommand.hcc-ccommand.cdisplay.o:display.cdefs.hbuffer.hcc-cdisplay.cinsert.o:insert.cdefs.hbuffer.hcc-cinsert.csearch.o:search.cdefs.hbuffer.hcc-csearch.cfiles.o:files.cdefs.hcommand.hcc-cfiles.cutils.o:utils.cdefs.hcc-cutils.cclean:rmeditmain.okbd.ocommand.odisplay.o\insert.osearch.ofiles.outils.o反斜杠(\)是換行符的意思。這樣比較便于Makefile的易讀。我們可以把這個(gè)內(nèi)容保存在文件為“Makefile”或“makefile”的文件中,然后在該目錄下直接輸入命令“make”就可edit一下“makeclean”就可以了。akefile(taeedt(*o.c文件和.h文件。每一個(gè).o文件都有一組依賴文件,而這些.o文件又是執(zhí)行文件edit的依賴文件。依賴關(guān)系的實(shí)質(zhì)上就是說明了目標(biāo)文件是由哪些文件生成的,換言之,目標(biāo)文件是哪些文件更新的。make會(huì)比較targets文件和prerequisitesprerequisites文件的日期要比targetstarget不存在的話,那么,make就會(huì)執(zhí)行后續(xù)定義的命令。這里要說明一點(diǎn)的是,cleanClablemakemakemakefile的命令,比如程序的打包,程序的備份,等等。三、make是如何工作的在默認(rèn)的方式下,也就是我們只輸入make命令。那么,1、make會(huì)在當(dāng)前目錄下找名字叫“Makefile”或“makefile”的文件。2、如果找到,它會(huì)找文件中的第一個(gè)目標(biāo)文件(taget,在上面的例子中,他會(huì)找到“edit”這個(gè)文件,并把這個(gè)文件作為最終的目標(biāo)文件。3、如果edit文件不存在,或是edit所依賴的后面的.o文件的文件修改時(shí)間要比edit這個(gè)文件新,那么,他就會(huì)執(zhí)行后面所定義的命令來生成edit這個(gè)文件。4、如果edit所依賴的.o文件也存在,那么make會(huì)在當(dāng)前文件中找目標(biāo)為.o文件的依賴性,如果找到則再根據(jù)那一個(gè)規(guī)則生成.o文件。(這有點(diǎn)像一個(gè)堆棧的過程)5CHmake.o.o文件生命make的終極任務(wù),也就是執(zhí)行文件edit了。make的依賴性,make會(huì)一層又一層地去找文件的依賴關(guān)系,直到最終編譯出第一個(gè)目標(biāo)文件。在找尋的過程中,如果出現(xiàn)錯(cuò)誤,比如最后被依賴的文件找不到,那么make根本不make那么對(duì)不起,我就不工作啦。cleanmakeclenfile.o(也就是在這個(gè)依性關(guān)系后面所定義的命令fileofileodtedit也會(huì)被重新鏈接了(edit目標(biāo)文件后定義的命令。coand.hkdbooand.o和filesoedit會(huì)被重鏈接。四、makefile中使用變量在上面的例子中,先讓我們看看edit的規(guī)則:edit:main.okbd.ocommand.odisplay.o\insert.osearch.ofiles.outils.occ-oeditmain.okbd.ocommand.odisplay.o\insert.osearch.ofiles.outils.o我們可以看到[.o]文件的字符串被重復(fù)了兩次,如果我們的工程需要加入一個(gè)新的[.o]文件,那么我們需要在兩個(gè)地方加(clean中。當(dāng)然,我們的makefilemakefilemakefilemakefilemakefileC語言中的宏可能會(huì)更好。objects,OBJECTS,objs,OBJS,obj,objmakefile一開始就這樣定義:objects=main.okbd.ocommand.odisplay.o\insert.osearch.ofiles.outils.omakefile中以“$(objects)”的方式來使用這個(gè)變量了,makefile就變成下面這個(gè)樣子:objects=main.okbd.ocommand.odisplay.o\insert.osearch.ofiles.outils.oedit:$(objects)cc-oedit$(objects)main.o:main.cdefs.hcc-cmain.ckbd.o:kbd.cdefs.hcommand.hcc-ckbd.ccommand.o:command.cdefs.hcommand.hcc-ccommand.cdisplay.o:display.cdefs.hbuffer.hcc-cdisplay.cinsert.o:insert.cdefs.hbuffer.hcc-cinsert.csearch.o:search.cdefs.hbuffer.hcc-csearch.cfiles.o:files.cdefs.hcommand.hcc-cfiles.cutils.o:utils.cdefs.hcc-cutils.cclean:rmedit$(objects).oobjects關(guān)于變量更多的話題,我會(huì)在后續(xù)給你一一道來。五、讓make自動(dòng)推導(dǎo)GNU的make很強(qiáng)大,它可以自動(dòng)推導(dǎo)文件以及文件依賴關(guān)系后面的命令,于是我們就沒必要去在每一個(gè)[.o]文件后都寫上類似的命令,因?yàn)?,我們的make會(huì)自動(dòng)識(shí)別,并自己推導(dǎo)命令。make看到一個(gè)[.o]文件,它就會(huì)自動(dòng)的把[.c]make找到一whatever.owhatever.cwhatever.occ-cwhatever.c也會(huì)makefilemakefile又出爐了。objects=main.okbd.ocommand.odisplay.o\insert.osearch.ofiles.outils.oedit:$(objects)cc-oedit$(objects)main.o:defs.hkbd.o:defs.hcommand.hcommand.o:defs.hcommand.hdisplay.o:defs.hinsert.o:defs.hsearch.o:defs.hfiles.o:defs.hbuffer.hcommand.hutils.o:defs.h.PHONY:cleanclean:rmedit$(objects)akeNYclen六、另類風(fēng)格的makefilemake可以自動(dòng)推導(dǎo)命令,那么我看到那堆[.o]和[.h]的依賴就有點(diǎn)不爽,那么多的重復(fù)的[.h]makemakefile吧。objects=main.okbd.ocommand.odisplay.o\insert.osearch.ofiles.outils.oedit:$(objects)cc-oedit$(objects)$(objects):defs.hkbd.ocommand.ofiles.o:command.hdisplay.oinsert.osearch.ofiles.o:buffer.h.PHONY:cleanclean:rmedit$(objects)makefile二是如果文件一多,要加入幾個(gè)新的.o文件,那就理不清楚了。七、清空目標(biāo)文件的規(guī)則Makefile(.o和執(zhí)行文件clean:rmedit$(objects)更為穩(wěn)健的做法是:.PHONY:cleanclean:-rmedit$(objects)前面說過,.PHONYcleanrm命令前面加了一個(gè)小減號(hào)的意思就是,也許某些文件出現(xiàn)問題,但不要管,繼續(xù)做后面的事。當(dāng)然,cleanmakemakefilemakefilemakefile的相關(guān)細(xì)節(jié),準(zhǔn)備好了嗎?準(zhǔn)備好了就來。Makefile總述一、Makefile里有什么?Makefile里主要包含了五個(gè)東西:顯式規(guī)則、隱晦規(guī)則、變量定義、文件指示和注釋。1Makefile的書寫者明顯指出,要生成的文件,文件的依賴文件,生成的命令。2、隱晦規(guī)則。由于我們的make有自動(dòng)推導(dǎo)的功能,所以隱晦的規(guī)則可以讓我們比較粗糙地簡略地書寫Makefile,這是由make所支持的。3MakefileCMakefile被執(zhí)行時(shí),其中的變量都會(huì)被擴(kuò)展到相應(yīng)的引用位置上。4MakefileMakefileCincludeMakefileC語言中的預(yù)編譯#if部分中講述。5、注釋。MakefileUNIXShell腳本一樣,其注釋是用“#”字符,這C/C++中的“//Makefile中使用“#”字符,可以用反斜框\Makefile中的命令,必須要以鍵開始。二、Makefile的文件名akeUkeeakeie個(gè)文件名,因?yàn)?,這個(gè)文件名第一個(gè)字符為大寫,這樣有一種顯目的感覺。最好不要用“UkeeU的ake識(shí)別的。有另外一些ake只對(duì)全小寫的makeMakefile”這兩種默認(rèn)文件名。當(dāng)然,你可以使用別的文件名來書寫MakeflekeixMalisMakefilemake--file”參數(shù),如:makefMake.Linuxmake--fileMake.AIX。三、引用其它的MakefileMakefileincludeMakefileC語言的#include,被包含的文件會(huì)原模原樣的放在當(dāng)前文件的包含位置。include的語法是:include<filename>filename可以是當(dāng)前操作系統(tǒng)Shell的文件模式(可以保含路徑和通配符)include前面可以有一些空字符,但是絕不能是鍵開始。include和<filename>可以用Makefile:a.mkb.mkfoo.make,以及一個(gè)變量$(bar)e.mkf.mk,那么,下面的語句:includefoo.make*.mk$(bar)等價(jià)于:includefoo.makea.mkb.mkc.mke.mkf.mkmakeincludeC/C++的#include會(huì)在當(dāng)前目錄下首先尋找,如果當(dāng)前目錄下沒有找到,那么,make還會(huì)在下面的幾個(gè)目錄下找:1make執(zhí)行時(shí),有“-I”或“--include-dirmake就會(huì)在這個(gè)參數(shù)所指定的目錄下去尋找。2、如果目錄<prefix>/include(一般是:/usr/local/bin或/usr/include)存在的話,make也會(huì)去找。如果有文件沒有找到的話,makemakefile的讀取,make取的文件,如果還是不行,makemakeinlde-include<filename>其表示,無論include過程中出現(xiàn)什么錯(cuò)誤,都不要報(bào)錯(cuò)繼續(xù)執(zhí)行。和其它版本make兼容的相關(guān)命令是sinclude,其作用和這一個(gè)是一樣的。四、環(huán)境變量MAKEFILESMAKEFILES,那么,make會(huì)把這個(gè)變量中的值做一inueMaefieicldeMakefile的文件發(fā)現(xiàn)錯(cuò)誤,make也會(huì)不理。makeMakefileMakefile有定義這個(gè)變量。五、make的工作方式Uake(ake)1Makefile。2includeMakefile。3、初始化文件中的變量。4、推導(dǎo)隱晦規(guī)則,并分析所有規(guī)則。5、為所有的目標(biāo)文件創(chuàng)建依賴關(guān)系鏈。6、根據(jù)依賴關(guān)系,決定哪些目標(biāo)要重新生成。7、執(zhí)行生成命令。1-5步為第一個(gè)階段,6-7makemake并不會(huì)完全馬上展開,make使用的是拖延戰(zhàn)術(shù),make個(gè)基礎(chǔ),后續(xù)部分也就容易看懂了。書寫規(guī)則規(guī)則包含兩個(gè)部分,一個(gè)是依賴關(guān)系,一個(gè)是生成目標(biāo)的方法。MakefilemakeMakefile目標(biāo)。如果第一條規(guī)則中的目標(biāo)有很多個(gè),那么,第一個(gè)目標(biāo)會(huì)成為最終的目標(biāo)。make完成的也就是這個(gè)目標(biāo)。好了,還是讓我們來看一看如何書寫規(guī)則。一、規(guī)則舉例foo.ofoo.cdefs.h #foo模塊cc-c-gfoo.cdefs.h是目標(biāo)所依賴的源文件,而只有一個(gè)命令“cc-c-gfoo.b1foo.ofoo.c和defs.hfoo.c和defs.h的文件日foo.ofoo.o不存在,那么依賴關(guān)系發(fā)生。2(或更新)foo.occfoo.o這(foo.c文件include了defs.h文件)二、規(guī)則的語法targets:prerequisitescommand...或是這樣:targets:prerequisites;commandcommand...targets但也有可能是多個(gè)文件。commandtarget:prerequisites鍵]開頭,prerequisites(見上)prerequisites(或依賴目標(biāo)‘a(chǎn)kemake兩件事,文件的依賴關(guān)系和如何成成目標(biāo)文件。一般來說,makeUNIXShell,也就是/bin/sh來執(zhí)行命令。三、在規(guī)則中使用通配符如果我們想定義一系列比較類似的文件,我們很自然地就想起使用通配符。make?Unixl波浪號(hào)“~)字符在文件名中也有比較特殊的用途。如果是“~/test的$HOMEtesthchentest目錄。(Unix下的小知識(shí)了,make也支持)WindowsMS-DOS下,用戶沒有宿主目錄,那么波浪號(hào)所指的目錄則根據(jù)環(huán)境變量“HOME”而定。通配符代替了你一系列的文件,如“*.cc*\\*”來表示真實(shí)的“*”字符,而不是任意長度的字符串。好吧,還是先來看幾個(gè)例子吧:clean:rm-f*.o上面這個(gè)例子我不不多說了,這是操作系統(tǒng)Shell所支持的通配符。這是在命令中的通配符。print:*.clpr-p$?touchprintprint依賴于所有的[.c]其中的“$?”是一個(gè)自動(dòng)化變量,我會(huì)在后面給你講述。objects=*.o[*.o]objects*oMkefleC/+objects的值是所有[.o]的文件名的集合,那么,你可以這樣:objects:=$(wildcard*.o)這種用法由關(guān)鍵字“wildcard”指出,關(guān)于Makefile的關(guān)鍵字,我們將在后面討論。四、文件搜尋makemakemake在自動(dòng)去找。Makefile只會(huì)在當(dāng)前的目錄中去找尋依賴文件和目標(biāo)文件。如果定義了這個(gè)變量,那么,make在當(dāng)當(dāng)前目錄找不到的情況下,到所指定的目錄中去找尋文件了。VPATH=src:../headersc”和“../hederake會(huì)按照這個(gè)順序進(jìn)行搜索。目錄(當(dāng)然,當(dāng)前目錄永遠(yuǎn)是最高優(yōu)先搜索的地方)ake的“vpth(注意,它是全小寫的make方法有三種:1、vpath<pattern><directories>為符合模式<pattern>的文件指定搜索目錄<directories>。2、vpath<pattern>清除符合模式<pattern>的文件的搜索目錄。3、vpath清除所有已被設(shè)置好了的文件搜索目錄。vapth使用方法中的<pattern>vpath%.h../headersmake../headers.h(如果某文件在當(dāng)前目錄沒有找到的話)vpathvpath同的vpath語句的先后順序來執(zhí)行搜索。如:vpath%.cfoovpath% vpath%.cbar其表示“.cfo”目錄,然后是“blih”目錄。vpath%.cfoo:barvpath% blish而上面的語句則表示“.c”結(jié)尾的文件,先在“foo”目錄,然后是“bar”目錄,最后才是“blish”目錄。五、偽目標(biāo)最早先的一個(gè)例子中,我們提到過一個(gè)“cleclean:rm*.otemp正像我們前面例子中的“clean”一樣,即然我們生成了許多文件編譯文件,我們也應(yīng)該提供一個(gè)清除它們的“目標(biāo)”以備完整地重編譯而用。(以“makeclean”來使用該目標(biāo))cleanmake然其就失去了“偽目標(biāo)”的意義了。.PHONYae.PHONY:cleanmakeclean”這樣。于是整個(gè)過程可以這樣寫:.PHONY:cleanclean:rm*.otempMaefiemakeMakefile中,那么你可以使用“偽目標(biāo)”這個(gè)特性:all:prog1prog2prog3.PHONY:allprog1:prog1.outils.occ-oprog1prog1.outils.oprog2:prog2.occ-oprog2prog2.oprog3:prog3.osort.outils.occ-oprog3prog3.osort.outils.o.PHONYall”聲明了“all為依賴??聪旅娴睦樱?PHONY:cleanallcleanobjcleandiffcleanall:cleanobjcleandiffrmprogramcleanobj:rm*.ocleandiff:rm*.diff“makecleanobjmakecleanallmakecleanobjmakecleandiff”命令來達(dá)到清除不同種類文件的目的。六、多目標(biāo)Makefile化變量“$(的集合,這樣說可能很抽象,還是看一個(gè)例子吧。bigoutputlittleoutput:text.ggeneratetext.g-$(substoutput,,$@)>$@上述規(guī)則等價(jià)于:bigoutput:text.ggeneratetext.g-big>bigoutputlittleoutput:text.ggeneratetext.g-little>littleoutput其中,-$(substoutput,,$@)中的“$Makefilesubst,$”依次取出目標(biāo),并執(zhí)于命令。七、靜態(tài)模式靜態(tài)模式可以更加容易地定義多目標(biāo)的規(guī)則,可以讓我們的規(guī)則變得更加的有彈性和靈活。我們還是先來看一下語法:<targets...>:<target-pattern>:<prereq-patterns...><commands>...targets定義了一系列的目標(biāo)文件,可以有通配符。是目標(biāo)的一個(gè)集合。target-parrtern是指明了targets的模式,也就是的目標(biāo)集模式。prereq-parrternstarget-parrtern形成的模式再進(jìn)行一次依賴目標(biāo)的定義。這樣描述這三個(gè)東西,可能還是沒有說清楚,還是舉個(gè)例子來說明一下吧。如果我們的tttn>定義成“%.o<age>集合中都是以“o”結(jié)尾的,而如果我們的<prereq-parrterns定義成“%.ctttn所形成的目標(biāo)集進(jìn)行二次定義,其計(jì)算方法是,取<taet-partern>模式中的“%(也就是去掉了[.o]這個(gè)結(jié)尾,并為其加上[.c]這個(gè)結(jié)尾,形成的新集合??匆粋€(gè)例子:objects=foo.obar.oall:$(objects)$(objects):%.o:%.c$(CC)-c$(CFLAGS)$<-o$@obeto.foooa.o$bect%.c%.o”%fooa.cfoo.cbac$$<(foocba.c“@”表示目標(biāo)集(也就是“ooo.o的規(guī)則:foo.o:foo.c$(CC)-c$(CFLAGS)foo.c-ofoo.obar.o:bar.c$(CC)-c$(CFLAGS)bar.c-obar.o試想,如果我們的“%.o一個(gè)很強(qiáng)大的功能。再看一個(gè)例子:files=foo.elcbar.olose.o$(filter%.o,$(files)):%.o:%.c$(CC)-c$(CFLAGS)$<-o$@$(filter%.elc,$(files)):%.elc:%.elemacs-fbatch-byte-compile$<$(filtero,$(files))Makefilefilter%.o”Makefile中更大的彈性。八、自動(dòng)生成依賴性在Makefile中,我們的依賴關(guān)系可能會(huì)需要包含一系列的頭文件,比如,如果我們的main.c中有一句“#ncuedefsdefs.hCC/C++C/C++編譯器都支持一個(gè)“-M”的選項(xiàng),即自動(dòng)找尋源文件中包含的頭文件,并生成一個(gè)依賴關(guān)系。例如,如果我們執(zhí)行下面的命令:cc-Mmain.c其輸出是:main.o:main.cdefs.h于是由編譯器自動(dòng)生成的依賴關(guān)系,這樣一來,你就不必再手動(dòng)書寫若干文件的依賴關(guān)系,而由編譯器自動(dòng)生成了。需要提醒一句的是,如果你使用GNU的C/C++編譯器,你得用“-MM”參數(shù),不然,“-M”參數(shù)會(huì)把一些標(biāo)準(zhǔn)庫的頭文件也包含進(jìn)來。gcc-Mmain.c的輸出是:main.o:main.cdefs.h/usr/include/stdio.h/usr/include/features.h\/usr/include/sys/cdefs.h/usr/include/gnu/stubs.h\/usr/lib/gcc-lib/i486-suse-linux/2.95.3/include/stddef.h\/usr/include/bits/types.h/usr/include/bits/pthreadtypes.h\/usr/include/bits/sched.h/usr/include/libio.h\/usr/include/_G_config.h/usr/include/wchar.h\/usr/include/bits/wchar.h/usr/include/gconv.h\/usr/lib/gcc-lib/i486-suse-linux/2.95.3/include/stdarg.h\/usr/include/bits/stdio_lim.hgcc-MMmain.c的輸出則是:main.o:main.cdefs.h那么,編譯器的這個(gè)功能如何與我們的Makefile聯(lián)系在一起呢。因?yàn)檫@樣一來,我們的MakefileMakefile自已依賴于源文件?這個(gè)功能并不現(xiàn)實(shí),不過我們可以有其它手段來迂回地實(shí)現(xiàn)這一功能。GNU組織建議把編譯器為每一個(gè)源e.d”Makefile文件,[.d]文件中就存放對(duì)應(yīng)[.c]文件的依賴關(guān)系。[.c]文件和[.d]make自動(dòng)更新或自成[.d]Makefile這里,我們給出了一個(gè)模式規(guī)則來產(chǎn)生[.d]文件:%.d:%.c@set-e;rm-f$@;\$(CC)-M$(CPPFLAGS)$<>$@.$$$$;\sed's,\($*\)\.o[:]*,\1.o$@:,g'<$@.$$$$>$@;\rm-f$@.$$$$這個(gè)規(guī)則的意思是,所有的[.d[.crm-f$”的意思是刪除所有的目標(biāo),也就是d]文件,第二行的意思是,為每個(gè)依賴文件“$<[.c]文件生成依賴文件,“$%.Cnae.c%nae$$$”nae.d.24sedsed命令的用法請參看相關(guān)的使用文檔。第四行就是刪除臨時(shí)文件。總而言之,這個(gè)模式要做的事就是在編譯器生成的依賴關(guān)系中加入[.d]文件的依賴,即把依賴關(guān)系:main.o:main.cdefs.h轉(zhuǎn)成:main.omain.d:main.cdefs.h[.d][.d]加入的不只是依賴關(guān)系,包括生成的命令也可一并加入,讓每個(gè)[.d]文件都包含一個(gè)完賴的規(guī)則。一旦我們完成這個(gè)工作,接下來,我們就要把這些自動(dòng)生成的規(guī)則放進(jìn)我們的主MakefileMakefileMakefile(前面講過,例如:sources=foo.cbar.cinclude$(sources:.c=.d)$(sources:.c=.d).c=.d$(sources)所有[.c]的字串都替換成[.d]include[.d]文件中的目標(biāo)會(huì)成為默認(rèn)目標(biāo)。書寫命令Shellmake會(huì)一按順序一條一條的執(zhí)行命令,每條命令的開頭必須以鍵開頭,除非,命令是緊跟在依賴規(guī)則后面的分號(hào)后的。make會(huì)認(rèn)為其是一個(gè)空命令。UNIXShellmake的命令默認(rèn)是被“/bin/sh”——UNIXl。Maefie#C/中的“//一、顯示命令通常,make會(huì)把其要執(zhí)行的命令行在命令執(zhí)行前輸出到屏幕上。當(dāng)我們用“@make像屏幕顯示一些信息。如:@echoXXX模塊......當(dāng)ake執(zhí)時(shí)會(huì)輸“正在編譯X模塊 字串但不會(huì)輸出命令如果沒“,那么,make將輸出:echo正在編譯XXX模塊......XXX模塊......akeaken--justprin么樣子的或是什么順序的。make參數(shù)“-s”或“--slient二、命令執(zhí)行當(dāng)依賴目標(biāo)新于目標(biāo)時(shí),也就是當(dāng)規(guī)則的目標(biāo)需要被更新時(shí),makecdcd分隔。如:exec:

cd/home/hchenpwdcd/home/hchen;pwd當(dāng)我們執(zhí)行“makeexec”時(shí),第一個(gè)例子中的cd沒有作用,pwd會(huì)打印出當(dāng)前的Makefile目錄,而第二個(gè)例子中,cdpd會(huì)打印出“/oe/hcemakeSHELLShellUNIX的標(biāo)準(zhǔn)Shell——/bin/shMS-DOSMS-DOS下沒有SHELLIXakeLLMS-DOS命令解釋器沒有找到,其會(huì)給你的命令解釋器加上諸如“.exe.co.bat.sh”等后綴。三、命令出錯(cuò)每當(dāng)命令運(yùn)行完后,makemake則中的某個(gè)命令出錯(cuò)了(命令退出碼非零ake能終止所有規(guī)則的執(zhí)行。mkdirmkdirmkdirmkdir出錯(cuò)而終止規(guī)則的運(yùn)行。Maefile-(在ab,標(biāo)記為不管命令出不出錯(cuò)都認(rèn)為是成功的。如:clean:-rm-f*.o還有一個(gè)全局的辦法是,給make加上“-i”或是“--ignore-errors”參數(shù),那么,Makefile歡設(shè)置。akek”或是“g四、嵌套執(zhí)行makeMkefieMkefieMakefile個(gè)技術(shù)對(duì)于我們模塊編譯和分段編譯有著非常大的好處。MakefileMakefile可以這樣書寫:subsystem:cdsubdir&&$(MAKE)其等價(jià)于:subsystem:$(MAKE)-Csubdir定義$(MAKE)makemake命令。MaefieMefilMaefieMaefile(如果你顯示的聲明Maefiee”參數(shù)。如果你要傳遞變量到下級(jí)Makefile中,那么你可以使用這樣的聲明:export<variable...>如果你不想讓某些變量傳遞到下級(jí)Makefile中,那么你可以這樣聲明:unexport<variable...>如:示例一:exportvariable=value其等價(jià)于:variable=valueexportvariable其等價(jià)于:exportvariable:=value其等價(jià)于:variable:=valueexportvariable示例二:exportvariable+=value其等價(jià)于:variable+=valueexportvariableexport所有的變量。MAKEFLAGS,這兩個(gè)變量不管你是exportMakefileMAKEFILESmakeMakefilemakeMakefile中定義了MAKEFILESMakefile中,這是一個(gè)系統(tǒng)級(jí)的環(huán)境變量。akeC““o(有Makefile參數(shù)的細(xì)節(jié)將在后面說明subsystem:cdsubdir&&$(MAKE)MAKEFLAGS=MAKEFLAGS,那么你得確信其中的選項(xiàng)是大家都會(huì)用到的,如果pake的過程中輸出一些信息,讓你看到目前的工作目錄。比如,如果我們的下級(jí)make目錄是“/hoe/hcn/n/akeake”來執(zhí)行,那么當(dāng)進(jìn)入該目錄時(shí),我們會(huì)看到:make:Enteringdirectory`/home/hchen/gnu/make'.而在完成下層make后離開目錄時(shí),我們會(huì)看到:make:Leavingdirectory`/home/hchen/gnu/make'當(dāng)你使用“CakeMakefle”會(huì)被自動(dòng)打開的。如果參數(shù)中有““--slien)或是“no-prnt-irctor”總是失效的。五、定義命令包如果Makefile中出現(xiàn)一些相同命令序列,那么我們可以為這些相同的命令序列定義一個(gè)變量。定義這種命令序列的語法以“define”開始,以“endef”結(jié)束,如:definerun-yaccyacc$(firstwordmv$@endefrun-accMaefiedefine命令包放到一個(gè)示例中來看看吧。foo.c:foo.y$(run-yacc)run-acc$foo$foo.$ake行。使用變量MakefileC/C++語言中的宏一樣,他代表了一個(gè)文本字串,在MakefileC/C++MkefieMkefieMakefile的其它部分中。變量的命名字可以包含字符、數(shù)字,下劃線(可以是數(shù)字開頭:“=”或是空字符(空格、回車等fooFoo”和“FO”是三Makefile的變量名是全大寫的命名方式,但我推薦使用大小寫搭配的變量名,如:MakeFlags。這樣可以避免和系統(tǒng)的變量沖突,而發(fā)生意外的事情。有一些變量是很奇怪字串,如“$<$一、變量的基礎(chǔ)變量在聲明時(shí)需要給予初值,而在使用時(shí),需要給在變量名前加上“$(”或是大括號(hào)“{}”把變量給包括起來。如果你要使用真實(shí)的“$需要用“$$”來表示。個(gè)例子:objects=program.ofoo.outils.oprogram:$(objects)cc-oprogram$(objects)$(objects):defs.h變量會(huì)在使用它的地方精確地展開,就像C/C++中的宏一樣,例如:foo=cprog.o:prog.$(foo)$(foo)$(foo)-$(foo)prog.$(foo)展開后得到:prog.o:prog.ccc-cprog.c當(dāng)然,千萬不要在你的Makefile中這樣干,這里只是舉個(gè)例子來表明Makefile中的變量在使用處展開的真實(shí)樣子??梢娖渚褪且粋€(gè)“替代”的原理。給變量加上括號(hào),那也可以,但我還是強(qiáng)烈建議你給變量加上括號(hào)。二、變量中的變量在定義變量的值時(shí),我們可以使用其它變量來構(gòu)造變量的值,在Makefile中有兩種方式來在用變量定義變量的值。先看第一種方式,也就是簡單的使用“=”號(hào),在“=”左側(cè)是變量,右側(cè)是變量的值,右值,其也可以使用后面定義的值。如:foo=$(bar)bar=$(ugh)ugh=Huh?all:echo$(foo)我們執(zhí)行“akell$(foo的值是“u?()的值是$(bar),$(bar)的值是$(uh,$uh的值是“u?)定義,如:CFLAGS=$(include_dirs)-Oinclude_dirs=-Ifoo-IbarS-Ifoo-Ibar-CFLAGS=$(CFLAGS)-O或:A=$(B)B=$(A)makemakemake運(yùn)行時(shí)非常make的函數(shù)“wildcard”和“shell”發(fā)生不可預(yù)知的錯(cuò)誤。因?yàn)槟悴粫?huì)知道這兩個(gè)函數(shù)會(huì)被調(diào)用多少次。為了避免上面的這種方法,我們可以使用make中的另一種用變量來定義變量的方法。這種方法使用的是“:=”操作符,如:x:=fooy:=$(x)barx:=later其等價(jià)于:y:=foobarx:=later量。如果是這樣:y:=$(x)barx:=foo那么,y的值是“bafoob上面都是一些比較簡單的變量使用了,讓我們來看一個(gè)復(fù)雜的例子,其中包括了make的函數(shù)、條件表達(dá)式和一個(gè)系統(tǒng)變量“MAKELEVEL”的使用:ifeq(0,${MAKELEVEL})cur-dir :=$(shellpwd)whoami :=$(shellhost-type:=$(shellarch)MAKE:=${MAKE}host-type=${host-type}whoami=${whoami}endifake(ake,那么,這個(gè)變量Makefile的調(diào)用層數(shù)。下面再介紹兩個(gè)定義變量時(shí)我們需要知道的,請先看一個(gè)例子,如果我們要定義一個(gè)變量,其值是一個(gè)空格,那么我們可以這樣來:nullstring:=space:=$(nullstring)#endofthelinenullstringEmptyspaceEmpty變量的值開始了,而后面采用“#意,如果我們這樣定義一個(gè)變量:dir:=/foo/bar #directorytoputthefrobsindir/fooba4?=FOO?=barOO的值就是“baO先前被定義過,那么這條語將什么也不做,其等價(jià)于:ifeq($(originFOO),undefined)FOO=barendif三、變量高級(jí)用法這里介紹兩種變量的高級(jí)使用方法,第一種是變量值的替換。$(var:=b${vr:a=bvaraab還是看一個(gè)示例吧:foo:=a.ob.oc.obar:=$(foo:.o=.c).o”字串“結(jié)尾”全部替換成“.c$(bar)”的值就是“a.cb.ccc()定義的,如:foo:=a.ob.oc.obar:=$(foo:%.o=%.c)這依賴于被替換字串中的有相同的模式,模式中必須包含一個(gè)“%”字符,這個(gè)例子同樣讓$(bar)a.cb.cc.c第二種高級(jí)用法是——“把變量的值再當(dāng)成變量”。先看一個(gè)例子:x=yy=za:=$($(x))在這個(gè)例子中,$x)的值是“y$($(x))就是$(),于是$(a)的值就是“z(注意,是“x=x=$()我們還可以使用更多的層次:x=yy=zz=ua:=$($($(x)))這里的$(a的值是“u讓我們再復(fù)雜一點(diǎn),使用上“在變量定義中使用變量”的第一個(gè)方式,來看一個(gè)例子:x=$(y)y=zz=Helloa:=$($(x))這里的$($(x被替換成了$($(),因?yàn)?()值是“za:$(z),也就是“Hell再復(fù)雜一點(diǎn),我們再加上函數(shù):x=variable1variable2:=Helloy=$(subst1,2,$(x))z=ya:=$($($(z)))$($($(z)))$($($($(subst12,$(x))$(x)varabesubtvaiale112“varab1”變成“ib2$()的值就是$varibl2)的值——“Hell喔,好不容易)在這種方式中,或要可以使用多個(gè)變量來組成一個(gè)變量的名字,然后再取其值:first_second=Helloa=firstb=secondall=$($a_$b)這里的“$a$bd$(allHella_objects:=a.ob.oc.o1_objects:=1.o2.o3.osources:=$($(a1)_objects:.o=.c)$(a1a$(souresa.cb.cc$(a1)的值是“1$(souces的值是“1.c2.c3c再來看一個(gè)這種技術(shù)和“函數(shù)”與“條件語句”一同使用的例子:ifdefdo_sortfunc:=sortelsefunc:=stripendifbar:=adbgqcfoo:=$($(func)$(bar))d_sorfoo$(sortadbgqc(fooabcdgd_sotfo:=$(sortadbgqcp函數(shù)。dir=foo$(dir)_sources:=$(wildcard$(dir)/*.c)define$(dir)_printlpr$($(dir)_sources)endefdifoo_oure”和“fooprin我們可以使用“+=”操作符給變量追加值,如:objects=main.ofoo.obar.outils.oobjects+=another.o$(ojets值變成ain.ofo.oba.otilsonte.o(nt.o被追加進(jìn)去了)使用“+=”操作符,可以模擬為下面的這種例子:objects=main.ofoo.obar.outils.oobjects:=$(objects)another.o所不同的是,用“+=”更為簡潔。=variable:=valuevariable+=more等價(jià)于:variable:=valuevariable:=$(variable)more但如果是這種情況:variable=valuevariable+=more=make五、override指示符makeMakefile中對(duì)這個(gè)變量的賦值會(huì)被忽略。Makefile中設(shè)置這類參數(shù)的值,那么,你可以使用“override”指示符。其語法是:override<variable>=<value>override<variable>:=<value>當(dāng)然,你還可以追加:override<variable>+=<moretext>對(duì)于多行的變量定義,我們用define指示符,在define指示符前,也同樣可以使用ovveride指示符,如:overridedefinefoobarendef六、多行變量definedefine關(guān)鍵字設(shè)置變量的值可以有換行,這有利于定義一系列的命令(前面我們講過“命令包”的技術(shù)就是利用這個(gè)關(guān)鍵字。defineendef關(guān)鍵字結(jié)因?yàn)槊钚枰詃efine定義的命令變量中沒有以鍵開頭,那么make就不會(huì)把其認(rèn)為是命令。下面的這個(gè)示例展示了define的用法:definetwo-linesechofooecho$(bar)endef七、環(huán)境變量makemakeMakefile文件中,但是如果Makefilemake(makeMakefile中定義的變量)因此,如果我們在環(huán)境變量中設(shè)置了“CFLAGS”環(huán)境變量,那么我們就可以在所有的MakefileMakefileCFLAGSMakefile中的這個(gè)變量,如果沒有定義則使用系統(tǒng)環(huán)境變量的值,一個(gè)共性和個(gè)性的統(tǒng)一,很像“全局變量”和“局部變量”的特性。ake嵌套調(diào)用時(shí)(參見前面的“嵌套調(diào)用”章節(jié)MaefileMakefileMakefileexprot(參見前面章節(jié))當(dāng)然,我并不推薦把許多的變量都定義在系統(tǒng)環(huán)境中,這樣,在我們執(zhí)行不用的Makefile時(shí),擁有的是同一套系統(tǒng)變量,這可能會(huì)帶來更多的麻煩。八、目標(biāo)變量Mkfile$當(dāng)然,我樣同樣可以為某個(gè)目標(biāo)設(shè)置局部變量,這種變量被稱為“aet-specific其語法是:<target...>:<variable-assignment><target...>:overide<variable-assignment><varabe-assgnent>==make命令行帶入的變量,或是系統(tǒng)環(huán)境變量。所有的規(guī)則中去。如:prog:CFLAGS=-gprog:prog.ofoo.obar.o$(CC)$(CFLAGS)prog.ofoo.obar.oprog.o:prog.c$(CC)$(CFLAGS)prog.cfoo.o:foo.c$(CC)$(CFLAGS)foo.cbar.o:bar.c$(CC)$(CFLAGS)bar.c在這個(gè)示例中,不管全局的$(CFLAGS)prog目標(biāo),以及其所引發(fā)的所有規(guī)則中(pro.ofoo.oa.o,$的值都是“g”九、模式變量Uake(cae,通過上面的目標(biāo)變量中,可以把變量定義在符合這種模式的所有目標(biāo)上。我們知道,make的“模式”一般是至少含有一個(gè)“%”的,所以,我們可以以如下方式給所有以[.o]結(jié)尾的目標(biāo)定義目標(biāo)變量:%.o:CFLAGS=-O同樣,模式變量的語法和“目標(biāo)變量”一樣:<pattern...>:<variable-assignment><pattern...>:override<variable-assignment>override同樣是針對(duì)于系統(tǒng)環(huán)境傳入的變量,或是make命令行指定的變量。使用條件判斷使用條件判斷,可以讓make根據(jù)運(yùn)行時(shí)的不同情況選擇不同的執(zhí)行分支。條件表達(dá)式可以是比較變量的值,或是比較變量和常量的值。一、示例下面的例子,判斷$(CC變量是否“cU函數(shù)編譯目標(biāo)。libs_for_gcc=-lgnunormal_libs=foo:$(objects)ifeq($(CC),gcc)$(CC)-ofoo$(objects)$(libs_for_gcc)else$(CC)-ofoo$(objects)$(normal_libs)endif可見,在上面示例的這個(gè)規(guī)則中,目標(biāo)“foo”可以根據(jù)變量“$(CC)”值來選取不同的函數(shù)庫來編譯程序。我們可以從上面的示例中看到三個(gè)關(guān)鍵字:ifeq、else和endif。ifeq的意思表示條件語句的開始,并指定一個(gè)條件表達(dá)式,表達(dá)式包含兩個(gè)參數(shù),以逗號(hào)分隔,表達(dá)式以圓括號(hào)括起。else表示條件表達(dá)式為假的情況。endif表示一個(gè)條件語句的結(jié)束,任何一個(gè)條件表達(dá)式都應(yīng)該以endif結(jié)束。當(dāng)我們的變量$(CC)值是“gcc”時(shí),目標(biāo)foo的規(guī)則是:foo:$(objects)$(CC)-ofoo$(objects)$(libs_for_gcc)而當(dāng)我們的變量$(CCgcc(比如“cco的規(guī)則是:foo:$(objects)$(CC)-ofoo$(objects)$(normal_libs)當(dāng)然,我們還可以把上面的那個(gè)例子寫得更簡潔一些:libs_for_gcc=-lgnunormal_libs=ifeq($(CC),gcc)libs=$(libs_for_gcc)elselibs=$(normal_libs)endiffoo:$(objects)$(CC)-ofoo$(objects)$(libs)二、語法條件表達(dá)式的語法為:<conditional-directive><text-if-true>endif以及:<conditional-directive><text-if-true>else<text-if-false>endif其中<cnitnal-iretie表示條件關(guān)鍵字,如“ifeqifeq(<arg1>,<arg2>)ifeq'<arg1>''<arg2>'ifeq"<arg1>""<arg2>"ifeq"<arg1>"'<arg2>'ifeq'<arg1>'"<arg2>"比較參數(shù)“arg1”和“arg2”的值是否相同。當(dāng)然,參數(shù)中我們還可以使用make的函數(shù)。如:ifeq($(strip$(foo)),)<text-if-empty>endifstri(Ept<txt-if-epty>就生效。第二個(gè)條件關(guān)鍵字是“ifneifneq(<arg1>,<arg2>)ifneq'<arg1>''<arg2>'ifneq"<arg1>""<arg2>"ifneq"<arg1>"'<arg2>'ifneq'<arg1>'"<arg2>"其比較參數(shù)“arg1”和“arg2”的值是否相同,如果不同,則為真。和“ifeq”類似。第三個(gè)條件關(guān)鍵字是“ifdef”。語法是:ifdef<variable-name>如果變量<variable-name>的值非空,那到表達(dá)式為真。否則,表達(dá)式為假。當(dāng)然,<variable-name>示例一:bar=foo=$(bar)ifdeffoofrobozz=yeselsefrobozz=noendif示例二:foo=ifdeffoofrobozz=yeselsefrobozz=noendif$(frobozz”值是“nifndef<variable-name>這個(gè)我就不多說了,和“ifdef”是相反的意思。在<conditional-directive>(不然就被認(rèn)為是命令。而注釋符“#else”和“endif”也一樣,只要不是以鍵開始就行了。特別注意的是,makeMakefile時(shí)就計(jì)算條件表達(dá)式的值,并根據(jù)條件表達(dá)式的值來選擇語句,所以,你最好不要把自動(dòng)化變量(如“$@”等)放入條件表達(dá)式中,因?yàn)樽詣?dòng)化變量是在運(yùn)行時(shí)才有的。而且,為了避免混亂,make不允許把整個(gè)條件語句分成兩部分放在不同的文件中。使用函數(shù)在Makefile中可以使用函數(shù)來處理變量,從而讓我們的命令或是規(guī)則更為的靈活和具有智能。make所支持的函數(shù)也不算很多,不過已經(jīng)足夠我們的操作了。函數(shù)調(diào)用后,函數(shù)的返回值可以當(dāng)做變量來使用。一、函數(shù)的調(diào)用語法函數(shù)調(diào)用,很像變量的使用,也是以“$”來標(biāo)識(shí)的,其語法如下:$(<function><arguments>)或是${<function><arguments>}這里,<function>就是函數(shù)名,make支持的函數(shù)不多。<arguments>是函數(shù)的參數(shù),參數(shù)間,$為了風(fēng)格的統(tǒng)一,函數(shù)和變量的括號(hào)最好一樣,如使用“$(substa,b,$(x))”這樣的形式,而不是“$(substa,b,${x})”的形式。因?yàn)榻y(tǒng)一會(huì)更清楚,也會(huì)減少一些不必要的麻煩。還是來看一個(gè)示例:comma:=,empty:=space:=$(empty)$(empty)foo:=abcbar:=$(subst$(space),$(comma),$(foo))$(space)使用了$(empty)定義了一個(gè)空格,$(foo)的值是“abc$bar)的定義用,調(diào)用了函數(shù)“subs字串。這個(gè)函數(shù)也就是把$(foo$(bar)的值是“a,bc二、字符串處理函數(shù)$(subst<from>,<to>,<text>)名稱:字符串替換函數(shù)——subst。功能:把字串<text>中的<from>字符串替換成<to>。返回:函數(shù)返回被替換過后的字符串。示例:$(substee,EE,feetonthestreet),feetonthestreeeeEEfEEtonthestEEt$(patsubst<pattern>,<replacement>,<text>)名稱:模式字符串替換函數(shù)——patsubst。<txt>(b是否符<pattern>可以包括通配符“%<replceent>%<rplceent>中的這個(gè)“%”將是<pattern>中的那個(gè)“%(可以用“\”來轉(zhuǎn)義,以“\%”來表示真實(shí)含義的“%”字符)返回:函數(shù)返回被替換過后的字符串。示例:$(patsubst%.c,%.o,x.c.cbar.c)把字串“x.c.cbar.c”符合模式[%.c]的單詞替換成[%.o],返回結(jié)果是“x.c.obar.o”備注:這和我們前面“變量章節(jié)”說過的相關(guān)知識(shí)有點(diǎn)相似。如:“$(var:<pattern>=<replacement>)”相當(dāng)于$(patubstaern>,<rpacent>,$(ar)<suffix>=<replacement>)”則相當(dāng)于$(patubtsuix>%<rplaceent>$(var)foo.obaz.o,$(objcs:.o.c$(patubt%.o,.c$(bects)”是一樣的。$(strip<string>)名稱:去空格函數(shù)——strip。功能:去掉<string>字串中開頭和結(jié)尾的空字符。返回:返回被去掉空格的字符串值。示例:$(stripabc)abc”去到開頭和結(jié)尾的空格,結(jié)果是“abc$(findstring<find>,<in>)名稱:查找字符串函數(shù)——findstring。功能:在字串<in>中查找<find>字串。返回:如果找到,那么返回<find>,否則返回空字符串。示例:$(findstringa,abc)$(findstringa,bc)第一個(gè)函數(shù)返回“a”字符串,第二個(gè)返回“”字符串(空字符串)$(filter<pattern...>,<text>)名稱:過濾函數(shù)——filter。功能:以<pattern>模式過濾<text>字符串中的單詞,保留符合模式<pattern>的單詞??梢杂卸鄠€(gè)模式。返回:返回符合模式<pattern>的字串。示例:sources:=foo.cbar.cbaz.sugh.hfoo:$(sources)cc$(filter%.c%.s,$(sources))-ofoo$(fiter%.c%.s$sources))foocba.cbz.$(filter-out<pattern...>,<text>)名稱:反過濾函數(shù)——filter-out。功能:以<pattern>模式過濾<text>字符串中的單詞,去除符合模式<pattern>的單詞??梢杂卸鄠€(gè)模式。返回:返回不符合模式<pattern>的字串。示例:objects=main1.ofoo.omain2.obar.omains=main1.omain2.o$(fite-out$(ais),$(obets))返回值是“foo.oba.$(sort<list>)名稱:排序函數(shù)——sort。功能:給字符串<list>中的單詞排序(升序返回:返回排序后的字符串。示例:$(sortfoobarlose)返回“barfoolose”。備注:sort函數(shù)會(huì)去掉<list>中相同的單詞。$(word<n>,<text>)名稱:取單詞函數(shù)——word。功能:取字符串<text>中第<n>個(gè)單詞。(從一開始)返回:返回字符串<text>中第<n>個(gè)單詞。如果<n>比<text>中的單詞數(shù)要大,那么返回空字符串。$(ord2,foobrbazba$(wordlist<s>,<e>,<text>)名稱:取單詞串函數(shù)——wordlist。功能:從字符串<text>中取從<s>開始到<e>的單詞串。<s>和<e>是一個(gè)數(shù)字。返回:返回字符串<text>中從<s>到<e>的單詞字串。如果<s>比<text>中的單詞數(shù)要大,那么返回空字符串。如果<e>大于<text>的單詞數(shù),那么返回從<s>開始,到<text>結(jié)束的單詞串。$(ordlit3,foaraz返回值是“rba$(words<text>)名稱:單詞個(gè)數(shù)統(tǒng)計(jì)函數(shù)——words。功能:統(tǒng)計(jì)<text>中字符串中的單詞個(gè)數(shù)。返回:返回<text>中的單詞數(shù)。$(words,foobarbaz)3備注:如果我們要取<text>中最后的一個(gè)單詞,我們可以這樣:$(word$(words<text>),<text>)。$(firstword<text>)名稱:首單詞函數(shù)——firstword。功能:取字符串<text>中的第一個(gè)單詞。返回:返回字符串<text>的第一個(gè)單詞。示$(firstwordfoobar)返回值是“foo備注:這個(gè)函數(shù)可以用word函數(shù)來實(shí)現(xiàn):$(word1,<text>)。如:overrideCFLAGS+=$(patsubst%,-I%,$(subst:,,$(VPATH)))如果我們的“$(VPATH)”值是“src:../headers”,那么“$(patsubstt:,)”將返回“ccc或gc搜索頭文件路徑的參數(shù)。三、文件名操作函數(shù)系列的文件名來對(duì)待。$(dir<names...>)名稱:取目錄函數(shù)——dir。<naes>“/前的部分。如果沒有反斜杠,那么返回“./返回:返回文件名序列<names>的目錄部分。示$(dirsrc/oochaks)src/.$(notdir<names...>)名稱:取文件函數(shù)——notdir。<naes>之后的部分。返回:返回文件名序列<names>的非目錄部分。$(ntirsrc/fo.chaksfoochck$(suffix<names...>)名稱:取后綴函數(shù)——suffix。功能:從文件名序列<names>中取出各個(gè)文件名的后綴。返回:返回文件名序列<names>$(suixsrc/oocsrc-10/a.chaks.c.$(basename<names...>)名稱:取前綴函數(shù)——basename。功能:從文件名序列<names>中取出各個(gè)文件名的前綴部分。返回:返回文件名序列<names>的前綴序列,如果文件沒有前綴,則返回空字串。$(basnaesrc/foo.csrc-10/a.chckssrc/foosrc-./barhaks$(addsuffix<suffix>,<names...>)名稱:加后綴函數(shù)——addsuffix。功能:把后綴<suffix>加到<names>中的每個(gè)單詞后面。返回:返回加過后綴的文件名序列。$(addufix.c,oar返回值是“foo.cbac$(addprefix<prefix>,<names...>)名稱:加前綴函數(shù)——addprefix。功能:把前綴<prefix>加到<names>中的每個(gè)單詞后面。返回:返回加過前綴的文件名序列。$(adprefxsrc/ooar返回值是“src/foosrc/ba$(join<list1>,<list2>)名稱:連接函數(shù)——join。功能:把<list2>中的單詞對(duì)應(yīng)地加到<list1>的單詞后面。如果<list1>的單詞個(gè)數(shù)要比<list2>的單詞個(gè)數(shù)要比<list1>多,那么,<list2>多出來的單詞將被復(fù)制到<list2>中。返回:返回連接過后的字符串。$(jonaabb12233返回值是“aa1bb2233四、foreach函數(shù)foreach函數(shù)和別的函數(shù)非常的不一樣。因?yàn)檫@個(gè)函數(shù)是用來做循環(huán)用的,Makefile中的foreachUnix標(biāo)準(zhǔn)Shell(/bin/sh)forC-Shell(/bin/csh)foreach語句而構(gòu)建的。它的語法是:$(foreach<var>,<list>,<text>)<list>中的單詞逐一取出放到參數(shù)<var>執(zhí)行<text><text>的所返回<text>整個(gè)字符串(以空格分隔)foreach函數(shù)的返回值。所以,<var>最好是一個(gè)變量名,<list>可以是一個(gè)表達(dá)式,而<text>中一般會(huì)使用<var>這個(gè)參數(shù)來依次枚舉<list>中的單詞。舉個(gè)例子:names:=abcdfiles:=$(foreachn,$(names),$(n).o)$(nae)n$(n).n”foreacha.oco.注意,foreach中的<var>參數(shù)是一個(gè)臨時(shí)的局部變量,foreach函數(shù)執(zhí)行完后,參數(shù)<var>的變量將不在作用,其作用域只在foreach函數(shù)當(dāng)中。五、if函數(shù)ifUakeifeq(,if$(if<condition>,<then-part>)或是$(if<condition>,<then-part>,<else-part>)可見,if函數(shù)可以包含“elseif<condition>ifif函數(shù)的返回值是,如果nitn>為真(tnt會(huì)是整個(gè)函數(shù)<condition>(空字符串<else-part>所以,<then-part>和<else-part>只會(huì)有一個(gè)被計(jì)算。六、call函數(shù)callcall法是:$(call<expression>,<parm1>,<parm2>,<parm3>...)當(dāng)akepin>$(1$2$(3<par1>,<parm2>,<parm3>依次取代。而<expression>的返回值就是call函數(shù)的返回值。例如:reverse= $(1)$(2)foo=$(callreverse,a,b)那么,foo值就是“a。當(dāng)然,參數(shù)的次序是可以自定義的,不一定是順序的,如reverse= $(2)$(1)foo=$(callreverse,a,b)foob七、origin函數(shù)origin其語法是:$(origin<variable>)注意,<variable>是變量的名字,不應(yīng)該是引用。所以你最好不要在<variable>中使用“$”字符。gnorign函數(shù)的返回值:“undefined”如果vaibl>oriinudefie“default”如果<variable>是一個(gè)默認(rèn)的定義,比如“CC”這個(gè)變量,這種變量我們將在后面講述?!癳nvironment”如果vaibl>Mkefiee“file”如果<variable>這個(gè)變量被定義在Makefile中。“commandline”如果<variable>這個(gè)變量是被命令行定義的?!皁verride”如果<variable>是被override指示符重新定義的。“automatic”如果<variable>是一個(gè)命令運(yùn)行中的自動(dòng)化變量。關(guān)于自動(dòng)化變量將在后面講述。MakefileMakefile其包了一Mae.eMakedef中定義了一個(gè)變量“blchbeth了,如果來源于Make.def或是命令行等非環(huán)境的,那么我們就不重新定義它。于是,在我們的Makefile中,我們可以這樣寫:ifdefbletchifeq"$(originbletch)""environment"bletch=barf,gag,etc.endifendifoverride關(guān)鍵字不就可以重新定義環(huán)境中的變量了嗎?為什么需要overrideoverride過于粗暴,八、shell函數(shù)shellShellawk,sed等等命令來生成一個(gè)變量,如:contents:=$(shellcatfoo)files:=$(shellecho*.c)ShellMakefileMakefileshell函數(shù)執(zhí)行的次數(shù)比你想像的多得多。九、控制make的函數(shù)make提供了一些函數(shù)來控制make的運(yùn)行。通常,你需要檢測一些運(yùn)行Makefile時(shí)的運(yùn)行時(shí)信息,并且根據(jù)這些信息來決定,你是讓make繼續(xù)執(zhí)行,還是停止。$(error<text...>)...>函數(shù)不會(huì)在一被使用就會(huì)產(chǎn)生可以的。例如:示例一:ifdefERROR_001$(errorerroris$(ERROR_001))endif示例二:ERR=$(errorfoundanerror!).PHONY:errerr:;$(ERR)示例一會(huì)在變量ERROR_001定義了后執(zhí)行時(shí)產(chǎn)生error調(diào)用,而示例二則在目錄err被執(zhí)行時(shí)才發(fā)生error調(diào)用。$(warning<text...>)這個(gè)函數(shù)很像error函數(shù),只是它并不會(huì)讓make退出,只是輸出一段警告信息,而make繼續(xù)執(zhí)行。make的運(yùn)行——————akeake命令會(huì)找當(dāng)前目錄的akefilemakemake命令的。一、make的退出碼make命令執(zhí)行后有三個(gè)退出碼:make1。makemake2。Make的相關(guān)參數(shù)我們會(huì)在后續(xù)章節(jié)中講述。二、指定MakefilemakeMakefile的規(guī)則是在當(dāng)前目錄下依次找三個(gè)文件——“Ukeeakele”和“Maefie讀取這個(gè)文件并執(zhí)行。makeMakefile。要達(dá)到這個(gè)功能,我們要使ake的“”或是“--file”參數(shù)“--akefileakefile的名字是“hcen.kake來執(zhí)行這個(gè)文件:make–fhchen.mkmake的命令行是,你不只一次地使用了

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論