A binding directory (*BNDDIR
) on IBM i is a container that lists what to bind to (service programs, modules, or even other binding directories) when you create or update programs and service programs. It saves you from spelling out a long list of BNDSRVPGM
/ modules every time you compile.
What it’s for
-
Simplify builds: one place to list common dependencies.
-
Consistency: every program using the BNDDIR picks up the same set of service programs.
-
Layering: you can nest BNDDIRs (a BNDDIR can reference another BNDDIR).
What can a BNDDIR contain?
-
*SRVPGM
(service programs) -
*MODULE
(modules) -
*BNDDIR
(other binding directories)
The binder searches entries in the order they appear in the directory, and searches BNDDIRs you pass on the compile command left to right.
Core commands
/* Create a binding directory */
CRTBNDDIR BNDDIR(MYLIB/APPBND)
/* Add entries */
ADDBNDDIRE BNDDIR(MYLIB/APPBND) OBJ((MYLIB/UTILSRV *SRVPGM)
(MYLIB/LOGSRV *SRVPGM)
(MYLIB/BASEBND *BNDDIR))
/* Display / maintain */
WRKBNDDIRE BNDDIR(MYLIB/APPBND)
DSPBNDDIR BNDDIR(MYLIB/APPBND)
/* Remove entry */
RMVBNDDIRE BNDDIR(MYLIB/APPBND) OBJ(MYLIB/LOGSRV) OBJTYPE(*SRVPGM)
Using a BNDDIR at compile time
1) With CRTBNDRPG (one-step create)
CRTBNDRPG PGM(MYLIB/MAINPGM)
SRCFILE(MYLIB/QRPGLESRC)
BNDDIR(MYLIB/APPBND)
2) With CRTRPGMOD + CRTPGM (two-step)
CRTRPGMOD MODULE(MYLIB/MAINMOD) SRCFILE(MYLIB/QRPGLESRC)
CRTPGM PGM(MYLIB/MAINPGM) MODULE(MYLIB/MAINMOD) BNDDIR(MYLIB/APPBND)
3) Creating a service program that imports from others
CRTRPGMOD MODULE(MYLIB/BILLING)
CRTSRVPGM SRVPGM(MYLIB/BILLINGSRV)
MODULE(MYLIB/BILLING)
BNDDIR(MYLIB/APPBND) /* resolve imports here */
EXPORT(*SRCFILE) SRCFILE(MYLIB/QSRVSRC) SRCMBR(BILLINGSRV)
4) Rebinding an existing program to new entries
UPDPGM PGM(MYLIB/MAINPGM) BNDDIR(MYLIB/APPBND)
RPG shortcut: specify BNDDIR in the source
ctl-opt dftactgrp(*no) actgrp(*caller)
bnddir('APPBND'); // library must be on compile-time LIBL
(You can qualify it like bnddir('MYLIB/APPBND')
if you prefer.)
How this relates to binder source & signatures
-
BNDDIR just tells the binder where to find exports.
-
Binder source (
QSRVSRC
) in your service programs controls what you export and the signature (version). -
If you change a service program’s signature, callers must be re-created/rebound (BNDDIR won’t avoid that).
If you keep the signature the same (bug fix), you can rebuild the SRVPGM and avoid recompiling callers.
Typical setup pattern
-
Create one BNDDIR per application layer:
-
APPBND
→ app-level SRVPGMs (e.g.,UTILSRV
,LOGSRV
,SECURESrv
) -
BASEBND
→ low-level/common SRVPGMs
-
-
Point programs and higher-level SRVPGMs to
APPBND
. -
Keep
APPBND
tidy and order entries so most commonly-used SRVPGMs are earlier.
Gotchas & tips
-
Order matters: the binder picks the first matching export it finds.
-
Reproducibility: pin exact service programs in BNDDIR; avoid relying on LIBL accidents.
-
Don’t use
EXPORT(*ALL)
in production SRVPGMs—use binder source to control exports and signatures. -
Nesting BNDDIRs is fine, but avoid circular references.
-
If an import can’t be resolved, you’ll get a binding error at create time; check which symbol is missing and add the correct SRVPGM to your BNDDIR.
Minimal working example
Service program:
// UTILMOD.RPGLE
ctl-opt dftactgrp(*no) actgrp(*caller);
dcl-proc ToUpper export;
dcl-pi *n varchar(256); s varchar(256); end-pi;
return %upper(s);
end-proc;
CRTRPGMOD MODULE(MYLIB/UTILMOD)
CRTSRVPGM SRVPGM(MYLIB/UTILSRV) MODULE(MYLIB/UTILMOD)
EXPORT(*SRCFILE) SRCFILE(MYLIB/QSRVSRC) SRCMBR(UTILSRV)
QSRVSRC/UTILSRV
:
STRPGMEXP PGMLVL(*CURRENT) SIGNATURE('UTIL 1.0')
EXPORT SYMBOL('TOUPPER')
ENDPGMEXP
Binding directory:
CRTBNDDIR BNDDIR(MYLIB/APPBND)
ADDBNDDIRE BNDDIR(MYLIB/APPBND) OBJ((MYLIB/UTILSRV *SRVPGM))
Program using it:
// MAINPGM.RPGLE
ctl-opt dftactgrp(*no) actgrp(*caller) bnddir('MYLIB/APPBND');
dcl-pr ToUpper varchar(256) extproc(*dclcase);
s varchar(256);
end-pr;
dsply ToUpper('hello ibmi');
*inlr = *on; return;
CRTBNDRPG PGM(MYLIB/MAINPGM) SRCFILE(MYLIB/QRPGLESRC)