“Is not that nice,” you say to yourself,
“but how are files actually ``re-created'', as he likes to
spell it?”
The re-creation is accomplished by commands you place in the
makefile. These commands are passed to the Bourne shell (better
known as /bin/sh
) to be executed and are
expected to do what is necessary to update the target file
(PMake does not actually check to see
if the target was created. It just assumes it is there).
Shell commands in a makefile look a lot like shell commands you would type at a terminal, with one important exception: each command in a makefile must be preceded by at least one tab.
Each target has associated with it a shell script made up of
one or more of these shell commands. The creation script for a
target should immediately follow the dependency line for that
target. While any given target may appear on more than one
dependency line, only one of these dependency lines may be
followed by a creation script, unless the ::
operator was used on the dependency line.
If the double-colon was used, each dependency line for the target may be followed by a shell script. That script will only be executed if the target on the associated dependency line is out-of-date with respect to the sources on that line, according to the rules I gave earlier. I'll give you a good example of this later on.
To expand on the earlier makefile, you might add commands as follows:
program : a.o b.o c.o cc a.o b.o c.o -o program a.o b.o c.o : defs.h a.o : a.c cc -c a.c b.o : b.c cc -c b.c c.o : c.c cc -c c.c
Something you should remember when writing a makefile is,
the commands will be executed if the target on the dependency
line is out-of-date, not the sources. In this example, the
command cc -c a.c
will be executed if
a.o
is out-of-date. Because of the
:
operator, this means that should
a.c
or defs.h
have
been modified more recently than a.o
, the
command will be executed (a.o
will be
considered out-of-date).
Remember how I said the only difference between a makefile
shell command and a regular shell command was the leading tab?
I lied. There is another way in which makefile commands differ
from regular ones. The first two characters after the initial
whitespace are treated specially. If they are any combination
of @
and -
, they cause
PMake to do different things.
In most cases, shell commands are printed before they are
actually executed. This is to keep you informed of what is
going on. If an @
appears, however, this
echoing is suppressed. In the case of an echo command,
say
echo Linking index
it would be rather silly to see
echo Linking index Linking index
so PMake allows you to place an
@
before the command to prevent the command
from being printed:
@echo Linking index
The other special character is the -
.
In case you did not know, shell commands finish with a certain
“exit status”. This status is made available by
the operating system to whatever program invoked the command.
Normally this status will be 0
if everything
went ok and non-zero if something went wrong. For this reason,
PMake will consider an error to have
occurred if one of the shells it invokes returns a non-zero
status. When it detects an error,
PMake's usual action is to abort
whatever it is doing and exit with a non-zero status itself (any
other targets that were being created will continue being made,
but nothing new will be started.
PMake will exit after the last job
finishes). This behavior can be altered, however, by placing a
-
at the front of a command
(e.g. -mv index index.old
), certain
command-line arguments, or doing other things, to be detailed
later. In such a case, the non-zero status is simply ignored
and PMake keeps chugging
along.
Because all the commands are given to a single shell to
execute, such things as setting shell variables, changing
directories, etc., last beyond the command in which they are
found. This also allows shell compound commands (like for
loops) to be entered in a natural manner. Since this could
cause problems for some makefiles that depend on each command
being executed by a single shell,
PMake has a -B
flag
(it stands for backwards-compatible) that forces each command to
be given to a separate shell. It also does several other
things, all of which I discourage since they are now
old-fashioned.
A target's shell script is fed to the shell on its (the shell's) input stream. This means that any commands, such as ci that need to get input from the terminal will not work right – they will get the shell's input, something they probably will not find to their liking. A simple way around this is to give a command like this:
ci $(SRCS) < /dev/tty
This would force the program's input to come from the terminal. If you cannot do this for some reason, your only other alternative is to use PMake in its fullest compatibility mode. See “Compatibility” in Chapter 4, PMake for Gods.
All FreeBSD documents are available for download at https://download.freebsd.org/ftp/doc/
Questions that are not answered by the
documentation may be
sent to <freebsd-questions@FreeBSD.org>.
Send questions about this document to <freebsd-doc@FreeBSD.org>.