Compiler Directives - Controlling the Compiler Like a Pro

Compiler directives are one of the most powerful (and under-used) features in ILE RPG. They let you control the compiler listing, insert external source members, set default behaviors, and conditionally include or exclude code at compile time. Think of them as the “pre-processor” commands that make your life easier when you are writing maintainable, reusable RPG code.

All directives start with a slash (/) and can appear almost anywhere in your source. In column-limited source they start in column 7 or later. In fully free-form source they can start in column 1 or later. The only place you cannot put most directives is inside a single free-form calculation statement.

Let's walk through most of the directives you will actually use in real-world RPG/CL/SQLRPGLE work.

Listing RPG Control Directives

These directives affect only the compiler listing (they have no effect on the generated program).

/TITLE

Puts a custom heading at the top of every page of the compiler listing.

/TITLE 'Customer Inquiry Program - Version 2026.01'

Use this at the very top of your main source member.

/EJECT

Forces the compiler listing to start a new page. Useful for separating major sections.

/SPACE

Controls line spacing in the listing.

/SPACE 3 // skip 3 lines

(NOTE: this number can be 1 to 112)

I liked using these keywords back in the days when I printed all my source code. Nowadays I rarely print anything! So... you will rarely need these in day-to-day work, but they can make your compile listings much cleaner when you are debugging.

/FREE and /END-FREE (Obsolete – Ignore Them)

In very old RPG IV code you used /FREE and /END-FREE to mark free-form calculation blocks. The compiler now ignores them completely (they are kept only for backward compatibility). Modern fully free-form source starts with **FREE in column 1 of the first line and needs no /FREE directives at all.

/SET and /RESTORE allow you to Temporarily Change Defaults

These two directives let you temporarily override control-specification defaults inside a source member or /COPY file.

You can change:

  • CCSID(*CHAR : …)
  • CCSID(*GRAPH : …)
  • CCSID(*UCS2 : …)
  • DATFMT(…)
  • TIMFMT(…)

Example

/SET CCSID(*CHAR : 37) CCSID(*UCS2 : 1200) DATFMT(*ISO)

  // fields defined here use the new defaults

// put it back to whatever it was before
/RESTORE CCSID(*CHAR)

My recommendation is to put a /SET block at the top of any /COPY member that defines prototypes or data structures. This guarantees every module that includes the copy file uses the same CCSID and date formats.

/OVERLOAD DETAIL | NODETAIL

Controls how much detail the compiler prints about overloaded prototypes in the listing. Use DETAIL when you are debugging which prototype the compiler chose for a call. Use NODETAIL (the default) in normal production compiles to keep the listing clean.

/CHARCOUNT NATURAL | STDCHARSIZE

Controls how RPG treats the length of strings that contain multi-byte characters (especially UTF-8).

  • NATURAL – counts the actual number of characters (recommended for modern Unicode work).
  • STDCHARSIZE – counts bytes (the old RPG behavior).
/CHARCOUNT NATURAL

Place this once at the top of your source if you are working with UTF-8 data.

/COPY and /INCLUDE – The Most Important Directives

These insert the entire contents of another member at the point where the directive appears.

/COPY library/file,member
/INCLUDE qsysinc/qrpglesrc,membername // IFS style also supported

/COPY and /INCLUDE work the same way, except when embedded SQL is involved. You can nest them up to 32 levels, as controlled by COPYNEST in the control specification. Put prototypes, standard data structures, and constants in /COPY members, and use /INCLUDE for members that contain embedded SQL.

My recommendation is to create a standard /COPY member every program includes. It keeps your prototypes consistent across the entire application.

Conditional Compilation Directives

This is where compiler directives become really powerful.

Defining and Removing Conditions

/DEFINE MY_RELEASE_V75
/UNDEFINE DEBUG_MODE

Testing Conditions

/IF DEFINED(*V7R5M0)
   // code that only runs on 7.5 or higher
/ELSE
   // fallback code for older releases
/ENDIF

Full Conditional Structure

/IF DEFINED(*ILERPG)
   // ILE RPG specific code
/ELSEIF DEFINED(*CRTBNDRPG)
   // CRTBNDRPG specific code
/ELSE
   // other compiler
/ENDIF

Useful Predefined Conditions

  • *ILERPG – always true for the ILE RPG compiler
  • *CRTBNDRPG / *CRTRPGMOD
  • *V7R5M0, *V7R4M0, etc. (target release)
  • *THREAD_CONCURRENT, *THREAD_SERIALIZE

The /EOF Directive

Use /EOF inside a /COPY member to stop processing the rest of that member on subsequent includes. Perfect for preventing a copy member from being processed more than once:

/IF DEFINED(XYZ_COPIED)
/EOF
/ELSE
/DEFINE XYZ_COPIED
   // prototypes and definitions here
/ENDIF

In Summary

Keep your /COPY members small and focused, with each serving a single purpose. Use conditional compilation to handle multiple releases from the same source. Always include a comment at the top to document the purpose of any /COPY member. Place /SET and /RESTORE inside /COPY members so every module shares the same defaults.

{"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}
>