使用make更新函數庫檔案
———————————
函數庫檔案也就是對Object檔案(程式編譯的中間檔案)的打封包件。在Unix下,一般是由指令"ar"來完成打包工作。
一、函數庫檔案的成員
一個函數庫檔案由多個檔案組成。你可以以如下格式指定函數庫檔案及其組成:
archive(member)
這個不是一個指令,而一個目标和依賴的定義。一般來說,這種用法基本上就是為了"ar"指令來服務的。如:
foolib(hack.o) : hack.o
ar cr foolib hack.o
如果要指定多個member,那就以空格分開,如:
foolib(hack.o kludge.o)
其等價于:
foolib(hack.o) foolib(kludge.o)
你還可以使用Shell的檔案通配符來定義,如:
foolib(*.o)
二、函數庫成員的隐含規則
當make搜尋一個目标的隐含規則時,一個特殊的特性是,如果這個目标是"a(m)"形式的,其會把目标變成"(m)"。于是,如果我們的成員是"%.o"的模式定義,并且如果我們使用"make foo.a(bar.o)"的形式調用Makefile時,隐含規則會去找"bar.o"的規則,如果沒有定義bar.o的規則,那麼内建隐含規則生效,make會去找bar.c檔案來生成bar.o,如果找得到的話,make執行的指令大緻如下:
cc -c bar.c -o bar.o
ar r foo.a bar.o
rm -f bar.o
還有一個變量要注意的是"$%",這是專屬函數庫檔案的自動化變量,有關其說明請參見"自動化變量"一節。
三、函數庫檔案的字尾規則
你可以使用"字尾規則"和"隐含規則"來生成函數庫打封包件,如:
.c.a:
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $*.o
$(AR) r $@ $*.o
$(RM) $*.o
其等效于:
(%.o) : %.c
四、注意事項
在進行函數庫打封包件生成時,請小心使用make的并行機制("-j"參數)。如果多個ar指令在同一時間運作在同一個函數庫打封包件上,就很有可以損壞這個函數庫檔案。是以,在make未來的版本中,應該提供一種機制來避免并行操作發生在函數打封包件上。
但就目前而言,你還是應該不要盡量不要使用"-j"參數。
後序
——
終于到寫結束語的時候了,以上基本上就是GNU make的Makefile的所有細節了。其它的産商的make基本上也就是這樣的,無論什麼樣的make,都是以檔案的依賴性為基礎的,其基本是都是遵循一個标準的。這篇文檔中80%的技術細節都适用于任何的make,我猜測"函數"那一章的内容可能不是其它make所支援的,而隐含規則方面,我想不同的make會有不同的實作,我沒有精力來檢視GNU的make和VC的nmake、BCB的make,或是别的UNIX下的make有些什麼樣的差别,一是時間精力不夠,二是因為我基本上都是在Unix下使用make,以前在SCO Unix和IBM的AIX,現在在Linux、Solaris、HP-UX、AIX和Alpha下使用,Linux和Solaris下更多一點。不過,我可以肯定的是,在Unix下的make,無論是哪種平台,幾乎都使用了Richard Stallman開發的make和cc/gcc的編譯器,而且,基本上都是GNU的make(公司裡所有的UNIX機器上都被裝上了GNU的東西,是以,使用GNU的程式也就多了一些)。GNU的東西還是很不錯的,特别是使用得深了以後,越來越覺得GNU的軟體的強大,也越來越覺得GNU的在作業系統中(主要是Unix,甚至Windows)"殺傷力"。
對于上述所有的make的細節,我們不但可以利用make這個工具來編譯我們的程式,還可以利用make來完成其它的工作,因為規則中的指令可以是任何Shell之下的指令,是以,在Unix下,你不一定隻是使用程式語言的編譯器,你還可以在Makefile中書寫其它的指令,如:tar、awk、mail、sed、cvs、compress、ls、rm、yacc、rpm、ftp……等等,等等,來完成諸如"程式打包"、"程式備份"、"制作程式安裝包"、"送出代碼"、"使用程式模闆"、"合并檔案"等等五花八門的功能,檔案操作,檔案管理,程式設計開發設計,或是其它一些異想天開的東西。比如,以前在書寫銀行交易程式時,由于銀行的交易程式基本一樣,就見到有人書寫了一些交易的通用程式模闆,在該模闆中把一些網絡通訊、資料庫操作的、業務操作共性的東西寫在一個檔案中,在這些檔案中用些諸如"@@@N、###N"奇怪字串标注一些位置,然後書寫交易時,隻需按照一種特定的規則書寫特定的處理,最後在make時,使用awk和sed,把模闆中的"@@@N、###N"等字串替代成特定的程式,形成C檔案,然後再編譯。這個動作很像資料庫的"擴充C"語言(即在C語言中用"EXEC SQL"的樣子執行SQL語句,在用cc/gcc編譯之前,需要使用"擴充C"的翻譯程式,如cpre,把其翻譯成标準C)。如果你在使用make時有一些更為絕妙的方法,請記得告訴我啊。
回頭看看整篇文檔,不覺記起幾年前剛剛開始在Unix下做開發的時候,有人問我會不會寫Makefile時,我兩眼發直,根本不知道在說什麼。一開始看到别人在vi中寫完程式後輸入"!make"時,還以為是vi的功能,後來才知道有一個Makefile在作怪,于是上網查啊查,那時又不願意看英文,發現就根本沒有中文的文檔介紹Makefile,隻得看别人寫的Makefile,自己瞎碰瞎搞才積累了一點知識,但在很多地方完全是知其然不知是以然。後來開始從事UNIX下産品軟體的開發,看到一個400人年,近200萬行代碼的大工程,發現要編譯這樣一個龐然大物,如果沒有Makefile,那會是多麼恐怖的一樣事啊。于是橫下心來,狠命地讀了一堆英文文檔,才覺得對其掌握了。但發現目前網上對Makefile介紹的文章還是少得那麼的可憐,是以想寫這樣一篇文章,共享給大家,希望能對各位有所幫助。
現在我終于寫完了,看了看檔案的建立時間,這篇技術文檔也寫了兩個多月了。發現,自己知道是一回事,要寫下來,跟别人講述又是另外一回事,而且,現在越來越沒有時間專研技術細節,是以在寫作時,發現在闡述一些細節問題時很難做到嚴謹和精練,而且對先講什麼後講什麼不是很清楚,是以,還是參考了一些國外站點上的資料和題綱,以及一些技術書籍的語言風格,才得以完成。整篇文檔的提綱是基于GNU的Makefile技術手冊的提綱來書寫的,并結合了自己的工作經驗,以及自己的學習曆程。因為從來沒有寫過這麼長,這麼細的文檔,是以一定會有很多地方存在表達問題,語言歧義或是錯誤。因些,我迫切地得等待各位給我指證和建議,以及任何的回報。
最最後,我還想介紹一下make程式的設計開發者。
首當其沖的是: Richard Stallman

計算機、音樂、蝴蝶就是他的最愛
第二位是:Roland McGrath
1) 合作編寫了并維護GNU make。
2) 和Thomas Bushnell一同編寫了GNU Hurd。
3) 編寫并維護着GNU C library。
4) 合作編寫并維護着部分的GNU Emacs。
在此,向這兩位開源項目的鬥士緻以最真切的敬意。