PMake takes as input a file that
tells which files depend on which other files to be complete and
what to do about files that are “out-of-date”.
This file is known as a “makefile” and is usually
kept in the top-most directory of the system to be built.
While you can call the makefile anything you want,
PMake will look for
Makefile
and makefile
(in that order) in the current directory if you do not tell it
otherwise. To specify a different makefile, use the
-f
flag, e.g.
%
pmake -f
program.mk
A makefile has four different types of lines in it:
File dependency specifications
Creation commands
Variable assignments
Comments, include statements and conditional directives
Any line may be continued over multiple lines by ending it with a backslash. The backslash, following newline and any initial whitespace on the following line are compressed into a single space before the input line is examined by PMake.
As mentioned in the introduction, in any system, there are dependencies between the files that make up the system. For instance, in a program made up of several C source files and one header file, the C files will need to be re-compiled should the header file be changed. For a document of several chapters and one macro file, the chapters will need to be reprocessed if any of the macros changes. These are dependencies and are specified by means of dependency lines in the makefile.
On a dependency line, there are targets and sources, separated by a one- or two-character operator. The targets “depend” on the sources and are usually created from them. Any number of targets and sources may be specified on a dependency line. All the targets in the line are made to depend on all the sources. Targets and sources need not be actual files, but every source must be either an actual file or another target in the makefile. If you run out of room, use a backslash at the end of the line to continue onto the next one.
Any file may be a target and any file may be a source, but the relationship between the two (or however many) is determined by the “operator” that separates them. Three types of operators exist: one specifies that the datedness of a target is determined by the state of its sources, while another specifies other files (the sources) that need to be dealt with before the target can be re-created. The third operator is very similar to the first, with the additional condition that the target is out-of-date if it has no sources. These operations are represented by the colon, the exclamation point and the double-colon, respectively, and are mutually exclusive. Their exact semantics are as follows:
: | If a colon is used, a target on the line is considered to be “out-of-date” (and in need of creation) if any of the sources has been modified more recently than the target, or the target does not exist. Under this operation, steps will be taken to re-create the target only if it is found to be out-of-date by using these two rules. |
! | If an exclamation point is used, the target will always be re-created, but this will not happen until all of its sources have been examined and re-created, if necessary. |
:: | If a double-colon is used, a target is “out-of-date” if any of the sources has been modified more recently than the target, or the target does not exist, or the target has no sources. If the target is out-of-date according to these rules, it will be re-created. This operator also does something else to the targets, but I will go into that in the next section (see Shell Commands). |
Enough words, now for an example. Take that C program I
mentioned earlier. Say there are three C files
(a.c
, b.c
and
c.c
) each of which includes the file
defs.h
. The dependencies between the files
could then be expressed as follows:
program : a.o b.o c.o a.o b.o c.o : defs.h a.o : a.c b.o : b.c c.o : c.c
You may be wondering at this point, where
a.o
, b.o
and
c.o
came in and why they depend on
defs.h
and the C files do not.
The reason is quite simple: program
cannot be made by linking together .c
files—it must be made from .o
files.
Likewise, if you change defs.h
, it is not
the .c
files that need to be re-created,
it is the .o
files. If you think of
dependencies in these terms—which files (targets) need to
be created from which files (sources)—you should have no
problems.
An important thing to notice about the above example, is
that all the .o
files appear as targets on
more than one line. This is perfectly all right: the target is
made to depend on all the sources mentioned on all the
dependency lines. For example, a.o
depends
on both defs.h
and a.c
.
The order of the dependency lines in the makefile is important: the first target on the first dependency line in the makefile will be the one that gets made if you do not say otherwise. That is why program comes first in the example makefile, above.
Both targets and sources may contain the standard C-Shell wildcard
characters ({
, }
,
*
, ?
, [
, and
]
), but the non-curly-brace ones may only appear in
the final component (the file portion) of the target or source.
The characters mean the following things:
{} | These enclose a comma-separated list of options and
cause the pattern to be expanded once for each element
of the list. Each expansion contains a different
element. For example,
src/{whiffle,beep,fish}.c expands
to the three words src/whiffle.c ,
src/beep.c , and
src/fish.c . These braces may be
nested and, unlike the other wildcard characters, the
resulting words need not be actual files. All other
wildcard characters are expanded using the files that
exist when PMake is
started. |
* | This matches zero or more characters of any sort.
src/*.c will expand to the same
three words as above as long as src contains those three
files (and no other files that end in
.c ).> |
? | Matches any single character. |
[] | This is known as a character class and contains
either a list of single characters, or a series of
character ranges (a-z , for example
means all characters between a and
z ), or both. It matches any single
character contained in the list. For example,
[A-Za-z] will match all letters,
while [0123456789] will match all
numbers. |
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>.