2452

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?

mokagio
  • 16,391
  • 3
  • 51
  • 58
Lazer
  • 90,700
  • 113
  • 281
  • 364

10 Answers10

2782

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.

Eli Bendersky
  • 263,248
  • 89
  • 350
  • 412
  • 2
    I think I have some idea about it now (having gone through the link that you mentioned). btw, why is it called `"phony"`? – Lazer Jan 27 '10 at 09:39
  • 85
    @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 '10 at 09:41
  • 159
    @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. http://en.wiktionary.org/wiki/phony says: Fraudulent; fake; having a misleading appearance. – Bahbar Aug 26 '10 at 10:58
  • 74
    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. – synthesizerpatel Mar 27 '13 at 09:10
  • 1
    @synthesizerpatel 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. – Evgeni Sergeev Jan 19 '14 at 03:15
  • 2
    Does the .PHONY target apply to all makes or just to GNU make? – frankster Jun 27 '14 at 10:44
  • 1
    I've just come across this now, and thirty years ago these were called "pseudotargets". Specifically, this was their name. dummy or buildall was preferred over bogus,phony and the like. In those days I would "touch" everything in any case to force a full build, which could be overnight. Nothing worse than trying to recompile something after a few months and having it fail. – mckenzm Mar 06 '15 at 08:00
  • 27
    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 '16 at 03:11
  • 56
    "a phony target is simply a target that is always out-of-date" - great explanation! – Danijel Nov 06 '18 at 09:54
  • If you have ```all```, ```clean``` and few other command labels inside make file, what is the convention for naming a "```.PHONY```" for each one of them? (maybe ```.PHONY1```, ```.PHONY2``` etc?) @synthesizerpatel – User 10482 Aug 11 '19 at 21:12
  • 2
    @User10482 you would write something like this `.PHONY: all clean` – goldenratio Apr 04 '20 at 23:47
  • 1
    @Bahbar I discovered the word "phony" while reading "The Catcher in the Rye" and consequently I am always confused by this choice of name. – Mig Aug 17 '20 at 07:13
  • So it's right to say that if you were to mark ALL your targets as `.PHONY`, you could instead use flag `-B` or `--always-make` and achieve same behavior – artu-hnrq Jan 29 '21 at 02:50
  • @Lazer Why "PHONY"? Like "bogus" and "pseudo-", though less common today than "fake" or "mock", these likewise signify non-real without the usual negative connotation from non-technical English. Reduced negative connotation is common in tech jargon, e.g. "spy", "garbage", "corrupt". This may come from habitual understatement in the culture and the broader western subcultural trend of cherished playful irreverence. Understatement of intended negatives is also common: "nontrivial" (very difficult) and from aerospace: "RUD event". – Chris Mountford Feb 02 '22 at 23:56
  • what if I have a file called `.PHONY` in my project? – axolotl Feb 07 '22 at 04:00
  • 1
    It must be an American who termed this as .PHONY. Yeah they did things like that in the past and will continue to do. – ProPlayerMaxUltra Jan 04 '23 at 09:39
  • If you have a file called `.PHONY` in your project, then you're out of luck. – MadScientist Jan 06 '23 at 18:40
  • What does it mean " the file doesn't appear to be up-to-date with regards to its dependencies"? – Brunisboy Aug 21 '23 at 16:26
850

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.

Mechanical snail
  • 29,755
  • 14
  • 88
  • 113
George Y.
  • 11,307
  • 3
  • 24
  • 25
  • 11
    @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. – Mark Amery Dec 02 '14 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. – nucleartide Jan 18 '15 at 17:02
  • 9
    @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 '16 at 19:26
  • 14
    @Kyle Yes, I'm not sure what my past self meant. These days I use `.PHONY` all the time... – nucleartide Feb 15 '16 at 22:43
  • 6
    @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. – Mateen Ulhaq Jun 25 '18 at 01:51
  • I always find this kind of "what-happens-if-not" answers incredibly useful. – Rocío García Luque Oct 25 '18 at 13:08
  • @George Y. Can you elaborate on this "...and its dependencies didn't change, nothing will be done". I am running `all : foo ... recipe` and while I am not changing `foo` file the make command still runs. – Anton May 16 '22 at 15:48
  • What does it mean "its dependencies did not change?" What constitutes as a dependency change? – Brunisboy Aug 21 '23 at 16:29
229

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:

prerit@vvdn105:~/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.
iluu
  • 406
  • 3
  • 13
prerit jain
  • 2,349
  • 1
  • 11
  • 3
  • 19
    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 '16 at 21:05
  • 2
    Here is what a simple rule looks like: ``` target: dependencies ... commands ... ``` Ref: https://www.gnu.org/software/make/ – VicX Jun 08 '20 at 03:51
