GEOS SDK TechDocs
|
|
13.4 Contents of a Makefile
|
13.6 The Way Things Work
This section is devoted to those facilities in
pmake
that allow you to do a great deal in a makefile with very little work, as well as do some things you couldn't do in make without a great deal of work (and perhaps the use of other programs). The problem with these features is that they must be handled with care, or you will end up with a mess.
The
pmake
tool supports the dispersal of files into multiple directories by allowing you to specify places to look for sources with .PATH targets in the makefile. The directories you give as sources for these targets make up a "search path." Only those files used exclusively as sources are actually sought on a search path, the assumption being that anything listed as a target in the makefile can be created by the makefile and thus should be in the current directory.
There are two types of search paths in
pmake
: one is used for all types of files (including included makefiles) and is specified with a plain .PATH target (e.g. ".PATH : RCS"), while the other is specific to a certain type of file, as indicated by the file's suffix. A specific search path is indicated by immediately following the .PATH with the suffix of the file. For instance
.PATH.H : \GEOSDEV\DEVEL\APPL\WORPRO \GEOSDEV\DEVEL
would tell
pmake
to look in the directories \GEOSDEV\DEVEL\APPL\WORPRO and \GEOSDEV\DEVEL for any files whose suffix is .H.
The current directory is always consulted first to see if a file exists. Only if it cannot be found are the directories in the specific search path, followed by those in the general search path, consulted.
A search path is also used when expanding wildcard characters. If the pattern has a recognizable suffix on it, the path for that suffix will be used for the expansion. Otherwise the default search path is employed.
When a file is found in some directory other than the current one, all local variables that would have contained the target's name (.ALLSRC and .IMPSRC) will instead contain the path to the file, as found by
pmake
. Thus if you have a file ..\LIB\MUMBLE.C and a makefile
.PATH.c : ..\LIB MUMBLE.EXE : MUMBLE.C $(CCOM) -o $(.TARGET) $(.ALLSRC)
the command executed to create MUMBLE.EXE would be "bcc -o MUMBLE ..\LIB\MUMBLE.C"
If a file exists in two directories on the same search path, the file in the first directory on the path will be the one
pmake
uses. So if you have a large system spread over many directories, it would behoove you to follow a naming convention that avoids such conflicts.
Something you should know about the way search paths are implemented is that each directory is read, and its contents cached, exactly once--when it is first encountered--so any changes to the directories while
pmake
is running will not be noted when searching for implicit sources, nor will they be found when
pmake
attempts to discover when the file was last modified, unless the file was created in the current directory.
Like a C compiler,
pmake
allows you to configure the makefile using conditional statements. A conditional looks like this:
#if <Boolean expression> <lines> #elif <another Boolean expression> <more lines> #else <still more lines> #endif
They may be nested to a depth of 30 and may occur anywhere (except in a comment, of course). The "#" must be the very first character on the line.
Each Boolean expression is made up of terms that look like function calls, the standard C Boolean operators &&, ||, and !, and the standard relational operators ==, !=, >, >=, <, and <=, with == and != being overloaded to allow string comparisons as well. The && operator represents logical AND; || is logical OR and ! is logical NOT. The arithmetic and string operators take precedence over all three of these operators, while NOT takes precedence over AND, which takes precedence over OR. This precedence may be overridden with parentheses, and an expression may be parenthesized to any level. Each Boolean term looks like a call on one of four functions:
pmake
is being run.!defined(var) || empty(var)
#if !empty(var:Mword)
The arithmetic and string operators may only be used to test the value of a variable. The left-hand side must contain the variable expansion, while the right-hand side contains either a string, enclosed in double-quotes, or a number. The standard C numeric conventions (except for specifying an octal number) apply to both sides. For example,
#if $(OS) == 4.3 #if $(MACHINE) == "sun3" #if $(LOAD_ADDR) < 0xc000
are all valid conditionals. In addition, the numeric value of a variable can be tested as a Boolean as follows:
#if $(LOAD)
would see if LOAD contains a non-zero value and
#if !$(LOAD)
would test if LOAD contains a zero value.
In addition to the bare #if, there are other forms that apply one of the first two functions to each term. They are as follows:
ifdef defined ifndef !defined ifmake make ifnmake !make
There are also the "else if" forms: elif, elifdef, elifndef, elifmake, and elifnmake.
GEOS SDK TechDocs
|
|
13.4 Contents of a Makefile
|
13.6 The Way Things Work