Makefile Debugging: A introduction to remake

[article]
Summary:

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. 

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

Pages

About the author

AgileConnection is one of the growing communities of the TechWell network.

Featuring fresh, insightful stories, TechWell.com is the place to go for what is happening in software development and delivery.  Join the conversation now!