天天看點

PHONY的用法以及意義

拾遺是自己平時查閱另一個資料,然後引申出來的知識了解,答應自己,寫完這個趕緊去睡覺咯,明早還有大物課

PHONY的用法以及意義:以下内容來自于stackoverflow上面的一個問題的翻譯以及對一些部落格的總結和自己的一些了解https://stackoverflow.com/questions/2145590/what-is-the-purpose-of-phony-in-a-makefile

這是大牛的原回答,我把大概意思精簡一下:

By default, Makefile targets are "file targets" - they are used to build files from other files. Make assumes its target is a file, and this makes writing Makefiles relatively easy:

foo: bar
  create_one_from_the_other foo bar
           

However, sometimes you want your Makefile to run commands that do not represent physical files in the file system. Good examples for this are the common targets "clean" and "all". Chances are this isn't the case, but you may potentially have a file named 

clean

 in your main directory. In such a case Make will be confused because by default the 

clean

 target would be associated with this file and Make will only run it when the file doesn't appear to be up-to-date with regards to its dependencies.

These special targets are called phony and you can explicitly tell Make they're not associated with files, e.g.:

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

Now 

make clean

 will run as expected even if you do have a file named 

clean

.

In terms of Make, a phony target is simply a target that is always out-of-date, so whenever you ask 

make <phony_target>

, it will run, independent from the state of the file system. Some common 

make

 targets that are often phony are: 

all

install

clean

distclean

TAGS

info

check

.

就是說makefile認為你寫一個指令,比如說是clean,是一個目标檔案,這樣Make這個指令會認為clean是一個檔案,這樣讓編寫makefile更加的容易,但是有個問題,如果說和你的makefile同級目錄下還有一個clean的檔案,那麼你去make clean就會失敗,這時候你就需要用PHONY,說明這個是一個假的目标檔案,這樣你的make clean 就會成功執行,否則就會彈出 makefile is

 up to date,你需要使用PHONY 的場合還有:

all

install

clean

distclean

TAGS

info

check

.這些時候

a phony target is simply a target that is always out-of-date 這句話很經典啊,一個phony的目标檔案就像是一個過時的目标檔案

有個人提出了一個問題:So, if 

a: b

b: c

c: ph

 where 

ph

 is 

.PHONY

, you ask for 

a

, and 

b

 is up-to-date, your comment implies that 

ph

 will be run. In fact, none of 

a

b

c

 can ever be up-to-date, actually.

這個東西我會這周周末的時候試一下,因為要準備機率論的考試,累的一匹。。。

有這樣一個例子大家可以參考:

NOTE: The make tool reads the makefile and checks the modification time-stamps of the files at both the side of ':' symbol in a rule.

Example

In a directory 'test' following files are present:

[email protected]:~/test$ ls
hello  hello.c  makefile
           

In makefile a rule is defined as follows:

hello:hello.c
    cc hello.c -o hello
           

Now assume that file 'hello' is a text file containing some data, which was created after 'hello.c' file. So the modification (or creation) time-stamp of 'hello' will be newer than that of the 'hello.c'. So when we will invoke 'make hello' from command line, it will print as:(假設hello這個file包含一些資料,)

make: `hello' is up to date.
           

Now access the 'hello.c' file and put some white spaces in it, which doesn't affect the code syntax or logic and then save and quit. Now the modification time-stamp of hello.c is newer than that of the 'hello'. Now if you invoke 'make hello', it will execute the commands as:(這段和上面那段的大概意思就是你本來有一個hello的文本檔案,但是你gcc之後生成了一個hello的可執行檔案,這個就會覆寫原本的hello文本檔案)

cc hello.c -o hello
           

And the file 'hello' (text file) will be overwritten with a new binary file 'hello' (result of above compilation command).

If we use .PHONY in makefile as follow:

.PHONY:hello

hello:hello.c
    cc hello.c -o hello
           

and then invoke 'make hello', it will ignore if any file present in the pwd named 'hello' and execute the command every time.

Now suppose if no dependencies of target is there in makefile:(假設他沒有依賴檔案)

hello:
    cc hello.c -o hello
           

and 'hello' file is already present in the pwd 'test', then 'make hello' will always show as:

make: `hello' is up to date.
           

還有一個例子,我會在周末的時候一并翻譯,另外一個關于PHONY用法的範例:

There's also one important tricky treat of ".PHONY" - when a physical target depends on phony target that depends on another physical target:

TARGET1 -> PHONY_FORWARDER1 -> PHONY_FORWARDER2 -> TARGET2

You'd simply expect that if you updated TARGET2, then TARGET1 should be considered stale against TARGET1, so TARGET1 should be rebuild. And it really works this way.

The tricky part is when TARGET2 isn't stale against TARGET1 - in which case you should expect that TARGET1 shouldn't be rebuild.

This surprisingly doesn't work because: the phony target was run anyway (as phony targets normally do), which means that the phony target was considered updated. And because of that TARGET1 is considered stale against the phony target.

Consider:

all: fileall

fileall: file2 filefwd
    echo file2 file1 >fileall


file2: file2.src
    echo file2.src >file2

file1: file1.src
    echo file1.src >file1
    echo file1.src >>file1

.PHONY: filefwd
.PHONY: filefwd2

filefwd: filefwd2

filefwd2: file1
    @echo "Produced target file1"


prepare:
    echo "Some text 1" >> file1.src
    echo "Some text 2" >> file2.src
           

You can play around with this:

  • first do 'make prepare' to prepare the "source files"
  • play around with that by touching particular files to see them updated

You can see that fileall depends on file1 indirectly through a phony target - but it always gets rebuilt due to this dependency. If you change the dependency in 

fileall

 from 

filefwd

 to 

file

, now 

fileall

 does not get rebuilt every time, but only when any of dependent targets is stale against it as a file.

如果你想了解更多的關于PHONY的知識還是得浏覽官方文檔,周末我會浏覽官方文檔: https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html

繼續閱讀