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
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)
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))
Step C: Creating an Executable
For a standalone program:
crtpgm pgm(Executable) bndsrvpgm(ucall urtl ulib yrtl) stgmdl(*teraspace) module(Object(s))
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
⚠️ 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_orui_.- Problem: If your file is named
myfunction.c, Uniface might look foruo_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#includestatements inside the generated stub files.
- Problem: If your file is named
- 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 theLIBPATHso the linker finds the shared libraries in/uniface/lib.
Top comments (0)