Simple Example of Dynamic loading in xlisp-stat

Here's a simple C function to find the sum of a vector of n doubles:
void sum(double *x,long *n,double *ans)
{
   long i,nn=*n;
   double sum;

   *ans = 0.;
   for(i=0;i<nn;i++)*ans += x[i];
}

The function is written with three arguments, all pointers. All arguments must be pointers in order for the code to work after it's dynamically loaded. I included a third argument to hold the result; memory for this argument (in this case a scalar) must be ``allocated'' in the calling xlisp-stat program by passing a suitable object through the call-cfun function, as shown below.

To compile the code into an object file suitable for dynamic loading, use the UNIX command

	      cc -KPIC -O -c sum.c
If you were using several different object files, you'd need to link them together into a single shared object using the cc command. For example, suppose you wanted to combine two object files, first.o and second.o. First, compile the two files using the -KPIC option as shown below. Then call cc to create the shared object as follows:
	     cc -G -o ./both.so first.o second.o
Then, in the dyn-load function, you'd specify that you wanted to dynamically load ./both.so. (The dynamic loading command needs a full pathname - it won't even resolve file names in your current directory.) If you need to include the NAG libraries, you would use a command like:
      cc --f77 -G -o ./both.so first.o second.o -R/usr/local/lib -lnag
The --f77 flag is a local option which makes sure all the necessary Fortran libraries are available. The -R option is required to tell the operating system where to find the shareable version of the NAG library ( /usr/local/lib) at run time.

Getting back to the simple example using sum, to dynamically load the sum.o object file, you'd use the xlisp-stat function dyn-load.

> (dyn-load "sum.o")

We now want to call the C sum function from within xlisp-stat; this is done with the xlisp-stat call-cfun function. You pass this function the name of the C routine you wish to access, and each of the arguments to the function, including the one which is large enough to hold the result. If any of the arguments are pointers to double, you must use the float function of xlisp-stat to insure they are properly passed; integers can simply be passed as is. The call-cfun routine will then return a list containing each of the arguments to the function, some of which may have been changed by the C routine. Here's the function call, with a trivial example showing xlisp-stat's response:

> (call-cfun "sum" (float '(3 5 7 9 12)) 5 (float 0))
((3.0 5.0 7.0 9.0 12.0) (5) (36.0))
Since there were three arguments to call-cfun, it returns a list with three elements; the first two are just the input arguments which were not changed by the C function, and the last contains the answer. To store the answer in an xlisp-stat variable for future use, you can surround the call-cfun call with the select function. For example, if we wanted to create an xlisp-stat variable called sumx to hold the result of the previous call to sum, we would call call-cfun as follows:
> (def sumx (select (call-cfun "sum" (float '(3 5 7 9 12)) 5 (float 0)) 2))
SUMX
> sumx
(36.0)

Phil Spector
Wed Mar 5 16:06:49 PST 1997