Skip to content

Instantly share code, notes, and snippets.

@graue
Last active December 15, 2015 15:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save graue/5279439 to your computer and use it in GitHub Desktop.
Save graue/5279439 to your computer and use it in GitHub Desktop.
Using TJ Holowaychuk's "watch" with make

Using TJ Holowaychuk's "watch" with make

Note: I edited this and turned it into a blog post - read that instead.

While poking around some random projects by the prolific TJ Holowaychuk, I came upon his version of watch, which simply executes a given command periodically.

The idea is to pair it with make to run tests and automatically rebuild/recompile code. Since make tracks dependencies and looks at file modification times, it won't do anything if the relevant source files haven't changed.

There's a program called watch that comes with Linux, but it doesn't play as nicely with make. In particular, it clears the screen every time the command is run. For pairing this with make, we want new output to be printed whenever make actually does anything, and otherwise we want it to be silent.

To avoid any confusion I patched TJ's version of the program, changing its binary name to tjwatch. Now if we run tjwatch make, make will be run once per second.

There's a small problem though. make prints out this status message if it doesn't have anything to do:

$ make
make: Nothing to be done for `all'.

So by running it once a second we get flooded with the message over and over again.

$ tjwatch make
make: Nothing to be done for `all'.
make: Nothing to be done for `all'.
make: Nothing to be done for `all'.
^C

We don't want this. We do want output when make actually does something:

$ touch example.lua
$ make
lua2js example.lua example.js

In this example, Lua code is being compiled to JavaScript. Note how it prints out the command that was executed.

GNU make doesn't have an option to suppress the "Nothing to be done" message, but still show other output. One idea would be to use grep:

$ tjwatch "make | grep -v 'Nothing to be done for'"
exit: 1

exit: 1

exit: 1

^C

But now we keep getting warned by tjwatch about the non-zero exit code, which is the exit code of grep, not of make.

A Stack Overflow answer suggests a better workaround. We can make an "all" task in the Makefile that does nothing, yet makes make think it's doing something, by changing this:

all: example.js stuff.js

to this:

.PHONY: all realAll

all: realAll
        @true

realAll: example.js stuff.js

@true runs the true(1) command without echoing the command (that's what the @ means).

Now tjwatch make is silent while idle, but prints commands and output when it actually does anything. Perfect.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment