Go to the previous, next section.

Multiple Languages In One Address Space

With ILU version 2.0 or later, modules implemented in different programming languages can be mixed in the same address space, with ILU doing automatic translation between data representations. (14) There are a number of things to consider when doing this; this section discusses some of them.

Dueling Runtimes

Some languages simply cannot be mixed in the same address space because their runtimes will conflict. ILU offers no solutions to this problem. Typical examples are two languages like Franz Allegro Common Lisp and Java with "green threads". They each implement a user-level threads package, and their implementations of threads probably cannot co-exist in the same address space.

A possible solution to this problem, called the POSIX Portable Common Runtime (PPCR), is available from Xerox PARC, as ftp://ftp.parc.xerox.com/pub/ppcr/. It contains a basic runtime which can be used as the platform for a particular language implementation's runtime. Languages which use PPCR will have a lower chance of having conflicting runtimes.

In general, the non-threaded languages C, C++, and Python are the best languages to construct libraries with; that is, code which is intended to be loaded into another language's address space. Modules constructed with one of these languages can be loaded into any of the other ILU-supported languages' address spaces.

Module Initialization and Binding

Module initialization really consists of two operations: interface initialization and object instantiation. The first operation initializes all the interfaces used or exported by the module; the second creates one or more true instances of objects to be used by other modules. The act of binding is finding a true object in the surrogate space, so that client code can access the true module.

Initialization

Generally, each ILU interface must be initialized. The process of doing this initialization varies from programming language to programming language. In ANSI C, ILU requires explicit calls to interface__Initialize() for interfaces being used, or interface__InitializeServer() for interfaces being exported. In languages like C++ and Java, interface initialization is performed automatically, but at some indeterminate time before the first symbol from that interface is referenced from outside the interface. When C++ code is used in a shared library, sometimes this initialization must be forced manually. In Python or Common Lisp, interface initialization is performed automatically by the language at the time the module describing the interface is "loaded" into the address space.

In addition to initializing all interfaces being used or exported, a module must create one or more true object instances, to allow other modules to access it. Again, the specific way of doing this varies from programming language to programming language. Once the true instance has been created, it can be exported from the module by either publishing it, via the ILU simple binding system, or taking its string binding handle, and passing that outside the module for other modules to use.

When multiple languages are used in the same address space, each must be initialized according to the standards used for that programming language. This can be tricky when using both statically compiled and dynamically compiled languages together. Consider the case where Python and ANSI C are linked together. This use of Python may be as an extension language to a program written in C. In this case, the C code must do all initialization of modules written in C before calling into any Python module which might reference them. Similarly, Python initialization (import) of modules must occur before the C code can use them. See `ILUSRC/src/examples/multlang/' for an example of a situation of this sort.

In the other case, C true modules which are to be used from a Python program in the same address space must somehow be first loaded into that address space, then initialized. The loading is done by turning the C module into a Python extension module, and either linking it into the python image, or creating a dynamically loadable module from it. The initialization is done by then calling import on that module from within the Python interpreter. The extension module's initialization routine initializes all of its interfaces, creates one or more true objects, and exports them. After the import statement returns, the objects are available for finding (see next section) from within Python.

Finding Objects (Binding)

Object instances may be located by calls on the variations of LookupObject and ObjectOfSBH that exist in the various language runtimes. LookupObject is implemented so that it first looks to see if the true object for the specified object ID is available in the local address space. If so, it returns a version of that object. Only if the object is not locally available does it perform external lookups in an attempt to locate the object. Note that for an object to be found via LookupObject, the true instance must first have been published via the implementation language ILU runtime's variant of PublishObject. If you do not want your objects published outside your address space, you should use ObjectOfSBH to find them.

Suggested Modularization Strategies

One of the most effective ways of building a module to be loadable into another language's address space is to create a shared library containing the module. The library can provide binding hooks in various ways, but a suggested strategy is to provide a, from the shared library, a C-callable function which returns the string binding handle of an object, and to make all the functionality of the module available through that object, possibly by getting other objects from that object. There are then a handful of stylized ways of invoking that C procedure; we'll discuss them for each programming language.

Building a Shared Library Around a C or C++ Module

This is typically quite simple. You must implement the true module in either C or C++, leaving a C-callable hook into the implementation available. Here's what a typical initialization procedure for a module called testImpl, providing the test interface, which implements the Strlen object type, might look like in C++ (using ILU's CORBA C++ mapping):

extern "C" {

  ilu_string testImpl__initialize ()
    {
      iluServer *s;
      test_Strlen_impl *i;

      // in case static initializers weren't run,
      // this will cause them to be run
      ILU_INIT_test_SERVER_ONLY();
      iluCppRuntime::iluInitialize();

      // create a new ILU kernel server
      s = new iluServer ();

      // now create an instance of test.Strlen
      // and return its SBH
      i = new test_Strlen_impl((iluCString) NULL, *s);
      return i->iluObjectToString();
    }
}
A C version would look quite similar.

ILU provide an Imake rule called SharedLibrary, which can be used to build a shared library from C code. It also works in most cases for C++ code, though in this case you will need to explicitly specify your C++ library. A better idea, with C++, is to use the C++ compile command to build the library. Specifics of how to do this will differ from compiler to compiler.

Building a Shared Library Around a Python Module

It may seem odd building a shared library around a Python implementation of a module, but that will allow it to be loaded into other languages that don't support Python bytecodes. To do this, one first implements the module in Python, providing an initialization function similar to that shown in the C++ case:

def init():

	global inst

	# we create the server carefully here.  We don't create
	# a normal port, and it doesn't become the default server
	# (though it could be)
	server = ilu.CreateServer()

	# now make an instance of Strlen with the server
	inst = Strlen(None, server)

	# and return its SBH
	return inst.IluSBH()

Initializing a Shared Library from C or C++

For the C or C++ programming languages, accessing a shared library is trivial. The client code simply loads in the shared library, then calls

Initializing a Shared Library from Python

Initializing a Shared Library from Java

Initializing a Shared Library from Common Lisp

Go to the previous, next section.