a single command. First it stores the result of __PROMPT in __INPUT and the it calls the __DEBUG function (which handles debugger commands) with two arguments: the command and its argument returns by __PROMPT in __INPUT.
__BREAK = $(eval __INPUT := $(__PROMPT)) \
$(call __DEBUG, \
$(word 1,$(__INPUT)), \
$(word 2,$(__INPUT)))
The core of the debugger is handled by the __DEBUG function. __DEBUG takes a single character command in its first argument ($1) and an optional argument to the command in $2. $1 is stored in the variable __c, and $2 in __a. Then __DEBUG examines __c to see whether it is one of the supported debugger commands (c, q, v, d, o, or h) (if not a call to $(warning) will output an error message).
__DEBUG consists of a set of nested $(if) statements that use the GMSL seq function to determine is the __c is a valid debugger command. If it is then $(if)'s first argument is expanded, if not then the next $(if) is examined. For example, the v command (which outputs the value of a variable) is handled like this: $(if $(call seq,$(__c),v),$(warning $(__a) has value '$($(__a))'), ... next if ... ). If the __c command is v then $(warning) is used to output the value of the variable named by __a (the $($(__a)) outputs the value of the variable whose name is stored in __a).
When __DEBUG is done it returns either $(true) or $(false) (the empty string). $(true) indicates that the debugger show stop prompting for commands and continue execution. (The q command is handled by calling GNU Make's $(error) function to cause a fatal error, which stops the Make).
__DEBUG = $(eval __c = $(strip $1)) \
$(eval __a = $(strip $2)) \
$(if $(call seq,$(__c),c), \
$(true), \
$(if $(call seq,$(__c),q), \
$(error Debugger terminated build), \
$(if $(call seq,$(__c),v), \
$(warning $(__a) has value '$($(__a))'), \
$(if $(call seq,$(__c),d), \
$(warning $(__a) is defined as '$(value $(__a))'), \
$(if $(call seq,$(__c),o), \
$(warning $(__a) came from $(origin $(__a))), \
$(if $(call seq,$(__c),h), \
$(warning c continue) \
$(warning q quit) \
$(warning v VAR print value of $$(VAR)) \
$(warning o VAR print origin of $$(VAR)) \
$(warning d VAR print definition of $$(VAR)), \
$(warning Unknown command '$(__c)')))))))
Finally, we come to the definition of __BREAKPOINT (the breakpoint variable we used in the example above). It first outputs a banner containing information (see __BANNER below), then it loops asking for commands by calling __BREAK. The loop terminates if it either runs out of items in __LOOP (which is where the 32 command limit is defined, see above), or if a call to __BREAK returns $(true)).
__BREAKPOINT = $(__BANNER) \
$(eval __TERMINATE := $(false)) \
$(foreach __HISTORY, \
$(__LOOP), \
$(if $(__TERMINATE),, \
$(eval __TERMINATE := $(__BREAK)))) __BANNER is used to show that the debugger has stopped at a breakpoint and by examining GNU Make automatic variables it is able to give information about the current rule being built.
__BANNER = $(warning GNU Make Debugger Break) \
$(if $^, \
$(warning - Building '$@' from '$^'), \
$(warning - Building '$@')) \
$(if $<,$(warning - First prerequisite is '$<')) \
$(if $%,$(warning - Archive target is '$%')) \
$(if $?,$(warning - Prequisites '$?' are newer than '$@')) ConclusionAnd there you have it. An interactive GNU Make debugger written entirely in GNU Make. Next time I'll build on this foundation to provide interactive tracing. In the meantime, I hope that this debugger helps you with your Makefile problems.
The Debugger for Copy and Paste
include gmsl __LOOP := 1 2 3 4






