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: COPY and REPLACE. 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 >>DEFINE or >>IF. A directive never ends with a period and occupies a line of its own.

  • Compiler options: settings given outside the program (the cobc command line, the PARM of the IBM compile step) or inside it on a PROCESS or CBL statement. 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

>>DEFINE

yes

yes

compilation variables; the forms differ (see below)

>>IF / >>ELSE / >>END-IF

yes

yes

GnuCOBOL adds >>ELIF; IBM allows AND, OR and NOT in the condition

>>ELIF

yes

no

not in the 6.5 format of >>IF

>>EVALUATE / >>WHEN / >>END-EVALUATE

no

yes

GnuCOBOL 3.2 answers with a warning and compiles every branch

>>SET

yes

not documented

>>SET CONSTANT, SOURCEFORMAT, FOLDCOPYNAME

>>TURN

yes

not documented

exception checking on and off

>>CALL-CONVENTION

yes

no, use >>CALLINTERFACE

same idea, different name and values

>>PUSH / >>POP

no

yes (PTF PH73031)

saves and restores CALLINTERFACE only

>>D

yes

no, use a D in column 7

debugging lines

>>PAGE, >>LISTING

yes

no

IBM uses EJECT, SKIP1 to SKIP3 and TITLE

PROCESS / CBL

warning, ignored

yes

compiler options inside the source

-D name=value

yes

no, use the DEFINE option

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 words IS, THAN and TO are optional. IBM allows only IS 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 was OFF is 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 by NOT), and AND, OR and NOT combinations of all of these. GnuCOBOL 3.2 accepts one comparison only; nest a second >>IF to simulate AND, and use >>ELIF for OR.

  • 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

IGY-ARCH

target architecture

the ARCH value in effect; the 6.5 table prints 10, 11, 12, 13 or 14 and does not mention 15

IGY-CICS

embedded CICS statements accepted

B'1' if the CICS option is in effect, else B'0'

IGY-COMPILER-VRM

compiler version

VVRRMM, so 6.5.0 is 060500

IGY-DLL

compiled as DLL code

boolean, from the DLL option

IGY-DYNAM

CALL literal loads programs dynamically

boolean, from the DYNAM option

IGY-JAVAIOP-JAVA64

interoperating with 64-bit Java

boolean, from JAVAIOP(JAVA64)

IGY-LP

AMODE 31 or AMODE 64 program

32 or 64, from the LP option

IGY-OPTIMIZE

optimization level

0, 1 or 2

IGY-SQL

embedded SQL processed

boolean, from the SQL option

IGY-SQLIMS

embedded SQLIMS processed

boolean, from the SQLIMS option

IGY-THREAD

multithread support

boolean, from the THREAD option

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

Two rules were observed in 3.2.

  • A -D variable can be used by directives only. Using one in a data description is a syntax error unless it was defined with >>SET CONSTANT or >>DEFINE CONSTANT in the source (the pitfall table at the end shows the message).

  • A >>DEFINE of a name that -D already defined is an error ("duplicate DEFINE directive") unless the directive says OVERRIDE, 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; write AS PARAMETER or test IS DEFINED if 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

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

>>IF BRANCH = "MAIN" AND LEVEL = 2

error: syntax error, unexpected Variable, expecting end of line

one comparison only in 3.2; nest >>IF or use >>ELIF. IBM allows AND and OR

>>DEFINE BRANCH AS "MAIN" with -DBRANCH=OTHER

error: duplicate DEFINE directive 'BRANCH'

add OVERRIDE (then the source wins) or leave one of the two definitions out

a -D name used in a VALUE clause

error: syntax error, unexpected Identifier

only >>SET CONSTANT or >>DEFINE CONSTANT variables can be used in code

>>EVALUATE

warning: ignoring invalid directive: '>>EVALUATE' (one per line)

not implemented; every branch is compiled

>>PUSH / >>POP / >>CALLINTERFACE

warning: ignoring invalid directive

IBM only

IS DEFINED for GNUCOBOL or DEBUG

no message, the branch is silently skipped

use IS SET for the compiler’s own switches

IS SET for a variable you defined

warning: compiler flag 'NUMVAR' unknown

use IS DEFINED

CBL ... at the top of a file

warning: ignoring unknown directive

options must go on the cobc command line

>> in column 7

note: free format detected

start directives in column 8 or later

EJECT or SKIP1

error: ... unknown statement 'EJECT'

needs -std=ibm

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 >>IF doubles 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 >>IF with 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 (the MDECK output) 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-CICS and IGY-SQL on z/OS and give GnuCOBOL a stub copybook for the same lines.