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 shown). Typing h gives complete help information:
mdb<0> h
Command Short Name Aliases
---------------------- ---------- ---------
break *target* (b) L
cd *dir* (C)
comment *text* (#)
continue (c)
delete breakpoint numbers.. (d)
down [amount] (D)
eval *string* (e)
examine *string* (x)
finish (F)
frame *n* (f)
help [command] (h) ?, ??
info [thing] (i)
next [amount] (n)
print {*variable* [attrs...]} (p)
Print working directory (P)
quit [exit-status] (q) exit, return
run (R) restart
set {*option*|variable} *value* (=)
setq *variable* *value* (")
shell *string* (!) !!
show [thing] (S)
skip (k)
step [amount] (s)
target (t)
up [amount] (u)
where (T) backtrace, bt
write [*target* [*filename*]] (w)
Readline command line editing (emacs/vi mode) is available.
For more detailed help, type h <cmd> or consult online-documentation.
mdb<0>
Since we are debugging the touch problem we'll just continue by single stepping with s:
mdb<0> s
(/home/jgc/Makefile:4)
foo: bar
mdb<0> s
/home/jgc/Makefile:4 File `foo' does not exist.
(/home/jgc/Makefile:4)
foo: bar
mdb<1> s
(/home/jgc/Makefile:7)
bar:
mdb<2> s
/home/jgc/Makefile:7 File `bar' does not exist.
(/home/jgc/Makefile:7)
bar:
mdb<3> s
/home/jgc/Makefile:7 Must remake target `bar'.
(/home/jgc/Makefile:7)
bar:
mdb<4> s
(/home/jgc/Makefile:8)
bar:
mdb<5> s
##>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
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
***Entering debugger because we encountered a fatal error.
***Exiting the debugger will exit make with exit code 1.
(/home/jgc/Makefile:8)
bar:
mdb<6>
Whilst in the debugger I can fix the error in the Makefile and then hit R to restart. Now things work correctly:
mdb<0> R
Changing directory to /home/jgc and restarting...
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> c
/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'.
+ touch bar
/home/jgc/Makefile:7 Successfully remade target file `bar'.
/home/jgc/Makefile:4 Must remake target `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'.
+ touch bam
/home/jgc/Makefile:13 Successfully remade target file `bam'.
/home/jgc/Makefile:10 Must remake target `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'.
Makefile terminated.
Use q to quit or R to restart
:
mdb<0>
Targets, Macro Values and Expansion
When stopped in the debugger it's possible to interrogate information about targets in the Makefile, macro values (expanded and unexpanded) and commands. For example, in the Makefile above, when stopped at a breakpoint we can ask for all the information remake has about the all target using the target command:
./remake -X
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> target all
all: foo bar baz
# Phony target (prerequisite of .PHONY).
# Implicit rule search has not been done.
# Implicit/static pattern stem: `'
# File does not exist.
# File has not been updated.
# automatic
# @ := all
# automatic
# % :=
# automatic
# * :=
# automatic
# + := foo bar baz
# automatic
# | :=
# automatic
# < := all
# automatic
# ^ := foo bar baz
# automatic
# ? :=
mdb<0>
Here you can see that all is a phony target, and information about the automatic variables that will be set for this rule. You are not restricted to asking about the current target, let's see the state of foo:
mdb<0> target foo
foo: bar
# Implicit rule search has not been done.
# Implicit/static pattern stem: `'
# Modification time never checked.
# File has not been updated.
# automatic
# @ := foo
# automatic
# % :=
# automatic
# * :=
# automatic
# + := bar
# automatic
# | :=
# automatic
# < := bar
# automatic
# ^ := bar
# automatic
# ? :=
# commands to execute (from `Makefile', line 5):
@touch $@
Since target foo has commands they are listed at the bottom (with where to find them in
which Makefile). If we wanted to see the expanded form of the commands we'd use the expand modified to the target command:
mdb<1> target foo expand
foo:
# commands to execute (from `Makefile', line 5):
@touch $@
# commands to execute (from `Makefile', line 5):
@touch foo
mdb<2>
To get information about a macro we use the print and examine commands: print gives the definition of the macro and examine gives its post-expansion value. Here we ask for the definition of built-in COMPILE.c macro (which contains the command used to compile .c files):
mdb<0> print COMPILE.c
(origin default) COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
To see the expanded value we examine it:
mdb<0> examine COMPILE.c
(origin default) COMPILE.c := cc -c
remake also lets you set macro values using set (which expands a string and sets the macro to that value) and setq (which sets the macro to a string without expansion). For example, we could change CC from cc to gcc:
mdb<1> print CC
(origin default) CC = cc
mdb<1> setq CC gcc
Variable CC now has value 'gcc'
mdb<3> print CC
(origin debugger) CC = gcc
mdb<2> examine COMPILE.c
(origin default) COMPILE.c := gcc -c
mdb<5>
Conclusion
In this article I've only touched on the major commands available in remake. I urge you to take a look at it for your Makefile debugging needs, it's a useful tool to have in your toolbox.