Make
| Site
| Docs
| Ref
| Resources
| Community
| FeedBack
|
| Mail
| Web
| Software
| Classes
| FAQs
|
MAKE/VMS is a utility which performs commands specified by the user when a dependency relationship specified by the user is not satisfied. This is useful in situations such as software development where the user is in an edit-compile-test cycle and wishes to simplify the steps between 'edit' and 'test'. Many other tasks lend themselves well to the MAKE structure. $ MAKE [Qualifier(s)] [Target(s)]
/INPUT=Choose an alternate makefile. The default value is "MAKEFILE". /OUTPUT= Specify the name of the command file. Use '/KEEP' also if you actually wish for the file to remain. /DEBUG /DEBUG /NODEBUG (default) Print debugging info (for bug reports). Much of the action of MAKE may be discerned from this output. /DEFAULTS /DEFAULTS (default) /NODEFAULTS Control reading of the default rules file MAKE_DEFAULTS or MAKE.INI. /DEFINE /DEFINE=("symbol1","symbol1=value1",...) Define symbols prior to execution. /EXECUTE /EXECUTE (default) /NOEXECUTE Execute the commands needed to update the targets. The negation of this qualifier is useful in order to obtain a static command file via a combination of qualifiers such as /KEEP, /FORCE, and /OUTPUT for later use. /FORCE Always rebuild all targets, even if they are in synch. /IGNORE /IGNORE /NOIGNORE (default) Ignore errors in the command file (via the command 'SET NOON'). /KEEP /KEEP /NOKEEP (default) Prevent deletion of the command file generated by running MAKE. /MACRO /MACRO=("file1","symbol1=value1",...) Define symbols either directly or from a file prior to execution. /SPAWN /SPAWN /NOSPAWN (default) The default action of MAKE is to call the routine LIB$DO_COMMAND to execute the command file (if any) that has been built during the Make phase. Use of this qualifier directs MAKE to perform a SPAWN/NOWAIT instead. /VERIFY /VERIFY /NOVERIFY (default) Echo commands as they execute (via the command 'SET VERIFY').
MAKE is a program which reads a file of dependencies and executes commands when one file is out of date with respect to one or more files upon which it depends. For instance, an executable image FOO.EXE depends upon FOO.OBJ, which in turn depends upon FOO.C and FOO.H. If FOO.H is modified, then it is newer than FOO.OBJ and so FOO.OBJ needs to be remade. Because FOO.OBJ is remade, FOO.EXE will become out of date and must be remade subsequently. MAKE reads user-supplied description files and executes any commands required to bring the target(s) up to date with respect to all dependents.
MAKE takes as input one or more description files which, appropriately enough, describe the relationships between targets and sources. An attempt is made to open the file MAKE_DEFAULTS, which may be a logical name. If this fails, the file MAKE.INI in the current directory is attempted. After the initialization file is parsed (only the first encountered will be used), an attempt is made to open MAKEFILE. This, too, may be a logical name. Alternatively, it may be specified on the command line with the /INPUT qualifier. There is no explicit requirement to access a makefile successfully, but the requirement of finding at least one target implicitly requires at least one makefile to be accessed. As the files are read in line by line, they are internalized into the various data structures used by MAKE, such as the Symbol list, the Target list, the File list, et al. Output from the /DEBUG qualifier demonstrates the parsing phase in gory detail.
After all makefiles have been digested, one or more targets are 'made'. If any targets were specified on the command line, each is 'made' in turn. If no targets were specified, the first bona fide target encountered during the parsing phase is 'made'. A target is 'made' by making in turn each of its prerequisites. If you are thinking that this is a recursive definition, you might consider becoming a programmer. When MAKE reaches the end of a branch, it climbs back down a level in the tree comparing the date of the current level's target to the newest dependent. If a target is older than at least one of its prerequisites (and a missing target is considered infinitely old), it is 'built' according to the commands that were supplied with the dependency rule being examined. A target is out of date if it is newer than a dependent, but obviously the more general case has a target out of date if it does not even exist. Also, one can create a target that has no dependents, a so-called 'terminal target'. Terminal targets exist or don't exist, but can't be out of date. If a terminal target does not exist, it will be 'built' (the commands for the target will be added to the command file). If it exists, fine. If any dependent of a target is built, then the target must be built as well. Since the 'making' is recursive, the leaves of the tree are checked before the branches so that this forces 'building' to propagate back to the root target.
The comparison date for normal files is the revision date of the file as returned by the VAXCRTL 'stat' function. This can be examined from DCL using the DIR/DAT=MOD command.
The comparison date for library modules (syntax = 'lib.typ(mod)') is the date of last modification of the module as returned by the LBR$SET_MODULE routine. Note that libraries may be of any type acceptable to the VAX Librarian facility (.OLB, .TLB, .MLB, etc.).
The comparison date for CMS elements is the date of last modification for the generation of the element in the specified class, or the newest generation along the main line of descent if no class is specified.
Building a target consists of placing the commands, suitably formatted, into a command file for later execution. When the Make phase completes, the command file is closed and it is executed (using LIB$DO_COMMAND) in the current process, unless the /SPAWN qualifier was specified or the %SPAWN directive was encountered without a countermanding %NOSPAWN. Simple error handling is included in the command file to cause command processing to terminate when an error (DCL ERROR severity) is encountered. Also, the command file contains a command to delete itself upon exiting. This can be prevented via the /KEEP qualifier.
The description file is called a 'MAKEFILE', as in the UNIX version. Lines in a VMS makefile fall into four categories: target lines, command lines, symbol lines, or directives.
Target lines must begin at column one (no preceding whitespace). The
colon separating the targets from the prerequisites must be followed
by at least one whitespace. Targets and prerequisites may be
separated from each other by commas and/or whitespace. Because commas
are simply replaced with whitespace in a target line, two commas in a
row do not signify a null target. If a target or prerequisite has a
qualifier attached ('/junk'), the qualifier is removed from the
module name. This allows a symbol to be used in both target lines and
command lines. For instance, you may have a symbol defined as the
list of LINK options files, with each options file followed by the
qualifier '/OPT'. This way, you can use the symbol in the target line
AND the LINK command.
There are no tricks to specifying a normal file. Use the standard VMS syntax as described in the DCL Dictionary (et al.).
A name like 'a.olb(b)' means the module named 'b' stored in the
library named 'a.olb'. This name is handled just like a normal file
name, except that a special routine is entered to read the
modification time of the module in the library. If the library
doesn't exist, then it is made. If there is a rule for creating the
library, such as:
###################
a.olb : #
lib/cre a #
###################
then it will be created. Otherwise, an error is signalled since the
library couldn't be found. The default library type is '.OLB' if no
type is specified (this is the VAX Librarian's default). Note that
you can use a default rule to create the library if it doesn't exist:
##########################
*.olb : #
lib/cre $* #
*.hlb : #
lib/help/cre $* #
*.tlb : #
lib/cre/text $* #
##########################
A CMS module is specified as the element name followed by the '~' (tilde) character, optionally followed by a CMS library name. You can specify a default CMS library using the '%CMSLIB' directive. For example, the element FOO.C in library [.CMS] would be 'FOO.C~[.CMS]'.
When dealing with complex programs, it is not reasonable to list
explicitly rules for compilation of every module. Rather, one would
like to be able to say "If X.Obj is out of date, go look for X.C and
compile it, regardless of who X is." This feature is provided by the
default rules mechanism:
####################
*.obj : *.c # '$*' is a symbol which means
cc $* # 'whatever matched the *'.
####################
With the above makefile, we may compile any C program (FOO) by giving
the DCL command '$ make foo.obj'. The default rule will match the
'*' with 'foo' and will insert '$ cc foo' into the command file.
The default rules will be searched for a pattern match only if either
there are no rules for the file in question or there are rules but no
command lines. If a match is found, the default rules will be added
just as though they were found explicitly in the makefile. The
symbol '$*' expands to the root name (the part that matches the
wildcard), '$@' expands to the name of the target, and '$<' expands
to the name of the prerequisite. '$?' expands to the list of all
the prerequisites whose date information forced the target to be
built. In the case of multiple rules for a target, the first rule
for which the prerequisite _exists_ will be used. If no rule has an
existing prerequisite, then the first matching rule will be used.
The wildcard character '*' does not have to be the first character in
the target. You might want to have your sources and objects in
different directories, for example. The following rule epitomizes the
flexibility of wildcards:
[OBJ]*.obj: [SRC]*.c
cc $ Command_lines
A command line is ANY line with whitespace in column one. The
commands apply to ALL targets on the most recent target line. If the
the last non-whitespace character on the command line is a '$', the
dollar sign is removed and no '$ ' will be prepended to the command
line on output. This allows you to indicate that a 'command line' is
actually a data line for a program and not a DCL command line. If a
command line ends in '-', the following line will be handled as a
continuation line, so no '$' will be prepended to the _next_ line.
If both the '$' and the '-' need to be used, such as when you wish to
continue a data line, the order of the two characters IS significant.
When using both special characters, the order should be '-$', since
the dollar sign is removed first. If '$-' was used, the '-' would be
detected as the last character and the '$' would be left at the end
of the line without having been processed.
Symbol_lines
Symbol definitions begin in column one. The presence of the '='
character distinguishes these lines from target lines. The symbol
name is the first string on the left side of the '='. The symbol's
value is everything to the right of the '=', not including any
whitespace following the '='. For instance, the symbol line
FOO BAR JOE'S GARAGE = This string
would result in the symbol 'FOO' being assigned the value "This
string". Note that since the delimiter for the symbol name is ONLY
whitespace, you can inadvertently have symbol names with special
characters such as punctuation or control characters. WARNING: if you
define the one-character symbols '{' or '(', you will be unable to
use multi-character symbols. Also, you must not define a multi-
character symbol with the characters ')' or '}' in them. The symbol
parsing routine is not smart enough to understand that these are not
symbol name terminators.
Predefined_symbol
The symbol __VAX is defined when MAKE is run on VAX platforms. The
symbol __ALPHA is define when MAKE is run on Alpha platforms.
Directives
Directives are signified by a '%' in column one. There can not be
whitespace between the '%' and the directive name. Some directives
take arguments, which must be separated by whitespace from the
directive name.
IFDEF_
Subsequent commands are executed only if is defined. This
processing state will exist until a matching ELSE, ELIFDEF, ELIFNDEF,
or ENDIF is encountered. These commands may be nested to any depth.
IFNDEF_
Subsequent commands are executed only if is not defined.
This processing state will exist until a matching ELSE, ELIFDEF,
ELIFNDEF, or ENDIF is encountered. These commands may be nested to
any depth.
ENDIF
Terminates the processing state established by a previous IFDEF or
IFNDEF directive.
ELSE
Inverts the processing state caused by a previous IFDEF, IFNDEF,
ELIFDEF, or ELIFNDEF directive.
ELIFDEF_
The processing state established by the closest previous IFDEF,
IFNDEF, ELIFDEF, or ELIFNDEF is overridden; subsequent commands will
be executed only if is defined.
ELIFNDEF_
The processing state established by the closest previous IFDEF,
IFNDEF, ELIFDEF, or ELIFNDEF is overridden; subsequent commands will
be executed only if is not defined.
INCLUDE_
Causes the parsing routine to digest the specified file.
CMSLIB_
Selects the specified directory as the default CMS library.
CMSGEN_
Specifies the generation to be used for determining element dates.
DEBUG
Turn on debugging (similar to the /DEBUG command qualifier).
NODEBUG
Turn off debugging (similar to the /NODEBUG command qualifier).
SPAWN
Direct MAKE to spawn the command file at the end of execution.
NOSPAWN
Direct MAKE to execute the command file in the current process at the
end of execution.
Example
# <== This is a comment indicator (in column one)
! <== As is this
%SPAWN !Force the command file to be spawned at the end of making
foo.exe: foo.obj # This is a target line
link foo # This is a DCL command line
foo.obj: foo.c foo.h ! <== This is also a comment indicator
cc/lis foo
As a human would read the description, it says:
"FOO.EXE depends upon FOO.OBJ. If FOO.EXE is out of date or FOO.OBJ
has been 'made', then add the command 'LINK FOO' to a file of
commands to be executed. FOO.OBJ depends upon FOO.C and FOO.H. If
it is out of date, or either of its dependents have been 'made', then
add 'CC/LIS FOO' to the command file to be executed."
Makefiles
MAKE tries to locate two description files. The first is nominally
the default rules file, while the second is the 'main' description
file. In reality, there is no internal distinction between the two
files. No error is reported if neither file is found. An error
during the MAKE phase will be displayed: if you specify a target on
the command line and it exists, nothing happens; if the target is
missing, the error is "target doesn't exist and couldn't be made"
since there are no rules; if no target was specified on the command
line, then MAKE has no target and complains accordingly.
Default_rules
The first file which MAKE attempts to locate is a description of the
default rules to be applied when no explicit rules for a target are
provided. Two attempts are made to locate a default rules file.
First, the file "MAKE_DEFAULTS" (which may be a logical name) is
tried. If the open fails on this file, MAKE tries for the file
"MAKE.INI".
Makefile
The second file which MAKE attempts to locate is "MAKEFILE", which
may be a logical name. You may also specify this file on the command
line via the '/INPUT' qualifier.
General_Advice
The Makefile that comes with MAKE/VMS is a very good example of what
can be done with the system. Also, UNIX makefiles are fairly useful
to examine, but obviously the command lines will be different. Also,
since it is horribly inefficient in VMS to spawn a subprocess for
each command, there is a fundamental difference between the operation
on VMS and UNIX. UNIX MAKE spins off a new process for each command,
but MAKE/VMS builds a command file and defers execution until the
end. I like my way much better, but I have the advantage of
hindsight. Of course, there are some significant drawbacks to the
batch method, too.
Bugs
There are always bugs. Report bugs to:
Ned Freed
Innosoft International, Inc.
Claremont, CA 91711
ned@innosoft.com
******** Please include /DEBUG output. *********
WebMaster@umkc.edu
Information Services, Central Computing
University
of Missouri Kansas City