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

ILE: modules, programs and service programs

Reviewed on Verified on IBM i 7.5

Log in to save

Before ILE a program was a single block: one source, one compile, one *PGM object holding everything. That model is called OPM, Original Program Model, and on many systems there is still code running inside it.

ILE (Integrated Language Environment) changed the unit of work. You no longer compile a program: you compile modules, and modules are bound together into a program or a service program.

The three objects

  • Module (*MODULE): the result of a compile. It does not run: it is a brick.
  • Program (*PGM): one or more modules bound together, with an entry point. This is what you call.
  • Service program (*SRVPGM): one or more modules exposing procedures to others, not called directly. The equivalent of a shared library.
CRTRPGMOD MODULE(PRODLIB/CALCS) SRCFILE(PRODLIB/QRPGLESRC)
CRTPGM    PGM(PRODLIB/INVOICES) MODULE(PRODLIB/INVOICES PRODLIB/CALCS)
CRTSRVPGM SRVPGM(PRODLIB/UTILS) MODULE(PRODLIB/UTILS) EXPORT(*ALL)

CRTBNDRPG does both in one move: it compiles the module and binds it straight into a program. By default it does so with DFTACTGRP(*YES): the program always runs in the default activation group, like an OPM program, and static binding is not available, so no BNDDIR, no ACTGRP, and every call in the source must call a program, not a procedure. IBM presents it as the way to move to ILE RPG one program at a time. Using service programs and activation groups needs DFTACTGRP(*NO).

Why separating pays

The difference shows when one function is needed by twenty programs.

In the old model you wrote it as a separate program and invoked it with CALL. That works, but a CALL is dynamic: it costs on every invocation, the compiler does not check the parameters, and you cannot return a value, only change parameters.

With ILE you write it as a procedure inside a service program and call it like any function. The binding is static: the compiler checks the number and type of parameters, and a return value exists.

**FREE
dcl-pr calcNetAmount packed(11:2) extproc('CALC_NET_AMOUNT');
  amount packed(11:2) const;
  rate packed(5:2) const;
end-pr;

netAmount = calcNetAmount(total: 22);

Tip

this is the modernisation with the best ratio of result to risk. It does not touch existing code, does not change data, does not require a rewrite: you extract into a procedure the logic currently copied across ten programs, and from then on you fix it in one place. The modernisation chapter picks up from here.

The binding directory

Listing modules and service programs by hand on every compile soon becomes unmanageable. A binding directory (*BNDDIR) is a list: declare it once and the compiler takes what it needs from it.

CRTBNDDIR BNDDIR(PRODLIB/APPBND)
ADDBNDDIRE BNDDIR(PRODLIB/APPBND) OBJ((PRODLIB/UTILS *SRVPGM))

In the source it is declared once:

ctl-opt bnddir('PRODLIB/APPBND');

The signature

A service program's public interface, the procedures and data it exports, is represented by a signature. If you do not declare one, the binder computes it from the exported names and their order. Programs bound to the service program keep it, and the system compares it when activating them.

Warning

with EXPORT(*ALL) and no binder source, adding a procedure changes the list and so the signature, and programs already bound no longer find theirs. IBM warns that an incompatible change can stop programs still bound to the old version from working correctly.

You avoid it with binder language: a source with STRPGMEXP, EXPORT and ENDPGMEXP. IBM's rules: existing names are never removed or reordered, new ones go at the end; without an explicit signature, every addition needs a new STRPGMEXP PGMLVL(*CURRENT) block, and the previous one stays as PGMLVL(*PRV), so programs bound to the old signature keep starting. RTVBNDSRC generates the source from the exports of an existing module or service program.

STRPGMEXP PGMLVL(*CURRENT)
  EXPORT SYMBOL('CALC_NET_AMOUNT')
  EXPORT SYMBOL('CALC_VAT')
ENDPGMEXP
STRPGMEXP PGMLVL(*PRV)
  EXPORT SYMBOL('CALC_NET_AMOUNT')
ENDPGMEXP

To replace a module in an existing program or service program without rebuilding it, there are UPDPGM and UPDSRVPGM. A job that has already activated the old version keeps using it; new activations use the updated one.

Activation groups

An activation group is the space an ILE program lives in while it runs: its static variables, the files it opened, its commitment control. There is no command to create one: it is decided by the ACTGRP attribute given to CRTPGM or CRTSRVPGM.

Value What happens
ACTGRP(name) a group with a name we chose, created the first time it is needed and used by every program and service program with the same name
ACTGRP(*NEW) a new group, named by the system, on every call. Not for service programs
ACTGRP(*CALLER) the caller's group; a new one is never created
ACTGRP(*ENTMOD) the system looks at the entry module and chooses by language

Warning

a named group does not close when the program returns: a normal return, even an RPG RETURN, leaves it in the job for reuse, with its variables and open files. A *NEW group, instead, is deleted on return, since nobody could reuse it. A named group is closed with RCLACTGRP, only when no active program is using it, or ends with the job.

Important

commitment control is usually defined at activation group or job level (STRCMTCTL, CMTSCOPE). With an activation-group-level definition, two programs in different groups have different transactions, and a COMMIT in one does not commit what the other did.

OPM programs run in the default activation groups, two of them, which the system creates when the job starts and deletes when it ends; they cannot be deleted earlier. An ILE program ends up there if it is created with ACTGRP(*CALLER) and called from there, or with DFTACTGRP(*YES).

What to look at in an application you inherit

DSPPGM PGM(PRODLIB/INVOICES) DETAIL(*MODULE)
DSPSRVPGM SRVPGM(PRODLIB/UTILS) DETAIL(*PROCEXP)

Three questions tell you nearly everything: are the programs ILE or OPM, are they made of one module or several, and which activation group do they run in. An RPG program created with CRTBNDRPG and the default settings runs in the default group like an OPM one, and cannot bind to a service program.

Sources

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