42

Consider a long makefile with numerous targets, all of which are PHONY (meaning that the target name does not represent an existing file).

I can do either:

.PHONY: a
a:
    do someting a

.PHONY: b
b:
    do someting b

.PHONY: c
c:
    do someting c

Or:

.PHONY: a b c
a:
    do someting a

b:
    do someting b

c:
    do someting c

The first option is cumbersome, and the second option is prone to error, when future me adds a target and forget to declare it as PHONY.

Is there a standard way to declare all targets in a makefile as PHONY?

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Adam Matan
  • 128,757
  • 147
  • 397
  • 562
  • 4
    If *all* targets are *PHONY*, `make` is not the correct tool because it has no advantage whatsoever over a plain script... `.PHONY: $(MAKECMDGOALS)` would make exactly the targets given at the command-line phony, which would work for you if none of your targets depend on other targets. –  Jun 12 '17 at 09:21
  • 2
    I agree with Felix. And I think the second version is more standard than the first one. I don't think it's that error prone, you should somehow keep control over what you have in your Makefile regardless of its size. – Tim Jun 12 '17 at 11:27
  • I will be more than happy to have these comments as answers – Adam Matan Jun 12 '17 at 11:39
  • 29
    I disagree with Felix and TimF. Make does have advantages over "plain scripts" in that you can use make to specify the order in which recipes and external scripts are run by using dependencies. You can also use the Makefile as a clean way to store and call multiple recipes/scripts from a single file. That way the Makefile is essentially a directory of commands and that you'd probably rather not have to type over and over. The target names can be used as aliases to the actual command/script name. – Shammel Lee Jun 12 '17 at 14:21
  • @ShammelLee You know about the `case` statement and functions in scripts, do you? The whole *idea* about `make` is that it decides based on timestamps, so if all your targets are *PHONY*, `make` is pointless. –  Jun 12 '17 at 19:11
  • 7
    @FelixPalmen So pointless, I use it for this very reason all the time. Make's syntax is much simpler than passing arguments to a script that then have to be interpreted by the ugly syntax of a switch statement. So why not use `.PHONY` for exactly what it was intended?-which is to trigger a target every time, regardless of whether or not it's out of date. Regarding the "whole idea" of Make, you forgot to mention the other part of the "whole idea"… dependency management. Which, in my case, is why I prefer to use Make than rewriting (and debugging) dependency logic in a shell script. – Shammel Lee Jun 12 '17 at 21:33
  • @ShammelLee dependencies between *PHONY* targets are very simple: unconditionally execute the recipes for these other targets before your own. This has to be stated explicitly and is completely functionally equivalent to first calling some *other* functions in a (shell) script. I rest my case, this misses the point of `make`. Sure it works, it's just like using pincers to pull a screw. –  Jun 12 '17 at 22:53
  • 2
    @FelixPalmen if they're equivalent, then your argument is basically that _you_ prefer to use scripts. The OP obviously sees the usefulness of using Make to run commands. – Shammel Lee Jun 12 '17 at 23:05
  • @ShammelLee yes, they're equivalent in functionality. But only `make` has all sorts of *bells and whistles* to support a real *building* process based on file timestamps. This goes to great lengths with `GNU make`. It just doesn't make sense to even *depend* on `make` here. –  Jun 12 '17 at 23:10
  • Let's call it a peculiar use of Make. – Shammel Lee Jun 12 '17 at 23:14
  • 14
    Here's an example of companies like Facebook using Makefiles in the exact way I described => https://github.com/graphql-python/graphene/blob/master/docs/Makefile – Shammel Lee Jun 29 '17 at 13:22
  • Old discussion, but I think 2 years later this question is more relevant than ever. I am trying to use `make` to setup an application that relies on some dozen microservices running on docker containers. I want to be able to start each service individually, so during development, I can just start one of them, develop something and test, without running the whole application. But the services have some common dependencies, and declaring them as `make` targets make it very convenient to start any number of services, being sure that all the dependencies are ran in the right order, and only once. – Thiago Barcala Nov 28 '19 at 09:04
  • Does `.PHONY: %` work in this situation? IIRC `%` matches all targets when used as a dependency. You could put that at the bottom of each Makefile. – Julius Ecker May 04 '20 at 14:18
  • You can use `just`. It's similar to `make` but all the rules are PHONY by default. https://github.com/casey/just – Marc Belmont Nov 20 '20 at 10:40
  • @JuliusEcker: `.PHONY: %` does not work for me, neither at the top nor at the bottom of a file. – vlz Dec 24 '20 at 09:55
  • After careful consideration, I think your first approach with `.PHONY` right before each target is the best way. Wildcards like `.PHONY: *` are good for DRY but will become useless if one day you will need non-phony target. And between DRY and flexibility I would choose flexibility. – kdmitry Nov 18 '22 at 11:39

