close

Makefile 中 .PHONY 的意思
Oct. 31, 2016

Makefile 是一個用來管理編譯的軟體。一個目標(target)以冒號隔開必需品(prerequisite),而左邊(目標)的最後修改日期必須晚於右邊的每一個,否則緊接的食譜(recipe)會被執行。例如我要做番茄義大利麵,要煮肉醬,要煮麵。如果麵是新買來的,我就會煮新的麵,不吃前一天我煮的隔夜的麵。

大家常會看到Makefile中常常有“.PHONY: clean”,用來刪除編譯的檔案。我聽說是因為,clean並不是實際的檔案,而是一個動作(刪除),所以為免資料夾裡有“clean”這個檔案,使電腦搞混而不執行,我們宣告他為 .PHONY 的必需品。“phony”的意思就是“虛假的”,或是我想“___(消音)就是矯情”比較貼切。

但是,當 phony 目標有必需品時,哪些必需品會被重做呢,又如何決定呢? 畢竟phony 目標並沒有最後修改日期。而且,當 phony 目標的必需品都有了,食譜依然會被執行嗎,就像剛才講的嗎? 

出於好奇,我做了一個小實驗,針對“all”。記得,如果你只打 make,那麼相當於 “make all”。我現在放這個Makefile

all: f1
    @echo recipe \`\`all\'\' executed.
f1:
    @echo process 1:
    touch f1
f2:
    @echo process 2:
    touch f2
clean:
    rm f1
    rm f2
.PHONY: clean

當f1和f2皆不存在,我按make,當然會出現輸出
process 1:
touch f1
process 2:
touch f2
recipe ``all'' executed.
也就是兩個都被製作。當我再按一次make,則是輸出
make: `all' is up to date.
也就是未經過“all”的食譜。

現在按“make clean”刪除f1和f2,回到原點。我若製造一個空的檔案“touch all”;接著按make,固然會製造f1和f2;再按一次make,則一樣是輸出
recipe ``all'' executed.
繼續按仍是一樣的。因為空檔案“all”的時間較早,電腦同樣認為“all”需要重做。

再按“make clean”刪除f1和f2,重新開始。這次我若先按make以製造f1和f2,然後再“touch all”。此時再按一次make,卻是輸出
make: `all' is up to date.
也就是空檔案“all”遮蔽了“all”的食譜,才沒有執行。電腦以為我講的是空檔案“all”,而且空檔案已經晚於右式了。

緊接著,我把makefile多加一行
.PHONY: all
存擋並且再按make,發現輸出
recipe ``all'' executed.
也就是的確經過了all的食譜。再按也是一樣。以上和我想的一樣,小確幸。

於是我的理解是, 一個目標若是 .PHONY 的必需品,該目標本身的食譜永遠會執行。當然,在食譜之前,必須確定必需品存在,而他們只要存在,就不會被重製;若不存在,當然會先製作了。特別地,若該 phony 目標沒有必需品,就會直接執行食譜,像一開頭講的。換言之,一個phony目標,其實就相當於開天闢地之時就存在的檔案,永遠會比較早。

這個問題在stack overflow 有人討論,但中文的網站比較沒有,我就記錄一下。

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 QED314159 的頭像
    QED314159

    定理至此證畢。

    QED314159 發表在 痞客邦 留言(1) 人氣()