Chapter 2
Description Files
The key to successfully building your software system with MMK is the creation of a complete and accurate description file. This chapter describes the format for a description file and its components.
2.1. Description File Components
A description file is a collection of the following components:
Dependencies, which describe how one object depends on one or more other objects.
Actions, which are commands to be executed when an object needs to be built.
Macro definitions, for defining symbols that may be used in rules or actions.
Inference rule definitions, which are rules based on suffixes (and possibly directories as well), from which MMK can infer dependencies and actions without you having to list them explicitly in your makefile.
MMK directives, which provide a means for adding commands to be executed before or after all other actions, provide a simple conditional-build mechanism, and other directives for modifying MMK's behavior (see Section 2.7, “Other Directives”).
Here is an example of a simple description file:
PROGRAM.EXE : MAIN.OBJ,SUBROUTINES.OBJ
LINK/EXEC=PROGRAM.EXE MAIN.OBJ,SUBROUTINES.OBJ
MAIN.OBJ : MAIN.FOR
FORTRAN MAIN
SUBROUTINES.OBJ : SUBROUTINES.MAR
MACRO SUBROUTINESThis is a simple collection of dependencies and actions for building an image called PROGRAM.EXE. PROGRAM.EXE depends on two object files, called MAIN.OBJ and SUBROUTINES.OBJ; MAIN is a FORTRAN module and SUBROUTINES is a MACRO module.
MMK accepts either a colon or the DEC/MMS DEPENDS_ON keyword to separate a target object from its sources. In either case, the separator must be surrounded by blanks—this differs from make, but is consistent with DEC/MMS syntax.
2.2. Using Inference Rules
MMK includes a collection of built-in inference rules and actions for most VMS programming languages. The rules are driven by the file type suffix attached to the object name; you must use the default file types in order to make use of the default rules.
For example, the description file in the last section could be simplified to just:
PROGRAM.EXE : MAIN.OBJ,SUBROUTINES.OBJ
LINK/EXEC=PROGRAM.EXE MAIN.OBJ,SUBROUTINES.OBJ
MAIN.OBJ : MAIN.FOR
SUBROUTINES.OBJ : SUBROUTINES.MARMMK's built-in inference rules automatically define the actions for building a .OBJ file from a .FOR (using the FORTRAN command) and for building a .OBJ file from a .MAR file (using the MACRO command).
The description file could even be simplified further, to just:
PROGRAM.EXE : MAIN.OBJ,SUBROUTINES.OBJ
LINK/EXEC=PROGRAM.EXE MAIN.OBJ,SUBROUTINES.OBJMMK automatically searches the suffixes list when constructing the dependency tree and locates inference rules for the .OBJ files automatically. This illustrates the second use for inference rules: they are used not only for inferring actions for a dependency that omits them, but they may also be used for inferring dependencies themselves based on a combination of source and target suffixes. This second purpose can greatly simplify your makefiles, and makes the build process more automatic.
2.3. Defining Inference Rules
You can define your own inference rules, either to extend or replace the ones built into MMK. You may include these rule definitions in your makefile, or in a separate file called a rules file. Rules files can be included by the use of a logical name or through the /RULES qualifier on the MMK command; see the MMK for further information.
MMK supports two types of inference rules: generic and prefixed. Generic rules are based solely on suffixes (file types), as in:
.C.OBJ :
CC/OBJECT=$(MMS$TARGET) $(MMS$SOURCE)which says, “to build filename.OBJ from an existing file called filename.C, use the CC command.” In general, generic rules work best when the source and target files reside in the same directory.
Prefixed inference rules are based on both suffixes and “prefixes” -- device and directory specifications. This provides a way to have MMK automatically infer dependencies between files that reside in different directories. For example: For example, the prefixed rule:
{SRC$:}.C{OBJ$:}.OBJ :
CC/OBJECT=$(MMS$TARGET) $(MMS$SOURCE)tells MMK, “to build OBJ$:filename.OBJ from an existing file called SRC$:filename.C, use the CC command.” This works like the generic rule above, but with the additional provision of having the source and target reside in different locations.
You can have more than one prefixed rule for a particular pair of suffixes; you may also mix generic rules and prefixed rules for a pair of suffixes. When attempting to infer a dependency, MMK will first use the prefixed rules, then fall back to using the generic rule.
In prefixed rules, the curly braces (“{” and “}”) are required. One of the two prefixes may be null, but specifying two null prefixes is equivalent to defining a generic rule.
In order to match a prefixed rule, file specification as it exists in the description file must match the prefix in the rule; MMK performs no logical name translation on prefixes, nor can it identify equivalencies between two prefixes that reference the same directory using different syntax.
The first inference rule for a pair of suffixes, whether it is generic or prefixed, must specify an action list; subsequent rules for the same pair of suffixes (with different prefixes) may have the action list omitted, in which case MMK will use the action list from the first rule. For example, MMK already has a built-in generic rule for .C.OBJ, which is:
.C.OBJ :
$(CC)$(CFLAGS) $(MMS$SOURCE)If you are simply adding a set of prefixed rules for the .C.OBJ suffix pair, you do not need to specify an action list on those rules; MMK will use the action list from the built-in generic rule.
2.4. Forced Setup/Teardown Actions in Inference Rules
MMK recognizes two special modifiers on action lines specified for inference rules. The setup modifier, “<”, forces the execution of an action prior to any unmodified action. The teardown modifier, “>”, forces the execution of an action after all other actions. Setup and teardown actions are performed for all dependencies matching the inference rule, even if a dependency includes explicit actions.
For example, the inference rule
.C.OBJ :
< DEFINE/USER DECC$SHR V6_ROOT:[SYSLIB]DECC$SHR
$(CC)$(CFLAGS) $(MMS$SOURCE)would cause the logical name DECC$SHR to be defined prior to the invocation of the C compiler for all compilations into .OBJ files. This would apply even on dependencies containing explicit actions, such as
FRED.OBJ : FRED.C $(CC)$(CFLAGS)/DEFINE=FRED $(MMS$SOURCE)
2.5. Modifying the Suffix List
MMK uses a suffix list to determine the inference rules it should search for inferring a dependency. MMK has a built-in suffix list which goes with its list of built-in inference rules; see Appendix B, Built-in Dependency Rules for more information on the built-in rules and suffix list.
You can augment or replace the built-in suffix list with your own suffixes by using the directives listed in Table 2.1, “Suffix List Directives” in a rules file or a makefile.
| Directive | Description |
|---|---|
| .SUFFIXES | Specify no file types to clear the list or append file types to the end of the suffix list |
| .SUFFIXES_BEFORE | Inserts a list of file types in the suffixes precedence list before the specified first file type |
| .SUFFIXES_AFTER | Inserts a list of file types in the suffixes precedence list after the specified first file type. |
| .SUFFIXES_DELETE | Removes a list of files types from the suffix precedence list. |
For example, let's say you have a Modula-2 compiler on your system, whose source files have a file type (suffix) of .MOD. MMK has no built-in inference rules for this file type; you could add one with the following sequence:
.SUFFIXES : .MOD
.MOD.OBJ :
MODULA2/OBJECT=$(MMS$TARGET) $(MMS$SOURCE)The .SUFFIXES directive above adds the .MOD suffix to the end of the suffix list. This is followed by the inference rule for creating an object file from a Modula-2 source file.
Specifying the .SUFFIXES directive with nothing to the right of the colon clears the current suffix list. You can do this to prevent MMK from using any inference rules for the current build, or to follow it with another .SUFFIXES directive that specifies only those suffixes for which you want inference rules to be enabled.
It is also possible to determine the current active .SUFFIXES list by using the builtin macro MMSSUFFIXES.
2.6. Using Conditionals
MMK provides several directives that can be used to modify the build sequence based on conditions. These directives are .IF, .IFDEF, .IFNDEF, .ELSE, .ELSIF and .ENDIF. The .IFDEF directive checks if the specified macro is defined and .IFNDEF is the logical inverse, the syntax of which is:
.IFDEF VEGETABLE ... .ENDIF
or,
.IFNDEF VEGETABLE ... .ENDIF
The .IF directive supports more general comparison (and thus greater power) by allowing the specification of a boolean expression, like so:
.IF expression ... [.ELSEIF expression] [...] [.ELSE] [...] .ENDIF
In the example above, expression can be replaced by any operations consisting of the operators (both MMS and MMK operators are listed) listed in Table 2.2, “Conditional Expression Operators”.
| MMS Syntax | MMK Syntax | Example |
|---|---|---|
| Boolean Operators | ||
| .AND | AND | expression .AND expression |
| .NOT | NOT | .NOT expression |
| .OR | OR | expression .OR expression |
| Comparison Operators | ||
| .EQ | EQL | expression .EQ expression |
| .GE | GEQ | expression .GE expression |
| .GT | GTR | expression .GT expression |
| .LE | LEQ | expression .LE expression |
| .LT | LSS | expression .LT expression |
| .NE | NEQ | expression .NE expression |
All expressions evaluate to a boolean result. After all macro substitution is performed and the operand is not an empty string it is the equivalent of a boolean TRUE. All comparisons are performed without regard to upper/lower case.
2.6.1. GNU Make Conditionals
Supplemental to the MMS/MMK conditionals, MMK also supports the specification of the GNU Make-style conditionals ifeq, ifneq, ifdef, ifndef, else and endif. The ifdef and ifndef conditionals behave exactly as their MMS/MMK counter-parts. However, ifeq and ifneq have a slightly different syntax:
ifeq (arg1, arg2) ifeq 'arg1' 'arg2' ifeq "arg1" "arg2" ifeq "arg1" 'arg2' ifeq 'arg1' "arg2"
Although the example lists ifeq, it can be replaced with its logical inverse, ifneq. These two directives simply compare their arguments (ignoring case) and test for equality. The following is an example adapted from the GNU Make manual:
ifeq ($(strip $(foo)),) # Come in here if foo is an empty string ... endif
In order to use the conditionals it is necessary to first enable them. This can be done from the command line with the specification of the /EXTENDED_SYNTAX=GNU_SYNTAX qualifier or with the .GNU_SYNTAX directive in the description file.
2.7. Other Directives
As well as the suffix list directives (Table 2.1, “Suffix List Directives”) and the conditionals (Section 2.6, “Using Conditionals”), MMK recognizes the following directives in a description file or rules file. Each begins with a period.
- .CASE_SENSITIVE
Makes the names of macros and objects case sensitive from this point on. Without it, MMK converts them to upper case, so that
fooandFOOare the same macro.- .DEFAULT
Begins a list of actions that MMK uses to build any object for which there is neither a dependency with actions nor an applicable inference rule. The action lines follow the directive, as they follow a dependency.
Unlike DEC/MMS, MMK lets any rule, including a built-in rule, take precedence over the .DEFAULT actions; see Section A.3, “Other Differences”.
- .FIRST
Begins a list of actions to be executed before any other action, when MMK starts the subprocess in which actions are executed. The action lines follow the directive. If nothing needs to be built, the .FIRST actions are not executed.
- .GNU_SYNTAX
Enables the GNU Make-style conditionals, as the /EXTENDED_SYNTAX=GNU_SYNTAX qualifier does; see Section 2.6.1, “GNU Make Conditionals”.
- .IGNORE
Causes MMK to ignore the status of all action lines, as /IGNORE=FATAL does, so that the build continues after an action fails. If /IGNORE or /NOIGNORE is specified on the MMK command, it takes precedence over this directive.
- .INCLUDE
file-spec Reads the description file
file-specat this point, as if its contents appeared in place of the directive. The default file type is .MMS, in the current default directory. With /LOG, MMK reports each file it includes.- .LAST
Begins a list of actions to be executed after all other actions, before MMK ends the subprocess in which actions are executed. The action lines follow the directive. Like the .FIRST actions, they are executed only if some other action was.
- .SILENT
Stops MMK from displaying action lines before executing them, as if every action line began with “@”. If /VERIFY or /NOVERIFY is specified on the MMK command, it takes precedence over this directive.
For example, the following description file writes a line before the first action and after the last:
.FIRST
@ WRITE SYS$OUTPUT "Build started"
.LAST
@ WRITE SYS$OUTPUT "Build finished"
PROGRAM.EXE : MAIN.OBJ,SUBROUTINES.OBJ
LINK/EXEC=PROGRAM.EXE MAIN.OBJ,SUBROUTINES.OBJIf PROGRAM.EXE is already up to date, MMK executes no actions, and neither message is displayed.
2.8. Macro Definitions
MMK supports a range of operators for assigning values to macros. To simplify description files it is possible to concatenate and test before assignment. Table 2.3, “Macro Assignment Operator” defines the available assignment operators.
| Operator | Description | Example |
|---|---|---|
| = | Assign value. |
FOO = BAR
|
| += | Concatenate to existing value. |
FOR += ,NEXT
|
| ?= | Assign if macro is undefined. |
FOO ?= FIRST
|
| |= | Assign command results. |
FOO |= DIRECTORY
|
| ~= | Completely evaluate value before assignment |
Two of these assignment operators behave a little differently than the others. They are both described in more detail below.
2.8.1. Command Assignment
Command assignment is the |= operator. The assigned value is taken as a command and executed, with the results being assigned to the macro. Using this mechanism it would be possible to determine some details of the running system, like so:
FOO |= SHOW SYSTEM/NOPROCESS
ALL :
@ WRITE SYS$OUTPUT "$(FOO)"the results of which might look something like:
$ MMK OpenVMS V7.3 on node BENDER 15-FEB-2013 16:05:10.03 Uptime 37 15:54:40
Note
The '!' character is already a comment delimiter in MMK. To resolve this, the MMK description file parser now tests for a '=' character immediately following a '!'. Usually when detecting a '!' character the remainder of the line (including the comment delimiter) will be stripped from the output. However, in this special case the delimiter and the following characters will not be stripped and instead parsed as an assignment. This may create issues for existing procedures that contain comments that match this pattern.
However, it is worth noting that this restriction only applies to the '!' comment delimiter. It is still possible to use '#' in any place and achieve the desired result.
2.8.2. Evaluated Assignment
Evaluated assignment is the ~= operator. This assignment operator is special in that it completely evaluated the value before assigning it to the macro.
All records in the description file are evaluated and an attempt is made to resolve all macros as they are read in to the parser. However, if an unresolved macro, or a builtin function call is found it is not evaluated to the empty string, rather it is retained for a time when those macros are available. An example from the default definitions within MMK is:
BASIC = BASIC BASFLAGS = /NOLIST/OBJECT=$(MMS$TARGET_NAME)$(OBJ)
The definition of BASFLAGS will not be evaluated fully as the description file is processed, leaving MMS$TARGET_NAME and OBJ unresolved until BASFLAGS is resolved as a part of executing the build actions that include this definition (shown below).
.BAS$(OBJ) : $(BASIC)$(BASFLAGS) $(MMS$SOURCE)
Sometimes this is not what is wanted and it is necessary to evaluate the definition completely. The following is an excerpt from the procedure that builds MMK's PCSI Product Definition File.
DOCUMENTATION ~= $(ADDPREFIX $(KITDIR),$(WILDCARD $(KITDIR)*.HTML)) - $(ADDPREFIX $(KITDIR),$(WILDCARD $(KITDIR)*.PDF)) - $(ADDPREFIX $(KITDIR),$(WILDCARD $(KITDIR)*.PS)) - $(ADDPREFIX $(KITDIR),$(WILDCARD $(KITDIR)*.TXT))
Without being able to evaluate the macro definition for DOCUMENTATION the list documentation files would actually evaluate to the function calls, not the results of the builtin function calls.
2.9. Deferring Macro Substitution
MMK provides a way to defer the resolution of a macro that is referenced in the right-hand side of a macro definition, as an extension to MMS. Macros are normally referenced using the $(name) syntax, which causes the value of the macro to be substituted immediately when a line is parsed (except for MMK's “special” macros, such as MMS$SOURCE and MMS$TARGET).
You can defer this substitution in MMK by using the syntax ${name} instead. However, this syntax is only recognized on the right-hand side of a macro definition. This can be useful when defining macros in a rules file that rely on macros that do not get defined until another rules file or a description file gets processed. For example, you might have the following definition in a rules file:
CFLAGS = /OBJECT=$(MMS$TARGET)/NOLIST/DEFINE=(VMS_BUILD,${MOREDEFINES})then in your description file, you can define the MOREDEFINES macro:
MOREDEFINES = ANOTHER_C_DEFINE
This will complete the CFLAGS macro value when it is referenced later in the description file.
2.10. Macro String Substitution
MMK provides two mechanisms for causing string substitution to occur when resolving a macro reference: suffix substitution and general string substitution.
2.10.1. Suffix Substitution
When a string contains a list of file specifications, you can replace the file type suffixes on each file specification with a different suffix. The general form of this type of substitution is:
$(macro-name:old-sfx=new-sfx)
which causes the replacement of all occurrences of the file type suffix
old-sfx with new-sfx. Both
suffixes must begin with a dot.
For example, in these macro definitions:
SOURCES = FIRST.C, SECOND.C, THIRD.C OBJECTS = $(SOURCES:.C=.OBJ)
the OBJECTS macro would have the value “FIRST.OBJ, SECOND.OBJ, THIRD.OBJ”. This form of substitution works with file specification lists separated by either blanks, commas, or both. The substitution rule following the colon may also contain blanks, which are ignored. Substitutions are case-insensitive.
2.10.2. General String Substitution
General string substitution in macro references is an extended feature of MMK. It looks very similar to suffix substitution, but uses a double colon (“::”) instead of a single colon and allows the substitution to occur anywhere within the string. The syntax is:
$(macro-name::old-str=new-str)
which causes the replacement of all occurrences
of the string old-str with
new-str. You may use a backslash “\” as a
“literal-next” escape when one of the strings contains an equals sign. Neither string may contain a right
parenthesis character (“)”), even quoted with a backslash, although this restriction will be lifted in a future
release of MMK. For example, the following macro definitions:
SOURCES = FIRST.C,SECOND.C,THIRD.C SOURCEPLUS = $(SOURCES::,=+)
would cause SOURCEPLUS to contain the list of filenames separated with plus signs (“+”) rather than commas.
General string substitutions in macro references are case-insensitive, but do not ignore blanks in the macro value or in the substitution rule. For example, in the following definitions:
TEST = Xyz xYz xyZ REPLACED = $(TEST::YZ =YZ,)
the REPLACED macro would have the value “XYZ,xYZ,xyZ”, due to the case-blind comparisons and the inclusion
of the space in the old-str specification.
2.11. Builtin Functions
As well as symbol substitution it is also possible to call a number of builtin functions that can process text to automate and simplify build definitions. The following reference describes what each of these functions does, with examples.
2.11.1. ADDPREFIX
Prefix List Elements
$(ADDPREFIXprefix,text[ ...])
Description
ADDPREFIX treats text as a whitespace delimited
list of words. Each word is prefixed with prefix and returned in a space delimited list.
Examples
The following examples show how to call the ADDPREFIX builtin function and demonstrate the expected output.
LIST = CAT, DOG, SECRET, HEAVY ALL : @ WRITE SYS$OUTPUT "Unprefixed = $(LIST)" @ WRITE SYS$OUTPUT "Prefixed = $(ADDPREFIX TOP ,$(LIST))"
Description file to demonstrate the ADDPREFIX function.
Unprefixed = CAT, DOG, SECRET, HEAVY Prefixed = TOP CAT, TOP DOG, TOP SECRET, TOP HEAVY
The output the above description file would generate.
2.11.2. ADDSUFFIX
Suffix List Elements
$(ADDSUFFIXsuffix,text[ ...])
Description
ADDSUFFIX treats text as a whitespace delimited
list of words. Each word is suffixed with suffix and returned in a space delimited list.
Examples
The following examples show how to call the ADDSUFFIX builtin function and demonstrate the expected output.
LIST = OX VAX QUICK LENGTH STRENGTH SUFFIX = EN, ALL : @ WRITE SYS$OUTPUT "Unsuffixed = $(LIST)" @ WRITE SYS$OUTPUT "Suffixed = $(ADDSUFFIX $(SUFFIX),$(LIST))"
Description file to demonstrate the ADDSUFFIX function. Notice that the suffix
to be appended to each word is a symbol. This is so that the text EN, will recognize the
',' character as part of the suffix and not an argument delimiter in the builtin function.
Unsuffixed = OX VAX QUICK LENGTH STRENGTH Suffixed = OXEN, VAXEN, QUICKEN, LENGTHEN, STRENGTHEN,
The output the above description file would generate.
2.11.3. AND
Logical And
$(ANDcondition[,condition[,...]])
Description
The AND function provides a logical and operation. Each of the
condition arguments are expanded until one evaluates to the empty string. The arguments are
evaluated individually and consecutively, so if one should fail (evaluate to an empty string) then the remaining
conditions will not be evaluated.
If all conditions evaluate to a non-empty string, then the result of this function is the expansion of the final condition. Otherwise this function will return the empty string.
Examples
The following examples show how to call the AND builtin function and demonstrate the expected output.
A = A B = B C = C D = FOO = $(AND $(A),$(B),$(C)) BAR = $(AND $(A),$(B),$(C),$(D)) ALL : @ WRITE SYS$OUTPUT "FOO = $(FOO)" @ WRITE SYS$OUTPUT "BAR = $(BAR)"
Description file to demonstrate the AND function.
FOO = C BAR =
The output the above description file would generate.
2.11.4. BASENAME
Get File Specification Without Type
$(BASENAME text[ ...])Description
BASENAME returns the node, device, directory and file name portions of the
specifications found in text. The result does not include the file type or version. If multiple
specifications are supplied, they will each be evaluated and returned in a space delimited list.
MMK checks only the syntax of each specification: the files need not exist, and only the parts actually written in
text are returned.
Examples
The following examples show how to call the BASENAME builtin function and demonstrate the expected output.
FSPEC = DISK$USER:[PROJ.SRC]MAIN.C;3 ECHO = WRITE SYS$OUTPUT ALL : @ $(ECHO) "FOO = $(BASENAME $(FSPEC))" @ $(ECHO) "BAR = $(BASENAME A.A;2 B.B C.C;12)"
Description file to demonstrate the BASENAME function.
FOO = DISK$USER:[PROJ.SRC]MAIN BAR = A B C
The output the above description file would generate.
2.11.5. CALL
Call User-defined Function
$(CALLmacro[,param[,...]])
Description
The CALL function makes it possible for a user to develop their own macro
functions. To call a macro function, specify the name in macro, not the substitution, and pass
up to 31 arguments in param.
Before macro is call (looked up and resolved) the arguments passed in
param are resolved and defined as symbols $(1)-$(31), with $(0) being
macro.
It is important to remember certain escaping rules when defining callable macros. MMK supports the concept of deferred
substitution (see Section 2.9, “Deferring Macro Substitution” by using ${ and } as the substitution
delimiters. It is necessary to use this method of substitution when specifying the macro arguments outside of any builtin
function call, for example:
REVERSE = ${2} ${1} FOO = $(CALL REVERSE,A,B)
Examples
The following examples show how to call the CALL builtin function and demonstrate the expected output. Another example can be found under the documentation for FINDSTRING.
ORIGINS = $(FOREACH VAR,$(1),$(ORIGIN $(VAR))) ECHO = WRITE SYS$OUTPUT ALL : @ $(ECHO) "$(CALL ORIGINS,MMSALPHA MMSIA64 MMSVAX)"
This description file shows the definition of the user defined function ORIGINS, which is a multi-argument version of the ORIGIN builtin.
This example also demonstrates that because the $(1) substitution is made within the FOREACH call, there is no need to use deferred substitution.
UNDEFINED UNDEFINED SPECIAL
The output the above description file would generate when run on a VAX system.
2.11.6. COLLAPSE
Collapse Whitespace
$(COLLAPSE text)Description
The COLLAPSE function removes all whitespace from
text, except within quoted strings: text between a pair of apostrophes (')
or quotation marks (") is kept as it is, quotes included.
Examples
The following examples show how to call the COLLAPSE builtin function and demonstrate the expected output.
FOO = $(COLLAPSE 1 2 3 4 5 6 7) 8 9 10 BAR = $(COLLAPSE 't e s t i n g' asdfasdf) ECHO = WRITE SYS$OUTPUT ALL : @ $(ECHO) "FOO = $(FOO)" @ $(ECHO) "BAR = $(BAR)"
Description file to demonstrate the COLLAPSE function.
FOO = 1234567 8 9 10 BAR = 't e s t i n g'asdfasdf
The output the above description file would generate.
2.11.7. DEVICE
Get Device
$(DEVICE text[ ...])Description
DEVICE returns the device portion of the specifications found in
text, including the colon. If multiple specifications are supplied, they will each be evaluated
and returned in a space delimited list.
MMK checks only the syntax of each specification: the files need not exist, and only the parts actually written in
text are returned.
To retrieve the device and directory together, see DIR.
Examples
The following examples show how to call the DEVICE builtin function and demonstrate the expected output.
FSPEC = DISK$USER:[PROJ.SRC]MAIN.C;3 ECHO = WRITE SYS$OUTPUT ALL : @ $(ECHO) "FOO = $(DEVICE $(FSPEC))"
Description file to demonstrate the DEVICE function.
FOO = DISK$USER:
The output the above description file would generate.
2.11.8. DIR
Get Device and Directory
$(DIR text[ ...])Description
DIR returns the node, device and directory portions of the specifications found in
text. If multiple specifications are supplied, they will each be evaluated and returned in a
space delimited list. A specification with no directory gives [], so each entry in the result
corresponds to one in text.
MMK checks only the syntax of each specification: the files need not exist, and only the parts actually written in
text are returned.
To retrieve only the directory, please see DIRECTORY.
Examples
The following examples show how to call the DIR builtin function and demonstrate the expected output.
FSPEC = DISK$USER:[PROJ.SRC]MAIN.C;3 ECHO = WRITE SYS$OUTPUT ALL : @ $(ECHO) "FOO = $(DIR $(FSPEC))" @ $(ECHO) "BAR = $(DIR DISK:[A]X.C A.C DISK:[B.C]Y.OBJ Z)"
Description file to demonstrate the DIR function.
FOO = DISK$USER:[PROJ.SRC] BAR = DISK:[A] [] DISK:[B.C] []
The output the above description file would generate.
2.11.9. DIRECTORY
Get Directory
$(DIRECTORY text[ ...])Description
DIRECTORY returns only the directory portion of the specifications found in
text. This is different to DIR which also returns the node and
device.
If multiple specifications are supplied, they will each be evaluated and returned in a space delimited list. A
specification with no directory gives [].
MMK checks only the syntax of each specification: the files need not exist, and only the parts actually written in
text are returned.
Examples
The following examples show how to call the DIRECTORY builtin function and demonstrate the expected output.
FSPEC = DISK$USER:[PROJ.SRC]MAIN.C;3 ECHO = WRITE SYS$OUTPUT ALL : @ $(ECHO) "FOO = $(DIRECTORY $(FSPEC))" @ $(ECHO) "BAR = $(DIRECTORY DISK:[A]X.C A.C DISK:[B.C]Y.OBJ Z)"
Description file to demonstrate the DIRECTORY function.
FOO = [PROJ.SRC] BAR = [A] [] [B.C] []
The output the above description file would generate.
2.11.10. ERROR
Signal an Error and Stop
$(ERROR text)Description
ERROR displays text as an MMK fatal error message,
%MMK-F-ERROR, and stops MMK. No further targets are built.
Use it to stop a build early when a description file finds a condition it cannot handle, such as a required macro that has not been defined. To report a problem and carry on, see WARN.
Examples
The following examples show how to call the ERROR builtin function and demonstrate the expected output.
CHECK ~= $(IF $(TARGET_CPU),,$(ERROR TARGET_CPU is not defined)) ALL : @ WRITE SYS$OUTPUT "Building for $(TARGET_CPU)"
Description file to demonstrate the ERROR function. Unless
TARGET_CPU is defined, for example with /MACRO=TARGET_CPU=X86_64, MMK stops
before building anything.
%MMK-F-ERROR, TARGET_CPU is not defined
The output the above description file would generate.
2.11.11. FILENAME
Get Filename
$(FILENAME text[ ...])Description
FILENAME returns only the file name portion of the specifications found in
text, in the case it was given. If multiple specifications are supplied, they will each be
evaluated and returned in a space delimited list.
MMK checks only the syntax of each specification: the files need not exist, and only the parts actually written in
text are returned.
Examples
The following examples show how to call the FILENAME builtin function and demonstrate the expected output.
FSPEC = DISK$USER:[PROJ.SRC]MAIN.C;3 ECHO = WRITE SYS$OUTPUT ALL : @ $(ECHO) "FOO = $(FILENAME $(FSPEC))" @ $(ECHO) "BAR = $(FILENAME A.C B A.OBJ;2 C.)"
Description file to demonstrate the FILENAME function.
FOO = MAIN BAR = A B A C
The output the above description file would generate.
2.11.12. FILETYPE
Get File Type
$(FILETYPE text[ ...])Description
FILETYPE returns only the file type portion of the specifications found in
text, including the leading period, in the case it was given. If multiple specifications are
supplied, they will each be evaluated and returned in a space delimited list.
A specification with no type gives an empty entry, so the result keeps one entry for each specification (note the two spaces in the second example). If none of the specifications has a type, the result is empty.
MMK checks only the syntax of each specification: the files need not exist, and only the parts actually written in
text are returned.
Examples
The following examples show how to call the FILETYPE builtin function and demonstrate the expected output.
FSPEC = DISK$USER:[PROJ.SRC]MAIN.C;3 ECHO = WRITE SYS$OUTPUT ALL : @ $(ECHO) "FOO = $(FILETYPE $(FSPEC))" @ $(ECHO) "BAR = $(FILETYPE A.C B A.OBJ;2 C.)"
Description file to demonstrate the FILETYPE function.
FOO = .C BAR = .C .OBJ .
The output the above description file would generate.
2.11.13. FILEVERSION
Get File Version
$(FILEVERSION text[ ...])Description
FILEVERSION returns only the file version portion of the specifications
found in text, including the leading semicolon. If multiple specifications are supplied, they
will each be evaluated and returned in a space delimited list.
A specification with no version gives an empty entry, so the result keeps one entry for each specification (note the
two spaces in the second example). If none of the specifications has a version, the result is empty. A specification that
ends in a semicolon alone gives ;.
MMK checks only the syntax of each specification: the files need not exist, and only the parts actually written in
text are returned.
Examples
The following examples show how to call the FILEVERSION builtin function and demonstrate the expected output.
FSPEC = DISK$USER:[PROJ.SRC]MAIN.C;3 ECHO = WRITE SYS$OUTPUT ALL : @ $(ECHO) "FOO = $(FILEVERSION $(FSPEC))" @ $(ECHO) "BAR = $(FILEVERSION A.A;2 B.B C.C;12)" @ $(ECHO) "BAZ = $(FILEVERSION A.A B.B)"
Description file to demonstrate the FILEVERSION function.
FOO = ;3 BAR = ;2 ;12 BAZ =
The output the above description file would generate.
2.11.14. FILTER
Filter Words
$(FILTERpattern[ ...],text[ ...])
Description
FILTER treats text as a whitespace delimited list for
words. It compares each word against pattern, which itself is a whitespace delimited list of
patterns, to determine if it should be included in the result. If the pattern matches the word, the word is included in
the space delimited result list. The pattern wildcard characters are '%' and '*'.
Examples
The following examples show how to call the FILTER builtin function and demonstrate the expected output.
SOURCES = FOO.C BAR.C BAZ.S UGH.H ALL : @ WRITE SYS$OUTPUT "$(FILTER *.C *.S,$(SOURCES))" @ WRITE SYS$OUTPUT "$(FILTER *.H,$(SOURCES))" @ WRITE SYS$OUTPUT "$(FILTER *.T,$(SOURCES))"
Description file to demonstrate the FILTER function.
FOO.C BAR.C BAZ.S UGH.H
The output the above description file would generate.
2.11.15. FILTER-OUT
Filter Out Words
$(FILTER-OUTpattern[ ...],text[ ...])
Description
FILTER treats text as a whitespace delimited list
for words. It compares each word against pattern, which itself is a whitespace delimited list
of patterns, to determine if it should be included in the result. If the pattern matches the word, the word is not
included in the space delimited result list. The pattern wildcard characters are '%' and
'*'.
Examples
The following examples show how to call the FILTER-OUT builtin function and demonstrate the expected output.
SOURCES = FOO.C BAR.C BAZ.S UGH.H ALL : @ WRITE SYS$OUTPUT "$(FILTER-OUT *.C *.S,$(SOURCES))" @ WRITE SYS$OUTPUT "$(FILTER-OUT *.H,$(SOURCES))" @ WRITE SYS$OUTPUT "$(FILTER-OUT *.T,$(SOURCES))"
Description file to demonstrate the FILTER-OUT function.
UGH.H FOO.C BAR.C BAZ.S FOO.C BAR.C BAZ.S UGH.H
The output the above description file would generate.
2.11.16. FINDSTRING
String Search
$(FINDSTRINGfind,text)
Description
FINDSTRING searchs text for any occurrence of
find. If find is found then the result is
find. Otherwise the result is an empty string.
Examples
The following examples show how to call the FINDSTRING builtin function and demonstrate the expected output.
ISPRESENT = ${IF $(FINDSTRING $(1),$(2)),YES,NO} TEXT = KERMIT PIGGY FOZZIE ALL : @ WRITE SYS$OUTPUT "LIST = $(LIST)" @ WRITE SYS$OUTPUT "1. KERMIT? $(CALL ISPRESENT,KERMIT,$(TEXT)) @ WRITE SYS$OUTPUT "2. GONZO? $(CALL ISPRESENT,GONZO,$(TEXT))"
Description file to demonstrate the FINDSTRING function. In this example FINDSTRING is being called indirectly via a macro call. For further information on this, please see the documentation for the CALL builtin function.
LIST = KERMIT PIGGY FOZZIE 1. KERMIT? YES 2. GONZO? NO
The output the above description file would generate.
2.11.17. FIRSTWORD
Get First Word
$(FIRSTWORD text[ ...])Description
FIRSTWORD fetches the first word in the whitespace separated list in
text. This is equivalent to:
$(word 1, text)Examples
The following examples show how to call the FIRSTWORD builtin function and demonstrate the expected output.
LIST = kermit the frog FOO = $(FIRSTWORD $(LIST)) BAR = $(WORD 1,$(LIST)) ALL : @ WRITE SYS$OUTPUT "$(FOO) = $(BAR)"
Description file to demonstrate the FIRSTWORD function.
kermit = kermit
The output the above description file would generate.
2.11.18. FOREACH
Repeat Expansion
$(FOREACHmacro,list[ ...text],text)
Description
FOREACH provides a basic "for" loop construct by treating
list as a whitespace delimited lost of words and executing text for
each word in list. The temporary variable macro is defined to the
next word before each execution of text.
Examples
The following examples show how to call the FOREACH builtin function and demonstrate the expected output. An example of FOREACH can also be found in the examples for CALL.
LETTERS = A B C D ALL : @ WRITE SYS$OUTPUT "$(FOREACH LETTER,$(LETTERS),A$(LETTER))"
Description file to demonstrate the FIRSTWORD function.
AA AB AC AD
The output the above description file would generate.
2.11.19. IF
Conditional Evaluation
$(IFcondition,then[,else]])
Description
The IF function evaluates condition. If it evaluates to a
non-empty string, then the then argument is evaluated and returned as the result. Otherwise, if
condition evaluates to an empty string (false) and the else argument
is present, it is evaluated and returned as the result.
The then and else arguments are not evaluated until
condition has been evaluated. Then only the appropriate argument is evaluated.
Examples
The following examples show how to call the IF builtin function and demonstrate the expected output.
TRUE = TRUE FALSE = FOO = $(IF $(TRUE),TRUE) BAR = $(IF $(FALSE),,FALSE) ALL : @ WRITE SYS$OUTPUT "FOO = $(FOO)" @ WRITE SYS$OUTPUT "BAR = $(BAR)"
Description file to demonstrate the IF function.
FOO = TRUE BAR = FALSE
The output the above description file would generate.
2.11.20. INFO
Display an Informational Message
$(INFOtext[,text[,...]])
Description
INFO displays each text argument as an MMK informational
message, %MMK-I-INFO, one message per argument. MMK carries on, and the function returns an empty
string, so it can be placed wherever a function call is allowed without changing the text around it.
Examples
The following examples show how to call the INFO builtin function and demonstrate the expected output.
START ~= $(INFO Starting the build,Target CPU is $(TARGET_CPU)) ALL : @ CONTINUE
Description file to demonstrate the INFO function, run with
/MACRO=TARGET_CPU=X86_64. The evaluated assignment (~=, see Section 2.8.2, “Evaluated Assignment”) makes MMK call INFO as it reads the line.
%MMK-I-INFO, Starting the build %MMK-I-INFO, Target CPU is X86_64
The output the above description file would generate.
2.11.21. JOIN
Merge Lists
$(JOINlist,text)
Description
JOIN merges the whitespace delimited lists in list and
text. If the length of the two lists are not the same, then the remainder of the longer list is
concatenated to the result.
Examples
The following examples show how to call the JOIN builtin function and demonstrate the expected output.
FOO = $(JOIN A B C D, 1 2 3 4) BAR = $(JOIN A , 1 2 3 4) ALL : @ WRITE SYS$OUTPUT "FOO = $(FOO)" @ WRITE SYS$OUTPUT "BAR = $(BAR)"
Description file to demonstrate the JOIN function.
FOO = A1 B2 C3 D4 BAR = A1 2 3 4
The output the above description file would generate.
2.11.22. LASTWORD
Get Last Word
$(LASTWORD text ...)Description
LASTWORD fetches the last word in the whitespace separated list in
text. This is equivalent to:
$(word $(wordstext),text)
Examples
The following examples show how to call the LASTWORD builtin function and demonstrate the expected output.
LIST = kermit the frog FOO = $(LASTWORD $(LIST)) BAR = $(WORD $(WORDS $(LIST)),$(LIST)) ALL : @ WRITE SYS$OUTPUT "$(FOO) = $(BAR)"
Description file to demonstrate the LASTWORD function.
frog = frog
The output the above description file would generate.
2.11.23. NOTDIR
Get Filename and Type
$(NOTDIR text[ ...])Description
NOTDIR is the opposite of DIR. NOTDIR returns the
file name and type portion of the specifications found in text, without the version. If
multiple specifications are supplied, they will each be evaluated and returned in a space delimited list.
MMK checks only the syntax of each specification: the files need not exist, and only the parts actually written in
text are returned.
To retrieve only filename, type or version, consider using FILENAME, FILETYPE or FILEVERSION respectively.
Examples
The following examples show how to call the NOTDIR builtin function and demonstrate the expected output.
FSPEC = DISK$USER:[PROJ.SRC]MAIN.C;3 ECHO = WRITE SYS$OUTPUT ALL : @ $(ECHO) "FOO = $(NOTDIR $(FSPEC))" @ $(ECHO) "BAR = $(NOTDIR [A]X.C;3 [B]Y.OBJ;7 Z)"
Description file to demonstrate the NOTDIR function.
FOO = MAIN.C BAR = X.C Y.OBJ Z
The output the above description file would generate.
2.11.24. OR
Logical Or
$(ORcondition[,condition[,...]])
Description
The OR function provides a logical or operation. Each of the
condition arguments are expanded until one evaluates to a non-empty string. The arguments are
evaluated individually and consecutively, so if one should succeed (evaluate to a non-empty string) then the remaining
conditions will not be evaluated.
If all conditions evaluate to an empty string, then the result of this function is the empty string. Otherwise this function will return the result of the last condition evaluated.
Examples
The following examples show how to call the OR builtin function and demonstrate the expected output.
A = B = C = D = D FOO = $(OR $(A),$(B),$(C)) BAR = $(OR $(A),$(B),$(C),$(D)) ALL : @ WRITE SYS$OUTPUT "FOO = $(FOO)" @ WRITE SYS$OUTPUT "BAR = $(BAR)"
Description file to demonstrate the OR function.
FOO = BAR = D
The output the above description file would generate.
2.11.25. ORIGIN
Symbol Origin
$(ORIGIN macro)Description
ORIGIN returns a string describing in which context
macro was defined. Table 2.4, “Macro Definition Origins” lists the possible results and what they
mean.
| Type | Description |
|---|---|
| UNDEFINED | The symbol is not yet defined. |
| FILE | These symbols have been defined within the description file. |
| COMMAND LINE | These symbols have been defined through use of the /MACRO= command line qualifier. |
| SPECIAL | Special symbols are defined per target, these include $(MMS$TARGET) and $(MMS$SOURCE). |
| DEFAULT | This includes all symbols defined by the default rules. |
| CLI SYMBOL | This macro takes its definition from a DCL symbol. |
| TEMPORARY | These symbols are defined through the use of CALL, like $(0) amd $(1), or FOREACH and the definition of the loop symbol. |
Examples
The following examples show how to call the ORIGIN builtin function and demonstrate the expected output.
FOO = BAR BAR = $(ORIGIN 0) ALL : @ WRITE SYS$OUTPUT "MMSVAX = $(ORIGIN MMSVAX)" @ WRITE SYS$OUTPUT "MMSALPHA = $(ORIGIN MMSALPHA)" @ WRITE SYS$OUTPUT "CC = $(ORIGIN CC)" @ WRITE SYS$OUTPUT "CALL ARGUMENT 0 = $(CALL BAR)" @ WRITE SYS$OUTPUT "FOO = $(ORIGIN FOO)" @ WRITE SYS$OUTPUT "VARIANT = $(ORIGIN VARIANT)" @ WRITE SYS$OUTPUT "CLISYM = $(ORIGIN CLISYM)"
Description file to demonstrate the ORIGIN function.
MMSVAX = SPECIAL MMSALPHA = UNDEFINED CC = DEFAULT CALL ARGUMENT 0 = TEMPORARY FOO = FILE VARIANT = COMMAND LINE CLISYM = CLI SYMBOL
The output the above description file would generate if run on a VAX system. With the following commands:
$ CLISYM == 1 $ MMK/MACRO=VARIANT=1
2.11.26. PATSUBST
Pattern Substitution
$(PATSUBSTpattern,to,text)
Description
PATSUBST replaces all instances of pattern with
to in text. However, unlike the function SUBST this builtin allows the specification of a pattern. Table 2.5, “PATSUBST Pattern Operators” details the
pattern operators.
| Operator | Match | Replace |
|---|---|---|
*
| Match any sequence of any length. | Insert the entire matched sequence. |
%
| Match any single character. | Insert the first character of the matched sequence. |
When matching the words in text if a match is found, the wild-carded portions of the match
are placed in a queue. Therefore, when specifying to it is also possible to include pattern
operators which will insert the wildcarded portions back into the output.
Note
Unlike the substitution mentioned in Section 2.10, “Macro String Substitution” the comparison done by PATSUBST is case-sensitive.
Examples
The following examples show how to call the PATSUBST builtin function and demonstrate the expected output.
LIST = FIRST.C SECOND.C THIRD.C FOO = $(PATSUBST *.C,*.OBJ,$(LIST)) BAR = $(PATSUBST *.*,*.%,$(FOO)) ALL : @ WRITE SYS$OUTPUT "FOO = $(FOO)" @ WRITE SYS$OUTPUT "BAR = $(BAR)"
Description file to demonstrate the PATSUBST function.
FOO = FIRST.OBJ SECOND.OBJ THIRD.OBJ BAR = FIRST.O SECOND.O THIRD.O
The output the above description file would generate.
2.11.27. SORT
Sort Words
$(SORT text[ ...])Description
SORT treats text as a whitespace delimited list of
words. These words are then sorted into lexical order, removing duplicates and returned to the caller.
Examples
The following examples show how to call the SORT builtin function and demonstrate the expected output.
ECHO = WRITE SYS$OUTPUT MUPPETS = PIGGY FOZZIE KERMIT GONZO BEAKER ROWLF DILBERT = DILBERT ALICE WALLY ASOK DOGBERT RATBERT ALL : @ $(ECHO) "$(SORT $(DILBERT)) @ $(ECHO) "$(SORT $(MUPPETS))
Description file to demonstrate the SORT function.
ALICE ASOK DILBERT DOGBERT RATBERT WALLY BEAKER FOZZIE GONZO KERMIT PIGGY ROWLF
The output the above description file would generate.
2.11.28. STRIP
Compress Whitespace
$(STRIP text)Description
STRIP replaces all whitespace characters with a single space as well as removing
the leading and trailing whitespace from text.
Examples
The following examples show how to call the STRIP builtin function and demonstrate the expected output.
FOO = $(STRIP This has lots of space ) ALL : @ WRITE SYS$OUTPUT "FOO = $(FOO)"
Description file to demonstrate the STRIP function.
FOO = This has lots of space
The output the above description file would generate.
2.11.29. SUBST
String Substitution
$(SUBSTfrom,to,text)
Description
SUBST replaces all instances of from found in
text with to.
Note
This builtin function, like PATSUBST, is case sensitive in its matching. For case-insensitive string substitution please use, Section 2.10, “Macro String Substitution”.
Examples
The following examples show how to call the SUBST builtin function and demonstrate the expected output.
ALL : @ WRITE SYS$OUTPUT "$(SUBST ee,EE,feet on the street)" @ WRITE SYS$OUTPUT "$(SUBST EE,ee,feet on the street)"
Description file to demonstrate the SUBST function.
fEEt on the strEEt feet on the street
The output the above description file would generate.
2.11.30. WARN
Display a Warning Message
$(WARNtext[,text[,...]]) $(WARNINGtext[,text[,...]])
Description
WARN displays each text argument as an MMK warning
message, %MMK-W-WARN, one message per argument. MMK carries on, and the function returns an empty
string.
WARNING is another name for WARN; the two are the same function.
Examples
The following examples show how to call the WARN builtin function and demonstrate the expected output.
CHECK ~= $(IF $(DEBUG),$(WARN DEBUG is set: building without optimization)) ALL : @ CONTINUE
Description file to demonstrate the WARN function. Run with
/MACRO=DEBUG=1.
%MMK-W-WARN, DEBUG is set: building without optimization
The output the above description file would generate.
2.11.31. WILDCARD
File Search
$(WILDCARD text)Description
WILDCARD searches for the files matching the specification in
text and returns the name and type portions as a space delimited list. It is also possible to
list multiple specifications in text, each must be separated by whitespace. The wildcard
characters '%' and '*' can also be used.
It is possible to specify multiple search specifications by separating them with space.
Examples
The following examples show how to call the WILDCARD builtin function and demonstrate the expected output.
FOO = $(WILDCARD BLISS32_BLD:LEX*.BLI) BAR = $(WILDCARD BLISS32_BLD:K*.BLI BLISS32_BLD:LEX*.BLI) ALL : @ WRITE SYS$OUTPUT "FOO = $(FOO)" @ WRITE SYS$OUTPUT "BAR = $(BAR)"
Description file to demonstrate the WILDCARD function.
FOO = LEXAN.BLI LEXFUN.BLI BAR = KFOLD.BLI KOST.BLI LEXAN.BLI LEXFUN.BLI
The output the above description file would generate.
2.11.32. WORD
Return the n'th Word
$(WORDn,text)
Description
WORD treats text as a space delimited (multiple
consecutive whitespace characters are treated as one) array of words. The parameter n is an
index into this array, specifying which word to return.
If you specify a value of n that is less than 1 or greater than the number of elements in
text, then the result will be an empty string, "". The builtin function WORDS can be used to determine the upper limit of the array in
text.
Examples
The following examples show how to call the WORDS builtin function and demonstrate the expected output.
FOO = $(WORD 2, first second third) BAR = $(WORD 5, kermit the frog) ALL : @ WRITE SYS$OUTPUT "FOO = $(FOO)" @ WRITE SYS$OUTPUT "BAR = $(BAR)"
Description file to demonstrate the WORD function.
FOO = second BAR =
The output the above description file would generate.
2.11.33. WORDLIST
Extract Words
$(WORDLISTstart,end,text[ ...])
2.11.34. WORDS
Count Words
$(WORDS text)Description
WORDS counts the number of words in text. The contents
of text is treated as a space delimited (multiple consecutive whitespace characters are treated
as one) array of words.
Examples
The following examples show how to call the WORDS builtin function and demonstrate the expected output.
FOO = $(WORDS first second third) BAR = $(WORDS ) ALL : @ WRITE SYS$OUTPUT "FOO = $(FOO)" @ WRITE SYS$OUTPUT "BAR = $(BAR)"
Description file to demonstrate the WORDS function.
FOO = 3 BAR = 0
The output the above description file would generate.