Combined CL.EXE Options

Many CL options can be grouped meaningfully according to the first letter (or letters) after the switch character. Indeed, the example is set by CL itself in the output produced for the /help option. The options shown under the heading Optimisation all begin with /O. Those for Code Generation mostly begin with /G, along with some specialisations for exception handling (/EH) and run-time checking (/RTC). Those shown under the heading Output Files all start as /F and most shown under the heading Language start as /Z.

CL supports a shorthand in which options in the same “group” can be given in one command-line token. Again, the /help text provides examples. The explanatory text for /Ox suggests in brackets an equivalence with /Ogityb2 /Gs. The option /GX is said to be the “same as /EHsc” and /RTC1 is equated in brackets with /RTCsu. In each case, the second option is a shorthand. For instance, /Ogityb2 is understood as expanding to /Og /Oi /Ot /Oy /Ob2. The understanding is apparently so plain and obvious that the product documentation does not trouble to describe it formally.

Any option that begins with, but is not solely, one of the case-sensitive sequences /clr:, /com+:, /EE, /EH, /G, /O, /RTC, /Zc: or /Z is interpreted as a combined option. The characters that follow are then interpreted as a series of elements, each of which may be followed by one optional comma. The combined option then expands to a series of options, one for each of the elements, each formed by appending the element to the same initial sequence.

Each element may be

A string argument means all the remaining characters of the combined option, including none. An element that is permitted a string argument is necessarily the last in the combined option. A numerical argument means as many decimal digits as follow without interruption, including none.

Note that the last two categories in the list are actually one. Any single character (including the comma, by the way) is acceptable as an element for the expansion. It’s just that some single characters are supported explicitly and some only by default.

The supported keywords and characters depend on the initial sequence:

/clr: keyword: assembly, noAssembly
/com+: keyword: assembly, noAssembly
/EE character and optional hyphen: a, g, m
character with no argument: b, n
/EH character and optional hyphen: a, c, s
/G character and optional string: E, h, s
character and optional number: p, t
character and optional hyphen: F, i, L, m, R, X, x
character with no argument: 3, 4, 5, 6, A, B, D, d, e, f, M, r, y, Z, z
/O character and optional number: b, V
character and optional hyphen: a, g, i, p, w, y
character with no argument: 1, 2, d, s, t, x
/RTC character with no argument: 1, c, s, u
/Z keyword: tmp, vc6
character and optional string: B, X
character and optional number: m, p
character and optional hyphen: M
character with no argument: 7, a, d, e, g, I, i, l, n, s
/Zc: keyword: forScope, wchar_t

Whether any of the options produced by expanding a combined option are syntactically valid as individual options is irrelevant to the syntax of expansion.

Where an extracted option turns out to be invalid, a plausible reason for its being supported in the combined syntax is that the option was valid once upon a time (or is still valid in some other of Microsoft’s C/C++ products) and may still appear in command lines, most likely if generated from old makefiles. Especially if the now-invalid option permitted an argument, removing the option from the combined syntax would mean that its presence in a combined option might cause subsequent options to be extracted incorrectly.

Support for the comma as a separator has occasional benefits for clarity, especially when using keywords. For instance, /Zc:forScopewchar_t does expand to the separate options /Zc:forScope and /Zc:wchar_t, but /Zc:forScope,wchar_t has an advantage in readability. The separator is even necessary if a single-character element that is a digit must follow an element that is permitted a numerical argument. For instance, /Z7 and /Zp1 can be combined as /Z7p1 without needing a separating comma, but if reordered, the combination must be /Zp1,7.