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