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.
Comments
No comments yet. Be the first to comment!
You need an account to comment. Log in · Sign up