Search code examples
common-lispecl

Embeddable Common Lisp (ECL): load shared library with extension functions


Is it possible to load a shared library in ECL, import some C functions which receive and return cl_object (as if they were defined with ecl_def_c_function()) and invoke them in REPL (without compiling a *.lisp file)?

For example:

// file 'extensions.c' compiled to 'extensions.so'

cl_object
    do_something
        (cl_object arg)
{
    cl_object
        result = ...;

    return result;
}

; in ECL REPL
(uffi:load-foreign-library #p".../extensions.so")
... ; importing stuff
(format t "got: ~a~%" (do-something "text"))

As I found there's no way of telling ECL (via UFFI) that C functions deal with cl_object, not a regular pointer (void*).


Solution

  • Looks like you can't do it as easy as in Python. The only solution I found so far:

    extlib.c

    #include <stdio.h>
    #include <ecl/ecl.h>
    
    static
    cl_object
        make_pair
            (cl_object arg)
    {
        return cl_cons(arg, arg);
    }
    
    void
        init_extlib
            (void)
    {
        ecl_def_c_function(
            ecl_read_from_cstring("make-pair"),
            make_pair,
            1
        );
    }
    

    Compile it:

    clang `ecl-config --cflags` extlib.c -shared -fPIC -o extlib.so `ecl-config --libs`
    

    load-extlib.lisp

    (uffi:load-foreign-library "~/extlib.so")
    (uffi:def-function ("init_extlib" init-extlib)
                       ()
                       :returning :void)
    (init-extlib)
    

    Compile it:

    ecl -compile load-extlib.lisp -o load-extlib.fas
    

    Load & test it:

    ecl -load load-extlib.fas
    > (make-pair "blah")
    
    ("blah" . "blah")