聲明,本文翻譯的是GNU make 3.8.1版用戶手冊;本手冊的原作者是司徒文(Richard M. Stallman),麥家府(Roland McGrath),史密斯(Paul D. Smith)。原手冊發布於2006年4月。此為原文下載地址

make概述

編輯

make工具能自動判斷一個大程序的哪些部分需要再編譯,並且能用命令來執行再編譯操作。本文檔討論的GNU make原來是由司徒文與麥家府開發製作的,從3.76版開始由史密斯接管開發工作。

GNU make遵從IEEE 1003.2-1992標準(POSIX.2)第6.2條。

在本文例子中,筆者用的是C語言程序,這是因為C語言最為流行,但讀者也可以用make來完成其他程式語言的編譯工作,前提是這種語言的編譯器能在 shell下運行。當然,make的應用不局限於程序;如果遇到一些任務,這些任務的文件必須隨著其他文件或數據的變化而更新,那麼讀者就可以用make 來應對這些任務。

在使用make之前,請讀者先寫好Makefile文件,該文件須描述清楚程序文件之間的關係,還要給出更新每個文件的命令。通常,一個程序的可執行文件由OBJ文件來更新,而這些OBJ文件則由原始碼編譯產生。

只要有合適的Makefile文件,在修改了一些原始碼後,只要在Shell命令行下輸入:

make

就足以完成所有必要的再編譯。make程序通過Makefile的資料庫以及諸文件的最後修改時間來判斷哪些文件需要更新。對於每個需要更新的文件, make會用資料庫中記錄的命令來對其操作。

讀者可以給make加上命令行參數,以此告訴make哪些文件需要再編譯、怎樣再編譯。參見第九章如何運行make

如何使用本文檔

編輯

如果讀者是個make新手,或者想閱讀大體介紹,那麼在閱讀每章時只需少量的看前幾節,後面幾節可以略過。每章的前幾節會有該章介紹以及該章的大體信息,而後幾節則會包括一些特殊的或技術性的信息。但第二章 make簡介是個例外,全章都是介紹性的內容。

如果讀者對其他make程序比較熟悉的話,請參閱第十二章 GNU make的特色功能,該章列出了GNU make的增強功能;另外請參閱第十三章 GNU make與標準make不兼容的部分,該章舉出GNU make在少數功能上遜色於其他make的例子。

如果需要閱讀摘要,請看第九章第七節 選項摘要附錄 A 快速參考以及第四章第八節所講的特殊目標

問題與漏洞

編輯

如果讀者發現了GNU make的一些問題或者認為發現了漏洞,那麼請與開發者聯繫;我們不作任何承諾,但我們會盡力解決問題。

在提交漏洞報告之前,請核實漏洞的真實性。另外請認真反覆閱讀文檔,確定文檔介紹的應用方法在實際操作中有效,如果文檔對功能上的一些問題沒有闡述清楚,那麼也請提交報告,這些都是文檔的「漏洞」!

在提交漏洞報告或者自己解決漏洞之前,請將Makefile文件簡化至最小且能體現漏洞問題的程度。然後把Makefile文件連同出錯和警告信息一齊發給我們。請勿改動原信息,最好將其剪切複製到漏洞報告中。請確保用以生成最簡Makefile文件的命令中不使用非自由軟體或者不常用的程序(其實對於這種工具,讀者隨時都可以用簡單的幾句Shell命令來測試)。最後,請詳述Makefile本應有的預期結果,以便於我們判斷問題是否出在文檔上。

如果讀者發現了一個如假包換的錯誤,那麼可以通過以下兩種途徑提交報告:一、通過發送電子郵件到:

bug-make@gnu.org

與我們聯繫;
二、使用我們的在線專案管理來提交報告,網址是:

http://savannah.gnu.org/projects/make/


除了上述的信息以外,請將使用的make完整的版本號一併發給我們;讀者可以通過使用命令「make --version」來獲取版本信息。請確保報告中包含make所運行機器的硬體信息與作業系統信息;順便提一句,獲取這些信息的一種方法是使用命令 「make --help」,一切盡在命令的最後一行輸出中。

