Re: Calling Lisp from C (SBCL as a shared object)

"J. Gareth Williams" <[email protected]> Sun, 19 Jan 2025 12:13:22 -0500
Newsgroups gmane.lisp.steel-bank.general
Message-ID <CALfqwArxAmvhEO9H3M+TkXaAw-wXNDNMjJn7+t1YwFq8WCUsvA@mail.gmail.com>
This did indeed work.  Thanks for your help, Christopher, et al! (Now to
grok what makes yours work...)

On Sat, Jan 18, 2025 at 4:21 PM Christopher Wicklein <[email protected]>
wrote:

> J.,
>
> I also had a bit of trouble getting a C program to call a function
> exported by Lisp.  I ultimately wrote this example for myself (based on
> references cited in README.md) of a Lisp function which is called from C
> to sum two signed integers and return the result by pointer (the sum
> function's return value is used to indicate success or failure.). I
> primarily work on macOS with SBCL 2.5.0, but I've tested this example on
> Debian 12.9 with SBCL 2.5.0 built from source (sh make.sh ; make -C
> src/runtime libsbcl.so), and it seems to work fine on that system, too.
>
> me@debian:~/common-lisp-shared-library$ *export LD_LIBRARY_PATH=.*
> me@debian:~/common-lisp-shared-library$ *make*
> gcc -c -o example.o example.c
> gcc -c -o libsum.o libsum.c
> /home/me/sbcl-2.5.0/run-sbcl.sh --noinform --script sum.lisp
> cp -a /home/me/sbcl-2.5.0/src/runtime/libsbcl.so .
> gcc -shared -o libsum.so libsum.o -L. -lsbcl
> gcc -o example example.o -L. -lsum
> me@debian:~/common-lisp-shared-library$ *./example*
> The sum of 2 and 3 is 5.
> me@debian:~/common-lisp-shared-library$
>
> me@debian:~/common-lisp-shared-library$ *for x in *; do printf
> "################\n# %s\n################\n\n" "$x"; cat "$x"; printf "\n";
> done*
> ################
> # example.c
> ################
>
> #include <stdio.h>
>
> #include "libsum.h"
>
> int
> main(int argc, char **argv) {
>   int a = 2, b = 3, result;
>
>   if (init_example() != 0) {
>     fprintf(stderr, "Failed to initialize Lisp!\n");
>     return 1;
>   }
>
>   /* The C compiler enforces the declaration of sum in libsum.h, but
>      that declaration must be correct, i.e. comport with the callable
>      produced by Lisp.  In writing this example, I had trouble with
>      SBCL's signed apparently not being the same as int and the
>      variables a and/or b being corrupted on the stack. */
>   if (sum(a, b, &result) != 0) {
>     fprintf(stderr, "The sum function failed!\n");
>     return 1;
>   }
>
>   printf("The sum of %d and %d is %d.\n", a, b, result);
>   return 0;
> }
>
>
> ################
> # libsum.c
> ################
>
> #include "libsum.h"
>
> /* Declare the function exported by SBCL (built as a shared library)
>    to initialize the Lisp runtime. */
> extern int initialize_lisp(int argc, char **argv);
>
> /* Defined here, this function pointer is initialized by calling
>    initialize_lisp. */
> int (*sum)(int, int, int *);
>
> /* Initialize the Lisp runtime by calling initialize_lisp which takes
>    the same arguments as the SBCL executable (argc, argv, and
>    optionally, envp.) The first element of argv (i.e. argv[0]) is an
>    empty string.  The argument --core is provided to specify a
>    non-default core to use, and --noinform is provided to suppress
>    printing a banner or other informational messages at start up. */
> int
> init_example() {
>   static int once = 0;
>   char *init_args[] = {"", "--core", "libsum.core", "--noinform"};
>
>   if (once) {
>     return 1;
>   }
>
>   if (initialize_lisp(4, init_args) != 0) {
>     return -1;
>   }
>
>   once = 1;
>   return 0;
> }
>
> ################
> # libsum.h
> ################
>
> #ifndef _libsum_h
> #define _libsum_h
>
> /* Declare a pointer to our function which adds signed integers. */
> extern int (*sum)(int, int, int *);
>
> /* Declare our function which calls initialize_lisp. */
> extern int init_example();
>
> #endif
>
> ################
> # Makefile
> ################
>
> .PHONY : all
> all : example
>
> SBCL_HOME := $(HOME)/sbcl-2.5.0
>
> %.o : %.c
>         gcc -c -o $@ $<
>
> libsbcl.so : $(SBCL_HOME)/src/runtime/libsbcl.so
>         cp -a $(SBCL_HOME)/src/runtime/libsbcl.so .
>
> libsum.core : sum.lisp
>         $(SBCL_HOME)/run-sbcl.sh --noinform --script sum.lisp
>
> libsum.o : libsum.c
>
> libsum.so : libsum.o libsum.core libsbcl.so
>         gcc -shared -o libsum.so libsum.o -L. -lsbcl
>
> example.o : example.c
>
> example : example.o libsum.so
>         gcc -o example example.o -L. -lsum
>
> .PHONY : clean
> clean :
>         rm -f *.o *.core *.so example *~
>
> ################
> # README.md
> ################
>
> # common-lisp-shared-library
>
> This is a trivial example of a shared library written in Common Lisp
> (SBCL.)
>
> References include [this blog post](
> https://mstmetent.blogspot.com/2022/04/using-lisp-libraries-from-other.html),
> [40ants/sbcl-shared-library-examples](
> https://github.com/40ants/sbcl-shared-library-examples), the delivery
> tool [quil-lang/sbcl-librarian](
> https://github.com/quil-lang/sbcl-librarian), and the SBCL user manual.
>
> A consideration missing from this example is coordinating the effects of
> garbage collection by SBCL on objects which cross the foreign function
> boundary.
>
> ################
> # sum.lisp
> ################
>
> (define-alien-callable sum int ((a int) (b int) (result (* int)))
>   "Sum the (integer) arguments A and B, store the result in
> *RESULT, and return 0 on success, 1 on any condition."
>   (handler-case
>       (progn
>         (setf (deref result) (+ a b))
>         0)
>     (t (condition) (declare (ignore condition)) 1)))
>
> ;; Save the Lisp core.  A C program can initialize the Lisp runtime
> ;; and the symbol sum by calling initialize_lisp which is exported by
> ;; libsbcl.so.
> (save-lisp-and-die "libsum.core" :callable-exports '(sum))
>
> me@debian:~/common-lisp-shared-library$
>
> On Sat, Jan 18, 2025 at 7:28 AM J. Gareth Williams <[email protected]>
> wrote:
>
>> Hi Robert,
>>
>> Appreciate the reply and suggestion! -- but I did try that -- per the
>> example in the Cookbook -- and I had pretty much the same result.   Same
>> with the example at https://github.com/svetlyak40wt/sbcl-lib.
>>
>> As soon as I have a non-NIL argument for :callable-exports in the
>> SAVE-LISP-AND-DIE call, it fails to initialize.  I've tried with different
>> call signatures and return values to no avail.
>>
>> There was a message in sbcl-bugs this September that raised the same
>> issue:
>>
>>     https://sourceforge.net/p/sbcl/mailman/message/58822085/
>>
>> Can anyone confirm they're using this successfully on recent SBCL on
>> Linux?  Ideally recent Debian?
>>
>> Thanks again, Robert.
>>
>> Gareth
>>
>>
>> On Sat, Jan 18, 2025, 4:34 a.m. Robert Smith <[email protected]> wrote:
>>
>>> Try SBCL-LIBRARIAN:
>>>
>>> https://github.com/quil-lang/sbcl-librarian
>>>
>>> https://lispcookbook.github.io/cl-cookbook/dynamic-libraries.html
>>>
>>> Robert
>>>
>>>
>>>
>>> On Fri, Jan 17, 2025 at 21:02 J. Gareth Williams <[email protected]>
>>> wrote:
>>>
>>>> Hi,
>>>>
>>>> I have been struggling to get even a trivial example of
>>>> DEFINE-ALIEN-CALLABLE to work, and was wondering if anyone could take a
>>>> look at what I might be doing wrong.
>>>>
>>>> Full source:
>>>>     git clone
>>>> https://gitlab.com/garethw14/simple-sbcl-alien-callable.git
>>>>
>>>> It compiles okay and links, but on initialize_lisp(), I land in the
>>>> debugger:
>>>>
>>>> ---
>>>> In main, about to initialize_lisp()
>>>>
>>>> debugger invoked on a SB-KERNEL::UNDEFINED-ALIEN-VARIABLE-ERROR in
>>>> thread
>>>> #<THREAD "main thread" RUNNING {10013A8003}>:
>>>>
>>>> *  Attempt to access an undefined alien variable.*
>>>> Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.
>>>>
>>>> restarts (invokable by number or by possibly-abbreviated name):
>>>>   0: [ABORT] Exit from the current thread.
>>>>
>>>> ("foreign function: call_into_lisp_")
>>>> 0]
>>>> ---
>>>>
>>>> I've tried some other examples I've found around the web, but they seem
>>>> to yield the same result.
>>>>
>>>> Tested on Debian 12.9, SBCL versions 2.5.0 and 2.3.2
>>>>
>>>> Would appreciate any insight!
>>>>
>>>> gareth
>>>>
>>>>
>>>>
>>>> _______________________________________________
>>>> Sbcl-help mailing list
>>>> [email protected]
>>>> https://lists.sourceforge.net/lists/listinfo/sbcl-help
>>>>
>>> _______________________________________________
>> Sbcl-help mailing list
>> [email protected]
>> https://lists.sourceforge.net/lists/listinfo/sbcl-help
>>
>
>
> --
> Christopher Wicklein <[email protected]>
>

_______________________________________________
Sbcl-help mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/sbcl-help