Suppose my module underwent some change so i had to update the service program as a result the signature got changed. So not which option should I take? Should I use CRTPGM or UPDPGM to recreate the programs that were using the service program. And can you tell the difference between CRTPGM and UPDPGM in this scenario.
First of all, you shouldn't need to CRTPGM or UPDPGM just because a *SRVPGM has changed. It should be a very rare and very intentional decision to require *PGM re-compiles due to changes in a *SRVPGM.
It's sounds like you're probably using CRTSRVPGM EXPORT(*ALL)
, don't do that. Instead use a binder source, CRTSRVPGM EXPORT(*SRCFILE) SRCFILE(..)
to control the exported procedures and the service program signature. The easy way it to hardcode a signature
STRPGMEXP SIGNATURE('MYSRVPGM Sig v1')
export symbol('Proc1')
export symbol('Proc2')
ENDPGMEXP
Now you can come along and add to procedures to the service program, and as long as you add the exports to the end, you can keep the same signature and not force a recompile of any programs using that service program.
STRPGMEXP SIGNATURE('MYSRVPGM Sig v1')
export symbol('Proc1')
export symbol('Proc2')
export symbol('Proc3')
export symbol('Proc4')
ENDPGMEXP
You can't delete, nor re-order the exports in this case.
If you truly need to insure a re-compile of all calling programs, then you simply update the hard coded signature.
STRPGMEXP SIGNATURE('MYSRVPGM Sig v2')
export symbol('Proc1')
export symbol('Proc3')
export symbol('Proc4')
ENDPGMEXP
The alternative is to have the system generate a signature, and use *CURRENT
and *PRV
blocks. But you still can't delete or re-order exports without breaking existing callers. So the community consensus is to simply hard code the signature. IBM itself follows this practice with the *SRVPGM objects included in the OS.
The two important thing to realize is that
So for instance, if I have this
dcl-pr Proc1 extproc(*dclcase);
parm1 char(10);
end-pr;
dcl-pr Proc2 extproc(*dclcase);
parm1 char(20);
end-pr;
with binder source
STRPGMEXP SIGNATURE('MYSRVPGM Sig v1')
export symbol('Proc1')
export symbol('Proc2')
ENDPGMEXP
I can do this
dcl-pr Proc1 extproc(*dclcase);
parm1 char(10);
parm2 char(20) option(*nopass);
end-pr;
dcl-pr Proc2_depreciated extproc(*dclcase);
parm1 char(20);
end-pr;
dcl-pr Proc2 extproc(*dclcase);
parm1 varchar(100) const;
end-pr;
with binder source
STRPGMEXP SIGNATURE('MYSRVPGM Sig v1')
export symbol('Proc1')
export symbol('Proc2_deprecated')
export symbol('Proc2')
export symbol('Proc3')
ENDPGMEXP
Existing *PGM's calling Proc2()
will continue to call the code now renamed Proc2_deprecated()
. A new or recompiled existing *PGM that calls Proc2()
will call the newly added code named Proc2()
.
Now to provide an incomplete answer to your question,
what is the difference between CRTPGM and UPDPGM?
I'm pretty sure there are differences, I know some of the meta-data in the *SRVPGM object isn't updated when UPDSRVPGM is used instead of CRTSRVPGM. I'd bet the same is true of UPDPGM. Also, CRTPGM has a parameter
Allow *SRVPGM library update . . ALWLIBUPD
that defaults to *NO
so if your updated service program is in another library, you'll probably have to use CRTPGM.
Honestly, in 30 years of being on the platform, I've never used UPDPGM or UPDSRVPGM. Most of time, my *PGMs are single module and use binding directories to find *SRVPGMs so recreating via CRTBNDRPG is simple enough. *SRVPGMs are either single module or have a unique binding directory specific for it's creation.
The change management tooling I've used over my career has also recreated objects rather than using UPDPGM or UPDSRVPGM.
Lastly, if you're new to ILE and *SRVPGM's Scott Klement's ILE Concepts (for the Impatient RPG Programmer) presentation is an oldie but a goodie.