make簡介

編輯

首先要有一個名為「Makefile」的文件告訴make需要作什麼。絕大多數情況下,Makefile主要讓make完成編譯與連結程序的工作。

本章我們討論一個簡單的Makefile,這個Makefile會編譯與連結一個由八個C原始碼文件和三個頭文件組成的文本編輯器程序。該 Makefile還會告訴make如何在有明確指示的時候運行各種各樣的命令(比如說接到清除指示時,make運行刪除某些文件的命令)。要閱讀更複雜的 Makefile代碼,翻至附錄C 一個複雜的Makefile實例

當make重新編譯該文本編輯器時,所有的C原始碼文件都會被重新編譯。如果一個頭文件被修改,那麼為了保證整體程序無損,包含該頭文件的所有C原始碼文件都必須要重新編譯。原始碼文件每經過一次編譯都會有一個與自己對應的OBJ文件生成。最後,若有原始碼文件被重新編譯,所有OBJ文件不管是以前生成的還是新生成的,都會被用來連結生成新的可執行文本編輯器程序。

規則大概是什麼樣的

編輯

一個簡單的Makefile所包含的「規則」形式如下

目标 ...:先决条件
     命令
     ...
     ...

目標的名稱一般與生成的文件名稱一致(像可執行程序和OBJ文件)。目標的名稱 也可以是要進行的動作,比如說「clean」(參見第四章第五節 偽目標)。

先決條件是用以生成目標的輸入文件,而一個目標往往依賴於多個文件。

命令是make要執行的動作,而一個規則往往要多行命令。請注意:在每個命令前都必須輸入一個Tab!一般粗心大意的人容易在這個問題上犯錯。

通常有先決條件規則的命令會在先決條件被改動之後執行。但也有一些執行特殊命令的規則沒有先決條件,比如說目標「clean」所在的規則就沒有先決條件,該規則含有刪除命令。

接下來規則會說明與特定規則關聯的文件應該何時被操作,如何被操作。然後make執行先決條件中的命令,用以生成或更新目標。此外,規則還可以對何時與如何進行一個動作下令。參見第四章 編寫規則

除了規則之外,Makefile文件也可以有其他內容,但一個簡單的Makefile只需有規則即可。規則寫出來會比模板中所寫的略顯複雜,但或多或少含有與其一致的部分。

一份簡單的Makefile文件

編輯

下面有一份簡單易懂的Makefile文件,該文件描述了各種依賴關係:可執行程序edit依賴於八個OBJ文件,八個OBJ文件依賴於八個C原始碼文件和三個頭文件。

在本例中,所有C原始碼文件都包含了「defs.h」頭文件,只有定義了編輯命令的C原始碼文件才包含「command.h」頭文件,而只有只有能改變編輯器緩衝區的低層C原始碼文件才包含「buffer.h」頭文件。

     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
     
     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 main.o kbd.o command.o display.o \
                insert.o search.o files.o utils.o


本例用反斜線「\」將每個長行都分成兩行,如此功能上與長行相同,而且減少了閱讀長行的難度。

要用此Makefile生成可執行程序edit,請鍵入:

make

要用此Makefile刪除目錄中所有OBJ文件和可執行程序「edit」,請鍵入:

make clean

在本例中,目標包括,可執行程序「edit」以及OBJ文件「main.o」與「kdb.o」;先決條件也有許多,如「main.c」與「defs.h」;而每個「.o」文件都既為目標,又是先決條件;命令包括「cc -c main.c」與「cc -c kbd.c」。

若目標為文件,則該文件會在其先決條件被改動後重編譯與連結。另外,會自動生成的先決條件首先更新。本例中,「edit」依賴於八個OBJ文件;OBJ文件「main.o」依賴於原始碼文件「main.c」與頭文件「defs.h」。

Shell命令跟隨在目標與先決條件的下一行,該命令控制更新目標文件。每個命令行首必須要有Tab鍵入,以此區分命令行與Makefile中的其他行。(想想看,make全然不知命令是如何工作的,必須由程式設計師提供命令來更新目標。make所能幹的只有執行程式設計師給出命令,然後再根據命令判斷目標文件是否需要更新;如需要,更新之)。

