Reputation: 8820
I ran into this useful tip that if you're working on files a lot and you want them to build automatically you run:
watch make
And it re-runs make every couple seconds and things get built.
However ... it seems to swallow all the output all the time. I think it could be smarter - perhaps show a stream of output but suppress Nothing to be done for 'all' so that if nothing is built the output doesn't scroll.
A few shell script approaches come to mind using a loop and grep ... but perhaps something more elegant is out there? Has anyone seen something?
Upvotes: 39
Views: 14340
Reputation: 56
Here is a quick script I wrote that does what is asked: watchmake. It is based on inotify
(so only runs on linux), with which it listens for changes on given files.
usage: watchmake [-h] [-e EXTENSIONS] [-q] [-i IGNORE] [-m MAKE_CMD]
[files ...]
Watch files and make on changes
positional arguments:
files Files or directories to watch. Defaults to current
directory
options:
-h, --help show this help message and exit
-e EXTENSIONS, --ext EXTENSIONS
Only watch files with this extension
-q, --quiet Run quietly
-i IGNORE, --ignore IGNORE
Ignore files or folders. Use a leading "/" to denote
files at the top level. Globs not supported
-m MAKE_CMD, --make-cmd MAKE_CMD
Define command to run upon modification of files.
Defaults to `make`. You may use {} in the command and
it will be replace by the changed file
Upvotes: 0
Reputation: 28268
Using classic gnu make
and inotifywait
, without interval-based polling:
watch:
while true; do \
$(MAKE) $(WATCHMAKE); \
inotifywait -qre close_write .; \
done
This way make is triggered on every file write in the current directory tree. You can specify the target by running
make watch WATCHMAKE=foo
Upvotes: 66
Reputation: 1138
Bit of archaeology, but I still find this question useful. Here is a modified version of @otto's answer, using fswatch (for the mac):
TARGET ?= foo
all:
@fswatch -1 . | read i && make $(TARGET)
@make -ski TARGET=$(TARGET)
%: %.go
@go build $<
@./$@
Upvotes: 0
Reputation: 4456
Here is a one-liner:
while true; do make -q || make; sleep 0.5; done
Using make -q || make
instead of just make
will only run the build if there is something to be done and will not output any messages otherwise.
You can add this as a rule to your project's Makefile:
watch:
while true; do $(MAKE) -q || $(MAKE); sleep 0.5; done
And then use make watch
to invoke it.
This technique will prevent Make from filling a terminal with "make: Nothing to be done for TARGET" messages.
It also does not retain a bunch of open file descriptors like some file-watcher solutions, which can lead to ulimit errors.
Upvotes: 14
Reputation: 4456
This shell script uses make
itself to detect changes with the -q
flag, and then does a full rebuild if and only if there are changes.
#!/bin/sh
while true;
do
if ! make -q "$@";
then
echo "#-> Starting build: `date`"
make "$@";
echo "#-> Build complete."
fi
sleep 0.5;
done
It does not have any dependencies apart from make
.
You can pass normal make
arguments (such as -C mydir
) to it as they are passed on to the make
command.
As requested in the question it is silent if there is nothing to build but does not swallow output when there is.
You can keep this script handy as e.g. ~/bin/watch-make
to use across multiple projects.
Upvotes: 3
Reputation: 12231
Twitter Bootstrap uses the watchr
ruby gem for this.
https://github.com/twbs/bootstrap/blob/v2.3.2/Makefile
https://github.com/mynyml/watchr
After two years the watchr
project seems not to be maintained anymore. Please look for another solution among the answers. Personally, if the goal is only to have a better output, i would recommend the answer from wch
here
Upvotes: 6
Reputation: 4117
This one-liner should do it:
while true; do make --silent; sleep 1; done
It'll run make
once every second, and it will only print output when it actually does something.
Upvotes: 13
Reputation: 1043
I do it this way in my Makefile:
watch:
(while true; do make build.log; sleep 1; done) | grep -v 'make\[1\]'
build.log: ./src/*
thecompiler | tee build.log
So, it will only build when my source code is newer than my build.log, and the "grep -v" stuff removes some unnecessary make output.
Upvotes: 2
Reputation: 11916
You could change your make file to output a growl (OS X) or notify-send (Linux) notification. For me in Ubuntu, that would show a notification bubble in the upper-right corner of my screen.
Then you'd only notice the build when it fails.
You'd probably want to set watch
to only cycle as fast as those notifications can display (so they don't pile up).
Upvotes: 0
Reputation: 71
How about
# In the makefile:
.PHONY: continuously
continuously:
while true; do make 1>/dev/null; sleep 3; done
?
This way you can run
make continuously
and only get output if something is wrong.
Upvotes: 7
Reputation: 121
You could try using something like inotify-tools. It will let you watch a directory and run a command when a file is changed or saved or any of the other events that inotify can watch for. A simple script that does a watch for save and kicks off a make when a file is saved would probably be useful.
Upvotes: 1
Reputation: 8694
@Dobes Vandermeer -- I have a script named "mkall" that runs make in every subdirectory. I could assign that script as a cron job to run every five minutes, or one minute, or thirty seconds. Then, to see the output, I'd redirect gcc results (in each individual makefile) to a log in each subdirectory.
Could something like that work for you?
It could be pretty elaborate so as to avoid makes that do nothing. For example, the script could save the modify time of each source file and do the make when that guy changes.
Upvotes: 1