Using the u3gl Program

The u3gl program is a pre-linked executable that calls a specified function in a specified shared library.

Linking a call-in executable can be a problem if you do not have a C++ compiler or if you do not have the correct version of the C runtime. Certain parts of Uniface are written in C++ and some platforms require that you can link these to the executable only if you use the same version of that C++ compiler. If you try this with a standard C compiler, you might get unresolved externals during linking because of the missing C++ run-time initialization.

For situations where buying the C++ compiler is a problem, Uniface introduces the u3gl program. The 3GL developer no longer needs to link an executable but only a shared library (for which no C++ compiler is needed). The u3gl program loads the library and calls the entry point. Because u3gl is distributed in executable format, it is linked with the proper C++ compiler and so is able to do the C++ run-time initialization on behalf of the shared library.

As an example, consider the simplest of call-in programs:

#include <h3gl.h>
void main (int argc, char* argv[])
{
(void)unifbeg(1);
(void)urun((unsigned char *)argv[1], 0, 0, 0, 0);
(void)unifend(-1);
}

Assume this program is named callin.c and you are working on 32-bits Sun Solaris. Normally, you would compile and link this code into an executable call-in as follows:

$ cc -mt -I3gl/include -o callin callin.c -L./lib -lucall -lyrtl

If you wanted to run the form ENT, you would execute it from the command line as follows:

$ callin ent

If the linking fails with an unresolved C++ symbol, for example Unresolved symbol: __shlinit (code), then it is time to use u3gl.

u3gl

To put u3gl into action, first change your C code not to use main but some other entry point, for example, one named callin:

#include <h3gl.h>
void callin (int argc, char* argv[])
{
(void)unifbeg(1);
(void)urun((unsigned char *)argv[1], 0, 0, 0, 0);
(void)unifend(-1);
}

Next, compile and link this code into a shared library callin.so rather than an executable callin:

$ cc -c -mt -KPIC -I3gl/include callin.c
$ cc -G -z defs -mt -KPIC -o lib/libcallin.so -lc -L./lib -lucall -lurtl -lulib -lyrtl callin.o

Lastly, instead of running your executable, you run u3gl which in turn loads and executes your code, which will then run the form ENT:

$ bin/u3gl --shared=libcallin.so --func=callin ENT

Note that as with other examples, we created the shared library in the Uniface lib directory, to avoid having to change the LD_LIBRARY_PATH setting.

In the compile command, you might notice a number of parameters we did not have in the ‘normal’ case:

  • -z defs

    Produce an error if not all symbols can be resolved at link time.

  • -KPIC

    Produce position-independent code, which is a requirement for shared libraries on Solaris

  • -G

    The output is to be a shared library rather than an executable.

To ensure that you detect any unresolved externals at link time, rather than at run time, we recommend that you use the -z defs flag (or equivalent) wherever possible. The link commands given in Appendix Compile and link commands use these flags whenever one is available for the platform.

The full syntax of the u3gl program is as follows:

  • --shared=SharedObjectName

    The default is libProgramnameStandardextension

  • --func=Functionname

    The default is Programname

  • --help

    This help

  • --usage

    Gives information about why and how

  • --verbose

    Verbose information

  • --

    (Optional) start user's arguments

You can run u3gl with the --help switch to produce the above information, or with the --usage switch to produce elaborate help information, including an example. The --verbose switch is useful for trouble-shooting in case the callin does not function properly.

The --shared and --func switches are the essential ones. With these, you specify the name of your shared library and the name of the entry point (function) that should be called. The default values allow you to work without any parameters at all, so the syntax can be the same as when you are working without using u3gl.

If you create a copy or symbolic link of u3gl, and give it the name callin, you can leave out these parameters, because both will default to the program name, in other words, the lib prefix and the .so suffix for the shared library are not mandatory. Then you can once again simply say:

$ callin

without even having to know that it is implemented via u3gl.

Some more remarks to round off the discussion of u3gl:

  • This functionality is available only on Unix and Linux platforms.
  • As with normal Uniface applications, it is necessary to call insunis and to ensure that the LD_LIBRARY_PATH (or whatever it is called on your platform) is set correctly
  • If your function has any command line parameters, such as the name of the form to run in the above example, you can give these at the end of the command line, for example:
    $ bin/u3gl --shared=libcallin.so --func=callin ENT
  • If you have a command line parameter that starts with a double-dash (--), you must tell u3gl that it is not a switch, but rather a parameter. You do this by adding a double-dash to signal the end of the switches and the start of the parameters, for example:
    $ bin/u3gl --shared=foo.so --func=bar -- --hello--