目標「clean」不是一個文件,僅僅是動作的名稱而已。因為這個規則不包含其他動作,而且也不是其他任何規則的先決條件,所以,make不會執行此處操作,除非被特別指定。請注意,此規則既非其他規則之先決條件,亦無先決條件,故此規則唯一目的為運行特定命令。目標若只含命令而與其他文件不相關聯,則稱此目標為偽目標。可參閱第四章第五節 偽目標,了解詳情。另外,請參閱第五章第五節 命令中的報錯信息,了解如何忽略rm或者其他命令的報錯信息。

make如何執行一個Makefie的指令

編輯

在默認情況下,make的工作始於第一個目標(只要這個目標不是以「。」開頭的)。此目標稱為默認最終目標(如果不想使用這個默認規定,可以在命令行中輸入「make 目標名」(參見第九章第二節 用以確定最終目標的參數)或者更改變量(參見第三章第六節 其它的特殊變量)「.DEFAULT_GOAL」以改變默認最終目標)。

上一節簡單示例中,默認最終目標是更新可執行程序「edit」,故將其列入規則首位。

因此,輸入以下命令:

make

make首先讀取本目錄的Makefile,而後開始運行第一個規則。在此例中,規則用以重連結「edit」;但在執行這條規則之前,make必須完成所有「edit」依賴的規則,這些規則就是那些OBJ文件;而每個OBJ文件都會運行自己的一套規則,這些規則會通過編譯各自原始碼的方式來更新每個「.o」文件。如果頭文件或者原始碼文件的修改時間比依賴其的OBJ文件要晚,或者OBJ文件不存在,那麼重新編譯就必須要進行。

那些非最終目標之所以會被運行,是因為最終目標與之相關。而與最終目標無關的規則就不會被執行,除非被特指(如「make clean」)。

在重編譯一個OBJ文件之前,make會先更新其先決條件,先決條件包括原始碼文件與頭文件。此例中的Makefile並沒有針對原始碼文件與頭文件的操作,另外這些「.c」與「.h」文件也不是規則的名稱,故make在此不做任何事情。但make會自動更新自動生成的C程序,比如說由Bison或Yacc生成的,由此次規則生成的。

在編譯完所有需要的OBJ文件後,make會決定是否重連結「edit」。如果「edit」文件不存在或者OBJ文件比「edit」文件要新,則重連結工作一定要作。如果OBJ文件是剛編譯出的,其時間晚於「edit」文件,故此時「edit」文件要被重連結。

因此,如果更改了「insert.c」文件再運行make;make會先編譯「insert.c」文件生成「insert.o」文件,再連結生成「edit」文件。若更改的是「command.h」,再運行make;make會編譯生成「kdb.o」、「command.o」、「files.o」再連結生成「edit」。

用變量簡化Makefile

編輯

在上例中,生成「edit」的OBJ文件組被列舉了兩次(這裡在重複一次):

     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


如此重複書寫,容易造成錯誤;另外,若有新OBJ文件加入系統,本應可以只添加新文件而不考慮原有的OBJ文件。若採用變量協助工作,則既可減少出錯機率,亦能簡化Makefile。變量允許先對一段文本字符串定義,以後需要書寫諸OBJ文件時,可以只輸入變量而不需要把所有OBJ文件列出(參見第六章 如何使用變量)。

此處,一個習慣性做法是,在每個Makefile中加入名為「objects」、「OBJECTS」、「objs」、「OBJS」、「obj」或者「OBJ」的變量,用以列出全部OBJ文件的名稱。在Makefile中,可以用如下方式定義變量「objects」:

 objects = main.o kbd.o command.o display.o \
               insert.o search.o files.o utils.o


定義之後,文件時需要列出諸OBJ文件處可用「$(objects)」代替(參見第六章 如何使用變量)。

下面就是用變量來描述諸OBJ文件的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)

