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.
As the others mentioned, make looks at the timestamps of the files to figure out if the dependencies have changed.
If you want to "emulate" a phony target with dependencies, you will have to create a real file with that name and use the
touch
command (on Unix systems).I needed a solution to only clean the directory if the makefiles were changed (i.e. the compiler flags were changed, so the object files needed to be recompiled).
Here's what I used (and runs before every compilation) with a file named
makefile_clean
:The
touch
command updates the last-modified timestamp to the current time.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":
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:
Now you have two things: a nice conventional "all" target that is correctly phony but won't do extra work. You are also in a better position to make this more generic so you can easily add more files:
There needs to be some target file to compare against the modification time of server.coffee file. Since you don't have a concrete target
make
cannot know if the output is newer then the dependency or not, so it will always buildall
.According to the Make documentation:
http://www.gnu.org/software/make/manual/html_node/Special-Targets.html
Make runs the recipe of PHONY targets unconditionally - prerequisites don't matter.