makefile中PHONY的重要性

    僞目標是這樣一個目標:它不表明一個真正的文件名,在執行make時能夠指定這個目標來執行所在規則定義的命令,有時也能夠將一個僞目標稱爲標籤。僞目標經過PHONY來指明。spa

     PHONY定義僞目標的命令必定會被執行,下面嘗試分析這種優勢的妙處。調試

一、若是咱們指定的目標不是建立目標文件,而是使用makefile執行一些特定的命令,例如:blog

clean:
        rm *.o temp

  咱們但願,只要輸入」make clean「後,」rm *.o temp「命令就會執行。可是,噹噹前目錄中存在一個和指定目標重名的文件時,例如clean文件,結果就不是咱們想要的了。輸入」make clean「後,「rm *.o temp」 命令必定不會被執行。io

    解決的辦法是:將目標clean定義成僞目標就成了。不管當前目錄下是否存在「clean」這個文件,輸入「make clean」後,「rm *.o temp」命令都會被執行。編譯

  注意:這種作法的帶來的好處還不止此,它同時提升了make的執行效率,由於將clean定義成僞目標後,make的執行程序不會試圖尋找clean的隱含規則。class

二、PHONY能夠確保源文件(*.c *.h)修改後,對應的目標文件會被重建。假若缺乏了PHONY,能夠看到狀況會很糟。test

    如今作一個實驗,實驗的目錄是/work,在這個目錄中,包含了四個目錄test、add、sub、include 和一個頂層目錄makefile文件。test、add、sub三個目錄分別包含了三個源程序test.c、add.c、sub.c和三個子目錄makefile,目錄include的是頭文件heads.h的目錄,分別展開四個目錄的內容以下。效率

test目錄
//test.c
#include <stdio.h>
#include "../include/heads.h"
int main()
{
        int a=15,b=16;

        printf("a+b=%d\n",add(a,b));

        return 0;
}

makefile
test.o:test.c ../include/heads.h 
    gcc -c -o $@ $<
.PHONY: clean
clean:
  rm -f *.o

    add目錄gcc

//add.c
#include "../include/heads.h"
int add(int a,int b)
{
        return (a+b);
}

makefile
add.o :add.c ../include/heads.h
    gcc -c -o $@ $< 

.PHONY: clean 
clean: 
    rm -f *.o

  sub目錄date

//sub.c
#include "../include/heads.h"
int sub(int a,int b)
{
        return a-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僞目標能夠解決源文件不是最終目標直接依賴(實際上能夠認爲是間接依賴)帶來的不能自動檢查更新規則。

相關文章
相關標籤/搜索