I added a new appendix to the GNU make manual for troubleshooting help; I haven't pushed it yet. See below. Comments welcome.
I think the outline you provided earlier, Bruno, has the problem that a lot of it isn't really about troubleshooting per se, it's about how to write makefiles in general. I tried to restrict this specifically to describing the types of problems you might see and the steps you might take to troubleshoot them. I'm thinking of adding another chapter on hints and tips for writing good makefiles. ----------------- Appendix C Troubleshooting Make and Makefiles ********************************************* Troubleshooting 'make' and makefiles can be tricky. There are two reasons: first, makefiles are not procedural programs and many users are used to procedural languages and scripts. Second, makefiles consist of two different syntaxes in one file: makefile syntax, that 'make' reads, and shell syntax, which is sent to a shell program for parsing and execution. If you have problems with GNU Make, first consider the type of problem you are having. Problems will generally be in one of these categories: * A syntax or other error was reported when 'make' attempted to parse your makefiles. * A command that 'make' invoked failed (exited with a non-0 exit code). * The command that 'make' invoked was not the one you expected. * 'make' was not able to find a rule to build a target. * 'make' rebuilds a target that you didn't think was out of date. * Or, 'make' did not rebuild a target that you expected it to build. The strategies for troubleshooting differ for different types of problems. For issues related to how makefiles are parsed, strategies include: * Using the '-p' option to show the makefile database, after evaluation (*note Summary of Options: Options Summary.). * Using the 'info' function to understand how elements of the makefile are expanded (*note Functions That Control Make: Make Control Functions.). For issues related to how rules are applied, strategies include: * Removing the '@' prefix from recipes, so you can see the commands make is invoking to rebuild the target (*note Recipe Echoing: Echoing.). * Using the '--trace' option to explain which rules 'make' invokes and why (*note Summary of Options: Options Summary.). * Using the '--debug=v,i' or '-d' options to show how 'make' is determining which recipes should be used, or why targets do not need to be rebuilt (*note Summary of Options: Options Summary.). * Menu: * Parse Error:: Syntax errors when parsing makefiles. * Command Failure:: Recipe commands exit with error codes. * Wrong Rule:: 'make' chooses the wrong rule. * No Rule Found:: No rule was found to build a target. * Extra Rebuilds:: Targets are rebuilt unnecessarily. * Missing Rebuilds:: Out-of-date targets are not rebuilt. * Troubleshooting Strategies:: Strategies used for troubleshooting issues. C.1 Errors When Parsing Makefiles ================================= This type of error is the simplest to resolve. The error output you will see will have a format like this: Makefile:10: *** missing separator. Stop. This message gives you all the information you need to address the error: it gives the name of the makefile (here 'Makefile') and the line number (here '10') in that makefile where GNU Make's parser failed. Following that is a description of the error. Further explanations of these error messages can be found in *note Errors Generated by Make: Error Messages. C.2 Errors Reported by Commands =============================== If GNU Make parses the makefiles correctly and runs a command to rebuild a target, it expects that command to exit with an error code of '0' (for success). Any other exit code will be reported by 'make' as a failure and will generate an error message with this form: make: *** [Makefile:10: target] Error 2 All the information you need to find that command are given: the name of the makefile (here 'Makefile') and line number (here '10') of the command make invoked, the target (here 'target') that make was trying to build, and finally the exit code of the command (here '2'). However, 'make' cannot know what the actual problem is. To troubleshoot these errors (*note Strategies for Troubleshooting: Troubleshooting Strategies.), first remove any '@' prefixes from the recipe that is failing so you can see the complete command line being invoked. Than, examine the output of the command that 'make' invoked to determine what went wrong and why: this output will appear _before_ the above error message. The error may be due to an incorrect command line in which case the error is in the way your command was written in the makefile, but it's far more likely to be a problem with something outside of the makefile (for example, a syntax error in the code you are trying to compile). C.3 Choosing the Wrong Rule =========================== If 'make' seems to be invoking a different command than the one you intended, it could be that the wrong rule is being chosen. To troubleshoot these errors (*note Strategies for Troubleshooting: Troubleshooting Strategies.), add the '--trace' option to the 'make' command line. This shows the rule that was chosen. You can also use the '--debug=v,i' or the full '-d' option to determine how 'make' decided to use that rule. C.4 No Rule to Build A Target ============================= If 'make' cannot locate a rule to build a target that you requested, either via the command line or as a prerequisite of another target, it shows an error such as: make: *** No rule to make target 'aprogram'. Stop. If the makefile doesn't provide a rule for this target, you can add one. If there is a rule which you intended 'make' to use to build this target and it wasn't used, the most common reasons for this are: * The target was misspelled. You should consider following the _DRY_ principle (Don't Repeat Yourself) by assigning file names (targets and prerequisites) to makefile variables and using those variables rather than retyping the file names. * The target is in a different directory. 'make' considers the targets 'target' and 'dir/target' (for example) to be different targets. If you are using rules that create targets outside of the current working directory, be sure you correctly prefix them with their directories everywhere that they appear in the makefile. * A pattern rule didn't match because one of its prerequisites cannot be built. Pattern rules will only be used when *all* prerequisites can be satisfied: either they exist already or 'make' can find a way to build them. If any prerequisite cannot be created, then the pattern does not match and 'make' will continue looking for another matching pattern. If no matching pattern can be found, then 'make' will fail. To troubleshoot these issues (*note Strategies for Troubleshooting: Troubleshooting Strategies.), run 'make' with the '--debug=v,i' option, or the full '-d' option, and examine the detailed output. If the definition of the rule in your makefile is complicated, you can use the '-p' option to ask make to print its internal database of rules to ensure they are correct, or as a last resort add invocations of 'info' function to show what steps 'make' is taking during evaluation. C.5 Unwanted Rebuilding of Targets ================================== If 'make' is rebuilding a target which you feel is already up to date and doesn't need to be rebuilt, there can be a number of reasons: * The recipe does not update the target. A makefile rule is a promise to 'make' that if it invokes the recipe, the target will be updated. The file which 'make' expects to be updated is placed in the '$@' variable. If the recipe doesn't update this file, and _exactly_ this file, then the next time 'make' is invoked it will try to re-build that target again. * A prerequisite is marked as phony (*note Special Built-in Target Names: Special Targets.). All phony targets are always considered out of date, and so any targets depending on them are also out of date. * A directory is used as a prerequisite. Directories are not treated specially by 'make': if their modification time is newer than the target then the target is considered out of date and rebuilt. Since directory modification times are changed whenever a file is created, deleted, or renamed in that directory, it means targets depending on the directory will be considered out of date whenever a file is created, deleted, or renamed in that directory. * Something is deleting the target file. Of course if a file does not exist it is always considered out of date (see the first item above). If something in your environment, either inside the 'makefile' or outside if it, is deleting the target file then 'make' will always rebuild it. * The target is created with a "too-old" modification time. If the recipe creates the target with a modification time in the past, then it may still be out of date with respect to its prerequisites. This could happen if, for example, you are extracting files from an archive or copying them from another location and the tool used to do the extraction or copying preserves the original file's modification time. To troubleshoot these issues (*note Strategies for Troubleshooting: Troubleshooting Strategies.), remove the '@' prefix in your recipe so you can see the full command line that 'make' is running. You can also use the '--trace' option, to understand why 'make' decides to build a target. C.6 Out-of-Date Targets Not Rebuilt =================================== The opposite of the previous problem is 'make' not rebuilding targets that you think should be rebuilt. Some reasons for this might be: * The target is not being considered. Unless the command line specifies otherwise, 'make' will only consider the first target in the makefile and its prerequisites. If the target you expected to be built is not one of these, then 'make' won't build it. * A different file is being built instead. Be sure that your target is the file you want to be built (including any directory prefix!) and that the recipe will create the file listed as '$@'. Also consider the directory that 'make' is running in and whether relative pathnames are the ones you expect. To troubleshoot these issues (*note Strategies for Troubleshooting: Troubleshooting Strategies.), remove the '@' prefix in your recipe when 'make' does rebuild the target so you can see what command is being invoked. You can also use the '--debug=v,i' option or the full '-d' option to obtain a complete description of everything 'make' considered and why it decided to build or not build every target. C.7 Strategies for Troubleshooting ================================== The strategies for troubleshooting differ for different types of problems. Remove '@' prefixes ------------------- If your makefile is using the '@' prefix in recipes to prevent 'make' from echoing the commands it invokes (*note Recipe Echoing: Echoing.), the first thing you should do is remove this token so that you can see the full command line that 'make' is running. This will help you understand what your recipe is actually doing. You should not add these prefixes until _after_ your makefile is working completely. They hide details which are critical when troubleshooting makefiles. Show the makefile database -------------------------- Use the '-p' option to show the makefile database, after evaluation (*note Summary of Options: Options Summary.). This allows you to see how 'make' has evaluated the variables and recipes in your makefile. The '-p' option asks GNU Make to print its internal database of rules, after all makefiles have been parsed. You might see output such as: program: prereq.o # Implicit rule search has not been done. # Modification time never checked. # File has not been updated. # recipe to execute (from 'Makefile', line 10): $(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS) Here we can see the target (here 'program') and prerequisites (here 'prereq.o') after variable expansion, as well as the location of the definition of the recipe for this rule (here, in 'Makefile' at line '10'). Add 'info' calls ---------------- The 'info' function can help to understand how elements of the makefile are expanded (*note Functions That Control Make: Make Control Functions.). Although it requires modifying the makefile, 'info' is a powerful tool for troubleshooting complex makefiles such as those using 'eval' and 'call' functions to dynamically generate rules. For example if your makefile contains: $(foreach T,$(TARGET),$(eval $(call makerule,$T,$($T_PREREQ)))) then duplicating this line and replacing 'eval' with 'info' will show exactly what content 'make' will be evaluating: $(foreach T,$(TARGET),$(info $(call makerule,$T,$($T_PREREQ)))) Use the '--trace' option ------------------------ Use the '--trace' option on the 'make' command line to explain which rules 'make' invokes and why (*note Summary of Options: Options Summary.). Adding this will result in output like this for each target which is rebuilt: Makefile:10: update target 'program' due to: target does not exist or: Makefile:10: update target 'program' due to: prereq.o This shows the filename of the makefile (here 'Makefile') and line number (here '10'), along with the name of the target (here 'program') and the reason why it was rebuilt: in the first example because the target does not exist, and in the second example because there were prerequisites (here, 'prereq.o') that were newer than the target. All newer prerequisites would be listed here. Use the '--debug' or '-d' option -------------------------------- Use the '--debug=v,i' or '-d' options to show how 'make' is determining which recipes should be used, or why targets do not need to be rebuilt (*note Summary of Options: Options Summary.). The amount of output generated by these options can be daunting, but redirecting the output to a file then searching it for the target you are concerned with will show you exactly what steps GNU Make took when considering this target, and why it decided to build, or not build, that target. If the issue is that 'make' decides _not_ to rebuild the target when you think it should, this may be your only recourse since '--trace' only shows why targets are considered out of date. -- Paul D. Smith <psm...@gnu.org> Find some GNU make tips at: https://www.gnu.org http://make.mad-scientist.net "Please remain calm...I may be mad, but I am a professional." --Mad Scientist