In the past I've written about Printing the value of a Makefile macro, Tracing Macro Values, An Interactive GNU Make Debugger and Tracing rule execution in GNU Make.
In this article, I present the remake project which is a fork of GNU Make that integrates a complete GNU Make ebugger by modifying the GNU Make source code.
remake forked from GNU Make 3.80 and is currently at version 0.62. This version incorporates some, but not all, of the changes made in GNU Make 3.81.
Just Print and Trace
To illustrate the operation of remake, here's a sample Makefile:
.PHONY: all
all: foo bar baz
foo: bar
@touch $@
bar:
@touch $@
baz: bam
@touch $@
bam:
@touch $@
Running the standard GNU Make -n (or --just-print) option against this Makefile produces the output:
touch bar
touch foo
touch bam
touch baz
But remake provides Makefile and line number information for each rule. The information shows the target (the value of $@) and the commands to be run:
$ remake -n
##>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/home/jgc/Makefile:8: bar
touch bar
##<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
##>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/home/jgc/Makefile:5: foo
touch foo
##<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
##>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/home/jgc/Makefile:14: bam
touch bam
##<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
##>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/home/jgc/Makefile:11: baz
touch baz
##<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Of course, any real Makefile has to be actually run to understand its execution. remake provides a very handy tracing option, -x, which runs the Makefile, while outputting information about why targets are being built and showing the commands executed and their output.
Reading makefiles...
Updating goal targets....
/home/jgc/Makefile:2 File `all' does not exist.
/home/jgc/Makefile:4 File `foo' does not exist.
/home/jgc/Makefile:7 File `bar' does not exist.
/home/jgc/Makefile:7 Must remake target `bar'.
##>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/home/jgc/Makefile:8: bar
touch bar
##<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+ touch bar
/home/jgc/Makefile:7 Successfully remade target file `bar'.
/home/jgc/Makefile:4 Must remake target `foo'.
##>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/home/jgc/Makefile:5: foo
touch foo
##<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+ touch foo
/home/jgc/Makefile:4 Successfully remade target file `foo'.
/home/jgc/Makefile:10 File `baz' does not exist.
/home/jgc/Makefile:13 File `bam' does not exist.
/home/jgc/Makefile:13 Must remake target `bam'.
##>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/home/jgc/Makefile:14: bam
touch bam
##<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+ touch bam
/home/jgc/Makefile:13 Successfully remade target file `bam'.
/home/jgc/Makefile:10 Must remake target `baz'.
##>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/home/jgc/Makefile:11: baz
touch baz
##<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+ touch baz
/home/jgc/Makefile:10 Successfully remade target file `baz'.
/home/jgc/Makefile:2 Must remake target `all'. Is a phony target.
/home/jgc/Makefile:2 Successfully remade target file `all'.
The trace option really comes into its own when an error occurs. Here's the output when I added a non-existent option to touch in the commands for target bar:
Reading makefiles...
Updating goal targets....
/home/jgc/Makefile:2 File `all' does not exist.
/home/jgc/Makefile:4 File `foo' does not exist.
/home/jgc/Makefile:7 File `bar' does not exist.
/home/jgc/Makefile:7 Must remake target `bar'.
##>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/home/jgc/Makefile:8: bar
touch -x bar
##<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+ touch -x bar
touch: invalid option -- x
Try `touch --help' for more information.
Makefile:8: *** [bar] Error 1
#0 bar at /home/jgc/Makefile:8
#1 foo at /home/jgc/Makefile:4
#2 all at /home/jgc/Makefile:2
Command-line arguments:
"-x"
Right at the bottom of that output is the 'call stack' of targets that were dependent on bar building successfully. Plus, of course, you see the error generated by touch and the actual command that was executed, and where to find it in the Makefile.
Debugging
Since remake contains an interactive debugger we can debug the touch problem above using it. We simply run remake with the -X option (uppercase X for the debugger, lowercase x for tracing) and the debugger breaks at the first target to be built:
Reading makefiles...
Updating makefiles....
Updating goal targets....
/home/jgc/Makefile:2 File `all' does not exist.
(/home/jgc/Makefile:2)
all: foo bar baz
mdb<0>
So, the first break is at line 2 of the Makefile and shows that the first target is all (and the complete prereq list is