4 Answers4

16

If really all targets are PHONY, this is a bit pointless. make is meant for "do what is necessary to update my output", and if the answer to what is necessary? is always the same, simple scripts would do the same job with less overhead.

That being said, I could imagine a situation where all targets intended to be given at the commandline should be PHONY -- Let's assume you want to build some documents like this:

all: doc1.pdf doc2.pdf doc3.pdf doc4.pdf doc5.pdf

manuals: doc3.pdf doc4.pdf

faqs: doc1.pdf

designdocs: doc2.pdf

apidocs: doc5.pdf

developerdocs: doc2.pdf doc5.pdf

userdocs: doc1.pdf doc3.pdf doc4.pdf

%.pdf: %.md
     $(somedocgenerator) -o $@ $<

Then you could do the following:

.PHONY: all $(MAKECMDGOALS)

This would dynamically make any target given at the command line PHONY. Note you have to include your default target here as this could be invoked without giving it explicitly, by simply typing make.

I would not recommend this approach because it has two drawbacks:

  • It's less portable to different flavors of make.
  • It will misbehave if someone decides to make a specific output file like here make doc3.pdf.
  • It will also misbehave if you decide to have one of your PHONY targets depend on another PHONY one.

So, better go with the approach to have one line declaring all the PHONY targets. If your Makefile is really huge, you could split it in several files and use include -- and have one .PHONY: line in each file.

  • 30
    I disagree with the premise that a Makefile with all phony targets should be replaced by arbitrary scripts. Make is an extremely prolific tool which has become the de facto standard for building most projects. Replacing it with arbitrary build scripts in a project would break from this standard and likely cause confusion among both developers and consumers. – Alex Jansen Dec 10 '19 at 20:10
  • Using Make for dep management in your project is great! Make is a wonderful tool, and given the nature of software development in 2020, building file by file is likely not the use case most people are trying to solve. `.PHONY: %` will do what most folks want. – Julius Ecker May 04 '20 at 14:30
  • 1
    @JuliusEcker `.PHONY: %` does not work for me (GNU make 4.3) – vlz Dec 24 '20 at 09:53
  • 1
    make's autocomplete and the huge chance of being already installed makes it a very convenient tool for grouping workflow scripts in a project, even if that wasn't the intended usage of the tool. – Hugo Mota Feb 27 '21 at 17:01
  • what if I need targets to be dependent on each other? `make` does it so easy to write and maintain. But what will turn out from a bunch of shell scripts. – Alexei Sosin Jul 24 '23 at 08:29
11

Just use MAKEFLAGS and set option --always-make like so:

MAKEFLAGS += --always-make
rags
  • 445
  • 5
  • 7
11

For me .PHONY: * worked. (GNU make 4.2.1)

Ruben
  • 390
  • 4
  • 6
3

One way to do it:

.PHONY: $(shell sed -n -e '/^$$/ { n ; /^[^ .\#][^ ]*:/ { s/:.*$$// ; p ; } ; }' $(MAKEFILE_LIST))

Works perfectly even for targets mentioned as dependencies.

Kamil Dziedzic
  • 4,721
  • 2
  • 31
  • 47