GNU make手冊翻譯系列(4)

4.5 僞目標

      有這麼一種目標,它不代表一個真正的文件名,執行make時可以指定這個目標來執行其所在規則定義的一系列配方,這種目標就叫僞目標.使用僞目標有兩個原因:一個是避免跟同名文件出現衝突,另一個是提高執行make 時的效率.

      如果你要書寫這麼一條規則:它的配方不會創建目標文件,並且反覆指定make該目標時,它的配方都會被執行.下面就是一個例子:

clean:

        rm*.o temp
由於rm命令並不會創建一個名爲"clean"的文件,當前目錄下通常也不會存在這個同名文件,所以每次你輸入"makeclean",規則中的rm命令總會被執行.

      在這個例子中,如果當前目錄下已經存在一個名爲"clean"的文件時,則目標"clean"所在的規則就不會被執行.因爲沒有依賴,目標"clean",也就是文件"clean",總被認爲是最新的,所以它的配方將不會被執行.爲了避免這個問題,你需要將目標"clean"聲明爲僞目標,方法是將它作爲特殊目標".PHONY"的依賴,如下:

.PHONY: clean

clean:

        rm*.o temp
目標"clean"聲明爲僞目標之後,無論在當前目錄下是否存在"clean"這個文件,輸入"makeclean"後都會執行目標"clean"對應的配方.

      僞目標在make程序執行遞歸的過程中同樣有用.在這種情況中,Makefile通常包含了這麼一個變量,該變量定義爲所有需要make的子目錄.處理這類場景的一種簡單的方法是定義一條規則,在規則的配方中使用shell循環遍歷每個子目錄進行make,就像下面這樣:

SUBDIRS= foo bar baz

subdirs:

        fordir in $(SUBDIRS); do \

            $(MAKE)-C $$dir;\

        done
但這種方法存在幾個問題.第一,子目錄中執行make時出現的任何錯誤都會被忽略掉,就是說,在對某一個目錄執行make失敗以後,會繼續對其他的目錄進行make.儘管可以在配方中添加出錯檢測並退出的shell命令,不幸的是,如果在執行make 時使用了"-k"選項,此方法將失效.第二,更重要的一點是,這種方法使你無法利用make並行處理規則目標的功能,因爲只有一條規則.

      將子目錄聲明爲僞目標(必須這樣做,因爲子目錄顯然總是存在的),就可以解決這些問題:

SUBDIRS= foo bar baz

.PHONY: subdirs $(SUBDIRS)

subidrs: $(SUBDIRS)

        $(MAKE)-C $@

foo: baz
這裏我們還聲明瞭一條規則"foo: baz",這條規則用來確保只有在子目錄"baz"make完畢後纔會對子目錄"foo"執行make.make並行處理規則目標時,這種順序關係聲明特別重要.

        make程序不會對僞目標嘗試搜索隱含規則,也不關心是否存在和僞目標同名的文件,這也就是爲什麼將目標聲明爲僞目標可以提高make執行效率的原因.

      僞目標通常不會作爲一個真正的目標文件的依賴,這是因爲如果僞目標成爲一個目標文件的依賴時,每次make程序嘗試刷新該目標文件時,作爲依賴的僞目標,其配方必然會被執行.只要僞目標不作爲一個真正目標的依賴,那麼該僞目標的配方只會在make程序顯式指定執行該目標時被執行.

      僞目標可以有自己的依賴.當一個目錄下需要創建多個可執行程序時,一種最方便的方法就是將所有程序的重建規則在一個Makefile中進行描述.因爲Makefile中第一個目標就是默認目標,約定的做法是使用一個稱爲"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"就可以構建所有的程序,或者在make的命令行參數中指定要構建的程序(比如"makeprog1 prog3").僞目標的特性是不會被繼承的:除非特定聲明某個目標爲僞目標,否則僞目標的依賴不會也變成僞目標.

      當一個僞目標作爲另外一個僞目標的依賴時,make程序會將該僞目標作爲另外一個僞目標的子程序來處理.在下面這個例子中,輸入"makeclean"就會刪除所有".o"文件,".diff"文件,以及"program"文件:

.PHONY: cleanall cleanobj cleandiff

cleanall: cleanobj cleandiff

        rm program

cleanobj:

        rm *.o

cleanobj:

        rm *.diff
(這裏似乎缺少關於上面這個例子的講解內容)    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章