Debugging Makefiles Is Somewhat of a Black Art
Total Page:16
File Type:pdf, Size:1020Kb
,ch12.8053 Page 229 Friday, March 25, 2005 2:55 PM Chapter 12 CHAPTER 12 Debugging Makefiles Debugging makefiles is somewhat of a black art. Unfortunately, there is no such thing as a makefile debugger to examine how a particular rule is being evaluated or a variable expanded. Instead, most debugging is performed with simple print state- ments and by inspection of the makefile. GNU make provides some help with various built-in functions and command-line options. One of the best ways to debug a makefile is to add debugging hooks and use defen- sive programming techniques that you can fall back on when things go awry. I’ll present a few basic debugging techniques and defensive coding practices I’ve found most helpful. Debugging Features of make The warning function is very useful for debugging wayward makefiles. Because the warning function expands to the empty string, it can be placed anywhere in a makefile: at the top-level, in target or prerequisite lists, and in command scripts. This allows you to print the value of variables wherever it is most convenient to inspect them. For example: $(warning A top-level warning) FOO := $(warning Right-hand side of a simple variable)bar BAZ = $(warning Right-hand side of a recursive variable)boo $(warning A target)target: $(warning In a prerequisite list)makefile $(BAZ) $(warning In a command script) ls $(BAZ): yields the output: $ make makefile:1: A top-level warning makefile:2: Right-hand side of a simple variable makefile:5: A target 229 This is the Title of the Book, eMatter Edition Copyright © 2005 O’Reilly & Associates, Inc. All rights reserved. ,ch12.8053 Page 230 Friday, March 25, 2005 2:55 PM makefile:5: In a prerequisite list makefile:5: Right-hand side of a recursive variable makefile:8: Right-hand side of a recursive variable makefile:6: In a command script ls makefile Notice that the evaluation of the warning function follows the normal make algorithm for immediate and deferred evaluation. Although the assignment to BAZ contains a warning, the message does not print until BAZ is evaluated in the prerequisites list. The ability to inject a warning call anywhere makes it an essential debugging tool. Command-Line Options There are three command-line options I find most useful for debugging: --just- print (-n), --print-data-base (-p), and --warn-undefined-variables. --just-print The first test I perform on a new makefile target is to invoke make with the --just- print (-n) option. This causes make to read the makefile and print every command it would normally execute to update the target but without executing them. As a con- venience, GNU make will also echo commands marked with the silent modifier (@). The option is supposed to suppress all command execution. While this may be true in one sense, practically speaking, you must take care. While make will not execute command scripts, it will evaluate shell function calls that occur within an immedi- ate context. For instance: REQUIRED_DIRS = ... _MKDIRS := $(shell for d in $(REQUIRED_DIRS); \ do \ [[ -d $$d ]] || mkdir -p $$d; \ done) $(objects) : $(sources) As we’ve seen before, the purpose of the _MKDIRS simple variable is to trigger the cre- ation of essential directories. When this is executed with --just-print, the shell command will be executed as usual when the makefile is read. Then make will echo (without executing) each compilation command required to update the $(objects) file list. --print-data-base The --print-data-base (-p) option is another one you’ll use often. It executes the makefile, displaying the GNU copyright followed by the commands as they are run by make, then it will dump its internal database. The data is collected into groups of 230 | Chapter 12: Debugging Makefiles This is the Title of the Book, eMatter Edition Copyright © 2005 O’Reilly & Associates, Inc. All rights reserved. ,ch12.8053 Page 231 Friday, March 25, 2005 2:55 PM values: variables, directories, implicit rules, pattern-specific variables, files (explicit rules), and the vpath search path: # GNU Make 3.80 # Copyright (C) 2002 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. # There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. normal command execution occurs here # Make data base, printed on Thu Apr 29 20:58:13 2004 # Variables … # Directories … # Implicit Rules … # Pattern-specific variable values … # Files … # VPATH Search Paths Let’s examine these sections in more detail. The variables section lists each variable along with a descriptive comment: # automatic <D = $(patsubst %/,%,$(dir $<)) # environment EMACS_DIR = C:/usr/emacs-21.3.50.7 # default CWEAVE = cweave # makefile (from `../mp3_player/makefile', line 35) CPPFLAGS = $(addprefix -I ,$(include_dirs)) # makefile (from `../ch07-separate-binaries/makefile', line 44) RM := rm -f # makefile (from `../mp3_player/makefile', line 14) define make-library libraries += $1 sources += $2 $1: $(call source-to-object,$2) $(AR) $(ARFLAGS) $$@ $$^ endef Automatic variables are not printed, but convenience variables derived from them like $(<D) are. The comment indicates the type of the variable as returned by the origin function (see the section “Less Important Miscellaneous Functions” in Chapter 4). If the variable is defined in a file, the filename and line number of the definition is given. Simple and recursive variables are distinguished by the Debugging Features of make | 231 This is the Title of the Book, eMatter Edition Copyright © 2005 O’Reilly & Associates, Inc. All rights reserved. ,ch12.8053 Page 232 Friday, March 25, 2005 2:55 PM assignment operator. The value of a simple variable will be displayed as the evalu- ated form of the righthand side. The next section, labeled Directories, is more useful to make developers than to make users. It lists the directories being examined by make, including SCCS and RCS subdi- rectories that might exist, but usually do not. For each directory, make displays imple- mentation details, such as the device number, inode, and statistics on file pattern matches. The Implicit Rules section follows. This contains all the built-in and user-defined pattern rules in make’s database. Again, for those rules defined in a file, a comment indicates the file and line number: %.c %.h: %.y # commands to execute (from `../mp3_player/makefile', line 73): $(YACC.y) --defines $< $(MV) y.tab.c $*.c $(MV) y.tab.h $*.h %: %.c # commands to execute (built-in): $(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@ %.o: %.c # commands to execute (built-in): $(COMPILE.c) $(OUTPUT_OPTION) $< Examining this section is a great way to become familiar with the variety and struc- ture of make’s built-in rules. Of course, not all built-in rules are implemented as pat- tern rules. If you don’t find the rule you’re looking for, check in the Files section where the old-style suffix rules are listed. The next section catalogs the pattern-specific variables defined in the makefile. Recall that pattern-specific variables are variable definitions whose scope is precisely the execution time of their associated pattern rule. For example, the pattern variable YYLEXFLAG, defined as: %.c %.h: YYLEXFLAG := -d %.c %.h: %.y $(YACC.y) --defines $< $(MV) y.tab.c $*.c $(MV) y.tab.h $*.h would be displayed as: # Pattern-specific variable values %.c : # makefile (from `Makefile', line 1) # YYLEXFLAG := -d # variable set hash-table stats: # Load=1/16=6%, Rehash=0, Collisions=0/1=0% 232 | Chapter 12: Debugging Makefiles This is the Title of the Book, eMatter Edition Copyright © 2005 O’Reilly & Associates, Inc. All rights reserved. ,ch12.8053 Page 233 Friday, March 25, 2005 2:55 PM %.h : # makefile (from `Makefile', line 1) # YYLEXFLAG := -d # variable set hash-table stats: # Load=1/16=6%, Rehash=0, Collisions=0/1=0% # 2 pattern-specific variable values The Files section follows and lists all the explicit and suffix rules that relate to specific files: # Not a target: .p.o: # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # commands to execute (built-in): $(COMPILE.p) $(OUTPUT_OPTION) $< lib/ui/libui.a: lib/ui/ui.o # Implicit rule search has not been done. # Last modified 2004-04-01 22:04:09.515625 # File has been updated. # Successfully updated. # commands to execute (from `../mp3_player/lib/ui/module.mk', line 3): ar rv $@ $^ lib/codec/codec.o: ../mp3_player/lib/codec/codec.c ../mp3_player/lib/codec/codec.c .. /mp3_player/include/codec/codec.h # Implicit rule search has been done. # Implicit/static pattern stem: `lib/codec/codec' # Last modified 2004-04-01 22:04:08.40625 # File has been updated. # Successfully updated. # commands to execute (built-in): $(COMPILE.c) $(OUTPUT_OPTION) $< Intermediate files and suffix rules are labeled “Not a target”; the remainder are tar- gets. Each file includes comments indicating how make has processed the rule. Files that are found through the normal vpath search have their resolved path displayed. The last section is labeled VPATH Search Paths and lists the value of VPATH and all the vpath patterns. For makefiles that make extensive use of user-defined functions and eval to create complex variables and rules, examining this output is often the only way to verify that macro expansion has generated the expected values. --warn-undefined-variables This option causes make to display a warning whenever an undefined variable is expanded. Since undefined variables expand to the empty string, it is common for typographical errors in variable names to go undetected for long periods. The problem Debugging Features of make | 233 This is the Title of the Book, eMatter Edition Copyright © 2005 O’Reilly & Associates, Inc. All rights reserved. ,ch12.8053 Page 234 Friday, March 25, 2005 2:55 PM with this option, and why I use it only rarely, is that many built-in rules include unde- fined variables as hooks for user-defined values.