Compiler Directives and Conditional Compilation
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. The reference material consulted while preparing these pages is listed in the section bibliography. |
This page was checked on 2026-10-20 against ISO/IEC 1989:2023 (the third edition of the COBOL standard, published in January 2023; a fourth edition is in its DIS ballot), GnuCOBOL 3.2 and IBM Enterprise COBOL for z/OS 6.5 (PTFs through September 2026). Every GnuCOBOL example was compiled with cobc -x -Wall (GnuCOBOL 3.2.0, plus -std=ibm where the example says so) and run, and the output and diagnostics shown are real. The Enterprise COBOL examples are labelled "z/OS; not run here": they were checked statement by statement against the 6.5 Language Reference and Programming Guide but never compiled, because no z/OS compiler was available. The ISO standard itself is not freely available, so what is said about the standard is limited to what the two vendor manuals say about their implementation of it.
A COBOL source program is not handed to the compiler as one finished text. Before the real parse the compiler runs a text-processing step that resolves COPY and REPLACE (see Copybooks, COPY and REPLACE), and it also obeys lines that are addressed to the compiler rather than to the program. Those lines make up the compiler directing facility (CDF) introduced by COBOL 2002. They let one source file produce several variants of a program (a debug build, a branch-specific build, a CICS build and a batch build), switch run-time checks on for a few lines, change the call convention, and control the listing. This page covers the facility in the Circulation nightly program, and for each feature says which of GnuCOBOL 3.2 and Enterprise COBOL 6.5 supports it, because they do not support the same set.
Three kinds of line addressed to the compiler
The word "directive" is used loosely, so it helps to separate the three things a compiler can obey outside the ordinary language statements.
-
Text-manipulation statements:
COPYandREPLACE. They end with a period, and they change the source text before it is parsed. -
Compiler directives (ISO) in the CDF: a line whose first word starts with
>>, such as>>DEFINEor>>IF. A directive never ends with a period and occupies a line of its own. -
Compiler options: settings given outside the program (the
cobccommand line, thePARMof the IBM compile step) or inside it on aPROCESSorCBLstatement. They are not part of the language, but a few of them (DEFINE,CONDCOMP) feed values to the directives and are therefore covered here.
IBM’s manuals add a fourth group, the compiler-directing statements: EJECT, SKIP1/SKIP2/SKIP3, TITLE, ENTER, READY/RESET TRACE, PROCESS/CBL and COPY/REPLACE. They are written like ordinary statements (no >>) but have no run-time effect.
Where a directive may appear
In fixed reference format (the format used on this page, see Reference Format: Fixed and Free) the GnuCOBOL Programmer’s Guide states that every CDF statement must begin in column 8 or beyond, so the >> goes in Area A or Area B and never in the indicator column. The 6.5 Language Reference says the same for its directives: each begins on a new line in Area A or B and is written entirely on that line. A real symptom of getting this wrong is shown below: with the >> in column 7 the GnuCOBOL scanner decides the whole file is free format.
cdf1.cob:1: note: free format detected
1 > >>DEFINE CONSTANT MAX-LOANS AS 5
2 | >>DEFINE LIBRARY-NAME AS "Circulation"
3 | >>DEFINE TRACE AS OFF
The output above comes from an early draft of the first example on this page, with the directive indented by six spaces instead of seven. The fix is one more space.
Directives are also never inside a statement: IBM forbids them in the middle of a COBOL statement, between the lines of a continued literal and inside COPY or REPLACE.
What each compiler supports
| Directive or statement | GnuCOBOL 3.2 | Enterprise COBOL 6.5 | Note |
|---|---|---|---|
|
yes |
yes |
compilation variables; the forms differ (see below) |
|
yes |
yes |
GnuCOBOL adds |
|
yes |
no |
not in the 6.5 format of |
|
no |
yes |
GnuCOBOL 3.2 answers with a warning and compiles every branch |
|
yes |
not documented |
|
|
yes |
not documented |
exception checking on and off |
|
yes |
no, use |
same idea, different name and values |
|
no |
yes (PTF PH73031) |
saves and restores |
|
yes |
no, use a |
debugging lines |
|
yes |
no |
IBM uses |
|
warning, ignored |
yes |
compiler options inside the source |
|
yes |
no, use the |
value from outside the source |
The "not documented" cells mean that the chapter "Compiler directives" in the 6.5 Language Reference lists CALLINTERFACE, DATA, INLINE, DEFINE, EVALUATE, IF, JAVA-CALLABLE, JAVA-SHAREABLE, PUSH and POP and nothing else. The table therefore says what the manuals document, not what an unlisted IBM release might accept. The GnuCOBOL cells were verified by compiling.
Compilation variables and >>DEFINE
A compilation variable exists only while the compiler runs. It has a name, and either a value (a number, a string or, on IBM, a boolean) or no value. It is never a data item: it does not exist in WORKING-STORAGE and there is no storage for it at run time.
GnuCOBOL syntax
>>DEFINE [CONSTANT] name [AS] { OFF | literal [OVERRIDE] | PARAMETER [OVERRIDE] }
PARAMETER takes the value from the environment variable with the same name at compile time. OFF creates the name without a value. CONSTANT makes the name usable inside ordinary COBOL code wherever a literal is allowed; without it the name can only be used in other directives. In 3.2, >>DEFINE CONSTANT produces the warning "DEFINE CONSTANT var is archaic" under -Wall, so the example below uses >>SET CONSTANT, which the manual documents as the equivalent. A variable is forgotten at the next END PROGRAM or END FUNCTION.
Enterprise COBOL syntax
>>DEFINE name [AS] { arith-expr | literal [OVERRIDE] | PARAMETER [OVERRIDE] | OFF }
The IBM form allows a compile-time arithmetic expression (integer operands, no exponentiation, no division by zero) as the value, so >>DEFINE VAR2 AS VAR1 + 2 is legal there. A literal is an alphanumeric literal ('abcd' or X'F1F2F3'), an integer or a boolean literal (B'0' or B'1'; national, DBCS and null-terminated literals are not supported). The name must not be a predefined variable name or a directive keyword. Without OFF or OVERRIDE, a second >>DEFINE of the same name is allowed only if the name was not defined before in the compilation group, or the previous definition was OFF, or it was given the same value. With OVERRIDE the new value is set unconditionally. A name whose most recent definition is OFF counts as not defined. AS PARAMETER takes the value from the DEFINE compiler option and leaves the variable undefined when there is no such option.
Conditional compilation with >>IF
>>IF selects, before the program is parsed, which source lines are compiled. Lines in a branch that is not selected are not even checked for syntax, and the branches may contain COBOL statements, COPY and REPLACE statements and further directives.
>>IF condition
lines
[>>ELIF condition (GnuCOBOL only)
lines]
[>>ELSE
lines]
>>END-IF
The condition is one of these:
-
A relation between compilation variables and literals, with
=,<>,<,<=,>and>=(or the words). In GnuCOBOL the wordsIS,THANandTOare optional. IBM allows onlyIS EQUAL TO,IS NOT EQUAL TO(or=) when the operands are not numeric. -
A defined condition,
name IS [NOT] DEFINED. On IBM, a variable whose latest definition wasOFFis not defined. GnuCOBOL 3.2 behaves the same way, as the first example shows. -
On IBM, a boolean condition (a boolean variable or
B'1', optionally preceded byNOT), andAND,ORandNOTcombinations of all of these. GnuCOBOL 3.2 accepts one comparison only; nest a second>>IFto simulateAND, and use>>ELIFforOR. -
In GnuCOBOL,
name IS [NOT] SET, which tests the compiler’s own switches (see the predefined variables below). It gave the warning "compiler flag 'NUMVAR' unknown" when applied to a user variable.
The first example uses the Circulation nightly program. It is a build that differs between the main building and the annex.
* Conditional compilation of the nightly circulation report.
>>DEFINE BRANCH AS "MAIN"
>>DEFINE MAX-LOANS AS 5
>>DEFINE AUDIT-TRAIL AS OFF
IDENTIFICATION DIVISION.
PROGRAM-ID. DEFLINKS.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 LOAN-LIMIT PIC 9(2).
PROCEDURE DIVISION.
MAIN-PARA.
>>IF MAX-LOANS > 3
MOVE 5 TO LOAN-LIMIT
>>ELSE
MOVE 3 TO LOAN-LIMIT
>>END-IF
>>IF AUDIT-TRAIL IS DEFINED
DISPLAY "audit trail is compiled in"
>>ELSE
DISPLAY "audit trail is not compiled in"
>>END-IF
>>IF BRANCH = "MAIN"
DISPLAY "limit " LOAN-LIMIT " at the main branch"
>>ELIF BRANCH = "ANNEX"
DISPLAY "limit " LOAN-LIMIT " at the annex"
>>ELSE
DISPLAY "unknown branch"
>>END-IF
STOP RUN.
The output shows the three outcomes: LOAN-LIMIT was set by the first >>IF (5 is above 3), the AUDIT-TRAIL variable that was defined OFF is not defined, and the BRANCH test chose the first branch.
audit trail is not compiled in
limit 05 at the main branch
Directives are processed before COPY
Conditional compilation directives are processed before COPY and REPLACE that follow them, and REPLACE/COPY ... REPLACING do not change the directive lines. IBM states this in the 6.5 Language Reference (section "Conditional compilation"): directives can be used to exclude COPY and REPLACE statements. The practical consequence is that a library member that does not exist in one environment can still be named in a branch that is not compiled. In the next example the second COPY names a member that does not exist, and it never causes an error because its branch is skipped.
* A COPY inside a false branch is never read from the library.
>>DEFINE WITH-LOANS AS 1
IDENTIFICATION DIVISION.
PROGRAM-ID. CONDCOPY.
DATA DIVISION.
WORKING-STORAGE SECTION.
>>IF WITH-LOANS = 1
COPY LOANREC.
>>ELSE
COPY NOSUCH.
>>END-IF
PROCEDURE DIVISION.
MAIN-PARA.
MOVE "O" TO LOAN-TYPE
IF LOAN-CHECKOUT
DISPLAY "checkout record in use"
END-IF
STOP RUN.
checkout record in use
Constants and >>SET
>>SET CONSTANT name literal defines a variable that can also be used in the DATA DIVISION and PROCEDURE DIVISION as if the literal had been typed. This is the way to give a business rule such as the loan limit one name that appears in the source exactly once. The same example uses >>DISPLAY, a GnuCOBOL directive that prints a message while the program is being compiled.
* A compile-time constant usable wherever a literal is allowed.
>>SET CONSTANT LOAN-LIMIT 5
>>DISPLAY Compiling the circulation limits
IDENTIFICATION DIVISION.
PROGRAM-ID. SETCONST.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 LIMIT-FIELD PIC 9(2) VALUE LOAN-LIMIT.
PROCEDURE DIVISION.
MAIN-PARA.
DISPLAY "limit field " LIMIT-FIELD " literal " LOAN-LIMIT
STOP RUN.
Compiling the circulation limits
limit field 05 literal 5
The other forms of >>SET in the manual are SOURCEFORMAT AS FIXED|FREE (the same as >>SOURCE FORMAT IS FIXED|FREE, covered on the format page), FOLDCOPYNAME AS UPPER|LOWER and NOFOLDCOPYNAME, which match the -ffold-copy option and decide how the copybook name is case-folded when a file is looked up. IBM does not document >>SET.
Predefined compilation variables
GnuCOBOL defines compiler switches that the program can test with IS SET. The manual calls them predefined compilation variables, and says a variable is defined only when its condition is true. The most useful ones are GNUCOBOL (the compiler is GnuCOBOL), EXECUTABLE and MODULE (the unit contains the main program or does not), DEBUG (the -d flag), TRUNC and NOTRUNC, IBMCOMP and GCCOMP (how the size of a COMP item follows from its PICTURE), HOSTSIGNS, STICKY-LINKAGE and P64. Despite the manual’s wording "defined", the tests that worked in 3.2 are the IS SET ones: IS DEFINED was false for all of them, including GNUCOBOL. The example follows.
* Which dialect and storage options is this program compiled with?
IDENTIFICATION DIVISION.
PROGRAM-ID. PREDEF.
PROCEDURE DIVISION.
MAIN-PARA.
>>IF GNUCOBOL IS SET
DISPLAY "compiled by GnuCOBOL"
>>END-IF
>>IF EXECUTABLE IS SET
DISPLAY "main program"
>>END-IF
>>IF IBMCOMP IS SET
DISPLAY "IBM sizes for COMP items"
>>ELSE
DISPLAY "GnuCOBOL sizes for COMP items"
>>END-IF
>>IF TRUNC IS SET
DISPLAY "binary items truncated to PICTURE"
>>END-IF
>>IF NOTRUNC IS SET
DISPLAY "binary items not truncated"
>>END-IF
>>IF DEBUG IS SET
DISPLAY "compiled with -d"
>>END-IF
STOP RUN.
The default build selects the GnuCOBOL sizes and TRUNC. With -std=ibm the dialect file turns on IBMCOMP and NOTRUNC, and with -d the DEBUG switch appears.
compiled by GnuCOBOL
main program
GnuCOBOL sizes for COMP items
binary items truncated to PICTURE
Output of the same program built with -std=ibm:
compiled by GnuCOBOL
main program
IBM sizes for COMP items
binary items not truncated
Output of the same program built with -d:
compiled by GnuCOBOL
main program
GnuCOBOL sizes for COMP items
binary items truncated to PICTURE
compiled with -d
The IGY- variables of Enterprise COBOL
Enterprise COBOL defines its own variables, which are tested with the normal conditions (a boolean variable stands alone, a numeric one is compared). The older names without the IGY- prefix are tolerated, but IBM asks you to use the prefixed names and not to use the prefix for your own variables.
| Variable | Meaning | Value |
|---|---|---|
|
target architecture |
the |
|
embedded CICS statements accepted |
|
|
compiler version |
|
|
compiled as DLL code |
boolean, from the |
|
|
boolean, from the |
|
interoperating with 64-bit Java |
boolean, from |
|
AMODE 31 or AMODE 64 program |
32 or 64, from the |
|
optimization level |
0, 1 or 2 |
|
embedded SQL processed |
boolean, from the |
|
embedded SQLIMS processed |
boolean, from the |
|
multithread support |
boolean, from the |
The 6.5 Language Reference gives an example that this page re-uses for the Circulation program: one source for both a CICS inquiry transaction and a batch program, selected by the CICS compiler option (z/OS; not run here).
>>IF IGY-CICS
EXEC CICS READ FILE('BOOKMAST')
INTO(BOOK-RECORD) RIDFLD(WS-BOOK-ID)
END-EXEC
>>ELSE
READ BOOK-FILE INTO BOOK-RECORD
KEY IS BOOK-ID
>>END-IF
Values from outside the source: -D and the DEFINE option
GnuCOBOL: cobc -D name=value (and -D name alone) defines a compilation variable on the command line. The variable can be tested by >>IF and compared with a string or a number. The next program has no definitions of its own.
* Values supplied on the cobc command line with -D.
IDENTIFICATION DIVISION.
PROGRAM-ID. PARAMS.
PROCEDURE DIVISION.
MAIN-PARA.
>>IF BRANCH IS NOT DEFINED
DISPLAY "no branch given"
>>ELIF BRANCH = "ANNEX"
DISPLAY "annex build"
>>ELSE
DISPLAY "main build"
>>END-IF
>>IF LIMIT IS DEFINED
>>IF LIMIT > 3
DISPLAY "limit above 3"
>>END-IF
>>END-IF
STOP RUN.
Built without -D, the program reports that no branch was given.
no branch given
Built with cobc -x -DBRANCH=ANNEX -DLIMIT=5:
annex build
limit above 3
Source: GnuCOBOL manual, cobc options
Two rules were observed in 3.2.
-
A
-Dvariable can be used by directives only. Using one in a data description is a syntax error unless it was defined with>>SET CONSTANTor>>DEFINE CONSTANTin the source (the pitfall table at the end shows the message). -
A
>>DEFINEof a name that-Dalready defined is an error ("duplicate DEFINE directive") unless the directive saysOVERRIDE, in which case the value in the source wins and the command-line value is discarded. The ISO text and IBM may treat the two orders differently; writeAS PARAMETERor testIS DEFINEDif the intent is "default unless given".
Enterprise COBOL has no -D. The compiler option DEFINE(name=literal) (abbreviation DEF, default NODEFINE) assigns a value to a variable that the program has declared with >>DEFINE name AS PARAMETER; if no such directive exists the option is ignored. An option without a value, DEFINE(name), sets the variable to B'1'. Several can be given and the last wins, NODEFINE after them cancels them all, and when written in a CBL statement the DEFINE options are accepted only for the first program of a batch compile, applying to every program of the file. The = cannot be used with the cob2 command on z/OS UNIX. The following example shows the program and the step that sets the value (z/OS; not run here).
>>DEFINE MAX-LOANS AS PARAMETER
>>IF MAX-LOANS IS DEFINED
>>DEFINE LIMIT AS MAX-LOANS + 2
>>ELSE
>>DEFINE LIMIT AS 5
>>END-IF
//COMPILE EXEC PGM=IGYCRCTL,REGION=0M,
// PARM='DEFINE(MAX-LOANS=3),CONDCOMP(SKIPSRC)'
//SYSLIB DD DISP=SHR,DSN=USERID.CIRC.COPYLIB
With MAX-LOANS=3 the variable LIMIT is 5, with no option it is also 5. The point of the example is that the program works with and without the option.
>>EVALUATE (Enterprise COBOL)
>>EVALUATE is the multi-branch version of >>IF, in two formats. Format 1 compares one literal or arithmetic expression with each >>WHEN value (a value, or a range with THRU); all operands must be of the same category and THRU needs numeric operands. Format 2 is >>EVALUATE TRUE with a constant conditional expression in each >>WHEN. The first branch that matches is included, >>WHEN OTHER is the last resort, and if nothing matches no branch is included. A string comparison is character by character on the binary value and strings of different lengths are never equal. The following z/OS-only fragment selects the housekeeping of the nightly run from a numeric level that comes from the DEFINE option (z/OS; not run here).
>>DEFINE RUN-LEVEL AS PARAMETER
>>EVALUATE RUN-LEVEL
>>WHEN 1
PERFORM LIGHT-CLEANUP
>>WHEN 2 THRU 4
PERFORM FULL-CLEANUP
>>WHEN OTHER
CONTINUE
>>END-EVALUATE
GnuCOBOL 3.2 does not implement the directive. Run through cobc, a program with >>EVALUATE compiles with four warnings and both branches are compiled, which is rarely what the author wanted. This is a deliberately wrong example for GnuCOBOL.
>>DEFINE LEVEL AS 2
IDENTIFICATION DIVISION.
PROGRAM-ID. EVALDIR.
PROCEDURE DIVISION.
>>EVALUATE LEVEL
>>WHEN 1
DISPLAY "one"
>>WHEN 2
DISPLAY "two"
>>END-EVALUATE
STOP RUN.
The first warning is shown (the other three directive lines produce the same message); the program then printed both branches.
evaldir.cob:5: warning: ignoring invalid directive: '>>EVALUATE' [-Wothers]
3 | PROGRAM-ID. EVALDIR.
4 | PROCEDURE DIVISION.
5 > >>EVALUATE LEVEL
6 | >>WHEN 1
7 | DISPLAY "one"
one
two
Use >>IF and >>ELIF in GnuCOBOL, which are portable to the standard text.
>>TURN: exception checking from inside the source
>>TURN exception-name CHECKING ON [WITH LOCATION] and >>TURN exception-name CHECKING OFF switch the run-time checking of an exception class for the statements that follow. It is the source-level counterpart of options such as -debug and, on z/OS, SSRANGE. In this example only one statement is checked; the exception name EC-BOUND-SUBSCRIPT covers subscripts outside the table. The write at slot 5 of a three-element table is stopped by the run-time library, and the second DISPLAY is never reached. (An unchecked write to the same subscript would silently overwrite neighbouring storage, which is why the example does not do that.)
* Run-time subscript checking switched on for one statement only.
IDENTIFICATION DIVISION.
PROGRAM-ID. TURNCHK.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 COPY-COUNTS.
05 COPY-COUNT PIC 9(3) OCCURS 3 TIMES VALUE 2.
01 SLOT PIC 9 VALUE 5.
PROCEDURE DIVISION.
MAIN-PARA.
MOVE 7 TO COPY-COUNT (1)
DISPLAY "first slot written"
>>TURN EC-BOUND-SUBSCRIPT CHECKING ON
MOVE 7 TO COPY-COUNT (SLOT)
>>TURN EC-BOUND-SUBSCRIPT CHECKING OFF
DISPLAY "not reached"
STOP RUN.
first slot written
libcob: turn.cob:14: error: subscript of 'COPY-COUNT' out of bounds: 5
note: maximum subscript for 'COPY-COUNT': 3
Last statement of "TURNCHK" was MOVE
MAIN-PARA at turn.cob:14
Started by ./turn.out
A name that is not a valid exception name is rejected at compile time: spelling it EC-BOUNDARY-SUBSCRIPT while preparing this page produced "invalid exception-name". IBM does not document >>TURN; in Enterprise COBOL the corresponding behaviour is the SSRANGE compiler option for the whole program, so switch it on in the CBL statement or the step PARM.
Call conventions: >>CALL-CONVENTION and CALLINTERFACE
>>CALL-CONVENTION (GnuCOBOL) chooses how program names in CALL are treated. COBOL (the default) maps the name as a COBOL program name, EXTERN treats it as an external reference, STATIC calls it as an included element, and STDCALL is listed without an explanation of its effect. The example calls the C library function getpid as an external function and returns to the default convention.
* Select the call convention for one statement, then restore it.
>>CALL-CONVENTION EXTERN
IDENTIFICATION DIVISION.
PROGRAM-ID. CALLCONV.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 PROCESS-ID PIC S9(9) COMP-5.
PROCEDURE DIVISION.
MAIN-PARA.
CALL "getpid" RETURNING PROCESS-ID
IF PROCESS-ID > 0
DISPLAY "getpid returned a process id"
END-IF
>>CALL-CONVENTION COBOL
STOP RUN.
getpid returned a process id
Enterprise COBOL names the same idea >>CALLINTERFACE with the suboptions DLL, DYNAMIC and STATIC; it affects CALL and function/procedure-pointer SET statements until the next >>CALLINTERFACE, overrides the DLL and DYNAM compiler options while it has a suboption, can appear in the PROCEDURE DIVISION only, and has no effect on CANCEL. Written without a suboption it returns control to the compiler options.
>>PUSH and >>POP (Enterprise COBOL 6.5)
PTF PH73031 for 6.5 added >>PUSH and >>POP, which save and restore a directive’s setting without having to remember what it was. In the manual they work for CALLINTERFACE (CALLINT) only. The saved values form a stack per compilation unit: >>POP restores the latest saved value, an empty stack is a compile error, a stack that is not empty at the end of the program is not an error, stacks are not shared between programs of a batch compile, and nested programs share one stack. The manual’s own example is the shape of this one for the Circulation program, which calls the inquiry module through the DLL interface by default but needs a static call to a utility (z/OS; not run here).
>>CALLINTERFACE DLL
CALL "BOOKINQ" USING BOOK-RECORD
>>PUSH CALLINTERFACE
>>CALLINTERFACE STATIC
CALL "DATEUTIL" USING LOAN-DATE
>>POP CALLINTERFACE
CALL "FINECALC" USING MEMBER-RECORD
FINECALC is called through the DLL interface again, because >>POP restored it. The directive does not exist in GnuCOBOL 3.2; it prints "ignoring invalid directive" for >>PUSH, >>CALLINTERFACE and >>POP, and a program that relied on it would compile with the wrong convention. The 6.5 What’s New page lists PH73031 among the PTFs of "September 2026".
Debugging lines and >>D
A debugging line is a source line that is compiled only in a debugging build. In the standard it is a line with a D in the indicator column (column 7), active when WITH DEBUGGING MODE is written in the SOURCE-COMPUTER paragraph; the 6.5 Language Reference describes exactly that and has no >>D. GnuCOBOL accepts the same D line, and also the free-floating directive >>D, which makes the rest of the line a debugging line. They are active when cobc is run with -fdebugging-line. Without it the line is a comment. That is why a debug DISPLAY costs nothing in production.
* A floating >>D line exists only when debugging lines are enabled.
IDENTIFICATION DIVISION.
PROGRAM-ID. DBGLINE.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 FINE-TOTAL PIC 9(5)V99 VALUE 62.50.
PROCEDURE DIVISION.
MAIN-PARA.
>>D DISPLAY "debug: fines " FINE-TOTAL
DISPLAY "total fines " FINE-TOTAL
STOP RUN.
Built normally, the debug line is ignored.
total fines 00062.50
Built with -fdebugging-line:
debug: fines 00062.50
total fines 00062.50
Source: GnuCOBOL Programmer’s Guide, >>D
On z/OS the equivalent is a D in column 7 plus WITH DEBUGGING MODE in SOURCE-COMPUTER; there is no compile-time switch other than that clause in the program.
Listing control: EJECT, SKIP, TITLE and >>PAGE
IBM’s compiler-directing statements affect only the source listing. EJECT starts the next source statement on a new page, SKIP1, SKIP2 and SKIP3 insert one, two or three blank lines, and TITLE literal prints a title at the top of every page (without it the compiler prints its own identification and release). They must stand alone on a line, may end in a period, must come after the CBL statements, and have no effect on the compiled program. GnuCOBOL accepts the same words only in the IBM dialect (the manual describes >>PAGE as the directive that allows these IBM paging controls); in the default dialect EJECT is an unknown statement. This deliberately wrong example (same source, two dialects) shows the difference.
IDENTIFICATION DIVISION.
PROGRAM-ID. LISTING.
PROCEDURE DIVISION.
MAIN-PARA.
EJECT
SKIP1
DISPLAY "listing controls"
STOP RUN.
With the default dialect, cobc rejects it.
listing.cob: in paragraph 'MAIN-PARA':
listing.cob:5: error: syntax error, unexpected Identifier, expecting SECTION or .
3 | PROCEDURE DIVISION.
4 | MAIN-PARA.
5 > EJECT
6 | SKIP1
7 | DISPLAY "listing controls"
listing.cob:5: note: unknown statement 'EJECT'
With -std=ibm the same file compiles and runs:
listing controls
>>LISTING ON|OFF is a GnuCOBOL directive that turns the program listing on and off; it compiled without a warning in the test and is only meaningful when a listing is requested.
PROCESS and CBL (Enterprise COBOL)
A PROCESS statement, or its synonym CBL, gives compiler options inside the source. It is placed before the IDENTIFICATION DIVISION header of the outermost program and before any comment lines or compiler-directing statements. It may start in column 1 or later, or in column 8 or later if there is a six-character sequence field; it must end at or before column 72; options are separated by a comma or a blank and nothing may be put between an option and its suboption; several statements may follow each other, with nothing between them, but one statement cannot be continued onto the next. The installation can inhibit them through the default options module, in which case the compiler issues an error. The example sets the options of the nightly update (z/OS; not run here).
CBL DEFINE(MAX-LOANS=5),CONDCOMP(SKIPSRC)
CBL SSRANGE,ARITH(EXTEND)
IDENTIFICATION DIVISION.
PROGRAM-ID. LOANUPD.
CONDCOMP(SKIPSRC) (abbreviation CC(SKIPS)) tells the compiler not to show, and not to write to the MDECK output or SYSMDECK, the source lines in the branches that were not selected; the default CONDCOMP(NOSKIPSRC) shows them in the listing as comments. The Programming Guide has a worked listing of both. A DEFINE option written on a CBL statement applies to every program of a batch compile only if it is on the first program.
GnuCOBOL has no equivalent statement. cobc meets CBL at the start of a file, prints "ignoring unknown directive" and goes on, so options placed there are silently not applied. This example shows the real message, with the program compiling and running anyway.
CBL NODYNAM,LIB
IDENTIFICATION DIVISION.
PROGRAM-ID. CBLSTMT.
PROCEDURE DIVISION.
DISPLAY "cbl line ignored"
STOP RUN.
cblstmt.cob:1: warning: ignoring unknown directive: 'CBL NODYNAM,LIB' [-Wothers]
1 > CBL NODYNAM,LIB
2 | IDENTIFICATION DIVISION.
3 | PROGRAM-ID. CBLSTMT.
cbl line ignored
Other IBM directives
The 6.5 Language Reference documents four more directives that have no counterpart in GnuCOBOL: >>DATA 31|64 (storage location of WORKING-STORAGE items under LP(64)), >>INLINE ON|OFF (whether PERFORM of a procedure may be inlined by the optimizer), and >>JAVA-CALLABLE and >>JAVA-SHAREABLE for non-object-oriented COBOL and Java interoperability. They are listed here so the table above is complete and are not exercised on this page.
Pitfalls with real diagnostics
| Mistake | Real GnuCOBOL 3.2 diagnostic | Cause and fix |
|---|---|---|
|
|
one comparison only in 3.2; nest |
|
|
add |
a |
|
only |
|
|
not implemented; every branch is compiled |
|
|
IBM only |
|
no message, the branch is silently skipped |
use |
|
|
use |
|
|
options must go on the |
|
|
start directives in column 8 or later |
|
|
needs |
The two diagnostics that need their sources are the duplicate definition and the use of a -D name in code. The first is the file with a >>DEFINE BRANCH AS "MAIN" plus a following test of BRANCH, built with -DBRANCH=OTHER:
dupdef.cob:1: error: duplicate DEFINE directive 'BRANCH'
1 > >>DEFINE BRANCH AS "MAIN"
2 | IDENTIFICATION DIVISION.
3 | PROGRAM-ID. DUPDEF.
The second is a data description that refers to LOAN-LIMIT while the name was only given on the command line as -DLOAN-LIMIT=5:
dasheffect.cob:5: error: syntax error, unexpected Identifier
3 | DATA DIVISION.
4 | WORKING-STORAGE SECTION.
5 > 01 LIMIT-FIELD PIC 9(2) VALUE LOAN-LIMIT.
6 | PROCEDURE DIVISION.
7 | DISPLAY LIMIT-FIELD
And the failed AND:
andir.cob:6: error: syntax error, unexpected Variable, expecting end of line
4 | PROGRAM-ID. ANDDIR.
5 | PROCEDURE DIVISION.
6 > >>IF BRANCH = "MAIN" AND LEVEL = 2
7 | DISPLAY "main, level 2"
8 | >>END-IF
Practical advice
-
Keep the number of switches small. Every
>>IFdoubles the number of variants that must be tested; a test matrix of the Circulation build with two variables is four builds. -
Prefer a runtime parameter to a compile-time one whenever the value can change without recompiling. A branch name read from a file needs no rebuild; a branch name compiled in does.
-
Keep portable code portable: write
>>IFwith a single comparison and>>ELSE, avoid directives the other compiler lacks, and keep dialect-specific lines in separate copybooks that each compiler’s library path selects, because a directive written for one compiler is at best ignored with a warning and at worst a compile error on the other. -
Use
CONDCOMP(SKIPSRC)on z/OS to keep the listing readable, and check the generated source (theMDECKoutput) when a variant behaves unexpectedly. -
Conditional compilation is also a way to move a mainframe program towards a Linux build: guard the CICS and Db2 parts with
IGY-CICSandIGY-SQLon z/OS and give GnuCOBOL a stub copybook for the same lines.