Index: head/en_US.ISO8859-1/books/pmake/basics/chapter.xml
===================================================================
--- head/en_US.ISO8859-1/books/pmake/basics/chapter.xml (revision 52713)
+++ head/en_US.ISO8859-1/books/pmake/basics/chapter.xml (nonexistent)
@@ -1,1528 +0,0 @@
-
-
-
- The Basics of PMake
-
- 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
- flag, e.g.
-
- &prompt.user; 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.
-
-
- Dependency Lines
-
- 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 ).
-
-
-
-
-
- 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.
-
-
-
-
-
-
-
- Shell Commands
-
- 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 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 .
-
-
-
-
- Variables
-
- PMake, like
- Make before it, has the ability to
- save text in variables to be recalled later at your convenience.
- Variables in PMake are used much like
- variables in the shell and, by tradition, consist of all
- upper-case letters (you do not have to use all upper-case
- letters. In fact there is nothing to stop you from calling a
- variable @^&$%$. Just tradition). Variables
- are assigned-to using lines of the form:
-
- VARIABLE = value
-
- appended-to by:
-
- VARIABLE += value
-
- conditionally assigned-to (if the variable is not already
- defined) by:
-
- VARIABLE ?= value
-
- and assigned-to with expansion (i.e. the value is expanded
- (see below) before being assigned to the variable—useful
- for placing a value at the beginning of a variable, or other
- things) by:
-
- VARIABLE := value
-
- Any whitespace before value is stripped off. When
- appending, a space is placed between the old value and the stuff
- being appended.
-
- The final way a variable may be assigned to is using:
-
- VARIABLE != shell-command
-
- In this case, shell-command has all its variables expanded
- (see below) and is passed off to a shell to execute. The output
- of the shell is then placed in the variable. Any newlines
- (other than the final one) are replaced by spaces before the
- assignment is made. This is typically used to find the current
- directory via a line like:
-
- CWD != pwd
-
-
- This is intended to be used to execute commands that
- produce small amounts of output
- (e.g. pwd).
- The implementation is less than intelligent and will likely
- freeze if you execute something that produces thousands of
- bytes of output (8 Kb is the limit on many &unix; systems).
- The value of a variable may be retrieved by enclosing the
- variable name in parentheses or curly braces and preceding the
- whole thing with a dollar sign.
-
-
- For example, to set the variable CFLAGS to
- the string -I/sprite/src/lib/libc -O, you
- would place a line:
-
- CFLAGS = -I/sprite/src/lib/libc -O
-
- in the makefile and use the word
- $(CFLAGS) wherever you would like the string
- -I/sprite/src/lib/libc -O to appear. This is
- called variable expansion.
-
-
- Unlike Make,
- PMake will not expand a variable
- unless it knows the variable exists. E.g. if you have a
- ${i} in a shell command and you have not
- assigned a value to the variable i (the
- empty string is considered a value, by the way), where
- Make would have substituted the
- empty string, PMake will leave the
- ${i} alone.
- To keep PMake from substituting for
- a variable it knows, precede the dollar sign with another
- dollar sign (e.g. to pass ${HOME} to
- the shell, use $${HOME}). This causes
- PMake, in effect, to expand the
- $ macro, which expands to a single
- $.
-
-
- For compatibility, Make's style
- of variable expansion will be used if you invoke
- PMake with any of the compatibility
- flags (, or
- . The flag alters just
- the variable expansion). There are two different times at which
- variable expansion occurs: when parsing a dependency line, the
- expansion occurs immediately upon reading the line. If any
- variable used on a dependency line is undefined,
- PMake will print a message and exit.
- Variables in shell commands are expanded when the command is
- executed. Variables used inside another variable are expanded
- whenever the outer variable is expanded (the expansion of an
- inner variable has no effect on the outer variable. For
- example, if the outer variable is used on a dependency line and
- in a shell command, and the inner variable changes value between
- when the dependency line is read and the shell command is
- executed, two different values will be substituted for the outer
- variable).
-
- Variables come in four flavors, though they are all expanded
- the same and all look about the same. They are (in order of
- expanding scope):
-
-
-
- Local variables.
-
-
-
- Command-line variables.
-
-
-
- Global variables.
-
-
-
- Environment variables.
-
-
-
- The classification of variables does not matter much, except
- that the classes are searched from the top (local) to the bottom
- (environment) when looking up a variable. The first one found
- wins.
-
-
- Local Variables
-
- Each target can have as many as seven local variables.
- These are variables that are only visible
- within that target's shell script and contain such things as
- the target's name, all of its sources (from all its dependency
- lines), those sources that were out-of-date, etc. Four local
- variables are defined for all targets. They are:
-
-
-
- .TARGET
-
-
- The name of the target.
-
-
-
-
- .OODATE
-
-
- The list of the sources for the target that were
- considered out-of-date. The order in the list is not
- guaranteed to be the same as the order in which the
- dependencies were given.
-
-
-
-
- .ALLSRC
-
-
- The list of all sources for this target in the order
- in which they were given.
-
-
-
-
- .PREFIX
-
-
- The target without its suffix and without any
- leading path. E.g. for the target
- ../../lib/compat/fsRead.c, this
- variable would contain fsRead.
-
-
-
-
- Three other local variables are set only for certain
- targets under special circumstances. These are the
- .IMPSRC,.ARCHIVE, and
- .MEMBER variables. When they are set and
- how they are used is described later.
-
- Four of these variables may be used in sources as well as
- in shell scripts. These are .TARGET,
- .PREFIX, .ARCHIVE and
- .MEMBER. The variables in the sources are
- expanded once for each target on the dependency line,
- providing what is known as a dynamic source,
- allowing you to specify several dependency lines at once.
- For example:
-
- $(OBJS) : $(.PREFIX).c
-
- will create a dependency between each object file and its
- corresponding C source file.
-
-
-
- Command-line Variables
-
- Command-line variables are set when
- PMake is first invoked by giving a
- variable assignment as one of the arguments.
- For example:
-
- pmake "CFLAGS = -I/sprite/src/lib/libc -O"
-
- would make CFLAGS be a command-line
- variable with the given value. Any assignments to
- CFLAGS in the makefile will have no effect,
- because once it is set, there is (almost) nothing you can do
- to change a command-line variable (the search order, you see).
- Command-line variables may be set using any of the four
- assignment operators, though only = and
- ?= behave as you would expect them to,
- mostly because assignments to command-line variables are
- performed before the makefile is read, thus the values set in
- the makefile are unavailable at the time.
- += is the same as =,
- because the old value of the variable is sought only in the
- scope in which the assignment is taking place (for reasons of
- efficiency that I will not get into here). :=
- and ?= will work if the only variables
- used are in the environment. != is sort of
- pointless to use from the command line, since the same effect
- can no doubt be accomplished using the shell's own command
- substitution mechanisms (backquotes and all that).
-
-
-
- Global Variables
-
- Global variables are those set or appended-to in the
- makefile. There are two classes of global variables: those
- you set and those PMake sets.
- As I said before, the ones you set can have any name you want
- them to have, except they may not contain a colon or an
- exclamation point.
- The variables PMake sets (almost)
- always begin with a period and always contain upper-case
- letters, only. The variables are as follows:
-
-
-
- .PMAKE
-
-
- The name by which PMake
- was invoked is stored in this variable. For
- compatibility, the name is also stored in the
- MAKE variable.
-
-
-
-
- .MAKEFLAGS
-
-
- All the relevant flags with which
- PMake was invoked.
- This does not include such things as
- or variable assignments. Again for compatibility, this
- value is stored in the MFLAGS
- variable as well.
-
-
-
-
- Two other variables, .INCLUDES and
- .LIBS, are covered in the section on
- special targets in .
-
- Global variables may be deleted using lines of the
- form:
-
- #undef variable
-
- The # must be the first character on
- the line. Note that this may only be done on global
- variables.
-
-
-
- Environment Variables
-
- Environment variables are passed by the shell that invoked
- PMake and are given by
- PMake to each shell it invokes.
- They are expanded like any other variable, but they cannot be
- altered in any way.
-
- One special environment variable, PMAKE, is
- examined by PMake for command-line
- flags, variable assignments, etc., it should always use. This
- variable is examined before the actual arguments to
- PMake are. In addition, all flags
- given to PMake, either through the
- PMAKE variable or on the command line, are
- placed in this environment variable and exported to each shell
- PMake executes. Thus recursive
- invocations of PMake automatically
- receive the same flags as the top-most one.
-
- Using all these variables, you can compress the sample
- makefile even more:
-
- OBJS = a.o b.o c.o
-
-program : $(OBJS)
- cc $(.ALLSRC) -o $(.TARGET)
-
-$(OBJS) : 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
-
-
-
-
- Comments
-
- Comments in a makefile start with a #
- character and extend to the end of the line. They may appear
- anywhere you want them, except in a shell command (though the
- shell will treat it as a comment, too). If, for some reason,
- you need to use the # in a variable or on a
- dependency line, put a backslash in front of it.
- PMake will compress the two into a
- single #.
-
-
- This is not true if PMake is
- operating in full-compatibility mode).
-
-
-
-
- Parallelism
-
- PMake was specifically designed
- to re-create several targets at once, when possible. You do not
- have to do anything special to cause this to happen (unless
- PMake was configured to not act in
- parallel, in which case you will have to make use of the
- and flags (see below)),
- but you do have to be careful at times.
-
- There are several problems you are likely to encounter. One
- is that some makefiles (and programs) are written in such a way
- that it is impossible for two targets to be made at once. The
- program xstr, for example, always
- modifies the files strings and
- x.c. There is no way to change it. Thus
- you cannot run two of them at once without something being
- trashed. Similarly, if you have commands in the makefile that
- always send output to the same file, you will not be able to
- make more than one target at once unless you change the file you
- use. You can, for instance, add a $$$$ to
- the end of the file name to tack on the process ID of the shell
- executing the command (each $$ expands to a
- single $, thus giving you the shell variable
- $$). Since only one shell is used for all
- the commands, you will get the same file name for each command
- in the script.
-
- The other problem comes from improperly-specified
- dependencies that worked in Make
- because of its sequential, depth-first way of examining them.
- While I do not want to go into depth on how
- PMake works (look in if you are interested), I will warn you that
- files in two different levels of the dependency tree may be
- examined in a different order in
- PMake than they were in
- Make.
- For example, given the makefile:
-
- a :
-
-b c b : d
-
- PMake will examine the targets in
- the order c,
- d, b,
- a. If the makefile's author expected
- PMake to abort before making
- c if an error occurred while making
- b, or if b
- needed to exist before c was made,
- (s)he will be sorely disappointed. The dependencies are
- incomplete, since in both these cases,
- c would depend on
- b. So watch out.
-
- Another problem you may face is that, while
- PMake is set up to handle the output
- from multiple jobs in a graceful fashion, the same is not so for
- input. It has no way to regulate input to different jobs, so if
- you use the redirection from /dev/tty I
- mentioned earlier, you must be careful not to run two of the
- jobs at once.
-
-
-
- Writing and Debugging a Makefile
-
- Now you know most of what is in a
- Makefile, what do you do next? There are
- two choices: use one of the uncommonly-available makefile
- generators or write your own makefile (I leave out the third
- choice of ignoring PMake and doing
- everything by hand as being beyond the bounds of common
- sense).
-
- When faced with the writing of a makefile, it is usually
- best to start from first principles: just what are you trying to
- do? What do you want the makefile finally to produce? To begin
- with a somewhat traditional example, let's say you need to write
- a makefile to create a program, expr, that
- takes standard infix expressions and converts them to prefix
- form (for no readily apparent reason). You have got three
- source files, in C, that make up the program:
- main.c, parse.c, and
- output.c. Harking back to my pithy advice
- about dependency lines, you write the first line of the
- file:
-
- expr : main.o parse.o output.o
-
- because you remember expr is made from
- .o files, not .c
- files. Similarly for the .o files you
- produce the lines:
-
- main.o : main.c
-
-parse.o : parse.c
-
-output.o : output.c
-
-main.o parse.o output.o : defs.h
-
- Great. You have now got the dependencies specified. What
- you need now is commands. These commands, remember, must
- produce the target on the dependency line, usually by using the
- sources you have listed. You remember about local variables?
- Good, so it should come to you as no surprise when you
- write:
-
- expr : main.o parse.o output.o
- cc -o $(.TARGET) $(.ALLSRC)
-
- Why use the variables? If your program grows to produce
- postfix expressions too (which, of course, requires a name
- change or two), it is one fewer place you have to change the
- file. You cannot do this for the object files, however, because
- they depend on their corresponding source files and
- defs.h, thus if you said:
-
- cc -c $(.ALLSRC)
-
- you will get (for main.o):
-
- cc -c main.c defs.h
-
- which is wrong. So you round out the makefile with these
- lines:
-
- main.o : main.c
- cc -c main.c
-
-parse.o : parse.c
- cc -c parse.c
-
-output.o : output.c
- cc -c output.c
-
- The makefile is now complete and will, in fact, create the
- program you want it to without unnecessary compilations or
- excessive typing on your part. There are two things wrong with
- it, however (aside from it being altogether too long, something
- I will address in ):
-
-
-
- The string main.o parse.o output.o is
- repeated twice, necessitating two changes when you add
- postfix (you were planning on that, were not you?). This is
- in direct violation of de Boor's First Rule of writing
- makefiles:
-
- Anything that needs to be written more than once should
- be placed in a variable. I cannot emphasize this enough as
- being very important to the maintenance of a makefile and
- its program.
-
-
-
- There is no way to alter the way compilations are
- performed short of editing the makefile and making the
- change in all places. This is evil and violates de Boor's
- Second Rule, which follows directly from the first:
-
- Any flags or programs used inside a makefile should be
- placed in a variable so they may be changed, temporarily or
- permanently, with the greatest ease.
-
-
-
- The makefile should more properly read:
-
- OBJS = main.o parse.o output.o
-
-expr : $(OBJS)
- $(CC) $(CFLAGS) -o $(.TARGET) $(.ALLSRC)
-
-main.o : main.c
- $(CC) $(CFLAGS) -c main.c
-
-parse.o : parse.c
- $(CC) $(CFLAGS) -c parse.c
-
-output.o : output.c
- $(CC) $(CFLAGS) -c output.c
-
-$(OBJS) : defs.h
-
- Alternatively, if you like the idea of dynamic sources
- mentioned in , you could write it
- like this:
-
- OBJS = main.o parse.o output.o
-
-expr : $(OBJS)
- $(CC) $(CFLAGS) -o $(.TARGET) $(.ALLSRC)
-
-$(OBJS) : $(.PREFIX).c defs.h
- $(CC) $(CFLAGS) -c $(.PREFIX).c
-
- These two rules and examples lead to de Boor's First
- Corollary:
- Variables are your friends.
-
- Once you have written the makefile comes the
- sometimes-difficult task of making sure the darn thing works.
- Your most helpful tool to make sure the makefile is at least
- syntactically correct is the flag, which
- allows you to see if PMake will choke
- on the makefile. The second thing the flag
- lets you do is see what PMake would
- do without it actually doing it, thus you can make sure the
- right commands would be executed were you to give
- PMake its head.
-
- When you find your makefile is not behaving as you hoped,
- the first question that comes to mind (after What time is
- it, anyway?) is Why not? In answering
- this, two flags will serve you well: -d m and
- -p 2.
- The first causes PMake to tell you as
- it examines each target in the makefile and indicate why it is
- deciding whatever it is deciding. You can then use the
- information printed for other targets to see where you went
- wrong. The -p 2 flag makes
- PMake print out its internal state
- when it is done, allowing you to see that you forgot to make
- that one chapter depend on that file of macros you just got a
- new version of. The output from -p 2 is intended
- to resemble closely a real makefile, but with additional
- information provided and with variables expanded in those
- commands PMake actually printed or
- executed.
-
- Something to be especially careful about is circular
- dependencies. For example:
-
- a : b
-
-b : c d
-
-d : a
-
- In this case,
- because of how PMake works,
- c is the only thing
- PMake will examine, because
- d and a will
- effectively fall off the edge of the universe, making it
- impossible to examine b (or them, for
- that matter). PMake will tell you
- (if run in its normal mode) all the targets involved in any
- cycle it looked at (i.e. if you have two cycles in the
- graph (naughty, naughty), but only try to make a target in one
- of them, PMake will only tell you
- about that one. You will have to try to make the other to find
- the second cycle). When run as Make,
- it will only print the first target in the cycle.
-
-
-
- Invoking PMake
-
- PMake comes with a wide variety
- of flags to choose from. They may appear in any order,
- interspersed with command-line variable assignments and targets
- to create. The flags are as follows:
-
-
-
-
-
-
- This causes PMake to spew
- out debugging information that may prove useful to you.
- If you cannot figure out why
- PMake is doing what it is
- doing, you might try using this flag.
- The what parameter is a string
- of single characters that tell
- PMake what aspects you are
- interested in. Most of what I describe will make little
- sense to you, unless you have dealt with
- Make before. Just remember
- where this table is and come back to it as you read on.
- The characters and the information they produce are as
- follows:
-
-
-
-
-
- a
-
- Archive searching and caching.
-
-
-
- c
-
- Conditional evaluation.
-
-
-
- d
-
- The searching and caching of
- directories.
-
-
-
- j
-
- Various snippets of information related to
- the running of the multiple shells. Not
- particularly interesting.
-
-
-
- m
-
- The making of each target: what target is
- being examined; when it was last modified; whether
- it is out-of-date; etc.
-
-
-
- p
-
- Makefile parsing.
-
-
-
- r
-
- Remote execution.
-
-
-
- s
-
- The application of suffix-transformation
- rules. (See .)
-
-
-
- t
-
- The maintenance of the list of targets.
-
-
-
- v
-
- Variable assignment.
-
-
-
-
-
- Of these all, the m and
- s letters will be most useful to you.
- If the is the final argument or the
- argument from which it would get these key letters (see
- below for a note about which argument would be used)
- begins with a –, all of these debugging flags will
- be set, resulting in massive amounts of output.
-
-
-
-
- makefile
-
-
- Specify a makefile to read different from the standard
- makefiles (Makefile or
- makefile).
- If makefile is -,
- PMake uses the standard input.
- This is useful for making quick and dirty makefiles.
-
-
-
-
-
-
-
- Prints out a summary of the various flags
- PMake accepts.
- It can also be used to find out what level of concurrency was
- compiled into the version of PMake you
- are using (look at -J and
- -L) and various other information on how
- PMake was configured.
-
-
-
-
-
-
-
- If you give this flag, PMake will
- ignore non-zero status returned by any of its shells. It is like
- placing a - before all the commands in the
- makefile.
-
-
-
-
-
-
-
- This is similar to in that it allows
- PMake to continue when it sees an
- error, but unlike , where
- PMake continues blithely as if nothing
- went wrong, causes it to recognize the error
- and only continue work on those things that do not depend on the
- target, either directly or indirectly (through depending on
- something that depends on it), whose creation returned the error.
- The is for keep going.
-
-
-
-
-
-
-
- PMake has the ability to lock a
- directory against other people executing it in the same directory
- (by means of a file called LOCK.make that it
- creates and checks for in the directory). This is a Good Thing
- because two people doing the same thing in the same place can be
- disastrous for the final product (too many cooks and all that).
- Whether this locking is the default is up to your system
- administrator. If locking is on, will turn it
- off, and vice versa.
- Note that this locking will not prevent you from invoking
- PMake twice in the same place–if
- you own the lock file, PMake will warn
- you about it but continue to execute.
-
-
-
-
-
-
-
- Tells PMake another place to search
- for included makefiles via the
- <filename> style.
- Several -m options can be given to form a
- search path. If this construct is used the default system
- makefile search path is completely overridden.
-
-
-
-
-
-
-
- This flag tells PMake not to
- execute the commands needed to update the out-of-date targets in
- the makefile. Rather, PMake will
- simply print the commands it would have executed and exit.
- This is particularly useful for checking the correctness of a
- makefile. If PMake does not do what
- you expect it to, it is a good chance the makefile is wrong.
-
-
-
-
-
-
-
- This causes PMake to print its
- input in a reasonable form, though not necessarily one that would
- make immediate sense to anyone but me. The number is a bitwise OR
- of 1 and 2, where 1 means it should print the input before doing
- any processing and 2 says it should print it after everything has
- been re-created.
- Thus would print it twice-a-once before
- processing and once after (you might find the difference between
- the two interesting). This is mostly useful to me, but you may
- find it informative in some bizarre circumstances.
-
-
-
-
-
-
-
- If you give PMake this flag, it
- will not try to re-create anything. It will just see if anything
- is out-of-date and exit non-zero if so.
-
-
-
-
-
-
-
- When PMake starts up, it reads a
- default makefile that tells it what sort of system it is on and
- gives it some idea of what to do if you do not tell it anything.
- I will tell you about it in .
- If you give this flag, PMake will not
- read the default makefile.
-
-
-
-
-
-
-
- This causes PMake to not print
- commands before they are executed. It is the equivalent of
- putting an @ before every command in the
- makefile.
-
-
-
-
-
-
-
- Rather than try to re-create a target,
- PMake will simply touch
- it so as to make it appear up-to-date.
- If the target did not exist before, it will when
- PMake finishes, but if the target did
- exist, it will appear to have been updated.
-
-
-
-
-
-
-
- Targets can still be created in parallel, however.
- This is the mode PMake will enter
- if it is invoked either as smake or
- vmake.
-
-
-
-
-
-
-
- This tells PMake it is OK to export
- jobs to other machines, if they are available. It is used when
- running in Make mode, as exporting in this mode tends to make
- things run slower than if the commands were just executed
- locally.
-
-
-
-
-
-
-
- Forces PMake to be as
- backwards-compatible with Make as
- possible while still being itself. This includes:
-
-
-
- Executing one shell per shell command
-
-
-
- Expanding anything that looks even vaguely like a
- variable, with the empty string replacing any variable
- PMake does not know.
-
-
-
- Refusing to allow you to escape a #
- with a backslash.
-
-
-
- Permitting undefined variables on dependency lines and
- conditionals (see below). Normally this causes
- PMake to abort.
-
-
-
-
-
-
-
-
-
- This nullifies any and all compatibility mode flags you may
- have given or implied up to the time the is
- encountered. It is useful mostly in a makefile that you wrote for
- PMake to avoid bad things happening
- when someone runs PMake as
- make or has things set in the
- environment that tell it to be compatible.
- is not placed in the PMAKE
- environment variable or the .MAKEFLAGS or
- MFLAGS global variables.
-
-
-
-
-
-
-
- Allows you to define a variable to have 1 as
- its value. The variable is a global variable, not a command-line
- variable. This is useful mostly for people who are used to the C
- compiler arguments and those using conditionals, which I will get
- into in .
-
-
-
-
-
-
-
- Tells PMake another place to search
- for included makefiles. Yet another thing to be explained in
- (, to be
- precise).
-
-
-
-
-
-
-
- Gives the absolute maximum number of targets to create at once
- on both local and remote machines.
-
-
-
-
-
-
-
- This specifies the maximum number of targets to create on the
- local machine at once.
- This may be 0, though you should be wary of
- doing this, as PMake may hang until a
- remote machine becomes available, if one is not available when it
- is started.
-
-
-
-
-
-
-
- This is the flag that provides absolute, complete, full
- compatibility with Make. It still
- allows you to use all but a few of the features of
- PMake, but it is non-parallel.
- This is the mode PMake enters if you
- call it make.
-
-
-
-
-
-
-
- When creating targets in parallel, several shells are
- executing at once, each wanting to write its own two cents'-worth
- to the screen.
- This output must be captured by PMake
- in some way in order to prevent the screen from being filled with
- garbage even more indecipherable than you usually see.
- PMake has two ways of doing this, one
- of which provides for much cleaner output and a clear separation
- between the output of different jobs, the other of which provides
- a more immediate response so one can tell what is really
- happening. The former is done by notifying you when the creation
- of a target starts, capturing the output and transferring it to
- the screen all at once when the job finishes. The latter is done
- by catching the output of the shell (and its children) and
- buffering it until an entire line is received, then printing that
- line preceded by an indication of which job produced the output.
- Since I prefer this second method, it is the one used by default.
- The first method will be used if you give the
- flag to PMake.
-
-
-
-
-
-
-
- As mentioned before, the flag tells
- PMake to use
- Make's style of expanding variables,
- substituting the empty string for any variable it does not
- know.
-
-
-
-
-
-
-
- There are several times when PMake
- will print a message at you that is only a warning, i.e. it
- can continue to work in spite of your having done something silly
- (such as forgotten a leading tab for a shell command). Sometimes
- you are well aware of silly things you have done and would like
- PMake to stop bothering you. This flag
- tells it to shut up about anything non-fatal.
-
-
-
-
-
-
-
- This flag causes PMake to not
- attempt to export any jobs to another machine.
-
-
-
-
- Several flags may follow a single -. Those flags
- that require arguments take them from successive parameters.
- For example:
-
- pmake -fDnI server.mk DEBUG /chip2/X/server/include
-
- will cause PMake to read
- server.mk as the input makefile,
- define the variable DEBUG as a global variable and
- look for included makefiles in the directory
- /chip2/X/server/include.
-
-
-
- Summary
-
- A makefile is made of four types of lines:
-
-
-
- Dependency lines
-
-
-
- Creation commands
-
-
-
- Variable assignments
-
-
-
- Comments, include statements and conditional directives
-
-
-
- A dependency line is a list of one or more targets, an operator
- (:, ::, or !),
- and a list of zero or more sources. Sources may contain wildcards and
- certain local variables.
-
- A creation command is a regular shell command preceded by a tab. In
- addition, if the first two characters after the tab
- (and other whitespace) are a combination of @ or
- -, PMake will cause the
- command to not be printed (if the character is @) or
- errors from it to be ignored (if -). A blank line,
- dependency line or variable assignment terminates a creation script.
- There may be only one creation script for each target with a
- : or ! operator.
-
- Variables are places to store text. They may be unconditionally
- assigned-to using the = operator, appended-to using
- the += operator, conditionally (if the variable is
- undefined) assigned-to with the ?= operator, and
- assigned-to with variable expansion with the :=
- operator. The output of a shell command may be assigned to a variable
- using the != operator. Variables may be expanded
- (their value inserted) by enclosing their name in parentheses or curly
- braces, preceded by a dollar sign. A dollar sign may be escaped with
- another dollar sign. Variables are not expanded if
- PMake does not know about them.
- There are seven local variables: .TARGET,
- .ALLSRC, .OODATE,
- .PREFIX, .IMPSRC,
- .ARCHIVE, and .MEMBER.
- Four of them (.TARGET, .PREFIX,
- .ARCHIVE, and .MEMBER) may be used
- to specify dynamic sources. Variables are good. Know
- them. Love them. Live them.
-
- Debugging of makefiles is best accomplished using the
- , , and
- flags.
-
-
Property changes on: head/en_US.ISO8859-1/books/pmake/basics/chapter.xml
___________________________________________________________________
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/sgml
\ No newline at end of property
Index: head/en_US.ISO8859-1/books/pmake/intro/chapter.xml
===================================================================
--- head/en_US.ISO8859-1/books/pmake/intro/chapter.xml (revision 52713)
+++ head/en_US.ISO8859-1/books/pmake/intro/chapter.xml (nonexistent)
@@ -1,37 +0,0 @@
-
-
-
- Introduction
-
- PMake is a program for creating other
- programs, or anything else you can think of for it to do. The basic idea
- behind PMake is that, for any given system, be
- it a program or a document or whatever, there will be some files that
- depend on the state of other files (on when they were last modified).
- PMake takes these dependencies, which you must
- specify, and uses them to build whatever it is you want it to
- build.
-
- PMake is almost fully-compatible with
- Make, with which you may already be familiar.
- PMake's most important feature is its ability
- to run several different jobs at once, making the creation of systems
- considerably faster. It also has a great deal more functionality than
- Make.
-
- This tutorial is divided into three main sections corresponding to
- basic, intermediate and advanced PMake usage.
- If you already know Make well, you will only
- need to skim (there are some aspects of
- PMake that I consider basic to its use that did
- not exist in Make).
- Things in make life much easier, while those in
- are strictly for those who know what they are doing.
- has definitions for the jargon I use and
- contains possible solutions to the problems
- presented throughout the tutorial.
-
Property changes on: head/en_US.ISO8859-1/books/pmake/intro/chapter.xml
___________________________________________________________________
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/sgml
\ No newline at end of property
Index: head/en_US.ISO8859-1/books/pmake/answers/chapter.xml
===================================================================
--- head/en_US.ISO8859-1/books/pmake/answers/chapter.xml (revision 52713)
+++ head/en_US.ISO8859-1/books/pmake/answers/chapter.xml (nonexistent)
@@ -1,55 +0,0 @@
-
-
-
- Answers to Exercises
-
- Exercise 3.1
-
- This is something of a trick question, for which I apologize.
- The trick comes from the &unix; definition of a suffix, which
- PMake does not necessarily share.
- You will have noticed that all the suffixes used in this tutorial
- (and in &unix; in general) begin with a period
- (.ms, .c, etc.).
- Now, PMake's idea of a suffix is more
- like English's: it is the characters at the end of a word. With
- this in mind, one possible solution to this problem goes as
- follows:
-
- .SUFFIXES : ec.exe .exe ec.obj .obj .asm
-ec.objec.exe .obj.exe :
- link -o $(.TARGET) $(.IMPSRC)
-.asmec.obj :
- asm -o $(.TARGET) -DDO_ERROR_CHECKING $(.IMPSRC)
-.asm.obj :
- asm -o $(.TARGET) $(.IMPSRC)
-
- Excercise 3.2
-
- The trick to this one lies in the :=
- variable-assignment operator and the :S
- variable-expansion modifier. Basically what you want is to take
- the pointer variable, so to speak, and transform it into an
- invocation of the variable at which it points. You might try
- something like:
-
- $(PTR:S/^/\$(/:S/$/))
-
- which places $( at the front of the
- variable name and ) at the end, thus
- transforming VAR, for example, into
- $(VAR), which is just what we want.
- Unfortunately (as you know if you have tried it), since, as it
- says in the hint, PMake does no further
- substitution on the result of a modified expansion, that is all
- you get. The solution is to make use of := to
- place that string into yet another variable, then invoke the other
- variable directly:
-
- *PTR := $(PTR:S/^/\$(/:S/$/)/)
-
- You can then use $(*PTR) to your heart's
- content.
-
Property changes on: head/en_US.ISO8859-1/books/pmake/answers/chapter.xml
___________________________________________________________________
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/sgml
\ No newline at end of property
Index: head/en_US.ISO8859-1/books/pmake/chapters.ent
===================================================================
--- head/en_US.ISO8859-1/books/pmake/chapters.ent (revision 52713)
+++ head/en_US.ISO8859-1/books/pmake/chapters.ent (nonexistent)
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
-
-
-
Property changes on: head/en_US.ISO8859-1/books/pmake/chapters.ent
___________________________________________________________________
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/sgml
\ No newline at end of property
Index: head/en_US.ISO8859-1/books/pmake/gods/chapter.xml
===================================================================
--- head/en_US.ISO8859-1/books/pmake/gods/chapter.xml (revision 52713)
+++ head/en_US.ISO8859-1/books/pmake/gods/chapter.xml (nonexistent)
@@ -1,943 +0,0 @@
-
-
-
- PMake for Gods
-
- This chapter 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
- could not do in Make without a great
- deal of work (and perhaps the use of other programs). The problem
- with these features, is they must be handled with care, or you
- will end up with a mess.
-
- Once more, I assume a greater familiarity with &unix; or Sprite
- than I did in the previous two chapters.
-
-
- Search Paths
-
- PMake 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 : /sprite/lib/include /sprite/att/lib/include
-
- would tell PMake to look in the
- directories /sprite/lib/include and
- /sprite/att/lib/include 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 there 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 like this:
-
- .PATH.c : ../lib
-mumble : mumble.c
- $(CC) -o $(.TARGET) $(.ALLSRC)
-
- the command executed to create mumble would be
- cc -o mumble ../lib/mumble.c.
- (as an aside, the command in this case is not strictly
- necessary, since it will be found using transformation rules
- if it is not given. This is because .out
- is the null suffix by default and a transformation exists
- from .c to
- .out. Just thought I would throw that in).
- 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. While people have suggested that
- PMake should read the directories
- each time, my experience suggests that the caching seldom causes
- problems. In addition, not caching the directories slows things
- down enormously because of PMake's attempts
- to apply transformation rules through non-existent files – the
- number of extra file-system searches is truly staggering,
- especially if many files without suffixes are used and the null
- suffix is not changed from .out.
-
-
-
- Archives and Libraries
-
- &unix; and Sprite allow you to merge files into an archive
- using the ar command. Further, if the files
- are relocatable object files, you can run
- ranlib on the archive and get
- yourself a library that you can link into any program you want.
- The main problem with archives is they double the space you need
- to store the archived files, since there is one copy in the
- archive and one copy out by itself. The problem with libraries
- is you usually think of them as rather
- than /usr/lib/libm.a and the linker thinks
- they are out-of-date if you so much as look at them.
-
- PMake solves the problem with
- archives by allowing you to tell it to examine the files in the
- archives (so you can remove the individual files without having
- to regenerate them later). To handle the problem with
- libraries, PMake adds an additional
- way of deciding if a library is out-of-date: if the table of
- contents is older than the library, or is missing, the library
- is out-of-date.
-
- A library is any target that looks like
- or that ends in a suffix that was marked as a library using the
- .LIBS target. .a
- is so marked in the system makefile. Members of an archive are
- specified as archive(member[member...]).
- Thus libdix.a(window.o) specifies the
- file window.o in the archive
- libdix.a. You may also use
- wildcards to specify the members of the archive. Just
- remember that most the wildcard characters will only find
- existing files. A file that is a member of an archive is
- treated specially. If the file does not exist, but it is
- in the archive, the modification time recorded in the
- archive is used for the file when determining if the file
- is out-of-date. When figuring out how to make an archived
- member target (not the file itself, but the file in the
- archive – the archive(member) target), special care
- is taken with the transformation rules, as follows:
-
-
-
- archive(member) is made to depend on member.
-
-
-
- The transformation from the member's suffix to the
- archive's suffix is applied to the archive(member) target.
-
-
-
- The archive(member)'s .TARGET
- variable is set to the name of the member if member is
- actually a target, or the path to the member file if
- member is only a source.
-
-
-
- The .ARCHIVE variable for the
- archive(member) target is set to the name of the
- archive.
-
-
-
- The .MEMBER variable is set to the
- actual string inside the parentheses. In most cases,
- this will be the same as the .TARGET
- variable.
-
-
-
- The archive(member)'s place in the local variables of
- the targets that depend on it is taken by the value of its
- .TARGET variable.
-
-
-
- Thus, a program library could be created with the following
- makefile:
-
- .o.a :
- ...
- rm -f $(.TARGET:T)
-OBJS = obj1.o obj2.o obj3.o
-libprog.a : libprog.a($(OBJS))
- ar cru $(.TARGET) $(.OODATE)
- ranlib $(.TARGET)
-
- This will cause the three object files to be compiled (if
- the corresponding source files were modified after the object
- file or, if that does not exist, the archived object file), the
- out-of-date ones archived in libprog.a, a
- table of contents placed in the archive and the newly-archived
- object files to be removed.
-
- All this is used in the makelib.mk system
- makefile to create a single library with ease. This makefile looks
- like this:
-
- #
-# Rules for making libraries. The object files that make up the library
-# are removed once they are archived.
-#
-# To make several libraries in parallel, you should define the variable
-# "many_libraries". This will serialize the invocations of ranlib.
-#
-# To use, do something like this:
-#
-# OBJECTS = <files in the library>
-#
-# fish.a: fish.a($(OBJECTS)) MAKELIB
-#
-#
-
-#ifndef _MAKELIB_MK
-_MAKELIB_MK =
-
-#include <po.mk>
-
-.po.a .o.a :
- ...
- rm -f $(.MEMBER)
-
-ARFLAGS ?= crl
-
-#
-# Re-archive the out-of-date members and recreate the library's table of
-# contents using ranlib. If many_libraries is defined, put the ranlib
-# off til the end so many libraries can be made at once.
-#
-MAKELIB : .USE .PRECIOUS
- ar $(ARFLAGS) $(.TARGET) $(.OODATE)
-#ifndef no_ranlib
-# ifdef many_libraries
- ...
-# endif many_libraries
- ranlib $(.TARGET)
-#endif no_ranlib
-
-#endif _MAKELIB_MK
-
-
-
- On the Condition...
-
- Like the C compiler before it, PMake
- allows you to configure the makefile, based on the current
- environment, 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 maximum depth of 30 and may occur
- anywhere (except in a comment, of course). The
- # must 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. && 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 your heart's content.
- Each term looks like a call on one of four functions:
-
-
-
-
-
-
-
-
- make
-
- The syntax is make(target) where target is
- a target in the makefile. This is true if the
- given target was specified on the command line, or
- as the source for a .MAIN
- target (note that the sources for
- .MAIN are only used if no
- targets were given on the command
- line).
-
-
-
- defined
-
- The syntax is
- defined(variable) and is true
- if variable is defined. Certain variables are
- defined in the system makefile that identify the
- system on which PMake
- is being run.
-
-
-
- exists
-
- The syntax is
- exists(file) and is true if the
- file can be found on the global search path (i.e.
- that defined by .PATH targets, not by
- .PATHsuffix
- targets).
-
-
-
- empty
-
- This syntax is much like the others, except
- the string inside the parentheses is of the same
- form as you would put between parentheses when
- expanding a variable, complete with modifiers and
- everything. The function returns true if the
- resulting string is empty. An undefined
- variable in this context will cause at the very
- least a warning message about a malformed
- conditional, and at the worst will cause the process
- to stop once it has read the makefile. If you want
- to check for a variable being defined or empty,
- use the expression:
- !defined(var) || empty(var)
- as the definition of || will
- prevent the empty() from being
- evaluated and causing an error, if the variable
- is undefined. This can be used to see if a
- variable contains a given word, for example:
- #if !empty(var:Mword)
-
-
-
-
-
- The arithmetic and string operators may only be used to test
- the value of a variable. The lefthand side must contain the
- variable expansion, while the righthand 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. E.g.:
-
- #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.
-
- For instance, if you wish to create two versions of a
- program, one of which is optimized (the production version) and
- the other of which is for debugging (has symbols for dbx),
- you have two choices: you can create two makefiles, one of
- which uses the flag for the compilation,
- while the other uses the flag, or you
- can use another target (call it debug) to create the debug
- version. The construct below will take care of this for you.
- I have also made it so defining the variable
- DEBUG (say with pmake -D DEBUG)
- will also cause the debug version to be made.
-
- #if defined(DEBUG) || make(debug)
-CFLAGS += -g
-#else
-CFLAGS += -O
-#endif
-
- There are, of course, problems with this approach. The most
- glaring annoyance is that if you want to go from making a
- debug version to making a production version, you have to
- remove all the object files, or you will get some optimized
- and some debug versions in the same program. Another
- annoyance is you have to be careful not to make two targets that
- conflict because of some conditionals in the makefile.
- For instance:
-
- #if make(print)
-FORMATTER = ditroff -Plaser_printer
-#endif
-#if make(draft)
-FORMATTER = nroff -Pdot_matrix_printer
-#endif
-
- would wreak havoc if you tried pmake draft print
- since you would use the same formatter for each target. As I said,
- this all gets somewhat complicated.
-
-
-
- A Shell is a Shell is a Shell
-
- In normal operation, the Bourne Shell (better known
- as sh) is used to execute the
- commands to re-create targets. PMake
- also allows you to specify a different shell for it to use when
- executing these commands. There are several things
- PMake must know about
- the shell you wish to use. These things are specified as the
- sources for the .SHELL target by
- keyword, as follows:
-
-
-
- path=path
-
-
- PMake needs to know where
- the shell actually resides, so it can execute it. If
- you specify this and nothing else,
- PMake will use the last
- component of the path and look in its table of the
- shells it knows and use the specification it finds, if
- any. Use this if you just want to use a different
- version of the Bourne or
- C Shell (yes,
- PMake knows how to use the
- C Shell too).
-
-
-
-
- name=name
-
-
- This is the name by which the shell is to be
- known. It is a single word and, if no other keywords
- are specified (other than path), it is the name by
- which PMake attempts to find
- a specification for it (as mentioned above). You
- can use this if you would just rather use the C Shell
- than the Bourne Shell
- (.SHELL: name=csh will do it).
-
-
-
-
- quiet=echo-off command
-
-
- As mentioned before, PMake
- actually controls whether commands are printed by
- introducing commands into the shell's input stream.
- This keyword, and the next two, control what those commands
- are. The quiet keyword is the command
- used to turn echoing off. Once it is turned off, echoing is
- expected to remain off until the echo-on
- command is given.
-
-
-
-
- echo=echo-on command
-
-
- The command PMake
- should give to turn echoing back on again.
-
-
-
-
- filter=printed echo-off command
-
-
- Many shells will echo the
- echo-off command when it is given.
- This keyword tells PMake in what
- format the shell actually prints the echo-off
- command. Wherever PMake
- sees this string in the shell's output, it will
- delete it and any following whitespace, up to and
- including the next newline. See the example at the
- end of this section for more details.
-
-
-
-
- echoFlag=flag to turn echoing on
-
-
- Unless a target has been marked
- .SILENT, PMake
- wants to start the shell running with echoing on. To do
- this, it passes this flag to the shell as one of its
- arguments. If either this or the next flag begins with a
- -, the flags will be passed to the
- shell as separate arguments. Otherwise, the two will
- be concatenated (if they are used at the same time, of
- course).
-
-
-
-
- errFlag=flag to turn error checking on
-
-
- Likewise, unless a target is marked
- .IGNORE,
- PMake wishes error-checking
- to be on from the very start. To this end, it will pass
- this flag to the shell as an argument. The same
- rules for an initial - apply as for
- the echoFlag.
-
-
-
-
- check=command to turn error checking on
-
-
- Just as for echo-control, error-control is achieved
- by inserting commands into the shell's input stream.
- This is the command to make the shell check for errors.
- It also serves another purpose if the shell does not
- have error-control as commands, but I will get into that
- in a minute. Again, once error checking has been turned
- on, it is expected to remain on until it is turned off
- again.
-
-
-
-
- ignore=commandto turn error checking off
-
-
- This is the command PMake
- uses to turn error checking off. It has another use if
- the shell does not do errorcontrol, but I will tell you
- about that...now.
-
-
-
-
- hasErrCtl=yes or no
-
-
- This takes a value that is either
- yes or no. Now
- you might think that the existence of the check and
- ignore keywords would be enough to tell
- PMake if the shell can do
- error-control, but you would be wrong. If
- hasErrCtl is yes,
- PMake uses the check and
- ignore commands in a straight-forward manner. If this
- is no, however, their use is rather different. In this
- case, the check command is used as a template, in which
- the string %s is replaced by the
- command that is about to be executed, to produce a
- command for the shell that will echo the command to be
- executed. The ignore command is also used as a template,
- again with %s replaced by the command
- to be executed, to produce a command that will
- execute the command to be executed and ignore any error
- it returns. When these strings are used as templates,
- you must provide newline(s) (\n) in
- the appropriate place(s).
-
-
-
-
- The strings that follow these keywords may be enclosed in
- single or double quotes (the quotes will be stripped off) and
- may contain the usual C backslash-characters
- (\n is newline, \r is
- return, \b is backspace,
- \' escapes a single-quote inside
- single-quotes, \" escapes a double-quote
- inside double-quotes). Now for an example.
-
- This is actually the contents of the <shx.mk> system
- makefile, and causes PMake
- to use the Bourne Shell in such a way
- that each command is printed as it is executed. That is, if
- more than one command is given on a line, each will be
- printed separately. Similarly, each time the body of a loop
- is executed, the commands within that loop will be printed,
- etc. The specification runs like this:
-
- #
-# This is a shell specification to have the Bourne shell echo
-# the commands just before executing them, rather than when it reads
-# them. Useful if you want to see how variables are being expanded, etc.
-#
-.SHELL : path=/bin/sh \
- quiet="set -" \
- echo="set -x" \
- filter="+ set - " \
- echoFlag=x \
- errFlag=e \
- hasErrCtl=yes \
- check="set -e" \
- ignore="set +e"
-
- It tells PMake the following:
-
-
-
- The shell is located in the file
- /bin/sh. It need not tell
- PMake that the name of the
- shell is sh as PMake can
- figure that out for itself (it is the last component of the
- path).
-
-
-
- The command to stop echoing is set -.
-
-
-
- The command to start echoing is set .
-
-
-
- When the echo off command is executed, the shell
- will print + set -
- (The + comes from using the
- flag (rather than the
- flag PMake
- usually uses)). PMake will
- remove all occurrences of this string from the output, so
- you do not notice extra commands you did not put
- there.
-
-
-
- The flag the Bourne Shell
- will take to start echoing in this way is the
- flag. The Bourne
- Shell will only take its flag arguments
- concatenated as its first argument, so neither this nor
- the errFlag specification begins with a
- -.
-
-
-
- The flag to use to turn error-checking on from the
- start is .
-
-
-
- The shell can turn error-checking on and off, and
- the commands to do so are set +e and
- set -e, respectively.
-
-
-
- I should note that this specification is for
- Bourne Shells
- that are not part of Berkeley &unix;, as shells from Berkeley
- do not do error control. You can get a similar effect,
- however, by changing the last three lines to be:
-
- hasErrCtl=no \
-check="echo \"+ %s\"\n" \
-ignore="sh -c '%s || exit 0\n"
-
- This will cause PMake to execute
- the two commands:
-
- echo "+ cmd"
-sh -c 'cmd || true'
-
- for each command for which errors are to be ignored. (In
- case you are wondering, the thing for ignore tells the shell
- to execute another shell without error checking on and
- always exit 0, since the || causes the
- exit 0 to be executed only if the first command exited
- non-zero, and if the first command exited zero, the shell
- will also exit zero, since that is the last command it
- executed).
-
-
-
- Compatibility
-
- There are three (well, 3 1/2) levels of
- backwards-compatibility built into
- PMake. Most makefiles will need none
- at all. Some may need a little bit of work to operate correctly
- when run in parallel. Each level encompasses the previous
- levels (e.g. (one shell per command) implies
- ). The three levels are described in the
- following three sections.
-
-
-
- DEFCON 3 – Variable Expansion
-
- As noted before, PMake will not
- expand a variable unless it knows of a value for it. This can
- cause problems for makefiles that expect to leave variables
- undefined except in special circumstances (e.g. if more flags
- need to be passed to the C compiler or the output from a text
- processor should be sent to a different printer). If the
- variables are enclosed in curly braces
- (${PRINTER}), the shell will let them pass.
- If they are enclosed in parentheses, however, the shell will
- declare a syntax error and the make will come to a grinding
- halt.
-
- You have two choices: change the makefile to define the
- variables (their values can be overridden on the command line,
- since that is where they would have been set if you used
- Make, anyway) or always give the
- flag (this can be done with the
- .MAKEFLAGS target, if you want).
-
-
-
- DEFCON 2 – The Number of the Beast
-
- Then there are the makefiles that expect certain commands,
- such as changing to a different directory, to not affect
- other commands in a target's creation script. You can solve
- this is either by going back to executing one shell per
- command (which is what the flag forces
- PMake to do), which
- slows the process down a good bit and requires you to use
- semicolons and escaped newlines for shell constructs, or by
- changing the makefile to execute the offending command(s) in
- a subshell (by placing the line inside parentheses), like
- so:
-
- install :: .MAKE
- (cd src; $(.PMAKE) install)
- (cd lib; $(.PMAKE) install)
- (cd man; $(.PMAKE) install)
-
- This will always execute the three makes (even if the
-
- flag was given) because of the combination of the
- ::
- operator and the .MAKE attribute.
- Each command will change to the proper directory to perform
- the install, leaving the main shell in the directory in
- which it started.
-
-
-
- DEFCON 1 – Imitation is the Not the Highest Form of
- Flattery
-
- The final category of makefile is the one where every command
- requires input, the dependencies are incompletely specified, or
- you simply cannot create more than one target at a time, as
- mentioned earlier. In addition, you may not have the time or
- desire to upgrade the makefile to run smoothly with
- PMake. If you are the conservative
- sort, this is the compatibility mode for you. It is entered
- either by giving PMake the
- flag (for Make),
- or by executing PMake as
- make. In either case,
- PMake performs things exactly like
- Make (while still supporting most
- of the nice new features PMake
- provides). This includes:
-
-
-
- No parallel execution.
-
-
-
- Targets are made in the exact order specified by the
- makefile. The sources for each target are made in strict
- left-to-right order, etc.
-
-
-
- A single Bourne shell is used to execute each command,
- thus the shell's $$ variable is
- useless, changing directories does not work across command
- lines, etc.
-
-
-
- If no special characters exist in a command line,
- PMake will break the command
- into words itself and execute the command directly,
- without executing a shell first. The characters that
- cause PMake to execute a shell
- are: #, =,
- |, ^,
- (, ),
- {, },
- ;, &,
- >, <,
- *, ?,
- [, ],
- :, $,
- `, and \. You should
- notice that these are all the characters that are given
- special meaning by the shell (except '
- and , which
- PMake deals with all by its
- lonesome).
-
-
-
- The use of the null suffix is turned off.
-
-
-
-
-
- The Way Things Work
-
- When PMake reads the makefile, it
- parses sources and targets into nodes in a graph. The graph is
- directed only in the sense that PMake
- knows which way is up. Each node contains not only links to all
- its parents and children (the nodes that depend on it and those
- on which it depends, respectively), but also a count of the
- number of its children that have already been processed.
-
- The most important thing to know about how
- PMake uses this graph is that the
- traversal is breadth-first and occurs in two passes.
-
- After PMake has parsed the
- makefile, it begins with the nodes the user has told it to make
- (either on the command line, or via a
- .MAIN target, or by the target being
- the first in the file not labeled with the
- .NOTMAIN attribute) placed in a queue. It
- continues to take the node off the front of the queue, mark it
- as something that needs to be made, pass the node to
- Suff_FindDeps (mentioned earlier) to find any
- implicit sources for the node, and place all the node's children
- that have yet to be marked at the end of the queue. If any of
- the children is a .USE rule, its
- attributes are applied to the parent, then its commands are
- appended to the parent's list of commands and its children are
- linked to its parent. The parent's unmade children counter is
- then decremented (since the .USE node
- has been processed). You will note that this allows a
- .USE node to have children that are
- .USE nodes and the rules will be
- applied in sequence. If the node has no children, it is placed
- at the end of another queue to be examined in the second pass.
- This process continues until the first queue is empty.
-
- At this point, all the leaves of the graph are in the
- examination queue. PMake removes the
- node at the head of the queue and sees if it is out-of-date. If
- it is, it is passed to a function that will execute the commands
- for the node asynchronously. When the commands have completed,
- all the node's parents have their unmade children counter
- decremented and, if the counter is then 0, they are placed on
- the examination queue. Likewise, if the node is up-to-date.
- Only those parents that were marked on the downward pass are
- processed in this way. Thus PMake
- traverses the graph back up to the nodes the user instructed it
- to create. When the examination queue is empty and no shells
- are running to create a target, PMake
- is finished.
-
- Once all targets have been processed,
- PMake executes the commands attached
- to the .END target, either explicitly
- or through the use of an ellipsis in a shell script. If there
- were no errors during the entire process but there are still
- some targets unmade (PMake keeps a
- running count of how many targets are left to be made), there is
- a cycle in the graph. PMake does a
- depth-first traversal of the graph to find all the targets that
- were not made and prints them out one by one.
-
-
Property changes on: head/en_US.ISO8859-1/books/pmake/gods/chapter.xml
___________________________________________________________________
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/sgml
\ No newline at end of property
Index: head/en_US.ISO8859-1/books/pmake/glossary/glossary.xml
===================================================================
--- head/en_US.ISO8859-1/books/pmake/glossary/glossary.xml (revision 52713)
+++ head/en_US.ISO8859-1/books/pmake/glossary/glossary.xml (nonexistent)
@@ -1,239 +0,0 @@
-
-
-
- Glossary of Jargon
-
-
- attribute
-
-
- A property given to a target that causes
- PMake to treat it differently.
-
-
-
-
- command script
-
-
- The lines immediately following a dependency line that specify
- commands to execute to create each of the targets on the dependency
- line. Each line in the command script must begin with a tab.
-
-
-
-
- command-line variable
-
-
- A variable defined in an argument when
- PMake is first executed.
- Overrides all assignments to the same variable name in the
- makefile.
-
-
-
-
- conditional
-
-
- A construct much like that used in C that allows a makefile to be
- configured on the fly based on the local environment, or on what is
- being made by that invocation of PMake.
-
-
-
-
- creation script
-
-
- Commands used to create a target.
-
-
-
-
- dependency
-
-
- The relationship between a source and a target. This comes in
- three flavors, as indicated by the operator between the target and the
- source. : gives a straight time-wise dependency
- (if the target is older than the source, the target is out-of-date),
- while ! provides simply an ordering and always
- considers the target out-of-date. :: is much like
- :, save it creates multiple instances of a target
- each of which depends on its own list of sources.
-
-
-
-
- dynamic source
-
-
- This refers to a source that has a local variable invocation in
- it. It allows a single dependency line to specify a different source
- for each target on the line.
-
-
-
-
- global variable
-
-
- Any variable defined in a makefile. Takes precedence over
- variables defined in the environment, but not over command-line or
- local variables.
-
-
-
-
- input graph
-
-
- What PMake constructs from a makefile.
- Consists of nodes made of the targets in the makefile, and the links
- between them (the dependencies). The links are directed (from source
- to target) and there may not be any cycles (loops) in the graph.
-
-
-
-
- local variable
-
-
- A variable defined by PMake visible
- only in a target's shell script.
- There are seven local variables, not all of which are defined for
- every target: .TARGET, .ALLSRC,
- .OODATE, .PREFIX,
- .IMPSRC, .ARCHIVE, and
- .MEMBER.
- .TARGET, .PREFIX,
- .ARCHIVE, and .MEMBER
- may be used on dependency lines to create
- dynamic sources.
-
-
-
-
- makefile
-
-
- A file that describes how a system is built. If you do not know
- what it is after reading this tutorial…
-
-
-
-
- modifier
-
-
- A letter, following a colon, used to alter how a variable is
- expanded. It has no effect on the variable itself.
-
-
-
-
- operator
-
-
- What separates a source from a target (on a dependency line) and
- specifies the relationship between the two. There are three:
- :, ::,
- and !.
-
-
-
-
- search path
-
-
- A list of directories in which a file should be sought.
- PMake's view of the contents of directories
- in a search path does not change once the makefile has been read.
- A file is sought on a search path only if it is exclusively a
- source.
-
-
-
-
- shell
-
-
- A program to which commands are passed in order to create
- targets.
-
-
-
-
- source
-
-
- Anything to the right of an operator on a dependency line.
- Targets on the dependency line are usually created
- from the sources.
-
-
-
-
- special target
-
-
- A target that causes PMake to do
- special things when it is encountered.
-
-
-
-
- suffix
-
-
- The tail end of a file name. Usually begins with a period, like
- .c or .ms.
-
-
-
-
- target
-
-
- A word to the left of the operator on a dependency line.
- More generally, any file that PMake might
- create. A file may be (and often is) both a target and a source (what
- it is depends on how PMake is looking at it
- at the time – sort of like the wave/particle duality of light,
- you know).
-
-
-
-
- transformation rule
-
-
- A special construct in a makefile that specifies how to create a
- file of one type from a file of another, as indicated by their
- suffixes.
-
-
-
-
- variable expansion
-
-
- The process of substituting the value of a variable for a
- reference to it. Expansion may be altered by means of modifiers.
-
-
-
-
- variable
-
-
- A place in which to store text that may be retrieved later.
- Also used to define the local environment.
- Conditionals exist that test whether a variable is defined or not.
-
-
-
Property changes on: head/en_US.ISO8859-1/books/pmake/glossary/glossary.xml
___________________________________________________________________
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/sgml
\ No newline at end of property
Index: head/en_US.ISO8859-1/books/pmake/shortcuts/chapter.xml
===================================================================
--- head/en_US.ISO8859-1/books/pmake/shortcuts/chapter.xml (revision 52713)
+++ head/en_US.ISO8859-1/books/pmake/shortcuts/chapter.xml (nonexistent)
@@ -1,1216 +0,0 @@
-
-
-
- Short-cuts and Other Nice Things
-
- Based on what I have told you so far, you may have gotten the
- impression that PMake is just a way of
- storing away commands and making sure you do not forget to compile
- something. Good. That is just what it is. However, the ways I
- have described have been inelegant, at best, and painful, at
- worst. This chapter contains things that make the writing of
- makefiles easier and the makefiles themselves shorter and easier
- to modify (and, occasionally, simpler). In this chapter, I assume
- you are somewhat more familiar with Sprite (or &unix;, if that is
- what you are using) than I did in , just so
- you are on your toes. So without further ado…
-
-
- Transformation Rules
-
- As you know, a file's name consists of two parts: a base
- name, which gives some hint as to the contents of the file, and
- a suffix, which usually indicates the format of the file. Over
- the years, as &unix; has developed, naming conventions, with
- regard to suffixes, have also developed that have become almost
- as incontrovertible as Law. E.g. a file ending in
- .c is assumed to contain C source code; one
- with a .o suffix is assumed to be a
- compiled, relocatable object file that may be linked into any
- program; a file with a .ms suffix is
- usually a text file to be processed by
- Troff with the -ms
- macro package, and so on. One of the best aspects of both
- Make and
- PMake comes from their understanding
- of how the suffix of a file pertains to its contents and their
- ability to do things with a file based solely on its suffix.
- This ability comes from something known as a transformation
- rule. A transformation rule specifies how to change a file with
- one suffix into a file with another suffix.
-
- A transformation rule looks much like a dependency line,
- except the target is made of two known suffixes stuck
- together. Suffixes are made known to
- PMake by placing them
- as sources on a dependency line whose target is the special
- target .SUFFIXES. E.g.:
-
- .SUFFIXES : .o .c
-.c.o :
- $(CC) $(CFLAGS) -c $(.IMPSRC)
-
- The creation script attached to the target is used to
- trans form a file with the first suffix (in this case,
- .c) into a
- file with the second suffix (here, .o).
- In addition, the target inherits whatever attributes have
- been applied to the transformation rule.
- The simple rule given above says that to transform a C source
- file into an object file, you compile it using
- cc with the
- flag. This rule is taken straight from the system makefile.
- Many transformation rules (and suffixes) are defined there,
- and I refer you to it for more examples
- (type pmake -h to find out where it
- is).
-
- There are several things to note about the
- transformation rule given above:
-
-
-
- The .IMPSRC variable.
- This variable is set to the
- implied source (the file from which
- the target is being created; the one with the first
- suffix), which, in this case, is the
- .c file.
-
-
-
- The CFLAGS variable. Almost all of
- the transformation rules in the system makefile are set
- up using variables that you can alter in your makefile
- to tailor the rule to your needs. In this case, if you
- want all your C files to be compiled with the
- flag, to provide information for
- dbx, you would set the CFLAGS variable to
- contain (CFLAGS =
- -g) and PMake
- would take care of the rest.
-
-
-
- To give you a quick example, the makefile in
- could be changed to this:
-
- OBJS = a.o b.o c.o
-program : $(OBJS)
- $(CC) -o $(.TARGET) $(.ALLSRC)
-$(OBJS) : defs.h
-
- The transformation rule I gave above takes the place of the
- 6 lines
-
- This is also somewhat cleaner, I think, than
- the dynamic source solution presented in
- .
- :
-
- a.o : a.c
- cc -c a.c
-b.o : b.c
- cc -c b.c
-c.o : c.c
- cc -c c.c
-
- Now you may be wondering about the dependency between the
- .o
- and .c files – it is not mentioned
- anywhere in the new makefile. This is because it is not needed:
- one of the effects of applying a transformation rule is the
- target comes to depend on the implied source. That's why it is
- called the implied source.
-
- For a more detailed example. Say you have a makefile like
- this:
-
- a.out : a.o b.o
- $(CC) $(.ALLSRC)
-
- and a directory set up like this:
-
- total 4
--rw-rw-r-- 1 deboor 34 Sep 7 00:43 Makefile
--rw-rw-r-- 1 deboor 119 Oct 3 19:39 a.c
--rw-rw-r-- 1 deboor 201 Sep 7 00:43 a.o
--rw-rw-r-- 1 deboor 69 Sep 7 00:43 b.c
-
- While just typing pmake will do
- the right thing, it is much more informative to type
- pmake -d s. This will
- show you what PMake is up
- to as it processes the files. In this case,
- PMake prints the following:
-
- Suff_FindDeps (a.out)
- using existing source a.o
- applying .o -> .out to "a.o"
-Suff_FindDeps (a.o)
- trying a.c...got it
- applying .c -> .o to "a.c"
-Suff_FindDeps (b.o)
- trying b.c...got it
- applying .c -> .o to "b.c"
-Suff_FindDeps (a.c)
- trying a.y...not there
- trying a.l...not there
- trying a.c,v...not there
- trying a.y,v...not there
- trying a.l,v...not there
-Suff_FindDeps (b.c)
- trying b.y...not there
- trying b.l...not there
- trying b.c,v...not there
- trying b.y,v...not there
- trying b.l,v...not there
---- a.o ---
-cc -c a.c
---- b.o ---
-cc -c b.c
---- a.out ---
-cc a.o b.o
-
- Suff_FindDeps is the
- name of a function in PMake that
- is called to check for implied sources for a target using
- transformation rules. The transformations it tries are,
- naturally enough, limited to the ones that have been defined
- (a transformation may be defined multiple times, by the way,
- but only the most recent one will be used). You will notice,
- however, that there is a definite order to the suffixes that
- are tried. This order is set by the relative positions of
- the suffixes on the .SUFFIXES line
- – the earlier a suffix appears, the earlier it is
- checked as the source of a transformation. Once a suffix
- has been defined, the only way to change its position in the
- pecking order is to remove all the suffixes (by having a
- .SUFFIXES dependency line with no sources)
- and redefine them in the order you want.
- (Previously-defined transformation rules will be
- automatically redefined as the suffixes they involve are
- re-entered.) Another way to affect the search order is to make
- the dependency explicit. In the above example,
- a.out depends on a.o
- and b.o. Since a transformation exists
- from .o to .out,
- PMake uses that, as indicated by
- the using existing source a.o
- message.
-
- The search for a transformation starts from the suffix of
- the target and continues through all the defined
- transformations, in the order dictated by the suffix ranking,
- until an existing file with the same base (the target name
- minus the suffix and any leading directories) is found. At that
- point, one or more transformation rules will have been found
- to change the one existing file into the target.
-
- For example, ignoring what's in the system makefile for
- now, say you have a makefile like this:
-
- .SUFFIXES : .out .o .c .y .l
-.l.c :
- lex $(.IMPSRC)
- mv lex.yy.c $(.TARGET)
-.y.c :
- yacc $(.IMPSRC)
- mv y.tab.c $(.TARGET)
-.c.o :
- cc -c $(.IMPSRC)
-.o.out :
- cc -o $(.TARGET) $(.IMPSRC)
-
- and the single file jive.l.
- If you were to type pmake -rd ms jive.out,
- you would get the following output for
- jive.out:
-
- Suff_FindDeps (jive.out)
- trying jive.o...not there
- trying jive.c...not there
- trying jive.y...not there
- trying jive.l...got it
- applying .l -> .c to "jive.l"
- applying .c -> .o to "jive.c"
- applying .o -> .out to "jive.o"
-
- and this is why: PMake starts with the
- target jive.out, figures out its suffix
- (.out) and looks for things it can
- transform to a .out file. In this case, it
- only finds .o, so it looks for the file
- jive.o. It fails to find it, so it
- looks for transformations into a .o
- file. Again it has only one choice: .c.
- So it looks for jive.c and, as you
- know, fails to find it. At this point it has two choices: it can
- create the .c file from either a
- .y file or a .l file.
- Since .y came first on the
- .SUFFIXES line, it checks for
- jive.y first, but can not find it, so it looks
- for jive.l and, lo and behold, there it is.
- At this point, it has defined a transformation path as follows:
-
- .l -> .c -> .o -> .out
-
- and applies the transformation rules accordingly. For completeness,
- and to give you a better idea of what PMake
- actually did with this three-step transformation, this is what
- PMake printed for the rest of the
- process:
-
- Suff_FindDeps (jive.o)
- using existing source jive.c
- applying .c -> .o to "jive.c"
-Suff_FindDeps (jive.c)
- using existing source jive.l
- applying .l -> .c to "jive.l"
-Suff_FindDeps (jive.l)
-Examining jive.l...modified 17:16:01 Oct 4, 1987...up-to-date
-Examining jive.c...non-existent...out-of-date
---- jive.c ---
-lex jive.l
-... meaningless lex output deleted ...
-mv lex.yy.c jive.c
-Examining jive.o...non-existent...out-of-date
---- jive.o ---
-cc -c jive.c
-Examining jive.out...non-existent...out-of-date
---- jive.out ---
-cc -o jive.out jive.o
-
- One final question remains: what does
- PMake do with targets that have no
- known suffix? PMake simply pretends
- it actually has a known suffix and searches for
- transformations accordingly. The suffix it chooses is the
- source for the .NULL target mentioned
- later. In the system makefile, .out is
- chosen as the null suffix because most people
- use PMake to create programs. You
- are, however, free and welcome to change it to a suffix
- of your own choosing. The null suffix is ignored, however,
- when PMake is in compatibility
- mode (see ).
-
-
-
- Including Other Makefiles
-
- Just as for programs, it is often useful to extract certain
- parts of a makefile into another file and just include it in
- other makefiles somehow. Many compilers allow you say something
- like:
-
- #include "defs.h"
-
- to include the contents of defs.h
- in the source file. PMake
- allows you to do the same thing for makefiles, with the
- added ability to use variables in the filenames. An include
- directive in a makefile looks either like this:
-
- #include <file>
-
- or this:
-
- #include "file"
-
- The difference between the two is where
- PMake searches for the file: the first way,
- PMake will look for the file only in the
- system makefile directory (or directories) (to find out what that
- directory is, give PMake the
- -h flag).
- The system makefile directory search path can be overridden via the
- option. For files in double-quotes, the search
- is more complex:
-
-
-
- The directory of the makefile that's including the
- file.
-
-
-
- The current directory (the one in which you
- invoked PMake).
-
-
-
- The directories given by you using
- flags, in the order in which you
- gave them.
-
-
-
- Directories given by
- .PATH dependency lines (see
- ).
-
-
-
- The system makefile directory.
-
-
-
- in that order.
-
- You are free to use PMake variables
- in the filename – PMake
- will expand them before searching for the file. You must
- specify the searching method with either angle brackets or
- double-quotes outside of a variable expansion. I.e. the following:
-
- SYSTEM = <command.mk>
-
-#include $(SYSTEM)
-
- will not work.
-
-
-
- Saving Commands
-
- There may come a time when you will want to save certain
- commands to be executed when everything else is done. For
- instance: you are making several different libraries at one
- time and you want to create the members in parallel. Problem is,
- ranlib is another one of those
- programs that can not be run more than once in the same directory
- at the same time (each one creates a file called
- __.SYMDEF into which it stuffs information
- for the linker to use. Two of them running at once will
- overwrite each other's file and the result will be garbage for
- both parties). You might want a way to save the ranlib
- commands til the end so they can be run one after the other,
- thus keeping them from trashing each other's file.
- PMake allows you to do this by
- inserting an ellipsis (...) as a command between
- commands to be run at once and those to be run later.
-
- So for the ranlib case above,
- you might do this:
-
- lib1.a : $(LIB1OBJS)
- rm -f $(.TARGET)
- ar cr $(.TARGET) $(.ALLSRC)
- ...
- ranlib $(.TARGET)
-
-lib2.a : $(LIB2OBJS)
- rm -f $(.TARGET)
- ar cr $(.TARGET) $(.ALLSRC)
- ...
- ranlib $(.TARGET)
-
- This would save both
-
- ranlib $(.TARGET)
-
- commands until the end, when they would run one after the
- other (using the correct value for the
- .TARGET variable, of course).
-
- Commands saved in this manner are only executed if
- PMake manages to re-create
- everything without an error.
-
-
-
- Target Attributes
-
- PMake allows you to give
- attributes to targets by means of special sources. Like
- everything else PMake uses, these
- sources begin with a period and are made up of all upper-case
- letters. There are various reasons for using them, and I will
- try to give examples for most of them. Others you will have to
- find uses for yourself. Think of it as an exercise for
- the reader. By placing one (or more) of these as a
- source on a dependency line, you are marking the
- target(s) with that attribute. That is just the way I
- phrase it, so you know.
-
- Any attributes given as sources for a transformation
- rule are applied to the target of the transformation rule
- when the rule is applied.
-
-
-
-
-
-
-
-
- .DONTCARE
-
- If a target is marked with this attribute and
- PMake can not figure out
- how to create it, it will ignore this fact and assume
- the file is not really needed or actually exists and
- PMake just can not find
- it. This may prove wrong, but the error will be
- noted later on, not when PMake
- tries to create the target so marked. This attribute also
- prevents PMake from attempting
- to touch the target if it is given the
- flag.
-
-
-
- .EXEC
-
- This attribute causes its shell script to be
- executed while having no effect on targets that depend
- on it. This makes the target into a sort of subroutine.
- An example. Say you have some LISP files that need to
- be compiled and loaded into a LISP process. To do this,
- you echo LISP commands into a file and execute a LISP
- with this file as its input when everything is
- done. Say also that you have to load
- other files from another system before you can compile
- your files and further, that you do not want to go
- through the loading and dumping unless one of your
- files has changed. Your makefile might look a little
- bit like this (remember, this is an educational example,
- and do not worry about the COMPILE
- rule, all will soon become clear, grasshopper):
-
- system : init a.fasl b.fasl c.fasl
- for i in $(.ALLSRC);
- do
- echo -n '(load "' >> input
- echo -n ${i} >> input
- echo '")' >> input
- done
- echo '(dump "$(.TARGET)")' >> input
- lisp < input
-
-a.fasl : a.l init COMPILE
-b.fasl : b.l init COMPILE
-c.fasl : c.l init COMPILE
-COMPILE : .USE
- echo '(compile "$(.ALLSRC)")' >> input
-init : .EXEC
- echo '(load-system)' > input
-
- .EXEC sources, do not appear in the
- local variables of targets that depend on them (nor are
- they touched if PMake is
- given the
- flag). Note that all the rules, not just that for
- system, include init as a source. This is because
- none of the other targets can be made until init
- has been made, thus they depend on it.
-
-
-
- .EXPORT
-
- This is used to mark those targets whose
- creation should be sent to another machine if at
- all possible. This may be used by some exportation
- schemes if the exportation is expensive. You
- should ask your system administrator if it is
- necessary.
-
-
-
- .EXPORTSAME
-
- Tells the export system that the job
- should be exported to a machine of the same
- architecture as the current one. Certain
- operations (e.g. running text through nroff) can be
- performed the same on any architecture (CPU and
- operating system type), while others (e.g. compiling
- a program with cc) must be performed on a
- machine with the same architecture. Not all export
- systems will support this attribute.
-
-
-
- .IGNORE
-
- Giving a target the
- .IGNORE attribute causes
- PMake to ignore errors
- from any of the target's commands, as if they all
- had - before them.
-
-
-
- .INVISIBLE
-
- This allows you to specify one target as a
- source for another without the one affecting the
- other's local variables. Useful if, say, you
- have a makefile that creates two programs, one
- of which is used to create the other, so it must
- exist before the other is created. You could say
-
- prog1 : $(PROG1OBJS) prog2 MAKEINSTALL
-prog2 : $(PROG2OBJS) .INVISIBLE MAKEINSTALL
-
- where MAKEINSTALL
- is some complex .USE rule (see
- below) that depends on the .ALLSRC
- variable containing the right things. Without the
- .INVISIBLE
- attribute for prog2,
- the MAKEINSTALL rule
- could not be applied. This is not as useful as it
- should be, and the semantics may change (or the
- whole thing go away) in the not-too-distant
- future.
-
-
-
- .JOIN
-
- This is another way to avoid performing some
- operations in parallel while permitting
- everything else to be done so. Specifically it forces
- the target's shell script to be executed only if
- one or more of the sources was out-of-date. In
- addition, the target's name, in both its
- .TARGET
- variable and all the local variables of any
- target that depends on it, is replaced by the value
- of its .ALLSRC variable. As an
- example, suppose you have a program that has
- four libraries that
- compile in the same directory along with, and at
- the same time as, the program. You again have
- the problem with ranlib that I mentioned
- earlier, only this time it is more severe: you can not
- just put the ranlib off to the end since the
- program will need those libraries before it can
- be re-created. You can do something like this:
-
- program : $(OBJS) libraries
- cc -o $(.TARGET) $(.ALLSRC)
-
-libraries : lib1.a lib2.a lib3.a lib4.a .JOIN
- ranlib $(.OODATE)
-
- In this case, PMake will re-create
- the $(OBJS)
- as necessary, along with lib1.a,
- lib2.a, lib3.a
- and lib4.a. It will then
- execute ranlib on any library that was changed and set
- program's .ALLSRC variable to contain
- what's in $(OBJS)
- followed by lib1.a
- lib2.a
- lib3.a
- lib4.a. In
- case you are wondering, it is called
- .JOIN because
- it joins together different threads of the
- input graph at the target marked
- with the attribute. Another aspect of the
- .JOIN
- attribute is it keeps the target from being
- created if the flag was
- given.
-
-
-
- .MAKE
-
- The .MAKE
- attribute marks its target as being a
- recursive invocation of PMake. This forces
- PMake to execute the
- script associated with the
- target (if it is out-of-date) even if you gave
- the or
- flag. By doing this, you can start
- at the top of a system and type
-
- pmake -n
-
- and have it descend the directory tree (if your
- makefiles are set up correctly), printing what
- it would have executed if you had not included
- the flag.
-
-
-
- .NOEXPORT
-
- If possible,
- PMake will attempt to
- export the creation of all targets to another machine
- (this depends on how PMake
- was configured). Sometimes, the creation is so
- simple, it is pointless to send it to another machine.
- If you give the target the
- .NOEXPORT attribute, it will be run
- loally, even if you have given
- PMake the flag.
-
-
-
- .NOTMAIN
-
- Normally, if you do not specify a target to
- make in any other way,
- PMake will take the first
- target on the first dependency line of a makefile as
- the target to create. That target is known as the
- Main Target and is labeled as such if
- you print the dependencies out using the
- flag. Giving a target this
- attribute tells PMake that
- the target is definitely not the Main Target. This
- allows you to place targets in an included makefile
- and have PMake create
- something else by default.
-
-
-
- .PRECIOUS
-
- When PMake is
- interrupted (you type control-C at the keyboard), it will
- attempt to clean up after itself by removing any
- half-made targets. If a target has the
- .PRECIOUS attribute, however,
- PMake will leave it alone.
- An additional side effect of the ::
- operator is to mark the targets as
- .PRECIOUS.
-
-
-
- .SILENT
-
- Marking a target with this attribute keeps its
- commands from being printed when they are
- executed, just as if they had an @
- in front of them.
-
-
-
- .USE
-
- By giving a target this attribute, you turn it
- into PMake's equivalent of
- a macro. When the target is
- used as a source for another target, the other target
- acquires the commands, sources and attributes (except
- .USE) of the source. If the target
- already has commands, the .USE target's
- commands are added to the end. If more than one
- .USE-marked source is given to a
- target, the rules are applied sequentially. The typical
- .USE rule (as I call them) will use
- the sources of the target to which it is applied (as
- stored in the .ALLSRC variable for
- the target) as its arguments, if you
- will. For example, you probably noticed that the
- commands for creating lib1.a and
- lib2.a in the example in section
- were exactly the same.
- You can use the .USE attribute to
- eliminate the repetition, like so:
-
- lib1.a : $(LIB1OBJS) MAKELIB
-lib2.a : $(LIB2OBJS) MAKELIB
-
-MAKELIB : .USE
- rm -f $(.TARGET)
- ar cr $(.TARGET) $(.ALLSRC)
- ...
- ranlib $(.TARGET)
-
- Several system makefiles (not to be confused
- with The System Makefile) make use of these
- .USE rules to make your life
- easier (they are in the default, system makefile
- directory...take a look). Note that the
- .USE rule source itself
- (MAKELIB) does not appear in
- any of the targets's local variables. There is no limit
- to the number of times I could use the
- MAKELIB rule. If there were
- more libraries, I could continue with
- lib3.a : $(LIB3OBJS) MAKELIB
- and so on and so forth.
-
-
-
-
-
-
-
- Special Targets
-
- As there were in Make, so there
- are certain targets that have special meaning to
- PMake. When you use one on a
- dependency line,
- it is the only target that may appear on the left-hand-side of the
- operator. As for the attributes and variables, all the special
- targets begin with a period and consist of upper-case letters
- only. I will not describe them all in detail because some of them
- are rather complex and I will describe them in more detail than you
- will want in . The targets are as follows:
-
-
-
-
-
-
-
-
- .BEGIN
-
- Any commands attached to this target are
- executed before anything else is done. You can use
- it for any initialization that needs
- doing.
-
-
-
- .DEFAULT
-
- This is sort of a .USE
- rule for any target (that was used only as a source)
- that PMake can not figure
- out any other way to create. It is only sort
- of a .USE rule because
- only the shell script attached to the
- .DEFAULT target is used.
- The .IMPSRC variable of a target
- that inherits .DEFAULT's
- commands is set to the target's own
- name.
-
-
-
- .END
-
- This serves a function similar to
- .BEGIN, in that commands
- attached to it are executed once everything
- has been re-created (so long as no errors
- occurred). It also serves the extra function of
- being a place on which PMake
- can hang commands you put off to the end. Thus the script
- for this target will be executed before any of the
- commands you save with the
- ....
-
-
-
- .EXPORT
-
- The sources for this target are passed
- to the exportation system compiled into
- PMake. Some systems will use
- these sources to configure themselves. You should ask
- your system administrator about this.
-
-
-
- .IGNORE
-
- This target marks each of its sources
- with the .IGNORE attribute.
- If you do not give it any sources, then it is
- like giving the flag when
- you invoke PMake –
- errors are ignored for all commands.
-
-
-
- .INCLUDES
-
- The sources for this target are taken to be
- suffixes that indicate a file that can be included in
- a program source file. The suffix must have
- already been declared with .SUFFIXES
- (see below).
- Any suffix so marked will have the directories on
- its search path (see .PATH,
- below) placed in the .INCLUDES
- variable, each preceded by a flag.
- This variable can then be used as an argument for
- the compiler in the normal fashion. The
- .h suffix is already marked in
- this way in the system makefile. E.g. if you have
-
- .SUFFIXES : .bitmap
-.PATH.bitmap : /usr/local/X/lib/bitmaps
-.INCLUDES : .bitmap
-
- PMake will place
- -I/usr/local/X/lib/bitmaps
- in the .INCLUDES variable and you can
- then say
-
- cc $(.INCLUDES) -c xprogram.c
-
- (Note: the .INCLUDES variable is
- not actually filled in until the entire makefile has
- been read.)
-
-
-
- .INTERRUPT
-
- When PMake is
- interrupted, it will execute the commands in the
- script for this target, if it exists.
-
-
-
- .LIBS
-
- This does for libraries what
- .INCLUDES does for include
- files, except the flag used is
- , as required by those linkers
- that allow you to tell them where to find libraries.
- The variable used is .LIBS.
- Be forewarned that PMake
- may not have been compiled to do this if the linker
- on your system does not accept the
- flag, though the .LIBS variable
- will always be defined once the makefile has been
- read.
-
-
-
- .MAIN
-
- If you did not give a target (or targets) to
- create when you invoked
- PMake, it will take the
- sources of this target as the targets to
- create.
-
-
-
- .MAKEFLAGS
-
- This target provides a way for you to
- always specify flags for PMake
- when the makefile is used. The flags are just as they
- would be typed to the shell (except you can not use shell
- variables unless they are in the environment), though
- the and
- flags have no effect.
-
-
-
- .NULL
-
- This allows you to specify what
- suffix PMake should pretend
- a file has if, in fact, it has no known suffix. Only
- one suffix may be so designated. The last source on the
- dependency line is the suffix that is used (you
- should, however, only give one suffix...).
-
-
-
- .PATH
-
- If you give sources for this target,
- PMake will take them as
- directories in which to search for files it cannot
- find in the current directory. If you give no
- sources, it will clear out any directories added to
- the search path before. Since the effects of this
- all get very complex, we will leave it till to give you a complete
- explanation.
-
-
-
- .PATHsuffix
-
- This does a similar thing to
- .PATH, but it does it only
- for files with the given suffix. The suffix must
- have been defined already. Look at Search Paths
- () for more
- information.
-
-
-
- .PRECIOUS
-
- Similar to .IGNORE,
- this gives the .PRECIOUS attribute to
- each source on the dependency line, unless there are
- no sources, in which case the .PRECIOUS
- attribute is given to every target in the file.
-
-
-
- .RECURSIVE
-
- This target applies the .MAKE
- attribute to all its sources. It does nothing if you
- do not give it any sources.
-
-
-
- .SHELL
-
- PMake is not
- constrained to only using the Bourne shell to
- execute the commands you put in the makefile. You
- can tell it some other shell to use with this
- target. Check out () for more
- information.
-
-
-
- .SILENT
-
- When you use
- .SILENT as a target, it
- applies the .SILENT attribute to
- each of its sources. If there are no sources on the
- dependency line, then it is as if you gave
- PMake the
- flag and no commands will be
- echoed.
-
-
-
- .SUFFIXES
-
- This is used to give new file suffixes
- for PMake to handle.
- Each source is a suffix
- PMake should
- recognize. If you give a
- .SUFFIXES dependency line
- with no sources, PMake
- will forget about all the suffixes it knew
- (this also nukes the null suffix). For those
- targets that need to have suffixes defined, this
- is how you do it.
-
-
-
-
-
- In addition to these targets, a line of the form:
-
- attribute : sources
-
- applies the attribute to all the targets listed as sources.
-
-
-
- Modifying Variable Expansion
-
- Variables need not always be expanded verbatim.
- PMake defines several modifiers
- that may be applied to a variable's value before it is expanded.
- You apply a modifier by placing it after the variable name with
- a colon between the two, like so:
-
- ${VARIABLE:modifier}
-
- Each modifier is a single character followed by something
- specific to the modifier itself. You may apply as many
- modifiers as you want – each one is applied to the
- result of the previous and is separated from the
- previous by another colon.
-
- There are seven ways to modify a variable's expansion,
- most of which come from the C shell variable modification
- characters:
-
-
-
- Mpattern
-
-
- This is used to select only those words (a word is a
- series of characters that are neither spaces nor tabs)
- that match the given pattern. The pattern is a
- wildcard pattern like that used by the shell, where
- * means 0 or more
- characters of any sort; ? is any
- single character; [abcd] matches any
- single character that is either a,
- b, c or
- d (there may be any number of
- characters between the brackets);
- [0-9] matches any single character
- that is between 0 and
- 9 (i.e. any digit. This form may be
- freely mixed with the other bracket form), and
- \ is used to escape any of the
- characters *, ?,
- [ or :, leaving
- them as regular characters to match themselves in a
- word. For example, the system makefile
- <makedepend.mk> uses
- $(CFLAGS:M-[ID]*) to extract all the
- and flags that
- would be passed to the C compiler. This allows it to
- properly locate include files and generate the correct
- dependencies.
-
-
-
-
- Npattern
-
-
- This is identical to :M except
- it substitutes all words that do not match the given
- pattern.
-
-
-
-
- S/search-string/replacement-string/[g]
-
-
- Causes the first occurrence of search-string in
- the variable to be replaced by replacement-string,
- unless the flag is given at the end,
- in which case all occurrences of the string are
- replaced. The substitution is performed on each word in
- the variable in turn. If search-string begins with a
- ^, the string must match starting at
- the beginning of the word. If search-string ends with a
- $, the string must match to the end
- of the word (these two may be combined to force an exact
- match). If a backslash precedes these two characters,
- however, they lose their special meaning. Variable
- expansion also occurs in the normal fashion inside both
- the search-string and the replacement-string, except
- that a backslash is used to prevent the expansion of a
- $, not another dollar sign, as is
- usual. Note that search-string is just a string, not a
- pattern, so none of the usual regularexpression/wildcard
- characters have any special meaning save
- ^ and $. In the
- replacement string, the & character
- is replaced by the search-string unless it is preceded
- by a backslash. You are allowed to use any character
- except colon or exclamation point to separate the two
- strings. This so-called delimiter character may be
- placed in either string by preceding it with a
- backslash.
-
-
-
-
- T
-
-
- Replaces each word in the variable expansion by
- its last component (its tail).
- For example, given:
-
- OBJS = ../lib/a.o b /usr/lib/libm.a
-TAILS = $(OBJS:T)
-
- the variable TAILS would expand
- to a.o b libm.a.
-
-
-
-
- H
-
-
- This is similar to :T, except
- that every word is replaced by everything but the tail
- (the head). Using the same definition of
- OBJS, the string
- $(OBJS:H) would expand to
- ../lib /usr/lib. Note that the final
- slash on the heads is removed and anything without
- a head is replaced by the empty string.
-
-
-
-
- E
-
-
- :E replaces each word by its
- suffix (extension). So
- $(OBJS:E) would give you
- .o .a.
-
-
-
-
- R
-
-
- This replaces each word by everything but the
- suffix (the root of the word).
- $(OBJS:R) expands to
- ../lib/a b /usr/lib/libm.
-
-
-
-
- In addition, the System V style of substitution is also
- supported. This looks like:
-
- $(VARIABLE:search-string=replacement)
-
- It must be the last modifier in the chain. The search is
- anchored at the end of each word, so only suffixes or whole
- words may be replaced.
-
-
-
- More Exercises
-
- Exercise 3.1
-
- You have got a set programs, each of which is created from
- its own assembly-language source file (suffix
- .asm). Each program can be assembled into
- two versions, one with error-checking code assembled in and one
- without. You could assemble them into files with different
- suffixes (.eobj and
- .obj, for instance), but your linker only
- understands files that end in .obj. To top
- it all off, the final executables must have the suffix
- .exe. How can you still use
- transformation rules to make your life easier (Hint: assume the
- errorchecking versions have ec tacked onto their prefix)?
-
- Exercise 3.2
-
- Assume, for a moment or two, you want to perform
- a sort of indirection by placing the name of
- a variable into another one, then you want to get the value
- of the first by expanding the second somehow. Unfortunately,
- PMake does not allow constructs like:
-
- $($(FOO))
-
- What do you do? Hint: no further variable expansion is
- performed after modifiers are applied, thus if you
- cause a $ to occur in the expansion,
- that is what will be in the result.
-
-
Property changes on: head/en_US.ISO8859-1/books/pmake/shortcuts/chapter.xml
___________________________________________________________________
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/sgml
\ No newline at end of property
Index: head/en_US.ISO8859-1/books/pmake/book.xml
===================================================================
--- head/en_US.ISO8859-1/books/pmake/book.xml (revision 52713)
+++ head/en_US.ISO8859-1/books/pmake/book.xml (nonexistent)
@@ -1,43 +0,0 @@
-
-
-%chapters.ent;
-]>
-
- PMake — A Tutorial
-
-
- Adamde Boor
-
-
- 1988
- 1989
- Adam de Boor
-
-
-
- 1989
- Berkeley Softworks
-
-
-
- 1988
- 1989
- 1993
- The Regents of the University of California.
-
-
- &pmake.legalnotice;
-
- $FreeBSD$
-
-
- &chap.intro;
- &chap.basics;
- &chap.shortcuts;
- &chap.gods;
- &chap.answers;
-
- &glossary;
-
Property changes on: head/en_US.ISO8859-1/books/pmake/book.xml
___________________________________________________________________
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/sgml
\ No newline at end of property
Index: head/en_US.ISO8859-1/books/pmake/Makefile
===================================================================
--- head/en_US.ISO8859-1/books/pmake/Makefile (revision 52713)
+++ head/en_US.ISO8859-1/books/pmake/Makefile (nonexistent)
@@ -1,28 +0,0 @@
-#
-# $FreeBSD$
-#
-# This is an XML version of the pmake tutorial by Adam de Boor that is
-# also part of the src/share/doc/psd collection of docs.
-#
-
-DOC?= book
-
-FORMATS?= html-split
-
-INSTALL_COMPRESSED?= gz
-INSTALL_ONLY_COMPRESSED?=
-
-# SRCS lists the individual XML files that make up the document.
-# Changes to any of these files will force a rebuild.
-
-# XML content
-SRCS= book.xml
-SRCS+= answers/chapter.xml
-SRCS+= basics/chapter.xml
-SRCS+= glossary/glossary.xml
-SRCS+= gods/chapter.xml
-SRCS+= intro/chapter.xml
-SRCS+= shortcuts/chapter.xml
-
-DOC_PREFIX?= ${.CURDIR}/../../..
-.include "${DOC_PREFIX}/share/mk/doc.project.mk"
Property changes on: head/en_US.ISO8859-1/books/pmake/Makefile
___________________________________________________________________
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Index: head/en_US.ISO8859-1/books/pmake/legalnotice.xml
===================================================================
--- head/en_US.ISO8859-1/books/pmake/legalnotice.xml (revision 52713)
+++ head/en_US.ISO8859-1/books/pmake/legalnotice.xml (nonexistent)
@@ -1,49 +0,0 @@
-
-
-
- All rights reserved.
-
- This code is derived from software contributed to Berkeley
- by Adam de Boor.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are
- met:
-
-
-
- Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
-
-
- Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the following
- disclaimer in the documentation and/or other materials provided
- with the distribution.
-
-
-
- Neither the name of the University nor the names of its
- contributors may be used to endorse or promote products derived
- from this software without specific prior written
- permission.
-
-
-
-
- THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS
- BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- THE POSSIBILITY OF SUCH DAMAGE.
-
-
Property changes on: head/en_US.ISO8859-1/books/pmake/legalnotice.xml
___________________________________________________________________
Deleted: svn:keywords
## -1 +0,0 ##
-FreeBSD=%H
\ No newline at end of property
Deleted: svn:mime-type
## -1 +0,0 ##
-text/sgml
\ No newline at end of property
Index: head/en_US.ISO8859-1/books/Makefile
===================================================================
--- head/en_US.ISO8859-1/books/Makefile (revision 52713)
+++ head/en_US.ISO8859-1/books/Makefile (revision 52714)
@@ -1,16 +1,15 @@
# $FreeBSD$
SUBDIR = arch-handbook
SUBDIR+= design-44bsd
SUBDIR+= dev-model
SUBDIR+= developers-handbook
SUBDIR+= faq
SUBDIR+= fdp-primer
SUBDIR+= handbook
-SUBDIR+= pmake
SUBDIR+= porters-handbook
ROOT_SYMLINKS= faq handbook
DOC_PREFIX?= ${.CURDIR}/../..
.include "${DOC_PREFIX}/share/mk/doc.project.mk"