Dynamic Breakpoints in the GNU Make Debugger


rather complex $(if). Concentrate for a moment on the call to $(__BP_CHECK). That's the macro that will actually check to see whether the macro needs to execute a breakpoint. It's defined like this:

__BP_CHECK = $(if $(call set_is_member,$@,$(__BREAKPOINTS)),\                
	$(eval __BP_FLAG := $@)                             \                
	$(eval __IGNORE := $(call SHELL,__BREAKPOINT)))  
__BP_FLAG := 

__BP_CHECK checks to see if the current target being built (stored in the standard GNU Make automatic variable $@) is present in the list of breakpoints. If does this using the new GMSL function set_is_member. If the target is present then it does two things: it sets an internal variable called

__BP_FLAG to be the target with the breakpoint and then proceeds to $(call) a macro and throw away the result by setting storing it in a variable called __IGNORE. That's done so that __BP_CHECK's return value will be empty; it's used, after all, in the definition of SHELL which ultimately needs to be just the name of the shell to execute.

Experienced GNU Make users will be scratching their heads wondering why I wrote the odd syntax $(call SHELL,__BREAKPOINT). That's where some GNU Make rocket science comes in.

Rocket Science

Instead of writing $(call SHELL,__BREAKPOINT) I would have wanted to write $(__BREAKPOINT) to get the breakpoint to activate. But I can't.

I can't because doing so would cause a fatal GNU Make error. If you follow the chain of macros up from __BP_CHECK you'll see that it's been expanded because SHELL was being expanded (because a rule was about to run). If you follow into __BREAKPOINT you'd have the nasty surprise that there's a call to $(shell) (you can see this in the GMD code or in my previous article) which is going to cause SHELL to be expanded.

Eek! SHELL is defined in terms of SHELL. This causes GNU Make to spot the recursion and give up. The $(call SHELL,__BREAKPOINT) syntax lets us play with fire. Any time a variable is $(call)ed in GNU Make the flag that is used to check for recursion is disabled. So doing $(call SHELL,__BREAKPOINT) means that the recursion flag on SHELL is turned off (avoiding the error) and if you examine the definition of SHELL you'll see that it calls

__BP_NEW_SHELL with one argument. The argument is the word __BREAKPOINT. __BP_NEW_SHELL checks to see if __BP_FLAG is set to the same value as $@ (which it does using the GMSL seq function) and then proceeds to $(call) its first argument (which is __BREAKPOINT) and the breakpoint fires and the prompt appears.

You might be worrying now that some horrible infinite recursion will occur when the $(shell) gets executed and SHELL is expanded again. Two things prevent that: firstly __BP_FLAG is still the same as $@ (so that __BP_CHECK is not called again) and this time SHELL has no argument (i.e. the value in $1 is empty) and so that $(call $1,) does nothing and recursion stops.


And with that v1.0.1 of the GNU Make Debugger is released. It can be downloaded from gmd.sf.net. See you next time.

About the author

AgileConnection is one of the growing communities of the TechWell network.

Featuring fresh, insightful stories, TechWell.com is the place to go for what is happening in software development and delivery.  Join the conversation now!