Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Makefile dependencies don't work for phony target

Tags:

Here is a reduced version of my Makefile:

.PHONY: all   all: src/server.coffee   mkdir -p bin   ./node_modules/.bin/coffee -c -o bin src/server.coffee 

I want to run make and only have it recompile when src/server.coffee has changed. However, it recompiles every time I run make:

$ make mkdir -p bin ./node_modules/.bin/coffee -c -o bin src/server.coffee $ make mkdir -p bin ./node_modules/.bin/coffee -c -o bin src/server.coffee 

If I change my Makefile to not use a phony target, it works as expected. New Makefile:

bin/server.js: src/server.coffee   mkdir -p bin   ./node_modules/.bin/coffee -c -o bin src/server.coffee 

Result:

$ make mkdir -p bin ./node_modules/.bin/coffee -c -o bin src/server.coffee $ make make: `bin/server.js' is up to date. 

Why won't it respect my dependencies with a phony target? The reason I ask is because in reality, I won't just be compiling a single file into a single other file, so I don't want to have to keep track of the names of all the output files to use as targets.

like image 890
Jonah Kagan Avatar asked Dec 13 '12 03:12

Jonah Kagan


People also ask

What does phony do in makefile?

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.

What does $@ mean in makefile?

The variable $@ represents the name of the target and $< represents the first prerequisite required to create the output file.

How do I call a target in makefile?

When you type make or make [target] , the Make will look through your current directory for a Makefile. This file must be called makefile or Makefile . Make will then look for the corresponding target in the makefile. If you don't provide a target, Make will just run the first target it finds.

What is .phony for?

Definition of phony (Entry 1 of 4) : not genuine or real: such as. a(1) : intended to deceive or mislead. (2) : intended to defraud : counterfeit.


1 Answers

Rather than a phony target (which as @cmotley points out, is working exactly as it should) what you might use when you want to avoid extra work is an "empty target":

The empty target is a variant of the phony target; it is used to hold recipes for an action that you request explicitly from time to time. Unlike a phony target, this target file can really exist; but the file's contents do not matter, and usually are empty.

The purpose of the empty target file is to record, with its last-modification time, when the rule's recipe was last executed. It does so because one of the commands in the recipe is a touch command to update the target file.

However, in this case there's really no need to add an extra empty output file — you already have the output of your CoffeeScript compilation! That fits the more typical Makefile pattern, as you already demonstrated in your question. What you could do is refactor to this approach:

.PHONY: all all: bin/server.js  bin/server.js: src/server.coffee   mkdir -p bin   ./node_modules/.bin/coffee -c -o bin src/server.coffee 

Now you have both things you wanted: a nice conventional "all" target that is correctly phony, and a build rule that won't do extra work. You are also in a better position to make this more generic so you can easily add more files:

.PHONY: all all: bin/server.js bin/other1.js bin/other2.js  bin/%.js: src/%.coffee   mkdir -p bin   ./node_modules/.bin/coffee -c -o bin $< 
like image 134
natevw Avatar answered Sep 22 '22 19:09

natevw