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