偽目標是這樣乙個目標:它不代表乙個真正的檔名,在執行make時可以指定這個目標來執行所在規則定義的命令,有時也可以將乙個偽目標稱為標籤。偽目標通過 phony來指明。
phony定義偽目標的命令一定會被執行,下面嘗試分析這種優點的妙處。
1、如果我們指定的目標不是建立目標檔案,而是使用makefile執行一些特定的命令,例如:
clean:
rm *.o temp
我們希望,只要輸入」make clean「後,」rm *.o temp「命令就會執行。但是,當當前目錄中存在乙個和指定目標重名的檔案時,例如clean檔案,結果就不是我們想要的了。輸入」make clean「後,「rm *.o temp」 命令一定不會被執行。
解決的辦法是,將目標clean定義成偽目標就成了。無論當前目錄下是否存在「clean」這個檔案,輸入「make clean」後,「rm *.o temp」命令都會被執行。
注意:這種做法的帶來的好處還不止此,它同時提高了make的執行效率,因為將clean定義成偽目標後,make的執行程式不會試圖尋找clean的隱含規則。
2、phony可以確保原始檔(*.c *.h)修改後,對應的目標檔案會被重建。倘若缺少了phony,可以看到情況會很糟。
現在做乙個實驗,實驗的目錄是/work,在這個目錄中,包含了四個目錄test、add、sub、include 和乙個頂層目錄makefile檔案。test、add、sub三個目錄分別包含了三個源程式test.c、add.c、sub.c和三個子目錄makefile,目錄include的是標頭檔案heads.h的目錄,分別展開四個目錄的內容如下。
test目錄
test.c
#include #include "../include/heads.h"
int main()
makefile
test.o:test.c ../include/heads.h
gcc -c -o $@ $<
.phony: clean
clean:
rm -f *.o
add目錄
add.c
#include "../include/heads.h"
int add(int a,int b)
makefile
add.o :add.c ../include/heads.h
gcc -c -o $@ $<
.phony: clean
clean:
rm -f *.o
sub目錄
sub.c
#include "../include/heads.h"
int sub(int a,int b)
makefile
sub.o:sub.c ../include/heads.h
gcc -c -o $@ $<
.phony: clean
clean:
rm -f *.o
inlcude目錄
heads.h
#ifndef _head_h_
#define _head_h_
extern int add(int,int);
extern int sub(int,int);
#endif
頂層makefile檔案
objs = ./add/add.o ./sub/sub.o ./test/test.o
program: $(objs)
gcc ./test/test.o ./add/add.o ./sub/sub.o -o program
$(objs):
make -c $(dir $@)
.phony: clean
clean:
make -c ./add clean
make -c ./sub clean
make -c ./test clean
rm -f program
編譯除錯:當在/work目錄中,執行make後,編譯出了program應用程式。修改了任意乙個原始檔(test.c、sub.c、add.c、heads.h)例如test.c,重新在/work目錄中執行make,發現一直提示「make: `program' is up to date.」 ,而不能重建test.o,更不用說重建program。
修改頂層makefile檔案,新增紅色的一行
objs = ./add/add.o ./sub/sub.o ./test/test.o
program: $(objs)
gcc ./test/test.o ./add/add.o ./sub/sub.o -o program
.phony : $(objs)
$(objs):
make -c $(dir $@)
.phony: clean
clean:
make -c ./add clean
make -c ./sub clean
make -c ./test clean
rm -f program
加上偽目標修改後,問題就會解決。修改了任意乙個原始檔,執行make對應的目標檔案就會重建,最後重建program。即使不修改原始檔,執行make也會進入源檔案目錄中執行子make,但不會更新目標檔案,最後還要重建program。
原因分析:由於(*.c *.h)- - > (*.o)- - > (program),修改前的頂層目標(program)依賴於(*.o)。執行make時,檢查 (program)的依賴(*.o)是否比(program)新,而不會檢查(*.h *.c)是否比(program)新,(*.h *.c)不是(program)的依賴。顯然,(*.o)沒有program新,所以不用重建。
注意修改後的makefile,把./add/add.o ./sub/sub.o ./test/test.o當做三個偽目標,所以不會再檢查 (program)的依賴(*.o)是否比(program)新。而原來的makefile中把./add/add.o ./sub/sub.o ./test/test.o當做三個依賴檔案。可以說加上「phony」後,make程式對./add/add.o ./sub/sub.o ./test/test.o的看法已經完全不一樣了。
修改後的makefile,強制執行./add/add.o ./sub/sub.o ./test/test.o這三個偽目標的命令,即進入相應的子目錄執行make,從而呼叫相應的子目錄makefile。由於子目錄中的makefile目標是(*.o),目標的依賴是(*.c heads.h),會檢查(*.c heads.h)是否比(*.o)新,從而有可能重建(*.o)。而在跳回到頂層makefile後,還要執行「 gcc ./test/test.o ./add/add.o ./sub/sub.o -o program」。
總結:phony偽目標可以解決原始檔不是最終目標直接依賴(實際上可以認為是間接依賴)帶來的不能自動檢查更新規則。
MAKEFILE中 PHONY的作用
本文 main1.c include intmain void main2.c include intmain void 分析 這裡需要生成兩個可執行檔案main1和main2 兩個目標 由於makefile只能有乙個目標,所以可以構造乙個沒有規則的終極目標all,並以這兩個可執行檔案作為依賴。如下...
Makefile中 PHONY的作用
拿clean舉例,如果make完成後,自己另外定義乙個名叫clean的檔案,再執行make clean時,將不會執行rm命令。為了避免出現這個問題,需要.phony clean 圖示 1 不新增.phony clean 在makefile所在的目錄下touch乙個clean檔案 執行make 執行m...
makefile中的all和 PHONY的作用
請編寫乙個makefile同時編譯 鏈結下面兩個程式 main1.c include int main void main2.c include int main void 分析 這裡需要生成兩個可執行檔案main1和main2 兩個目標 由於makefile只能有乙個目標,所以可以構造乙個沒有規則...