This is what happens when the install-HEADERS
target from
example 5.16 is invoked:
$ make install-HEADERS mkdir /usr/local/include mkdir: cannot make directory `/usr/local/include': File exists make: *** [install-HEADERS] Error 1
Not exactly what we wanted, yet we do need to keep the mkdir
command line in the rule incase the person who installs the project
really doesn't have a /usr/local/include
directory. Discarding
the error message is easy enough, we simply redirect it to
/dev/null
. The real problem is that when Make encounters an
error in the command sequence, it stops processing and prints a
message like the one above.
Make provides a facility to override this behaviour, and thus continue
normal processing and ignore any error from the shell command. By
prefixing the command with a -
character as follows, we tell
make
that it doesn't matter if that command fails:
install-HEADERS: $(include_HEADERS) -mkdir $(includedir) 2>/dev/null for p in $(include_HEADERS); do \ cp $$p $(includedir)/$$p; \ done
Example 5.17: Ignoring errors from shell commands in Make rules
Things progress as expected now:
$ make install-HEADERS mkdir /usr/local/include make: [install-HEADERS] Error 1 (ignored) for p in m4module.h error.h hash.h system.h; do \ cp $p /usr/local/include/$p; \ done
Notice that the $$p
references from the Makefile commands have
been passed to the shell as $p
as explained in the last section.
As long as it doesn't encounter any errors in the commands as it
processes them (except for -
prefix ignored errors), the normal
behaviour of Make is to echo each line of the command to your display
just before passing it to the shell. As this happens, Make variables
are replaced by their current value, as evidenced by the list of files
in the for
loop above where $(include_HEADERS)
was written
in the Makefile. Although double $$
sequences are replaced by a
single $
, the command itself along with any shell variable
references are then simply copied to your display before the shell
processes it.
There is another prefix that you can add to a command line to suppress
echoing. By inserting a @
at the start of a command, you tell
Make to pass that command directly to the shell for processing. We can
take advantage of this feature to clarify what the shell is doing in the
commands of our install-HEADERS
rule:
install-HEADERS: $(include_HEADERS) @test -d $(includedir) || \ { echo mkdir $(includedir); mkdir $(includedir); } @for p in $(include_HEADERS); do \ echo cp $$p $(includedir)/$$p; \ cp $$p $(includedir)/$$p; \ done
Example 5.18: Suppressing echoing of shell commands in Make rules
There are still two commands in this rule, but now we have turned off
echoing from Make with the @
prefix, and instead use the shell
echo
command to report what is being done:
$ make install-HEADERS cp m4module.h /usr/local/include/m4module.h cp error.h /usr/local/include/error.h cp hash.h /usr/local/include/hash.h cp system.h /usr/local/include/system.h
This time, we tested for the existence of a $(includedir)
, and
created it only if it was missing. In this example the directory was
already present, so the second clause of the first command in
example 5.18 didn't
trigger.
Because of the @
prefix on the first command in the rule, no
command is echoed by make. We control when something is displayed, and
echo the command only when it is executed. Much better.
Also, rather than letting Make echo the for
loop code directly,
we have the shell individually report each file that it copies, which
makes the output of the command reflect exactly what is going on, and
makes it easier for your users to see what is happening when that rule
is invoked.