From: george (George Jacob)

Subject: Re: [spr11421] Foreign Loading C++ in ACL 4.2 on SGI under IRIX 5.2?

Date: 1994-9-15 0:56

| I have some C++ code I would like to load into ACL 4.2, which is running
| under Irix 5.2 on an SGI.  I used "ld -shared -all -no_unresolved" to create
| an .so file, which loads without complaint into lisp.  However, ACL doesn't
| seem to be able to find entry points for any of the functions or global
| variables. 
| 
| Unfortunately, I have very little experience with C++ (it's someone else's
| code) so I'm at a bit of a loss to try to guess what to try.  Any
| suggestions?  Has anyone loaded C++ code into ACL?

The little blurb from our FAQ (ftp.uu.net:/vendor/franz/faq) gives
some information about going between Lisp and C++ that may be useful
here.  The FAQ entry pre-dates our Irix5.2 release, so you will want
to treat all comments about Solaris2 (i.e., SVR4-specific) as applying
to Irix5.2 as well.

---------------------------------------------------------------
George Jacob                      Internet: <franz.com at georgej>
Franz Inc.,                       uucp:     uunet!franz!georgej
1995 University Avenue,           Phone:    (510) 548-3600
Berkeley, CA 94704.               FAX:      (510) 548-8253
---------------------------------------------------------------
----------------------------------------------------------------------
Q) In ACL 4.2 can we call C++ functions as well as C functions?

A) Yes.  Described below is the recommended way of doing this:

   * Calling C++ methods.  Currently, C++ methods cannot be called
   directly from Allegro CL, so you must call them from C functions.

   * The naming conventions of C++ compilers cause problems when trying
   to define Common Lisp functions that point to C functions.  If you
   define your C functions like this:

	extern "C" int foo (char *whatever)
	{
	    //the rest of the function may use C++
	}

   then Allegro CL can find the name of `foo'.

   * Runtime initialization forms in C++ object files can cause
   problems on non-SVR4 systems.  On non-SVR4 systems, initializers
   are not run. 

   For the following declaration:

	foo x(3);

   Even though it is declared, the x.slot_value will not be set to
   the correct value (3 or whatever the foo initialization method 
   does to 3).

   In order to circumvent this problem, you need to call the
   initializers explicitly from Lisp.  For example, with the Cfront
   C++ compiler, static initialization is handled by generating a
   function with a name like _sti_xxxxx for each file that is
   compiled.  Ordinarily, the C++ linker arranges for the static init
   functions that are in a particular executable to be called at
   startup.  Obviously, when dynamically foreign loading into Lisp,
   this doesn't happen.  You therefore need to determine the names of
   the static initialization functions and then call them from Lisp.

   * Runtime initialization forms in dynamically loaded C++ object
   files are correctly loaded on SVR4 (ie, Sun's Solaris 2.x) systems.
   For further details, check the FAQ entry for loading in Solaris2.x.


Hope this explanation helps.  Essentially, you need to use the C
interface to buffer the interaction between Lisp and C++, regardless
of which C++ compiler you are using.
----------------------------------------------------------------------


----------------------------------------------------------------------
Q) How do I build a shared C/C++object file for loading in Solaris 2.x?

A) When running in Solaris 2.x, Allegro's foreign loader can only 
load shared object files.  The unix loader builds a shared object file
instead of a normal object file when you pass it the -G switch.
Thus given a file foo.o that you want to load into lisp, the simplest way
to build a shared object file is this:

% ld -G -o foo.so foo.o

Now in Lisp you can run (load "foo.so") to load in the file.
If foo.o calls functions in libraries (other than libc) then you must
specify them on the ld command line, e.g.:

% ld -G -o foo.so foo.o -lX11 -lm

If foo.o is C++ code  (or if any of the libraries mentioned contain C+++ 
code) then you have to be concerned with initializers.  In C++ user code 
(called constructors) can be called before a program starts in order to
initialize globally allocated data.  When you dynamically load C++ code
you want to ensure that all constructors are run during the dynamic loading.
Each .o file that is created by a C++ compiler contains a piece of a function
that initializes the data structures mentioned in that file.  When the 
unix loader combines a set of .o files to create an .so or a big .o it 
combines the initialization code.  In order to make the initializion
section into an initialization function that will be run when the file
is dynamically loaded you must include two specific files from your C compiler
vendor's library.  One of these files must be the first .o file mentioned
and one must be the last.  The purpose of these .o files is to put 
the prolog and epilog on the initialization function.  It can't hurt
to include these files if you are just linking C code.
For the SunPro C compiler the names of these files are crti.o and crtn.o
and they are found in the compiler's library.

So for building a C++ shared object a sample command line is:

% ld -G -o foo.so /usr/opt/SUNWspro/SC2.0.1/crti.o foo.o -lC /usr/opt/SUNWspro/SC2.0.1/crtn.o

----------------------------------------------------------------------