Categories
makefile phony-target

What is the purpose of .PHONY in a Makefile?

2264

What does .PHONY mean in a Makefile? I have gone through this, but it is too complicated.

Can somebody explain it to me in simple terms?

    2568

    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.

    15

    • 77

      @eSKay: ‘why is it called ‘phony’?’ — because it’s not a real target. That is, the target name isn’t a file that is produced by the commands of that target.

      – Bernard

      Jan 27, 2010 at 9:41

    • 144

      @Lazer: I don’t know if you’re a native english speaker. I’m not. the word phony does not mean what it sounds like. en.wiktionary.org/wiki/phony says: Fraudulent; fake; having a misleading appearance.

      – Bahbar

      Aug 26, 2010 at 10:58

    • 69

      This answer is not exactly complete – although it may be addressed in the linked tutorial. .PHONY forces a label/file in a Makefile to be built if it’s part of the topological-sort of whatever your target is. That is to say, if you have a ‘cleanup:’ label that is set phony, and the your install label is defined with cleanup as a prerequisite – i.e. ‘install: cleanup’, cleanup will always be run when the Makefile attempts to build ‘install’. This is useful for steps you always want taken regardless if they’re successful – it will ignore timestamps and just force it.

      Mar 27, 2013 at 9:10


    • 20

      Note that you don’t need to use .PHONY as long as you don’t have a file with the same name as the task. The task will always be executed anyway, and the Makefile will be more readable.

      – Bernard

      Jul 22, 2016 at 3:11

    • 47

      “a phony target is simply a target that is always out-of-date” – great explanation!

      – Danijel

      Nov 6, 2018 at 9:54

    816

    Let’s assume you have install target, which is a very common in makefiles. If you do not use .PHONY, and a file named install exists in the same directory as the Makefile, then make install will do nothing. This is because Make interprets the rule to mean “execute such-and-such recipe to create the file named install“. Since the file is already there, and its dependencies didn’t change, nothing will be done.

    However if you make the install target PHONY, it will tell the make tool that the target is fictional, and that make should not expect it to create the actual file. Hence it will not check whether the install file exists, meaning: a) its behavior will not be altered if the file does exist and b) extra stat() will not be called.

    Generally all targets in your Makefile which do not produce an output file with the same name as the target name should be PHONY. This typically includes all, install, clean, distclean, and so on.

    7

    • 8

      @PineappleUndertheSea The accepted answer has been improved significantly from its initial level of worthlessness, and is now just as good as this one. I had to look through its revision history to understand your comment.

      Dec 2, 2014 at 10:30

    • 2

      This seems kinda pointless since I’ll never have files named ‘install’ or the like in my codebase. Most files are going to have a file extension, and the files without a file extension are usually in all caps, like ‘README’. Then again, if you have a bash script named ‘install’ instead of ‘install.sh’, you are going to have a bad time.

      Jan 18, 2015 at 17:02


    • 8

      @JasonTu This is not necessarily true. Bash scripting conventions ask you to omit the .sh or .bash extension for “programs” that run like they have a main function and reserve adding an extension for libraries you include (source mylib.sh). In fact, I got to this SO question because I had a script in the same directory as my Makefile called install

      – Kyle

      Feb 15, 2016 at 19:26

    • 12

      @Kyle Yes, I’m not sure what my past self meant. These days I use .PHONY all the time…

      Feb 15, 2016 at 22:43

    • 5

      @JasonTu The solution here is simple: build a time machine and “replace” your past self. I recommend taking a shovel along with you so that no one realizes you’re the .PHONY version.

      Jun 25, 2018 at 1:51

    194

    +50

    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:

    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 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:

    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 any file present in the pwd ‘test’ and execute the command every time.

    Now suppose, that ‘hello’ target has no dependencies declared:

    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.
    

    2

    • 13

      Not only does this make the commands that I run make sense, this finally causes make as a whole to make sense, it’s all about the files! Thank you for this answer.

      – Kzqai

      Feb 29, 2016 at 21:05

    • 1

      Here is what a simple rule looks like: “` target: dependencies … commands … “` Ref: gnu.org/software/make

      – VicX

      Jun 8, 2020 at 3:51