bug-make
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: GNU make troubleshooting


From: Paul Smith
Subject: Re: GNU make troubleshooting
Date: Sat, 26 Aug 2023 12:48:05 -0400
User-agent: Evolution 3.48.4 (by Flathub.org)

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 <psmith@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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]