Programming on IBM i: sources, ILE, RPG and SQL Chapter 1 of 9

Where the code lives

Reviewed on Verified on IBM i 7.5

Log in to save

On any other platform, code is a file in a directory. Not here — or at least not traditionally: code lives inside a source file, which is an object of type *FILE in a library, and each program is a member of that file.

A source file is to a project what a directory is, except that it is a database object. That is why source can be queried in SQL, and also why you cannot give it a long name or put a subdirectory inside it.

The names you meet

By convention, one source file per language type:

File Holds
QRPGLESRC ILE RPG sources, and RPG with embedded SQL
QRPGSRC old-model RPG sources, where any remain
QCLSRC CL sources
QDDSSRC file descriptions: physical, logical, display, printer
QCMDSRC command definitions
QSQLSRC SQL scripts

The member typeRPGLE, SQLRPGLE, CLLE, PF, LF, DSPF, PRTF, CMD — is an attribute of the member, not of the file holding it, and decides how the editor colours it and which compiler is expected.

WRKMBRPDM FILE(PRODLIB/QRPGLESRC)
DSPFD FILE(PRODLIB/QRPGLESRC) TYPE(*MBRLIST)

And in SQL, the convenient way to search across all sources at once:

SELECT TABLE_NAME, SYSTEM_TABLE_SCHEMA, SOURCE_TYPE, LAST_SOURCE_UPDATE_TIMESTAMP
  FROM QSYS2.SYSPARTITIONSTAT
 WHERE SYSTEM_TABLE_NAME = 'QRPGLESRC'

Note

a source file has fixed-length lines. Historic ones were 92 characters — twelve of sequence number and date, eighty of code — and QRPGLESRC started at 112, that is a hundred usable characters. A line longer than the record is not cut at the right place with a warning: it is simply truncated, and what comes out is syntactically valid and wrong. It is why some sources are formatted so tightly they look written out of spite.

Code on the IFS

For several releases now the compilers have also accepted sources as IFS files — ordinary files in ordinary directories, with long names and no line-length limit.

CRTBNDRPG PGM(PRODLIB/INVOICES) SRCSTMF('/home/dev/invoices/invoices.rpgle')

Why this matters is not aesthetics: it is that a file in a directory can go under git. Version control over source file members has always been done with dedicated change management products, which work and cost money; with sources on the IFS you use the same tools as the rest of the world, and newcomers already know them.

Tip

this is not a decision to take for all the code at once. What works is leaving historic code where it is and putting on the IFS what gets written from now on, or the single application being rebuilt. The two coexist without trouble: the compiler produces the same object.

From source to object

Compiling does not produce an executable file: it produces an object in the library you named, with everything that follows — it has an owner, authorities, a description, and it is saved and restored like anything else.

CRTBNDRPG PGM(PRODLIB/INVOICES) SRCFILE(PRODLIB/QRPGLESRC) SRCMBR(INVOICES)
CRTBNDCL  PGM(PRODLIB/LAUNCH)   SRCFILE(PRODLIB/QCLSRC)    SRCMBR(LAUNCH)
CRTPF     FILE(PRODLIB/ORDERS)  SRCFILE(PRODLIB/QDDSSRC)   SRCMBR(ORDERS)

The object remembers where it came from, and this is one of the most useful things about the system:

DSPOBJD OBJ(PRODLIB/INVOICES) OBJTYPE(*PGM) DETAIL(*SERVICE)

Among the service data are the source file, the member, and the source's last-changed timestamp as of compile time. Comparing it with the member's date tells you whether the object in production matches the source in front of you.

Warning

this is the check to run before touching anything in an environment you do not know. Source newer than the object means somebody changed the code and did not compile it, or compiled it somewhere else: recompiling at that point ships changes nobody asked for and nobody tested.

SELECT OBJNAME, OBJTEXT, SOURCE_FILE, SOURCE_LIBRARY, SOURCE_MEMBER,
       SOURCE_TIMESTAMP, OBJCREATED
  FROM TABLE(QSYS2.OBJECT_STATISTICS('PRODLIB', '*PGM'))
 ORDER BY SOURCE_TIMESTAMP DESC

The compile listing

Every compile produces a spooled file: the compile listing. It holds the numbered source, the errors, and — on request — the expanded code after copies and after SQL precompilation.

It is where you look when an error makes no sense, because it shows the code as the compiler saw it, which is not always what you wrote: /COPY members have been expanded, and in a source with embedded SQL the EXEC SQL statements have been rewritten as calls.

Tip

compiling with OPTION(*EVENTF) also produces an events file that modern editors read to show errors on the right line, instead of making you hunt through the listing. It is how RDi and the VS Code extensions work.

What is missing, compared with other platforms

Three things, worth knowing straight away instead of looking for them.

There is no project file. No Makefile or pom.xml as standard: the build order — files first, then modules, then programs — is knowledge held by whoever works there, or lives inside a change management product, or inside a hand-written CL that compiles everything in sequence. Modern tools fill this gap, and the tools chapter covers them.

There is no virtual environment. Separation between test and production is done with libraries and the library list: same program, different libraries. That is why the library list is worth understanding properly, and why a mistake there costs more than elsewhere.

There is no package to ship. You move an object from one library to another, or save and restore. A production release is a copy of objects, and whoever does it by hand eventually forgets one.

Back to the guide index

← Back to blog

Comments

No comments yet. Be the first to comment!

You need an account to comment. Log in · Sign up