allegro-cl archives 1994-9-15 | home index prev H thread prev K thread next J next L |
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 ---------------------------------------------------------------------- |