Binder Language/Source/Directories and Service Programs, Oh My

Article ID: 55839

This week, I thought I'd review these four terms to clear up any mystery surrounding them. I get into a lot more details in the presentation I do at RPG World and user group meetings, but this article should at least get you on the right track.

ILE introduces a more complex way of compiling code than System/3X RPG programmers have been used to. In fact, between System/38's Programmer Menu (STRPGMMNU) and today's PDM, it has simply been a matter of pressing one or two keys and then hitting Enter to compile. How much easier could it get?

With ILE-based compiling, there are at least two steps to compile:

  1. Phase 1: Compile
  2. Phase 2: Bind

Phase 1 is the step in the compilation process that is most like what we had with RPG III. It compiles the code and produces an object. However, the object that is created is not a *PGM object; it is a new object (well, new if you've lived in a cave for the last 12 years). That new object is a module, or *MODULE.

*MODULEs contain the compiled and optimized code. The only problem is that they can't be called or run. To make that happen, you have to stuff them into either a program or another new object called a service program, or *SRVPGM.

Stuffing *MODULEs into a *PGM or *SRVPGM is the second phase of the compiler process. IBM calls it "binding" to make it sound cooler that "stuffing it," but you get the point.

If you've ever coded on a mainframe, you're probably familiar with "Compile and Link." "Compile and Bind" is very similar, and you could think of them as the same.

Now that we have a compiler workflow that is similar to everybody else's, everyone except AS/400/iSeries/System i programmers can easily adapt to it. As you've seen, there are now millions of new applications being written for the System i as a result of this new "like everybody else does it" compiler process. Oh, sorry, I blacked out for a minute.

What Are Service Programs?

In all seriousness, you can do a lot with this style of compiler, including introducing some pretty cool new capabilities. Most notably is the service program object. Service programs are a collection of subprocedures that you want to use in one or more programs. By storing them in a separate object (in a *SRVPGM), you can access the subprocedures in that service program by doing the following:

  1. Including their prototype in your RPG IV source code (via /COPY is preferred)
  2. Including the service program in the Bind phase when compiling that source member

Including prototypes still seems to be an area where very skilled RPG IV programmers are behaving as if they're nostalgic for vacuum tubes in their televisions. They won't use /COPY or /INCLUDE. I've heard a lot of reasons why people won't use /COPY or /INCLUDE -- none of them are valid, so get over it and start using them.

The second step, including the service program in the Bind phase of the compile process, is slightly tricky. You have two choices:

  1. Specify the service program name on the CRTPGM command's BNDSRVPGM parameter.
  2. Use a binding directory and specify it on the BNDDIR keyword of any of the compiler commands.

Virtually no one uses the first choice. The BNDSRVPGM keyword is fine but can't really be automated. That is, every time you compile a program that uses your service program, you would have to prompt and then type the service program name into the BNDSRVPGM parameter. Oh, what fun.

The second choice is, obviously, the only way to do it. But to use this option, you do have to introduce another object, the binding directory, or *BNDDIR.

Binding directories should be viewed as directories, in the literal sense. They do NOT contain any data, objects, or code. They contain a directory or list of service program names that you add to them, very similar to what a library list does for libraries. They don't contain copies of the actual libraries themselves, but only a list of library names that are searched for objects.

Binding directories contain a list of service program names that are searched for the names of the subprocedures you used in your program. They may also include *MODULE names, but that's another story. For now, we'll focus only in *SRVPGM names in binding directories.

Why create a binding directory? Simplicity.

You can specify binding directories on the BNDDIR keyword of the CRTBNDRPG and CRTPGM commands. In addition, RPG IV lets you specify the BNDDIR keyword on the Header specification in your source code. The RPG compiler automatically passes the binding directory keyword to the binder for you. So once you have created a binding directory and have added your service program names to it, all you need to do is add a simple keyword to your H-spec, as follows:

     H BNDDIR('QC2LE' : 'MYBD1')

As you can see, the BNDDIR keyword lets you include more than one binding directory name, but you can also specify multiple BNDDIR keywords if you prefer.

     H BNDDIR('QC2LE') BNDDIR('MYBD1')

Now you can forget about the complexity of using a binding directory and simply use PDM option 14 or 15 to compile your RPG IV source member.

Creating and Populating a Binding Directory

To create a binding directory, use the CRTBNDDIR command. There are few additional parameters beyond the name of the binding directory, so the following command creates the binding directory named MYBD1:

      CRTBNDDIR MYBD1 

An empty binding directory isn't very useful, so you need to populate it. To do that, use the Add Binding Directory Entry (ADDBNDDIRE) command. The command's Object (OBJ) parameter is a bit confusing if you've never used a System/38, as it is a complex mixed-list parameter, which is not something you see very much of anymore.

If you have two service programs named CUSTINFO and ITEMDATA, you could add them to the MYBD1 binding directory by running the following command:

ADDBNDDIRE BNDDIR(MYBD1) OBJ((CUSTINFO *SRVPGM) (ITEMDATA *SRVPGM))

Note that both service program names are included in the OBJ parameter but are also wrapped in parens to isolate them.

Now when BNDDIR('MYBD1') is added to an RPG IV source member, both the CUSTINFO and ITEMDATA service programs will be searched for any subprocedures called in the source member.

As new subprocedures are added to the service programs whose names appear in the binding directories, the binding directory and the BNDDIR keyword in your source code are not changed.

Binder Source (aka Binder Language)

Except for the word "bind," binding directories have nothing to do with binder source or binder language. Binding directories, as we've indicated, contain a directory or list of service program names. Binder source contains a list of subprocedures in a specified service program that can be called by any program. Subprocedures not specified in the binder source cannot be called by external programs.

Binder source is the source file member that contains binder language statements. There are only three CL-style statements in binder language, and they are:

  1. STRPGMEXP
  2. EXPORT
  3. ENDPGMEXP

The Start Program Export List (STRPGMEXP) statement identifies a list of exported subprocedure names that can be called by external programs. This list can also include exported variable names, but that's beyond the scope of most applications and of this article.

The Export (EXPORT) keyword identifies each exported subprocedure name. Only subprocedures whose P specification includes the EXPORT keyword are allowed to be specified on the EXPORT keyword in the binder source. So make your subprocedure's beginning P-spec look like the following, or it won't export:

     P GetItemInfo     B                   EXPORT

The End Program Export List (ENDPGMEXP) terminates the export list and has no parameters.

Here's an example binder source for a service program:

          STRPGMEXP  PGMLVL(*CURRENT) SIGNATURE('CUSTINFO')
             EXPORT     SYMBOL('IsCustValid')
             EXPORT     SYMBOL('GetCustInfo')  
             EXPORT     SYMBOL('toUpper')  
             EXPORT     SYMBOL('tolower')
             EXPORT     SYMBOL('UpdateCustRec')
             EXPORT     SYMBOL('DelCustRec')
          ENDPGMEXP

Only the subprocedure names that are identified with an EXPORT keyword in the binder source are available to be called by external programs. That is, they are the only subprocedures that are exported. The EXPORT keyword on a subprocedure's P-spec indicates that that subprocedure is eligible for exporting via an EXPORT binder language statement. Unless it is exported via an EXPORT binder language statement, you can't call the subprocedure from an external program. Also subprocedures that do not include the EXPORT keyword on their P-spec cannot be exported by an EXPORT binder language statement.

Summary

Binder language is the CL-like source language used to identify subprocedure names that are exported (available to be called) from a service program.

Binder source is the source member that contains the binder language statements.

Binding directories are objects that contain the names of service program that we want to search for the subprocedures used in our own programs.

A service program is an object. It is a collection of subprocedures that can be called (when exported) by other programs.

ProVIP Sponsors

ProVIP Sponsors