讓make自己推算出要執行的命令

編輯

不必將每個編譯C原始碼文件的命令全部寫出,因為make可以構造出這些命令:make有一個隱規則可通過命令「cc -c」生成與「.c」文件前綴名一致的「.o」文件的命令,比如將「main.c」編譯成「main.o」的命令「cc -c main.c -o main.o」。此處可以把命令中寫「.o」的部分省略。參閱第十章 使用隱規則

當「.c」文件以下例方法自動被使用時,「.c」文件會自動加入到先決條件中。在先決條件中省略「.c」文件的同時,編譯命令也被省略了。

下面是個完整的例子。例子中包括了上面兩種省略方法,而且也使用了上一節所說的「objects」變量。

  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)


本例與實際應用中Makefile相差無幾(複雜化的「clean」規則在其他地方有所討論。參見第四章第五節 偽目標第五章第五節 命令中的報錯信息)。

隱規則使用簡便,故尤為重要。讀者會頻繁見到隱規則的使用。

另一種格式的Makefile

編輯

當組成Makefile的全為規則時,可以用另一種形式的Makefile代替前面的。下面這種形式的Makefile全部以先決條件代替,此為全文:

     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」為所有OBJ文件的先決條件;「command.h」與「buffer.h」為特定OBJ文件的先決條件。

不知這樣緊湊的寫法是否為一些人的愛好,但還是有一些人不喜歡這種寫法,認為將一個目標跟與之對應的信息寫在一起顯得比較清楚。

清理目錄的規則

編輯

編寫Makefile所要寫的不僅僅編譯程序。Makefile還能做一些編譯外的事情,比如說,如何將一個目錄里的OBJ文件與可執行文件清理乾淨。

下面就是一例,演示如何用make以完成清除工作:

     clean:
             rm edit $(objects)


在實際應用中Makefile可能會寫得更複雜,以應對突發事件,下為例:

.PHONY : clean
     clean :
             -rm edit $(objects)