103
.PHONY: install
  • means the word "install" doesn't represent a file name in this Makefile;
  • means the Makefile has nothing to do with a file called "install" in the same directory.
Joshua D. Boyd
  • 4,808
  • 3
  • 29
  • 44
YourBestBet
  • 1,651
  • 1
  • 12
  • 17
54

It is a build target that is not a filename.

JohnMcG
  • 8,709
  • 6
  • 42
  • 49
49

The special target .PHONY: allows to declare phony targets, so that make will not check them as actual file names: it will work all the time even if such files still exist.

You can put several .PHONY: in your Makefile :

.PHONY: all

all : prog1 prog2

...

.PHONY: clean distclean

clean :
    ...
distclean :
    ...

There is another way to declare phony targets : simply put :: without prerequisites :

all :: prog1 prog2

...

clean ::
    ...
distclean ::
    ...

The :: has other special meanings, see here, but without prerequisites it always execute the recipes, even if the target already exists, thus acting as a phony target.

Edouard Thiel
  • 5,878
  • 25
  • 33
  • 1
    Are you sure that's the meaning of "::"? In the [doc of "::"](https://web.archive.org/web/20180122002430/http://owen.sj.ca.us/~rk/howto/slides/make/slides/makecolon.html), .PHONY is not mentioned at all and "::" is used also for non-phony targets. – janluke Jan 04 '21 at 16:28
  • In fact, phony is implied only when `::` is used without prerequisites, see the link above in gnu make documentation. – Edouard Thiel Jan 05 '21 at 10:13
  • not worked. seen strace output for stat( "target" with makefile "target ::" line. The only .PHONY: target worked. GNU Make 4.1 Built for x86_64-pc-linux-gnu – vGimly Jun 20 '22 at 08:57
38

The best explanation is the GNU make manual itself: 4.6 Phony Targets section.

.PHONY is one of make's Special Built-in Target Names. There are other targets that you may be interested in, so it's worth skimming through these references.

When it is time to consider a .PHONY target, make will run its recipe unconditionally, regardless of whether a file with that name exists or what its last-modification time is.

You may also be interested in make's Standard Targets such as all and clean.

James Wald
  • 13,626
  • 5
  • 52
  • 63
  • I disagree. That page is just confusing, unless you already know the answer! For example, I have an "all" target that makes all my programs. It is NOT declared phony as that page suggests, but it still works. I still don't really know what it is trying to tell me . . . Here is the Makefile to prove my point https://github.com/m4r35n357/ODE-Playground/blob/pure_c/Makefile – m4r35n357 Nov 24 '22 at 11:47
15

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.

Ethouris
  • 1,791
  • 13
  • 18
  • Linux kernel Makefile not uses multiple .PHONY target. They widely use multiple lines of variable PHONY (like PHONY += target1 target2) and final line of makefile is: .PHONY: $(PHONY) – vGimly Jun 20 '22 at 09:03
  • 1
    And that comment was to concern what exactly? – Ethouris Jun 23 '22 at 14:50
8

So, let's say you have a file named "clean" in your directory where the make is run. Now lets take an example of below Makefile:

clean:
        rm lol

Now when you run "make clean" you will get following output: enter image description here

but if you add ".PHONY: clean" to the Makefile and run "make clean" you will see the following output: enter image description here

What happened? make treated clean first time as target since a file is present in the directory. But after adding .PHONY, the make ignored the file (and also the timestamp tracking) and interpreted it as normal clean.

Now this can be applied to numerous cases where you want your make to ignore the argument given as target (when you have a file with same name in that directory).

Pannag
  • 136
  • 1
  • 3
5

I often use them to tell the default target not to fire.

superclean: clean andsomethingelse

blah: superclean

clean:
   @echo clean

%:
   @echo catcher $@

.PHONY: superclean

Without PHONY, make superclean would fire clean, andsomethingelse, and catcher superclean; but with PHONY, make superclean won't fire the catcher superclean.

We don't have to worry about telling make the clean target is PHONY, because it isn't completely phony. Though it never produces the clean file, it has commands to fire so make will think it's a final target.

However, the superclean target really is phony, so make will try to stack it up with anything else that provides deps for the superclean target — this includes other superclean targets and the % target.

Note that we don't say anything at all about andsomethingelse or blah, so they clearly go to the catcher.

The output looks something like this:

$ make clean
clean

$ make superclean
clean
catcher andsomethingelse

$ make blah 
clean
catcher andsomethingelse
catcher blah
jettero
  • 835
  • 2
  • 13
  • 26