偽目標makefile的乙個重要的特殊目標。偽目標:它不代表乙個真正的檔名,在執行make時可以指定這個目標來執行其所在規則定義的命令,也可以將乙個偽目標稱為標籤。
使用偽目標有兩點原因:
1)避免在我們的makefile中定義的只執行命令的目標(就是說定義該目標的目的是為了執行一系列的命令,比如clean,為了執行rm的一些操作)和工作目錄下的實際檔案出現名字衝突。
2)提高執行make時的效率,特別是對於乙個大型的工程來說,編譯的效率也許你同樣關心,以下就這兩個問題我們進行分析討論
如果我們需要書寫這樣乙個規則:規則定義的命令不是去建立目標檔案,而是通過make命令列明確指定它來執行一些特定的命令,像常見的clean目標:
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迴圈來完成(python中的迴圈方式,指令碼語言,只不過shell的列表和python的不太一樣)。如下:
subdirs=foo bar baz
subdirs:
fordirin
$(subdirs)
;do\
$(make)
-c $$dir
;\ done
但這種實現方法存在以下幾個問題。
1)當子目錄執行make出現錯誤時,make不會退出,就是說,在對某乙個目錄執行make失敗以後,會繼續對其他的目錄進行make,在最終執行失敗的情況下,我們很難根據錯誤提示定位出具體是在那個目錄下執行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過程(在處理「foo」目錄之前,需要等待「baz」目錄處理完成)。提醒大家:在書寫乙個並行執行make的makefile時,目錄的處理順序是需要特別注意的。
一般情況下,乙個偽目標不作為另乙個目標的依賴,這是因為當乙個目標檔案的依賴包含偽目標時,每一次在執行這個規則時偽目標所定義的命令都會被執行(因為它作為規則的依賴,重建規則目標時需要首先重建規劃的所有依賴檔案),當乙個偽目標沒有作為任何目標(此目標乙個可以被建立或者已存在的檔案)的依賴時,我們只能通過make的命令列來表明明確指定它為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"這兩個偽目標有點像「子程式」的意思(執行目標「cleanall」時會觸發它們所定義的命令被執行)。我們可以輸入「make cleanall」 和」make cleanobj「和」make cleandiff「命令來達到清除不同種類檔案的目的,例子首先通過特殊目標".phony"宣告了多個偽目標,它們之間使用空格分隔,之後才是各個偽目標的規則定義。
說明:通常在清除檔案clean的命令中」rm「使用選項」-f「(–force)來防止在缺少刪除檔案時出錯並退出,使」make clean「過程失敗,也可以在」rm「之前加上」-「來防止」rm「錯誤退出,這種方式時make會提示錯誤資訊但不會退出,為了不看到這些討厭的資訊,需要使用上述的第一種方式。
另外make存在乙個內嵌隱含資訊變數」rm「,它被定義為:」rm = rm -f「,因此在書寫」clean「規則的命令行時可以**使用變數」$rm「**來代替」rm「,這樣可以避免出現一些不必要的麻煩!
嵌入式學習Makefile
make是乙個工具,用來構建和管理軟體享目。之前是個編譯乙個hello.c的程式需要一條gcc命令。但是乙個軟體工程有大量的原始檔需要gcc編譯,手工逐條敲命令編譯顯然是低效且浪費時間的。make能夠使整個軟體工程的編譯,鏈結只需要乙個命令就可以完成。makefile檔案中記錄了一系列規則 targ...
嵌入式Linux學習歷程 Makefile
makefile用來完成以下功能 1 如果工程沒有編譯過,那麼工程中的所有.c檔案都要被編譯並且鏈結成可執行檔案。2 如果工程中只有個別c檔案被修改了,那麼只編譯這些被修改的c檔案。3 如果工程的標頭檔案被修改了,那麼需要編譯所有引用這個標頭檔案的c檔案,並且鏈結成可執行檔案。例 乙個工程 通過鍵盤...
嵌入式筆記之Makefile
1 src shell ls c 2 objs patsubst c,o,src 3 test objs 4 gcc o 5 o c 6 gcc c o 7 cleam 8 rm f test o 注 在makefile編寫規則中,表示規則的目標檔名,表示所有不重複的依賴檔名,表示第乙個依賴檔名。假...