user4118249
user4118249

Reputation:

How can make get confused without .PHONY targets?

I'm reading the make manual and I ended up on this paragraph:

Here is how we could write a make rule for cleaning our example editor:

clean:
    rm edit $(objects)

In practice, we might want to write the rule in a somewhat more complicated manner to handle unanticipated situations. We would do this:

.PHONY : clean clean :
    -rm edit $(objects)

This prevents make from getting confused by an actual file called clean and causes it to continue in spite of errors from rm. (See Phony Targets, and Errors in Recipes.)

I understand that clean target does not refer to a file on the filesystem but how make can getting confused if I omit the .PHONY declaration on a target that should be declared as .PHONY?

I would see an example that confuses the make command.

P.S.: what does the minus symbol before rm command represent?

Thanks.

Upvotes: 3

Views: 688

Answers (1)

Mihai Maruseac
Mihai Maruseac

Reputation: 21435

Let's test this. Fire your terminal of choice, navigate to your directory of choice and then create a new directory (to hold the test files). I chose so-27204300:

$ mkdir so-27204300
$ cd so-27204300

Now create a simple Makefile without the .PHONY annotation. I'll only show the contents:

clean:
    echo "Clean is executing"

Execute the make command, you should get the following output:

$ make
echo "Clean is executing"
Clean is executing

Now, create a clean file (touch clean) and execute make again. You'll get

$ make
make: `clean' is up to date.

because there is a file clean newer than the output of the target clean. Add .PHONY clean to the Makefile so it will read

.PHONY: clean
clean:
    echo "Clean is executing"

Now, even with the file clean in your directory, make will execute the target

$ make
echo "Clean is executing"
Clean is executing

Regarding your PS: change this Makefile so that it reads:

.PHONY: clean
clean:
    rm test
    echo "Done"

As you see, there's no - there but also there is no test file in the current directory. Running make will give you

$ make
rm test
rm: cannot remove ‘test’: No such file or directory
make: *** [clean] Error 1

And no output from echo. If the clean target was a prerequisite to another target then because of this error the other target would not have been built either.

Adding a - so that the Makefile reads:

.PHONY: clean
clean:
    -rm test
    echo "Done"

solves this problem:

$ make
rm test
rm: cannot remove ‘test’: No such file or directory
make: [clean] Error 1 (ignored)
echo "Done"
Done

For rm you can also use -f to let it stop complaining on errors. But there are other commands which don't have a silencer of errors argument.


If you want to hide the printing of command being executed you can use @ instead of -.

Upvotes: 3

Related Questions