Sample Debugger Sessions¶
An Extended Debug Session¶
In this session we will go into the debugger initially using the
--debugger or -X option. We’ll use the Makefile from the source
code from cd-paranoia
Basic Information when stopped inside Debugger¶
$ remake -X
Reading makefiles...
Updating makefiles...
-> (/tmp/libcdio-paranoia/Makefile:428)
Makefile: Makefile.in config.status
remake<0>
The line immediately before the prompt remake<0>, shows the
target name, Makefile and its dependencies: Makefile.in and
config.status.
The line before that has position information
(/tmp/libcdio-paranoia/Makefile:428). But at the beginning of the
line is an arrow made up of two characters, ->. This indicates that
we have not done the prerequisite checking for this target yet. Later we
will come across other two-character icons like ++.
See icons for a complete list.
The zero in the prompt remake<0> is the command history number. If GNU
Readline history is supported then it increments the number as we enter commands,
otherwise it stays zero.
For each recursive call to remake, we’ll add another pair of angle
brackets <> around the number.
More verbose information can be obtained using info program:
remake<0> info program
Starting directory `/tmp/libcdio-paranoia'
Program invocation:
remake/make -X
Recursion level: 0
Line 428 of "/tmp/libcdio-paranoia/Makefile"
Program stopped before rule-prequisite checking.
remake<1>
Notice that the prompt has incremented to 1 after entering the command.
Stepping¶
We can use the step, command to progress a little in the interpretation or execution of the makefile:
remake<1> step
-> (/tmp/libcdio-paranoia/Makefile:415)
Makefile.in: Makefile.am m4/ld-version-script.m4 ...
remake<2> step
-> (/src/external-vcs/github/rocky/libcdio-paranoia/Makefile:443)
aclocal.m4: m4/ld-version-script.m4 ...
remake<3>
I have elided the list of dependencies listed above and substituted ellipses (...).
There is a slight difference between what you will find in the Makefile and the target output seen above. Below I’ll compare what is in the Makefile (1st line displayed) with what is in the remake output (2nd line displayed).
For line 415:
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
Makefile.in: Makefile.am m4/ld-version-script.m4 ...
while line 443:
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
aclocal.m4: m4/ld-version-script.m4 ...
In the debugger, variables have been expanded and file paths have been canonicalized. Therefore you see:
Makefile |
remake output |
|---|---|
$(srcdir)/Makefile.in |
Makefile.in |
$(ACLOCAL_M4) |
aclocal.m4 … |
Let’s recap where remake is in the process of running the Makefile.
The first thing that seems to be done is that the Makefile
dependencies need to be checked. A dependency of Makefile is
Makefile.in and that in turn depends on target aclocal.m4. We have
now stepped into and stopped at that target. So, at the remake<3> prompt
we have not yet checked the dependencies of aclocal.m4.
You can see the dependency nesting that got us to this state using the backtrace command:
remake<3> backtrace
=>#0 aclocal.m4 at /tmp/libcdio-paranoia/Makefile:443
#1 Makefile.in at /tmp/libcdio-paranoia/Makefile:415
#2 Makefile at /tmp/libcdio-paranoia/Makefile:428
remake<4>
Stepping through the program can be illuminating as far as what is
going on, especially when the Makefile has been derived in some way,
as is the case here. This Makefile was created via autotools.
I had assumed that when I run make it looks for a default target and
runs that. But as we see here, the first thing that goes on is to
check to see if the Makefile being used is itself out of date. If
that is the situation, then the Makefile will get recreated and you
start again.
However while all of this may be interesting, stepping can be a bit tedious.
In the next section, we talk about breakpoints which can get you to where you want to debug faster. To finish this session use the quit command.
remake<4> quit
remake: That's all, folks...
Stopping with Continue¶
Let’s say I am interested in what goes on when make dist is run.
Again, I’ll invoke the debugger initially.
$ remake -X
Reading makefiles...
Updating makefiles...
-> (/tmp/libcdio-paranoia/Makefile:428)
Makefile: Makefile.in config.status
remake<0>
Instead of stepping we can set a breakpoint on the dist target and
continue running to that point in one command, using continue.
remake<0> continue dist
Breakpoint 1 on target `dist', mask 0x0f: file Makefile, line 703.
Updating goal targets...
-> (/src/external-vcs/github/rocky/libcdio-paranoia/Makefile:703)
dist:
remake<1>
Now when I issue a step, I will step into the commands associated with the dist target:
remake<1> step
File 'dist' does not exist.
Must remake target 'dist'.
Makefile:704: target 'dist' does not exist
##>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
remake dist-bzip2 dist-gzip am__post_remove_distdir='@:'
##<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
++ (/src/external-vcs/github/rocky/libcdio-paranoia/Makefile:703)
dist
remake<2>
Notice that the event icon above is ++ which means I am stepping shell commands, here those associated with the Make target dist.
Above the line with the event icon in between the two lines of chevrons is the command that is about to be run.
To see the build commands for the current target you can use the list command:
remake<2> list
/tmp/libcdio-paranoia/Makefile:705
dist:
# recipe to execute (from 'Makefile', line 706):
$(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:'
$(am__post_remove_distdir)
Alternatively you can use a form of the target command: target @ command. Note that in both cases variables are not expanded as they are in the trace output shown above between chevrons.
Debugging Make Variables¶
In the above session we have seen that output has variables expanded,
while in the list and target commands variables were not
expanded.
You can query any GNU Make variable that has been set in the program without performing expansion on its value by using the print command.
remake<2> print MAKE
(origin default) MAKE = $(MAKE_COMMAND)
The (origin default) means this is a built-in definition. Many
variables that you will be interested in though, are set somewhere,
and if the variable is not a default it’s location is also shown:
remake<3> print DATA
Makefile:168 (origin: makefile) DATA := libcdio_paranoia.pc libcdio_cdda.pc
The other kind of print which does full expansion of the variables value is
called expand or x. Here is an example
remake<4> expand MAKE
(origin default) MAKE := remake
Note that when printing expanded values we use := while for non-expanded
values we use = This output matches the semantics of these
assignment operators.
In fact, expand doesn’t need a variable name, it will work with a
string. For example:
remake<5> x $(MAKE) $(DIST_TARGETS)
remake dist-bzip2 dist-gzip
No location identification is given here since what I put in isn’t a
variable. Also note that for expand I add the dollar sign and
parenthesis when there is other stuff. If you just want information
about the variable you can leave that off.
However for print you never add the dollar sign; printing only
prints variables not strings.
You can change values too using either the setq or
setqx commands. Let’s see the difference between setq
and setqx:
remake<6> setq MAKE $(MAKE_COMMAND)
Variable MAKE now has value '$(MAKE_COMMAND)'
remake<7> setqx MAKE $(MAKE_COMMAND)
Variable MAKE now has value 'remake'
So with setqx, the value in the expression $(MAKE_COMMAND) is
expanded before the variable definition is assigned. With setq the
internal variables are kept unexpanded. Which you use or want is up to
you.
Note the irregular syntax of setq and setqx. Don’t put an equal sign
between the variable and the expression. That is, setq MAKE = $(MAKE_COMMAND) gives:
remake<8> setq MAKE = $(MAKE_COMMAND)
Variable MAKE now has value '= remake'
which is probably not what you want.
Debugging POSIX Shell Commands¶
Now consider the following sample Makefile test2.mk:
PACKAGE=make
all: $(PACKAGE).txt
$(PACKAGE).txt: ../doc/remake.texi
makeinfo --no-headers $< > $@
Running this with the debugger:
$ remake -X -f test2.mk
...
Reading makefiles...
updating makefiles....
Updating goal targets....
/tmp/remake/src/test2.mk:3 File `all' does not exist.
-> (/tmp/test2.mk:5)
make.txt: ../doc/remake.texi
We could use the target command to show information about the current target, but that returns lots of information. So let us instead narrow the information down to just the automatic variables that get set. The following commands will all do this: target make.txt variables, target @ variables, and info locals.
remake<1> target @ variables
@ := all
% :=
* :=
+ := make.txt
| :=
< := all
^ := make.txt
? :=
There is a target option to list just the shell commands of the
target:
remake<2> target @ commands
make.txt:
# commands to execute (from `test2.mk', line 6):
makeinfo --no-headers $< > $@
We can see a full expansion of the command that is about to be run:
remake<5> target @ expand
# commands to execute (from `test2.mk', line 6):
makeinfo --no-headers $< > $@
# commands to execute (from `test2.mk', line 6):
-makeinfo --no-headers ../doc/remake.texi > make.txt
Now if we want to write out commands as a shell script which we might want to execute, we can use the write command:
(/tmp/remake/src/test2.mk:6): make.txt
remake<6> write
File "/tmp/make.txt.sh" written.
We can issue the shell command cat -n /tmp/make.txt.sh to see what
was written. See shell.
remake<7> shell cat -n /tmp/make.txt.sh
#!/bin/sh
# cd /tmp/remake/src/
#/tmp/remake/src/test2.mk:5
makeinfo --no-headers ../doc/remake.texi > make.txt
If you issue step commands, the debugger runs the each command and stops. In this way, you can inspect the result of running that particular shell command and decide whether to continue or not.
remake<8> step
Must remake target `make.txt'.
Invoking recipe from test2.mk:6 to update target `make.txt'.
##>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
makeinfo --no-headers ../doc/remake.texi > make.txt
##<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
++ (/tmp/test2.mk:5)
Notice that we’ve shown the expansion automatically. One subtle difference in the above output, is that it only shows the single shell command that is about to be run when there are several commands. In our example though, there is only one command; so there is no difference.
The ++ icon means that we are about to run that code.
make.txt
remake<9> @b{step}
Successfully remade target file `make.txt'.
<- (/tmp/test2.mk:5)
make.txt
remake<10>
We ran the code, and are still at the target make.txt. The <-
icon means that we have finished with this target and are about to return.
If you are at a target and want to continue to the end of the target you
can use the command finish which is the same as finish 0.
Post-Mortem Debug Session¶
In this session we’ll go into the debugger on encountering an error. For this the --post-mortem
or -! option is used. We’ll use the Makefile from the source code of
this distribution.
to be continued…