VX/MMS - OpenVMS MMS to make and XML
Overview
VX/MMS is a native Linux implementation of the OpenVMS Module Management System (MMS), DEC's dependency-driven build tool and the OpenVMS analogue of make. It reads an MMS description file, builds an in-memory dependency graph, works out which targets are out of date by comparing file timestamps, and brings each target up to date by running its action lines through VX/DCL. Existing DESCRIP.MMS and MAKEFILE descriptions, their rules, macros, suffix rules and conditionals build the same way on Linux as they did on OpenVMS, so the build automation migrates alongside the application it drives.
Because the action lines are executed through the same VX/DCL command interpreter that runs migrated .COM procedures, the compile, link and utility commands inside a build (COPY, DELETE, LINK, CC, COBOL, FORTRAN and the rest) keep working after migration. VX/MMS plugs into Sector7's continuous integration migration approach: teams keep developing on OpenVMS while the same descriptions rebuild on Linux, so a build environment moves across without a code freeze.
<!-- Webflow embed (min). Source: mms-page-technical/mms-tech-body-embed-dark.html → python3 website/embeds/minify_webflow_embed.py … -->
<div class="s7-tech-embed" data-vxmmsd-body-embed="1" data-technical-mega-embed="1" lang="en"><h2 id="architecture">What VX/MMS is</h2><p>
VX/MMS is a standalone build engine, not a translator that emits an intermediate project
file. It is shipped as a single image and is also reachable as the <code>MMS</code> verb
inside the VX/DCL shell, so a description file that was invoked with <code>MMS</code> on
OpenVMS is invoked the same way on Linux. The engine reads a description file, resolves
OpenVMS-style file specifications through the VX runtime so they open on a Linux
filesystem, and drives the build directly.
</p><div class="table-wrapper"><table><thead><tr><th>OpenVMS MMS concept</th><th>VX/MMS counterpart</th><th>Role</th></tr></thead><tbody><tr><td>MMS utility</td><td><code>mms</code> image + <code>MMS</code> DCL verb</td><td>Reads the description file, builds the dependency graph, updates out-of-date targets.</td></tr><tr><td>Description-file parser</td><td>Line-oriented MMS lexer and parser</td><td>Parses comments, continuation, dependencies, directives, macros and conditionals.</td></tr><tr><td>Dependency and build engine</td><td>Verification and bottom-up build engine</td><td>Compares timestamps, applies built-in and suffix rules, orders the build.</td></tr><tr><td>Action execution (spawns DCL)</td><td>VX/DCL action-line bridge</td><td>Runs each action line through VX/DCL and translates the exit status back to VMS status.</td></tr><tr><td><code>MMS$STATUS</code> / <code>MMS$SEVEREST_STATUS</code></td><td>Published DCL global symbols</td><td>Exposes the per-image and worst-case build status to the surrounding procedure.</td></tr></tbody></table></div><div class="callout"><strong>Actions run through VX/DCL.</strong> VX/MMS does not reimplement the compilers or
file utilities a build calls. It hands each action line to VX/DCL, the same interpreter
that runs migrated <code>.COM</code> procedures, so <code>COPY</code>, <code>DELETE</code>,
<code>LINK</code>, <code>CC</code>, <code>COBOL</code> and <code>FORTRAN</code> behave
consistently across scripts and builds.
</div><h6>Build data flow</h6><p>The engine runs one description file through three stages and emits updated targets:</p><style>.s7-tech-embed .process-flow {margin: 1.5rem 0;padding: 16px;border: 1px solid var(--s7t-border);border-radius: 10px;background: rgba(255, 255, 255, 0.01);}.s7-tech-embed .process-inputs,.s7-tech-embed .process-stages,.s7-tech-embed .process-search {display: grid;gap: 10px;}.s7-tech-embed .process-inputs {grid-template-columns: repeat(3, minmax(0, 1fr));margin-bottom: 10px;}.s7-tech-embed .process-stages,.s7-tech-embed .process-search {grid-template-columns: repeat(4, minmax(0, 1fr));}.s7-tech-embed .process-stage {min-width: 0;padding: 15px;border-top: 3px solid var(--s7t-accent);border-radius: 6px;background: var(--s7t-surface2);color: var(--s7t-text);}.s7-tech-embed .process-input {border: 1px solid var(--s7t-note-bd);border-top-width: 3px;background: var(--s7t-note-bg);}.s7-tech-embed .process-number,.s7-tech-embed .process-label {display: block;margin-bottom: 10px;font-family: var(--s7t-mono);color: var(--s7t-accent);font-size: 0.76em;font-weight: 700;letter-spacing: 0.08em;text-transform: uppercase;}.s7-tech-embed .process-stage strong,.s7-tech-embed .process-stage span:last-child {display: block;}.s7-tech-embed .process-stage strong {margin-bottom: 4px;color: var(--s7t-text);}.s7-tech-embed .process-stage span:last-child {color: var(--s7t-muted);font-size: 0.9em;line-height: 1.45;}@media (max-width: 900px) {.s7-tech-embed .process-stages,.s7-tech-embed .process-search {grid-template-columns: repeat(2, minmax(0, 1fr));}}@media (max-width: 600px) {.s7-tech-embed .process-inputs,.s7-tech-embed .process-stages,.s7-tech-embed .process-search {grid-template-columns: 1fr;}}</style><div class="process-flow" aria-label="VX/MMS build data flow"><div class="process-inputs" aria-label="Description file inputs"><div class="process-stage process-input"><span class="process-label">Input candidate 1</span><strong>DESCRIP.MMS</strong><span>Preferred default description file.</span></div><div class="process-stage process-input"><span class="process-label">Input candidate 2</span><strong>MAKEFILE.</strong><span>Second default description file candidate.</span></div><div class="process-stage process-input"><span class="process-label">Input candidate 3</span><strong><target>.MMS</strong><span>Target-derived description file candidate.</span></div></div><div class="process-stages"><div class="process-stage"><span class="process-number">01</span><strong>Parse</strong><span>Expand macros and interpret directives from the selected input.</span></div><div class="process-stage"><span class="process-number">02</span><strong>Dependency graph</strong><span>Resolve targets, sources, and explicit or built-in rules.</span></div><div class="process-stage"><span class="process-number">03</span><strong>Verify timestamps</strong><span>Compare modification times to identify out-of-date targets.</span></div><div class="process-stage"><span class="process-number">04</span><strong>Update targets</strong><span>Run action lines through VX/DCL in bottom-up dependency order.</span></div></div></div><p>
The build is driven bottom-up: a target's sources are brought up to date first, recursively,
before the target's own action lines run. A target is considered out of date when it is
forced, when it is built from sources, when it does not exist, when any source is newer than
it, or when a prerequisite was itself just rebuilt.
</p><h2 id="lifecycle">Build lifecycle</h2><p>
VX/MMS follows the classic MMS three-phase model. The same phases and the same
description-file search order that OpenVMS MMS uses are preserved, so an existing build
resolves its description file and its default target identically on Linux.
</p><div class="table-wrapper"><table><thead><tr><th>Phase</th><th>What happens</th></tr></thead><tbody><tr><td>Initialization</td><td>Locate and parse the description file, expand macros, and build the dependency graph. With <code>/DESCRIPTION=foo</code> and no dot, <code>.MMS</code> is appended.</td></tr><tr><td>Verification</td><td>Stat each target and its sources and compare modification times to decide what must be rebuilt.</td></tr><tr><td>File processing</td><td>Bottom-up: build sources first (recursively), then run the target's action lines through VX/DCL.</td></tr></tbody></table></div><h6>Description-file search order</h6><p>
When no <code>/DESCRIPTION</code> qualifier is given, VX/MMS looks for a description file in
the OpenVMS order and uses the first one it finds:
</p><div class="process-flow" aria-label="VX/MMS description file search order"><div class="process-search"><div class="process-stage"><span class="process-number">Search 01</span><strong>DESCRIP.MMS</strong><span>Use immediately when this preferred default exists.</span></div><div class="process-stage"><span class="process-number">Search 02</span><strong>MAKEFILE.</strong><span>Checked only when <code>DESCRIP.MMS</code> is absent.</span></div><div class="process-stage"><span class="process-number">Search 03</span><strong>MAKEFILE</strong><span>Checked only when both earlier candidates are absent.</span></div><div class="process-stage"><span class="process-number">Search 04</span><strong><first-target>.MMS</strong><span>Target-derived fallback used after all standard names are absent.</span></div></div></div><p>
The default goal is the first target declared in the file when no target is named on the
command line, matching OpenVMS behaviour.
</p><h6>Special targets and ordering</h6><div class="table-wrapper"><table><thead><tr><th>Target</th><th>Effect</th></tr></thead><tbody><tr><td><code>.FIRST</code></td><td>Its actions run once, before any other target is processed.</td></tr><tr><td><code>.LAST</code></td><td>Its actions run once, after all targets, even if the build failed.</td></tr><tr><td><code>.DEFAULT</code></td><td>Supplies actions for any target that has none of its own.</td></tr></tbody></table></div><div class="callout"><strong>Cycle protection.</strong> Each target carries a visit state while the graph is
walked. Re-entering a target that is still on the build stack is reported as a circular
dependency (<code>%MMS-F-GWKLOOP</code>) rather than looping forever.
</div><h2 id="description-language">Description-file language</h2><p>
The parser is a real, line-oriented MMS lexer: it honours the same lexical rules,
dependency forms, action-line prefixes, directives and macro syntax as OpenVMS MMS. The
examples below use a banking demo estate, but the syntax is exactly what a migrated
description file contains.
</p><h6>Lexical rules</h6><div class="table-wrapper"><table><thead><tr><th>Construct</th><th>Handling</th></tr></thead><tbody><tr><td>Comment</td><td><code>!</code> to end of line, respecting text inside double quotes.</td></tr><tr><td>Line continuation</td><td>A trailing <code>-</code> or <code>\</code> joins the next physical line.</td></tr><tr><td>Blank line</td><td>Ends the current rule group.</td></tr><tr><td>Indented line</td><td>An action line for the current rule.</td></tr><tr><td>Column-1 line</td><td>A directive, a macro definition, or a dependency.</td></tr><tr><td>Target / source split</td><td>Commas and/or whitespace separate list members.</td></tr></tbody></table></div><h6>Dependency separators</h6><p>Three dependency forms are recognised:</p><ul><li><code>::</code> anywhere on the line declares a double-colon rule.</li><li><code>:</code> with whitespace on either side declares a single-colon rule.</li><li>the keyword <code>DEPENDS_ON</code> (case-insensitive) is treated as a single-colon rule.</li></ul><p>
Mixing <code>:</code> and <code>::</code> for the same target is flagged as an error
(<code>%MMS-E-GFBTYPEMIX</code>).
</p><h6>Action-line prefixes</h6><div class="table-wrapper"><table><thead><tr><th>Prefix</th><th>Meaning</th></tr></thead><tbody><tr><td><code>-</code></td><td>Ignore this line's error and keep going.</td></tr><tr><td><code>@</code></td><td>Silent: do not echo the line before running it.</td></tr><tr><td><code>?name</code></td><td>Remap this line's status through a matching <code>.ACTION_STATUS</code> definition.</td></tr></tbody></table></div><h6>A description file</h6><p>
A representative banking build: macros, a link target with two object sources, a compile
rule, and a conditional that selects debug or optimised compiler flags.
</p>
<pre><span class="cmt">! Ledger posting build</span>
CC = CC
LINK = LINK
<span class="kw">.IFDEF</span> prod
CFLAGS = /OPTIMIZE
<span class="kw">.ELSE</span>
CFLAGS = /DEBUG
<span class="kw">.ENDIF</span>
LEDGER.EXE : LEDGER.OBJ, POSTING.OBJ
$(LINK)/EXE=LEDGER.EXE LEDGER.OBJ, POSTING.OBJ
LEDGER.OBJ : LEDGER.C LEDGER.H
$(CC)$(CFLAGS) LEDGER.C
POSTING.OBJ : POSTING.C LEDGER.H
<span class="kw">-</span> $(CC)$(CFLAGS) POSTING.C</pre>
<h6>Directives</h6><div class="table-wrapper"><table><thead><tr><th>Directive</th><th>Effect</th></tr></thead><tbody><tr><td><code>.SILENT</code></td><td>Global no-echo of action lines.</td></tr><tr><td><code>.IGNORE</code> / <code>.IGNORE_ALL</code></td><td>Global ignore-error.</td></tr><tr><td><code>.FIRST</code> / <code>.LAST</code> / <code>.DEFAULT</code></td><td>Run-before, run-after, and fallback action sets.</td></tr><tr><td><code>.SUFFIXES</code></td><td>Replace the suffix precedence list (empty clears it).</td></tr><tr><td><code>.SUFFIXES_AFTER</code> / <code>.SUFFIXES_BEFORE</code> / <code>.SUFFIXES_DELETE</code></td><td>Append, prepend, or remove named suffixes.</td></tr><tr><td><code>.ACTION_STATUS name = val</code></td><td>Define a named status for <code>?name</code> action prefixes.</td></tr><tr><td><code>.INCLUDE "file"</code></td><td>Parse another description file inline (macro-expanded, quote-stripped).</td></tr><tr><td><code>.IF</code> / <code>.IFDEF</code> / <code>.IFNDEF</code></td><td>Open a conditional on an expression or on a macro being (un)defined.</td></tr><tr><td><code>.ELSE</code> / <code>.ELSIF</code> / <code>.ENDIF</code></td><td>Branch and close a conditional.</td></tr></tbody></table></div><div class="callout"><strong>Nothing is silently dropped.</strong> An unrecognised <code>.</code>-directive is
warned (<code>%MMS-W-DRVPARSERR</code>), not ignored without notice. <code>.INCLUDE</code>
nesting is capped to guard against loops (<code>%MMS-F-LEXFILELOOP</code>), and an
unterminated <code>.IF</code> at end of file warns (<code>%MMS-W-LEXNOENDIF</code>).
</div><h6>Special and user macros</h6><p>
Macro expansion is recursive, so <code>CFLAGS = $(OPT)/debug</code> resolves nested
references, with a depth guard that raises an error on a probable circular reference.
Undefined macros expand to the null string, per the OpenVMS manual, and a command-line
<code>/MACRO</code> definition wins over an in-file definition. The predefined per-rule
macros are populated while a rule's actions run:
</p><div class="table-wrapper"><table><thead><tr><th>Macro</th><th>Meaning</th></tr></thead><tbody><tr><td><code>$(MMS$TARGET)</code></td><td>The current target specification.</td></tr><tr><td><code>$(MMS$TARGET_NAME)</code></td><td>The target name.</td></tr><tr><td><code>$(MMS$SOURCE)</code></td><td>The first source.</td></tr><tr><td><code>$(MMS$SOURCE_LIST)</code></td><td>All sources, space-joined.</td></tr><tr><td><code>$(MMS$CHANGED_LIST)</code></td><td>Sources newer than the target.</td></tr></tbody></table></div><h6>Extended string functions</h6><p>
Under <code>/EXTENDED_SYNTAX</code>, VX/MMS adds a set of GNU-make-style string functions
for description files that use them. Patterns use a single <code>%</code> stem, and path
splitting recognises the OpenVMS and Unix separators <code>/</code>, <code>]</code> and
<code>:</code>.
</p><div class="kw-grid"><div>SUBST</div><div>STRIP</div><div>WORD</div><div>WORDS</div><div>WORDLIST</div><div>FIRSTWORD</div><div>LASTWORD</div><div>FILTER</div><div>FILTER-OUT</div><div>SORT</div><div>ADDPREFIX</div><div>ADDSUFFIX</div><div>DIR</div><div>NOTDIR</div><div>BASENAME</div><div>FILETYPE</div><div>FINDSTRING</div><div>PATSUBST</div><div>JOIN</div><div>WILDCARD</div><div>ORIGIN</div></div><h2 id="builtin-rules">Built-in rules, suffixes and macros</h2><p>
VX/MMS seeds the standard OpenVMS built-in rules, suffix precedence and rule macros after
the description file has been parsed, so any definition the file already provides takes
precedence over the built-in default. A description file that relies on the implicit
<code>.C.OBJ</code> or <code>.OBJ.EXE</code> rules builds without listing them.
</p><h6>Default suffix precedence</h6><p>Used only when the description file gives no <code>.SUFFIXES</code> of its own, most-derived first:</p>
<pre>.EXE .OLB .OBJ .C .FOR .COB .PAS .MAR .BAS .CLD .MSG</pre>
<h6>Built-in suffix rules</h6><div class="table-wrapper"><table><thead><tr><th>Rule</th><th>Action</th></tr></thead><tbody><tr><td><code>.C.OBJ</code></td><td><code>$(CC)$(CFLAGS) $(MMS$SOURCE)</code></td></tr><tr><td><code>.FOR.OBJ</code></td><td><code>$(FORT)$(FFLAGS) $(MMS$SOURCE)</code></td></tr><tr><td><code>.COB.OBJ</code></td><td><code>$(COBOL)$(COBFLAGS) $(MMS$SOURCE)</code></td></tr><tr><td><code>.PAS.OBJ</code></td><td><code>$(PASCAL)$(PFLAGS) $(MMS$SOURCE)</code></td></tr><tr><td><code>.MAR.OBJ</code></td><td><code>$(MACRO)$(MFLAGS) $(MMS$SOURCE)</code></td></tr><tr><td><code>.OBJ.EXE</code></td><td><code>$(LINK)$(LFLAGS) $(MMS$SOURCE)</code></td></tr></tbody></table></div><h6>Default rule macros</h6><p>Each of these is overridable from the description file or the command line:</p><div class="kw-grid"><div>CC = cc</div><div>CFLAGS =</div><div>LINK = link</div><div>LFLAGS =</div><div>FORT = fortran</div><div>FFLAGS =</div><div>COBOL = cobol</div><div>COBFLAGS =</div><div>PASCAL = pascal</div><div>PFLAGS =</div><div>MACRO = macro</div><div>MFLAGS =</div><div>LIBR = library</div></div><h6>Suffix-rule inference</h6><p>
When a target has no explicit sources and no actions, VX/MMS infers a rule: for each source
suffix in precedence order whose rule <code>.<src>.<tar></code> exists and whose
candidate file is present on disk, that source and the rule's actions are adopted. When a
target has explicit sources but no actions, the first source's suffix drives the rule
lookup. This is how a bare <code>LEDGER.EXE : LEDGER.OBJ</code> line links without spelling
out the link command.
</p><h2 id="execution">Action execution and status</h2><p>
The point of difference from a pure <code>make</code> clone is that VX/MMS action lines are
OpenVMS DCL, not shell. Each action line is handed to VX/DCL for execution, so the compile,
link and file commands inside a migrated build run through the same interpreter that runs
the estate's <code>.COM</code> procedures.
</p><h6>The VX/DCL bridge</h6><p>
Each action line is run by spawning a fresh VX/DCL process that executes just that command
and exits. The child's real exit status is captured and translated back into an OpenVMS
status value: success maps to a success status, a non-zero exit maps to error severity, and
a process killed by a signal maps to fatal severity. A <code>/OUTPUT=file</code> qualifier
redirects each child's output so that action output joins MMS's own output stream.
</p><div class="callout warn"><strong>DCL state does not persist across action lines.</strong> Because each line runs in
its own one-shot VX/DCL process, changes such as <code>SET DEFAULT</code>, local symbols
and logical names defined in one action line are not visible to the next. Lines that need
shared state must be combined onto one line or moved into a command procedure. This is a
deliberate, documented divergence from OpenVMS MMS, which runs actions in a single
subprocess context.
</div><h6>Status model</h6><p>
VX/MMS tracks the worst status seen across all action lines. A line whose status indicates
failure aborts the build (<code>%MMS-F-ABORT</code>) unless the failure is suppressed by a
line-level <code>-</code> prefix, a global <code>.IGNORE</code>, or a <code>/IGNORE</code>
severity floor. Severity is ranked WARNING below ERROR below FATAL. The final status is
returned by the image and published as the DCL global symbols <code>MMS$STATUS</code> and
<code>MMS$SEVEREST_STATUS</code> for the surrounding procedure to test.
</p><p>
The <code>.ACTION_STATUS</code> directive maps status letters to OpenVMS status values for
use with the <code>?name</code> action prefix:
</p><div class="table-wrapper"><table><thead><tr><th>Letter</th><th>Severity</th></tr></thead><tbody><tr><td><code>S</code></td><td>Success.</td></tr><tr><td><code>I</code></td><td>Informational.</td></tr><tr><td><code>W</code></td><td>Warning.</td></tr><tr><td><code>E</code></td><td>Error (the default).</td></tr><tr><td><code>F</code></td><td>Fatal.</td></tr></tbody></table></div><p>A numeric value is taken as-is, so a description file can define an exact status code.</p><h2 id="compatibility">CLI qualifiers and compatibility</h2><p>
The <code>MMS</code> verb takes a target list and the OpenVMS MMS qualifiers. The
qualifiers that control the build itself are honoured; a set of less common qualifiers is
parsed and warned as deferred rather than being silently accepted, so a build never behaves
differently than the description file implies.
</p><h6>Honoured qualifiers</h6><div class="table-wrapper"><table><thead><tr><th>Qualifier</th><th>Effect</th></tr></thead><tbody><tr><td><code>/DESCRIPTION=file</code></td><td>Use a named description file (<code>.MMS</code> appended if no dot).</td></tr><tr><td><code>/ACTION</code> / <code>/NOACTION</code></td><td>Run action lines, or print them without running.</td></tr><tr><td><code>/VERIFY</code> / <code>/NOVERIFY</code></td><td>Echo, or suppress the echo of, action lines.</td></tr><tr><td><code>/FORCE</code></td><td>Rebuild targets regardless of timestamps.</td></tr><tr><td><code>/FROM_SOURCES</code></td><td>Rebuild everything from sources.</td></tr><tr><td><code>/IGNORE[=WARNING|ERROR|FATAL]</code></td><td>Set the severity floor below which a failing action does not abort.</td></tr><tr><td><code>/MACRO=("N=V",...)</code></td><td>Define macros on the command line; these win over in-file definitions.</td></tr><tr><td><code>/EXTENDED_SYNTAX</code></td><td>Enable the extended string functions.</td></tr><tr><td><code>/OUTPUT=file</code></td><td>Send MMS and action output to a file.</td></tr><tr><td><code>/LOG</code></td><td>Emit informational diagnostics.</td></tr><tr><td><code>/IDENTIFICATION</code></td><td>Print the version and exit.</td></tr></tbody></table></div><h6>Compatibility status</h6><div class="table-wrapper"><table><thead><tr><th>Feature</th><th>Status</th></tr></thead><tbody><tr><td>Description-file parse (comments, continuation, blank-line grouping)</td><td><span class="ac-live">live</span></td></tr><tr><td>Single-colon, double-colon and <code>DEPENDS_ON</code> rules</td><td><span class="ac-live">live</span></td></tr><tr><td>Action prefixes <code>-</code>, <code>@</code>, <code>?name</code></td><td><span class="ac-live">live</span></td></tr><tr><td>Simple and recursive macro expansion, special macros</td><td><span class="ac-live">live</span></td></tr><tr><td>Conditionals (<code>.IF</code> / <code>.IFDEF</code> / <code>.IFNDEF</code> / <code>.ELSE</code> / <code>.ELSIF</code> / <code>.ENDIF</code>)</td><td><span class="ac-live">live</span></td></tr><tr><td>Directives (<code>.SILENT</code> / <code>.IGNORE</code> / <code>.FIRST</code> / <code>.LAST</code> / <code>.DEFAULT</code> / <code>.INCLUDE</code> / <code>.ACTION_STATUS</code>)</td><td><span class="ac-live">live</span></td></tr><tr><td><code>.SUFFIXES</code> family and built-in suffix rules</td><td><span class="ac-live">live</span></td></tr><tr><td>Suffix-rule inference for undeclared targets</td><td><span class="ac-live">live</span></td></tr><tr><td>DCL action execution, status and severity handling, abort/ignore</td><td><span class="ac-live">live</span></td></tr><tr><td><code>/EXTENDED_SYNTAX</code> string functions</td><td><span class="ac-live">live</span></td></tr><tr><td>Persistent DCL state across action lines</td><td><span class="ac-no">out of scope: per-line one-shot, documented</span></td></tr><tr><td><code>/OVERRIDE /REVISE_DATE /RULES /SKIP_INTERMEDIATE /LIST /CHANGED /CMS /SCA_LIBRARY /GENERATE</code></td><td><span class="ac-v2">deferred: parse-and-warn</span></td></tr></tbody></table></div><div class="callout"><strong>Deferred qualifiers are named, not ignored.</strong> A deferred qualifier emits
<code>%MMS-W-DRVQUALIF, /<q> is recognised but not yet implemented (deferred),
ignored</code>, so a build script relying on one is told clearly rather than getting a
silently different result.
</div><h6>Divergences from OpenVMS MMS</h6><div class="table-wrapper"><table><thead><tr><th>Divergence</th><th>Reason</th></tr></thead><tbody><tr><td>Action lines run as one VX/DCL process per line, with no shared DCL state.</td><td>The one-shot command path is reliable across platforms; lines needing shared state combine onto one line or use a command procedure.</td></tr><tr><td><code>/NODESCRIPTION</code> (build purely from built-in rules) is not yet supported.</td><td>Built-in-rule-only builds are planned for a later phase; the qualifier reports rather than misbuilds.</td></tr></tbody></table></div><h2 id="quickref">Quick reference</h2><h6>Invocation</h6>
<pre>MMS [/quals] target[,target...]</pre>
<h6>Common qualifiers</h6><div class="kw-grid"><div>/DESCRIPTION=file</div><div>/MACRO=("N=V")</div><div>/FORCE</div><div>/FROM_SOURCES</div><div>/NOACTION</div><div>/NOVERIFY</div><div>/IGNORE[=ERROR]</div><div>/LOG</div><div>/EXTENDED_SYNTAX</div><div>/OUTPUT=file</div><div>/IDENTIFICATION</div></div><h6>Description-file resolution</h6><p>
Without <code>/DESCRIPTION</code>, VX/MMS uses the first available candidate in the canonical
search order shown under <a href="#lifecycle">Build lifecycle</a>.
</p><h6>Rule syntax</h6><p><code>target[,...] : [source[,...]]</code> (or <code>::</code> / <code>DEPENDS_ON</code>),
then indented action lines. Action prefixes: <code>-</code> ignore error, <code>@</code>
silent, <code>?name</code> status map.
</p><h6>Special macros</h6><div class="kw-grid"><div>$(MMS$TARGET)</div><div>$(MMS$TARGET_NAME)</div><div>$(MMS$SOURCE)</div><div>$(MMS$SOURCE_LIST)</div><div>$(MMS$CHANGED_LIST)</div></div><h6>Built-in suffix rules</h6><div class="kw-grid"><div>.C.OBJ</div><div>.FOR.OBJ</div><div>.COB.OBJ</div><div>.PAS.OBJ</div><div>.MAR.OBJ</div><div>.OBJ.EXE</div></div><h6>Diagnostic codes</h6><div class="kw-grid"><div>ABORT</div><div>DRVBADPARSE</div><div>DRVDEPFIL</div><div>DRVOUTFIL</div><div>DRVPARSERR</div><div>DRVQUALIF</div><div>EXENCRE</div><div>GFBTYPEMIX</div><div>GWKCURRNT</div><div>GWKLOOP</div><div>GWKNOACTS</div><div>LEXFILELOOP</div><div>LEXNOENDIF</div><div>LEXNULLNAME</div><div>LFSBADFP</div><div>MBREDEFILL</div></div><h6>Related tools</h6><p>
VX/MMS drives, and runs alongside, the rest of a migrated OpenVMS build:
<a href="/technical/vx-dcl-vms-dcl">VX/DCL</a> executes the action lines,
<a href="/technical/vx-cdd-vms-cdd">VX/CDD</a> handles repository definitions,
<a href="/technical/vx-decforms---decforms-ifdl-compiler-and-forms">VX/DECFORMS</a> handles
forms, and <a href="/technical/vx-msg-vms-message-compiler">VX/MSG</a> compiles messages.
The compilers a build calls include
<a href="/technical/vx-c-vms-c-to-ansi-c">VX/C</a>,
<a href="/technical/vx-cobol-vms-cobol-to-ansi-cobol">VX/COBOL</a> and
<a href="/technical/vx-fortran-vms-fortran-to-ansi-fortran">VX/FORTRAN</a>.
</p></div>