本例的Makefile,可在有文件名為「clean」時避免混淆,還可在rm報錯時仍舊執行。(參見第四章第五節 偽目標第五章第五節 命令中的報錯信息

此類規則不可置於Makefile文首,這是由於一般不願讓其作為默認規則執行!故在前幾節的完整Makefile示例中,用「edit」為默認規則,以便編譯與重編譯。

因為「clean」並非「edit」的先決條件,故此規則在make沒有參數時不會運行。若要運行此規則,鍵入命令「make clean」(參見第九章 如何運行make)。

編寫Makefile

編輯

make重編譯系統的信息源於Makefile構建的資料庫。

Makefile裡包含的是什麼

編輯

「Makefile」文件應該取什麼樣的名字

編輯

包含其它的Makefile文件

編輯

「MAKEFILES」變量

編輯

「MAKEFILE_LIST」變量

編輯

其它的特殊變量

編輯

Makefile如可被make再執行

編輯

調用其它Makefile的重要技巧

編輯

make如何理解Makefile的內容

編輯

編寫規則

編輯

規則的語法結構

編輯

先決條件的種類

編輯

在文件名中使用通配符

編輯

通配符示例

編輯

使用通配符的陷阱

編輯

「wildcard」函數

編輯

為先決條件搜索目錄

編輯

「VPATH」:為所有先決條件搜索路徑

編輯

「vpath」指令

編輯

目錄搜索是如何進行的

編輯

編寫帶目錄搜索功能的Shell命令

編輯

目錄搜索與隱規則

編輯

為連接庫而做的目錄搜索

編輯

偽目標

編輯

無先決條件與命令的規則

編輯

用目標對應的空文件記錄事件

編輯

特殊內建目標的名稱

編輯

單規則使用多目標

編輯

單目標對應多規則

編輯

靜態模式規則

編輯

靜態模式規則的語法結構

編輯

靜態模式規則與隱規則的比較

編輯

帶雙冒號的規則

編輯

自動生成先決條件

編輯

編寫規則中的命令

編輯

命令的語法結構

編輯

將命令分為多行的方法

編輯

在命令中使用變量

編輯

輸出信息命令

編輯

命令的執行

編輯

選擇Shell

編輯

並行執行

編輯

命令中的報錯信息

編輯

中斷或強制結束make

編輯

遞歸使用make

編輯

make的變量是怎樣工作的

編輯

與低層的make互傳變量

編輯

與低層的make互傳選項

編輯

「--print-directory」選項

編輯

定義封裝的命令組

編輯

使用空命令

編輯

如何使用變量

編輯

變量的基本參考

編輯

變量的兩種風格

編輯

變量高級功能參考

編輯

替換功能參考

編輯

可運算的變量名

編輯

變量如何獲取其值

編輯

設置變量

編輯

向變量追加文本內容

編輯

「override」指令

編輯

逐字定義變量

編輯

來自環境變量的變量

編輯

目標特定變量的賦值

編輯

模式特定變量的賦值

編輯

Makefile的條件控制部分

編輯

條件示例

編輯

條件的語法結構

編輯

測試標誌位的條件

編輯

文本操控函數

編輯

函數調用的語法結構

編輯

對字符串做替換與分解的函數

編輯

對文件名操作的函數

編輯

條件控制函數

編輯

「foreach」函數

編輯

「call」函數

編輯

「value」函數

編輯

「eval」函數

編輯

「shell」函數

編輯

控制make的函數

編輯

如何運行make

編輯

用以確定Makefile文件的參數

編輯

用以確定最終目標的參數

編輯

用其它功能來取代執行命令的參數

編輯

避免重新編譯某些文件

編輯

初始變量

編輯

測試編譯程序

編輯

選項摘要

編輯

使用隱規則

編輯

使用隱規則

編輯

隱規則章目

編輯

隱規則使用的變量

編輯

隱規則鏈

編輯

定義與重定義模式的規則

編輯

模式的規則介紹

編輯

模式的規則示例

編輯

自變變量

編輯

模式是如何匹配的

編輯

匹配一切的模式規則

編輯

取消隱規則

編輯

定義去除依賴的默認規則

編輯

過時的附加規則

編輯

隱規則的搜索算法

編輯

使用make更新歸檔文件

編輯

歸檔成員作為目標

編輯

為歸檔成員目標而設的隱規則

編輯

更新歸檔字符目錄

編輯

使用歸檔的風險

編輯

歸檔文件的附加規則

編輯

GNU make的特色功能

編輯

GNU make與標準make不兼容的部分

編輯

GNU make的一些不成文規定

編輯

Makefile的通用習慣

編輯

Makefile的工具

編輯

指定變量的命令

編輯

安裝目錄的變量

編輯

為用戶設計的標準目標

編輯

安裝命令的條目

編輯

附錄

編輯

A 快速參考

編輯

B 常見錯誤

編輯

C 一個複雜的Makefile實例

編輯

下面是一段為GNU tar程序設計的Makefile代碼,相當複雜。

由於「all」是第一個目標,所以它也是默認目標。下面這個程序段有一個非常有趣的特色,這個特色就是原始碼程序中的「testpad.h」文件是一個由名叫testpad程序自動生成的,而這個testpad又是又是由「testpad.c」這個程序經過編譯產生的。

如果您輸入「make」或者「make all」,則make會讓名為「tar」的目標運行從而開始編譯指令,會讓名為「rmt」的目標運行從而生成一個遠程磁帶數據存取的守護程序,會讓名為 「tar.info」的目標運行從而生成INFO文檔。

如果您輸入「make install」,那麼make就執行的就不僅僅只是「tar」、「rmt」和「tar.info」這三個目標了,還會執行相應的安裝操作。< /br>
如果您輸入「make clean」,那麼make會清除所有的「.o」文件,以及「tar」、「rmt」、「testpad」、「testpad.h」和「core」這些文件。

如果您輸入「make distclean」,那麼make除了會清除「make clean」會清除的文件外,還會清除「TAGS」、「Makefile」和「config.status」這些文件(雖然不明顯,但下面這個 makefile和「config.status」都是用戶通過tar發行版中的「configure」文件生成的,這個「configure」文件這裡沒有列出)。

如果您輸入「make realclean」,那麼make除了清除「make distclean」會清除的文件外,還會清除由「tar.info」生成的INFO文檔。

# Generated automatically from Makefile.in by configure.
     # Un*x Makefile for GNU tar program.
     # Copyright (C) 1991 Free Software Foundation, Inc.
     
     # This program is free software; you can redistribute
     # it and/or modify it under the terms of the GNU
     # General Public License ...
     ...
     ...
     
     SHELL = /bin/sh
     
     #### Start of system configuration section. ####
     
     srcdir = .
     
     # If you use gcc, you should either run the
     # fixincludes script that comes with it or else use
     # gcc with the -traditional option.  Otherwise ioctl
     # calls will be compiled incorrectly on some systems.
     CC = gcc -O
     YACC = bison -y
     INSTALL = /usr/local/bin/install -c
     INSTALLDATA = /usr/local/bin/install -c -m 644
     
     # Things you might add to DEFS:
     # -DSTDC_HEADERS        If you have ANSI C headers and
     #                       libraries.
     # -DPOSIX               If you have POSIX.1 headers and
     #                       libraries.
     # -DBSD42               If you have sys/dir.h (unless
     #                       you use -DPOSIX), sys/file.h,
     #                       and st_blocks in `struct stat'.
     # -DUSG                 If you have System V/ANSI C
     #                       string and memory functions
     #                       and headers, sys/sysmacros.h,
     #                       fcntl.h, getcwd, no valloc,
     #                       and ndir.h (unless
     #                       you use -DDIRENT).
     # -DNO_MEMORY_H         If USG or STDC_HEADERS but do not
     #                       include memory.h.
     # -DDIRENT              If USG and you have dirent.h
     #                       instead of ndir.h.
     # -DSIGTYPE=int         If your signal handlers
     #                       return int, not void.
     # -DNO_MTIO             If you lack sys/mtio.h
     #                       (magtape ioctls).
     # -DNO_REMOTE           If you do not have a remote shell
     #                       or rexec.
     # -DUSE_REXEC           To use rexec for remote tape
     #                       operations instead of
     #                       forking rsh or remsh.
     # -DVPRINTF_MISSING     If you lack vprintf function
     #                       (but have _doprnt).
     # -DDOPRNT_MISSING      If you lack _doprnt function.
     #                       Also need to define
     #                       -DVPRINTF_MISSING.
     # -DFTIME_MISSING       If you lack ftime system call.
     # -DSTRSTR_MISSING      If you lack strstr function.
     # -DVALLOC_MISSING      If you lack valloc function.
     # -DMKDIR_MISSING       If you lack mkdir and
     #                       rmdir system calls.
     # -DRENAME_MISSING      If you lack rename system call.
     # -DFTRUNCATE_MISSING   If you lack ftruncate
     #                       system call.
     # -DV7                  On Version 7 Unix (not
     #                       tested in a long time).
     # -DEMUL_OPEN3          If you lack a 3-argument version
     #                       of open, and want to emulate it
     #                       with system calls you do have.
     # -DNO_OPEN3            If you lack the 3-argument open
     #                       and want to disable the tar -k
     #                       option instead of emulating open.
     # -DXENIX               If you have sys/inode.h
     #                       and need it 94 to be included.
     
     DEFS =  -DSIGTYPE=int -DDIRENT -DSTRSTR_MISSING \
             -DVPRINTF_MISSING -DBSD42
     # Set this to rtapelib.o unless you defined NO_REMOTE,
     # in which case make it empty.
     RTAPELIB = rtapelib.o
     LIBS =
     DEF_AR_FILE = /dev/rmt8
     DEFBLOCKING = 20
     
     CDEBUG = -g
     CFLAGS = $(CDEBUG) -I. -I$(srcdir) $(DEFS) \
             -DDEF_AR_FILE=\"$(DEF_AR_FILE)\" \
             -DDEFBLOCKING=$(DEFBLOCKING)
     LDFLAGS = -g
     
     prefix = /usr/local
     # Prefix for each installed program,
     # normally empty or `g'.
     binprefix =
     
     # The directory to install tar in.
     bindir = $(prefix)/bin
     
     # The directory to install the info files in.
     infodir = $(prefix)/info
     
     #### End of system configuration section. ####
     
     SRC1 =  tar.c create.c extract.c buffer.c \
             getoldopt.c update.c gnu.c mangle.c
     SRC2 =  version.c list.c names.c diffarch.c \
             port.c wildmat.c getopt.c
     SRC3 =  getopt1.c regex.c getdate.y
     SRCS =  $(SRC1) $(SRC2) $(SRC3)
     OBJ1 =  tar.o create.o extract.o buffer.o \
             getoldopt.o update.o gnu.o mangle.o
     OBJ2 =  version.o list.o names.o diffarch.o \
             port.o wildmat.o getopt.o
     OBJ3 =  getopt1.o regex.o getdate.o $(RTAPELIB)
     OBJS =  $(OBJ1) $(OBJ2) $(OBJ3)
     AUX =   README COPYING ChangeLog Makefile.in  \
             makefile.pc configure configure.in \
             tar.texinfo tar.info* texinfo.tex \
             tar.h port.h open3.h getopt.h regex.h \
             rmt.h rmt.c rtapelib.c alloca.c \
             msd_dir.h msd_dir.c tcexparg.c \
             level-0 level-1 backup-specs testpad.c
     
     .PHONY: all
     all:    tar rmt tar.info
     
     .PHONY: tar
     tar:    $(OBJS)
             $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
     
     rmt:    rmt.c
             $(CC) $(CFLAGS) $(LDFLAGS) -o $@ rmt.c
     
     tar.info: tar.texinfo
             makeinfo tar.texinfo
     
     .PHONY: install
     install: all
             $(INSTALL) tar $(bindir)/$(binprefix)tar
             -test ! -f rmt || $(INSTALL) rmt /etc/rmt
             $(INSTALLDATA) $(srcdir)/tar.info* $(infodir)
     
     $(OBJS): tar.h port.h testpad.h
     regex.o buffer.o tar.o: regex.h
     # getdate.y has 8 shift/reduce conflicts.
     
     testpad.h: testpad
             ./testpad
     
     testpad: testpad.o
             $(CC) -o $@ testpad.o
     
     TAGS:   $(SRCS)
             etags $(SRCS)
     
     .PHONY: clean
     clean:
             rm -f *.o tar rmt testpad testpad.h core
     
     .PHONY: distclean
     distclean: clean
             rm -f TAGS Makefile config.status
     
     .PHONY: realclean
     realclean: distclean
             rm -f tar.info*
     
     .PHONY: shar
     shar: $(SRCS) $(AUX)
             shar $(SRCS) $(AUX) | compress \
               > tar-`sed -e '/version_string/!d' \
                          -e 's/[^0-9.]*\([0-9.]*\).*/\1/' \
                          -e q
                          version.c`.shar.Z
     
     .PHONY: dist
     dist: $(SRCS) $(AUX)
             echo tar-`sed \
                  -e '/version_string/!d' \
                  -e 's/[^0-9.]*\([0-9.]*\).*/\1/' \
                  -e q
                  version.c` > .fname
             -rm -rf `cat .fname`
             mkdir `cat .fname`
             ln $(SRCS) $(AUX) `cat .fname`
             tar chZf `cat .fname`.tar.Z `cat .fname`
             -rm -rf `cat .fname` .fname
     
     tar.zoo: $(SRCS) $(AUX)
             -rm -rf tmp.dir
             -mkdir tmp.dir
             -rm tar.zoo
             for X in $(SRCS) $(AUX) ; do \
                 echo $$X ; \
                 sed 's/$$/^M/' $$X \
                 > tmp.dir/$$X ; done
             cd tmp.dir ; zoo aM ../tar.zoo *
             -rm -rf tmp.dir

D GNU 自由文檔許可證

編輯

GNU 自由文檔許可證