Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Phony targets in makefile

I was trying to execute the example in this link.

all : prog1 prog2 prog3
.PHONY : all

prog1 : prog1.o utils.o
    cc -o prog1 prog1.o utils.o

prog2 : prog2.o
    cc -o prog2 prog2.o

prog3 : prog3.o sort.o utils.o
    cc -o prog3 prog3.o sort.o utils.o

With or without PHONY (if i comment out the .PHONY line), the outputs are the same. What is the real use of PHONY here?

The article mentions this

When one directory contains multiple programs, it is most convenient to describe all of the programs in one makefile

Since the target remade by default will be the first one in the makefile, it is common to make this a phony target named ‘all’ and give it, as prerequisites, all the individual programs

I cant understand what is the real use of PHONY here. Can someone point me a scenario in this example in which the program would behave differently without PHONY?

like image 209
CHID Avatar asked Mar 14 '23 08:03

CHID


2 Answers

without .PHONY "all" is just a regular make target which depends on prog1, prog2, prog3. This means that if a file named "all" would happen to exist in the directory that is newer than prog1, prog2 and prog3, they will not be built (try it!) - but this is obviously not what you had in mind.

.PHONY tells GNU make the "all" target is phony - you don't REALLY intended for a file called "all" to be created and it should build the dependencies regardless if a file called "all" exists or not.

Added later:

My example with all and prog1 above was not correct although the general idea is true. Here is a much simple example

all: prog

prog: prog.c

clean:
  $(RM) prog prog.o


giladb@xxx:~/tmp$ ls
Makefile  prog.c
giladb@xxx:~/tmp$ make
cc     prog.c   -o prog
giladb@xxx:~/tmp$ make clean
rm -f prog prog.o
giladb@nps06:~/tmp$ make
cc     prog.c   -o prog
giladb@xxx:~/tmp$ touch clean
giladb@xxx:~/tmp$ make clean
make: `clean' is up to date.
like image 197
gby Avatar answered Mar 23 '23 00:03

gby


At least for GNU Make in combination with this example the behavior regarding the output is the same, no matter if the target "all" is a phony target or not. Even if there is a file named "all".

BUT as described in the manual behind your link the internal behavior of GNU Make is different. If "all" is not a phony target, GNU Make checks whether a file named "all" exists and is older than its prerequisites. Try "make -d" and you will see the difference.

Another important point is that the recipe of a phony target is always executed. If you take this example:

all: goal
    echo "Done"

.PHONY : clean

goal:
    echo "Hello World!" > $(@)

clean:
    rm -f goal all

... and execute this:

$ make clean
rm -f goal all
$ make
echo "Hello World!" > goal
echo "Done"
Done
$ make
echo "Done"
Done
$ touch all
$ make
make: 'all' is up to date.

... the recipe will not be executed after creating the file "all".

With "all" being a phony target:

all: goal
    echo "Done"

.PHONY : all clean

goal:
    echo "Hello World!" > $(@)

clean:
    rm -f goal all

... the recipe of "all" will be executed always independent of the existence of the file "all".

$ make clean
rm -f goal all
$ make
echo "Hello World!" > goal
echo "Done"
Done
$ make
echo "Done"
Done
$ make
echo "Done"
Done
$ touch all
$ make
echo "Done"
Done
$ make
echo "Done"
Done
like image 44
Karsten G. Avatar answered Mar 23 '23 00:03

Karsten G.