|
The debugger has breakpoints, dumps information about the rule at which a breakpoint is hit and allows interactive querying of variable values and definitions. In a follow up article I'll extend the debugger to provide detailed tracing of the execution of any rule. The Debugger In ActionBefore showing you how the debugger works, let's take a look at how to use it. The debugger and these examples all assume that you are using GNU Make 3.80 or above. Here's an example Makefile that builds all from prerequisites foo and bar. To illustrate the use of the debugger I've set a breakpoint in the all rule by inserting a line at the start of the rule's body that consists of just the variable $(__BREAKPOINT). $(__BREAKPOINT) will get expanded when the rule is ready to run and this will cause the debugger to break execution and prompt when the all rule is about to run. (I've ommitted all the debugger code, we'll take a look at it below). MYVAR1 = helloHere's what happens when this Makefile is executed with no existing files called all, foo or bar. Building fooFirst the output from the execution of the rules for foo and bar is seen (the Building foo and Building bar lines) and then there's a break into the debugger. The debugger break shows the line at which the break occurred and in which Makefile. In this case the breakpoint occurred at line 51 of Makefile. The debugger also outputs information about the rule being built. Here you can see that all is built from foo and bar; that the first prerequisite is foo (that's important because it's the first prerequisite and is stored in GNU Make's $< automatic variable. $< is typically used as the source code file name for compiles). The debugger also shows why the all rule ran: foo and bar are both newer than all (that's because they were both just build by their respective rules). Finally the debugger prompts 1> for a command. The debugger will accept 32 commands before automatically continuing execution of the Makefile. The number 1 indicates that this is the first command; once 32> is reached the debugger will continue automatically. The first thing to do is ask for help by typing h. 1> hThe debugger provides two means of stopping debugging: typing c continues with normal execution of the Makefile, typing q quits Make altogether. The three debugger commands v, o and d allow the user to interrogate GNU Make variables by asking for the value of a variable, its origin (where it was defined) or its definition. For example, the Makefile contains two variables MYVAR1 and MYVAR2 and a variable that is specific to the all rule: MYVAR3. A first step is to ask the debugger for the values of each of these variables: 2> v MYVAR1If it wasn't clear how MYVAR3 got its value we could ask the debugger for its definition: 5> d MYVAR3which shows that MYVAR3 is defined as $(MYVAR2). And so the obvious next step is to find out how MYVAR2 is defined (and also MYVAR1): 6> d MYVAR2And if it wasn't clear where MYVAR1 got its value from the o command will show its origin: 8> o MYVAR1which means that MYVAR1 is defined in a Makefile. In contrast, if the user has overriden the value of MYVAR1 on the command line of Make (by running say make MYVAR1=Hello) the o command would reflect that: 1> v MYVAR1Breakpoints In PatternsAs well as setting breakpoints in normal rules, you can also set them in patterns. Every time that pattern rule is used the breakpoint is hit. For example, all: foo.x bar.xHere all is built from foo.x and bar.x which requires building them from foo.y and bar.y using the %.x : %.y rule. I've inserted a breakpoint in the pattern rule and the debugger breaks twice: once for foo.x and once for bar.x: Makefile:66: GNU Make Debugger BreakEven pattern-specific variables work. %.x has a pattern-specific variable FOO with value foo the debugger v command can access it during a breakpoint on the pattern rule: Makefile:67: GNU Make Debugger BreakBreakpoints In MakefilesFinally, you can simply stick a breakpoint in a Makefile if needed. Parsing of Makefiles will pause at the breakpoint and the current state of variables in the Makefile can be examined. For example with a breakpoint after each definition of FOO in this Makefile it's possible to see its value change: FOO = fooThe DebuggerThe debugger itself draws on functions defined in the GNU Make Standard Library (you can read more about the GMSL in this article). The first line of the debugger includes the GMSL functions: include gmslThe __PROMPT variable is used by the debugger to output the n> and read in a command followed by a single argument. __PROMPT uses the read command to get the command and argument into shell variables $CMD and $ARG and then returns a list of two elements: the first element is the command and the second the argument. Expanding __PROMPT prompts for an returns a single command and argument pair. __PROMPT = $(shell read -p "$(__HISTORY)> " CMD ARG ; echo $$CMD $$ARG)The __BREAK variable is used to get and handle 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)) \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)) \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) \__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) \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 John Graham-Cumming is Founder and VP of Engineering at Electric Cloud, Inc. Prior to joining Electric Cloud, John was a Venture Consultant with Accel Partners, VP of Internet Technology at Interwoven, Inc. (IWOV), VP of Engineering at Scriptics Corporation (acquired by Interwoven), and Chief Architect at Optimal Networks, Inc. John holds BA and MA degrees in Mathematics and Computation and a Doctorate in Computer Security from Oxford University. John is the creator of the highly acclaimed open source POPFile project. He also holds two patents in network analysis and has others pending.
Set as favorite
Bookmark
Email this
Hits: 17886 Trackback(0)Comments (6)
|
|
... Thanks for the code. I note the links to the articles "trace macro values" and "print the value of a macro" are broken. Archives were lost? |
|
ajh
said:
|
... I got it to work. For the "-p" problem, I made sure my SHELL variable was set to bash. I also noticed that when I cut and pasted, all the lines that end with backslash had a extra space after the backslash. That has to be removed. |
|
The Tom Jones
said:
|
... Actually, it appears that installing a Cypress Semiconductor cygwin toolkit has buggerred up my cygwin installation - don't bother responding - let me fix my personal problem first and I'll let you know if I still have a gmd problem when I've cleared it up. ~Tom |
|
The Tom Jones
said:
|
... I have to echo Suze. It seems cool but no worky for me. I downloaded gmd and gmsl from sourceforge. make -f gmsl-tests - all OK. However, make -f gmd-test fails with: read: Illegal option -p gmd-test:57: Unknown command '' many, many times. I am using cygwin - it fails the same in DOS and bash shells. Any ideas? Tom |
|
John Graham-Cumming
said:
|
... Try downloading from http://gmd.sf.net/ instead of copy and paste and see if it works for you. John. |
|
suze brown
said:
|
... Hi John, Your tool seems so cool. But I dont seem to be able to get it to work.. i pasted the above debugger code in a file name debugger.mak and the example Makefile in a file named Makefile. i get the following error when i do:- # gmake -f Makefile -f debugger.mk debugger.mk:11: *** unterminated call to function `if': missing `)'. Stop. i'm a newbie, working to get better each day.. i'll wait for your reply. thanks.. |
|
Write comment
You must be logged in to post a comment. Please register if you do not have an account yet.



