DEV Community

Peter + AI
Peter + AI

Posted on

Bridging the Gap: Compiling and Linking 3GL Code in Uniface 10.4

If you are working with Uniface, there comes a time when you need to extend its capabilities using 3GL (Third Generation Language) code, typically C or C++. Whether you are creating call-in programs or call-out stubs, understanding how to compile and link correctly is crucial for stability.

Based on the official Uniface 10.4 documentation, here is a guide on how to handle the build process, with a specific deep dive into the IBM i (iSeries) platform constraints.

1. The Foundation: Where to Look

Before you start hacking away at compiler flags, always check your installation directory. Uniface provides the necessary include files and libraries in:

/uniface/3gl
Enter fullscreen mode Exit fullscreen mode

Pro Tip: Look for the makefile.inc file in this directory. This file is the "source of truth" for your specific platform. It contains the exact compile and link commands that Uniface used to build itself. If you are unsure which flags to use for your custom code, mimic what is defined here.

2. Linking Libraries: Better Safe Than Sorry

When linking your 3GL code, you will rely on the core Uniface shared libraries:

  • ucall
  • urtl
  • ulib
  • yrtl

Best Practice: Even if your specific program only strictly requires ucall (common for call-in programs), the documentation recommends linking against all of them.

"There is no harm in specifying all of them; doing so will keep your scripts or make files easier to maintain." [1][2]

3. Platform Focus: IBM i (iSeries)

Compiling C code on IBM i requires specific parameters to handle memory models correctly (Teraspace).

Step A: Compiling the Module

Use the crtcmod command. You must enable Teraspace interfaces.

crtcmod module(Source) srcfile(c) teraspace(*yes *tsifc) stgmdl(*teraspace) dtamdl(*llp64)
Enter fullscreen mode Exit fullscreen mode

Note: Compile one source file at a time.

Step B: Creating the Service Program (Shared Lib)

When creating a service program (*SRVPGM), you link against the Uniface libraries mentioned earlier.

crtsrvpgm srvpgm(SharedLib) bndsrvpgm(ucall urtl ulib yrtl) stgmdl(*teraspace) module(Object(s))
Enter fullscreen mode Exit fullscreen mode

Step C: Creating an Executable

For a standalone program:

crtpgm pgm(Executable) bndsrvpgm(ucall urtl ulib yrtl) stgmdl(*teraspace) module(Object(s))
Enter fullscreen mode Exit fullscreen mode

4. The "Export File" Gotcha

On IBM i, you cannot simply compile and hope the linker finds your functions. You must explicitly define which symbols are exported using an export file (usually located in QSRVSRC).

Example structure for a service program named ALL3GL:

STRPGMEXP PGMLVL(*CURRENT) LVLCHK(*NO)
EXPORT SYMBOL(USCALLOUTCALLOUTSIG)
ENDPGMEXP
Enter fullscreen mode Exit fullscreen mode

⚠️ Important Warning:

There must be no white space between the keyword SYMBOL and the following left parenthesis (. If you write SYMBOL (Function), it may fail silently or cause linker errors.

5. Common Pitfalls & Limitations

Based on typical integration scenarios, here are the problems you will likely face:

  • The 10-Character Limit (IBM i): If you are compiling call-out stubs, Uniface automatically adds a prefix like uo_ or ui_.
    • Problem: If your file is named myfunction.c, Uniface might look for uo_myfunction. On IBM i filesystems, member names are often limited to 10 characters. uo_myfunction (13 chars) will truncate or fail.
    • Solution: Rename your source files to be shorter (e.g., myfunc.c) before compiling, and remember to update the #include statements inside the generated stub files.
  • Environment Variables: The commands assume you are in the top-level Uniface directory. If you run this from elsewhere, you must manually set $LD_LIBRARY_PATH (on Unix/Linux) or the LIBPATH so the linker finds the shared libraries in /uniface/lib.

Sources

3GL Compile and Link Commands

Top comments (0)