Makefile偽目標

來源:互聯網
上載者:User

偽目標是這樣一個目標:它不代表一個真正的檔案名稱,在執行make時可以指定這個目標來執行其所在規則定義的命令,有時我們也可以將一個偽目標稱為標籤。使用偽目標有兩點原因:1. 避免在我們的Makefile中定義的只執行命令的的目標(此目標的目的為了執行執行一系列命令,而不需要建立這個目標)和工作目錄下的實際檔案出現名字衝突。2. 提高執行make時的效率,特別是對於一個大型的工程來說,編譯的效率也許你同樣關心。以下就這兩個問題我們進行分析討論: 

1. 如果我們需要書寫這樣一個規則:規則所定義的命令不是去建立目標檔案,而是使用make指定具體的目標來執一些特定的命令。像下邊那樣: 

clean: 

rm *.o temp 

 

規則中“rm”不是建立檔案“clean”的命令,只是刪除目前的目錄下的所有.o檔案和temp檔案。在工作目錄下不存在“clean”這個檔案時,我們輸入“make clean”後,“rm *.o temp”總會被執行。這是我們的初衷。 

但當前工作目錄下存在檔案“clean”時情況就不一樣了,在我們輸入“make clean”時。規則沒有依賴檔案,所以目標被認為是最新的而不去執行規則作定義的命令,命令“rm”將不會被執行。這並不是我們的初衷。為了避免這個問題,我們可以將目標“clean”明確的聲明為偽目標。將一個目標聲明為偽目標需要將它作為特殊目標.PHONY”的依賴。如下: 

.PHONY : clean 

這樣目標“clean”就是一個偽目標,無論目前的目錄下是否存在“clean”這個檔案。我們輸入“make clean”之後。“rm”命令都會被執行。而且,當一個目標被聲明為偽目標後,make在執行此規則時不會試圖去尋找隱含規則來建立這個目標。這樣也提高了make的執行效率,同時我們也不用擔心由於目標和檔案名稱重名而使我們的期望失敗。在書寫偽目標規則時,首先需要聲明目標是一個偽目標,之後才是偽目標的規則定義。目標“clean”書寫格式應該如下: 

.PHONY: clean 

clean: 

rm *.o temp 

2. 偽目標的另外一使用場合在make的並行和遞迴執行過程中。此情況下一般存在一個變數,其定義為所有需要make的子目錄。對多個目錄進行make的實現方式可以在一個規則中可以使用shell的迴圈來完成。如下: 

SUBDIRS = foo bar baz 

subdirs: 

for dir in $(SUBDIRS); do \ 

$(MAKE) -C $$dir; \ 

done 

但這種實現方法存在以下幾個問題。1. 當子目錄執行make出現錯誤時,make不會退出。就是說,在對某一個目錄執行make失敗以後,會繼續對其他的目錄進行make。在最終執行失敗的情況下,我們很難根據錯誤的提示定位出具體是是那個目錄下的Makefile出現錯誤。這給問題定位造成了很大的困難。為了避免這樣的問題,我們可以在命令列部分加入錯誤的監測,在命令執行錯誤後make退出。不幸的是,如果在執行make時使用了“-k”選項,此方式將失效。2. 另外一個問題就是使用這種shell的迴圈方式時,沒有用到make對目錄的平行處理功能,因為規則的命令是一條完整的shell命令,不能被並行的執行。 

我們可以通過偽目標方式來克服以上實現方式所存在的兩個問題。 

SUBDIRS = foo bar baz 

.PHONY: subdirs $(SUBDIRS) 

subdirs: $(SUBDIRS) 

$(SUBDIRS): 

$(MAKE) -C $@ 

foo: baz 

上邊的實現中使用了一個沒有命令列的規則“foo: baz”,用來限制子目錄的make順序。此規則的含義時在處理“foo”目錄之前,需要等待“baz”目錄處理完成。在書寫一個並存執行make的Makefile時,目錄的處理順序是需要特別注意的。 

一般情況下,一個偽目標不作為一個另外一個目標檔案的依賴。這是因為當一個目標檔案的依賴包含偽目標時,每一次在執行這個規則時偽目標所定義的命令都會被執行(因為它是規則的依賴,重建規則目標檔案時需要首先重建它的依賴)。當偽目標沒有作為任何目標(此目標是一個可被建立或者已存在的檔案)的依賴時,我們只能通過make的命令列選項明確指定這個偽目標,來執行它所定義的命令。例如我們的“make clean”。 

Makefile中,偽目標可以有自己的依賴。在一個目錄下如果需要建立多個可執行程式,我們可以將所有程式的重建規則在一個Makefile中描述。因為Makefile中第一個目標是“終極目標”,約定的做法是使用一個稱為“all”的偽目標來作為終極目標,它的依賴檔案就是那些需要建立的程式。下邊就是一個例子: 

#sample Makefile 

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時,目標“all”被作為終極目標。為了完成對它的更新,make會建立(不存在)或者重建(已存在)目標“all”的所有依賴檔案(prog1、prog2和prog3)。當需要單獨更新某一個程式時,我們可以通過make的命令列選項來明確指定需要重建的程式。(例如: “make prog1”)。 當一個偽目標作為另外一個偽目標依賴時,make將其作為另外一個偽目標的子常式來處理(可以這樣理解:其作為另外一個偽目標的必須執行的部分,就行C語言中的函數調用一樣)。下邊的例子就是這種用法: 

.PHONY: cleanall cleanobj cleandiff 

cleanall : cleanobj cleandiff 

rm program 

cleanobj : 

rm *.o 

cleandiff : 

rm *.diff 

“cleanobj”和“cleandiff”這兩個偽目標有點像“子程式”的意思(執行目標“clearall時會觸發它們所定義的命令被執行”)。我們可以輸入“make cleanall”和“make cleanobj”和“make cleandiff”命令來達到清除不同種類檔案的目的。例子首先通過特殊目標“.PHONY”聲明了多個偽目標,它們之間使用空各分割,之後才是各個偽目標的規則定義。 

說明: 

通常在清除檔案的偽目標所定義的命令中“rm”使用選項“–f”(--force)來防止在缺少刪除檔案時出錯並退出,使“make clean”過程失敗。也可以在“rm”之前加上“-”來防止“rm”錯誤退出,這種方式時make會提示錯誤資訊但不會退出。為了不看到這些討厭的資訊,需要使用上述的第一種方式。 

另外make存在一個內嵌隱含變數“RM”,它被定義為:“RM = rm –f”。因此在書寫“clean”規則的命令列時可以使用變數“$(RM)”來代替“rm”,這樣可以免出現一些不必要的麻煩!這是我們推薦的用法。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.