I apologize in advance for the length of this post.
I'm trying to build a gateway that allows CL to communicate with R (a
statistical package). R has a C API for embedding it, which I want to
use. I have an example python module (rpy) that does this, and I've
also written an eight-line C program which starts up an embedded R.
So far, my attempts to translate this to CL have not been successful.
I started with UFFI, but I've decided to work first directly at the
CMUCL level, and try to achieve portability later. At this point, I'm
guessing my primary difficulty is a lack of understanding of what's
necessary with shared libraries.
When I link my eight line C program, I have to link with a shared
library libR.so ("-lR" in the call to gcc). Doing an ldd on libR.so,
I see that it depends on a number of other libraries:
[EMAIL PROTECTED] rif]$ ldd /usr/local/lib/R/bin/libR.so
libblas.so.3 => /usr/lib/libblas.so.3 (0x00cf0000)
libg2c.so.0 => /usr/lib/libg2c.so.0 (0x00c48000)
libm.so.6 => /lib/tls/libm.so.6 (0x00111000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x00f82000)
libreadline.so.4 => /usr/lib/libreadline.so.4 (0x00f36000)
libdl.so.2 => /lib/libdl.so.2 (0x003eb000)
libncurses.so.5 => /usr/lib/libncurses.so.5 (0x00bc5000)
libc.so.6 => /lib/tls/libc.so.6 (0x00ded000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x007dc000)
libgpm.so.1 => /usr/lib/libgpm.so.1 (0x00522000)
>From the alien:load-foreign documentation, I see that load-foreign has
a :libraries keyword: "libraries is a list of simple-strings
specifying libraries in a format that ld, the Unix linker, expect."
Although the docs don't actually say what these strings are used for,
I'll choose to not be a rules-lawyer, and assume that this is supposed
to be a list of libraries that the foreign object file depends on.
Currently, I am using the following to load the R library:
(alien:load-foreign "/usr/local/lib/R/bin/libR.so"
:libraries '("-lc" "-lgpm" "-lncurses" "-ldl"
"-lreadline" "-lm" "-lblas"))
I removed "-lgcc_s" and "-lg2c" from an earlier version of the call
because their inclusion caused ld to fail, even though they are in the
same directories (/lib and /usr/lib) as other libraries that were
found --- I do not know why. I did not include /lib/ld-linux.so.2 at
all, as I'm not sure what the "link option" for this is. Any comments
on these choices are welcomed.
Question: Can I just load the library I want to call, or do I need to
climb up the tree of dependencies, calling load-foreign on each one
independently?
The function itself is declared as:
(alien:def-alien-routine ("Rf_initEmbeddedR" start-r)
integer
(argc integer :in)
(argv (* foreign-string) :in))
In any case, the upshot is that as of now, I have an eight-line C
program that can start an embedded R, but all attempts to do it from
CMUCL lead to an "Arithmetic error FLOATING-POINT-INVALID-OPERATION
signalled" inside the call, beneath about six "Foreign function call
land" stack frames, which I don't know of any way to directly debug.
(This is assuming I set the environment variable R_HOME appropriately,
which I do using the :osicat package. If I fail to do this, then
calling my function to start up R simply causes CL to crash.)
As a side piece of information, I wrote a tiny C program that contains
a single function with the same signature as Rf_initEmbeddedR (int
argc, char **argv) that returns the sum of the lengths of the strings
given as arguments. Doing a def-alien-routine with the same signature
as above, and in both cases (of course) converting an array of CL
strings into an aray of (* (alien:unsigned 8)), the little C program
works fine, so I'm guessing that I have the calling conventions and
the string handling OK, making me suspect some shared library problem.
Any help or advice is appreciated.
Cheers,
rif