Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

using compiled ecl functions/objects from C code

509 views
Skip to first unread message

Eric Schulte

unread,
Jun 21, 2011, 7:13:40 PM6/21/11
to
Hi,

I've written a common lisp library for reading/manipulating/writing ELF
files [1], and now I need to use this library from C code. Using ecl I
was able to fairly easily compile the ASDF package into a static library
by following the instructions on the ecl wiki [2]. I now have no idea
how to use this code from a C file, for example how would one call a
lisp function, or instantiate a pointer to an object defined in the
compiled lisp library?

Could anyone point me to documentation or examples of how this could be
done?

Thanks -- Eric

Footnotes:
[1] http://gitweb.adaptive.cs.unm.edu/elf.git

[2] http://ecls.wikispaces.com/Easier+Embedding

Rob Warnock

unread,
Jun 21, 2011, 8:24:54 PM6/21/11
to
Eric Schulte <schult...@gmail.com> wrote:
+---------------

| I've written a common lisp library for reading/manipulating/writing ELF
| files [1], and now I need to use this library from C code. Using ecl I
| was able to fairly easily compile the ASDF package into a static library
| by following the instructions on the ecl wiki [2]. I now have no idea
| how to use this code from a C file, for example how would one call a
| lisp function, or instantiate a pointer to an object defined in the
| compiled lisp library?
|
| Could anyone point me to documentation or examples of how this could be
| done?
...+---------------

While not an ECL user myself, I suspect you're very close.
As it says here:

http://ecls.wikispaces.com/C+and+lisp+conversion+functions
C and lisp conversion functions
All about interacting with lisp code from c!
...
[Note: You must #include <ecl/ecl.h> and link with libecl.so for
most of these. Also look in external.h where most of these are
declared. Most macros that are uppercase and deal with objects
are in object.h (SYMBOLP)]

And you must initialize ("boot") ECL before calling into it, see [4]:

http://ecls.wikispaces.com/Simple+embedded+usage
Simple embedded usage
When embedding ECL into C program, the CL environment must be
booted before first use, and shutdown when it is finished with.

#include <ecl/ecl.h>

int main(int argc, char **argv) {
cl_boot(argc, argv);
cl_object obj=c_string_to_object("\"Hello world\"");
cl_pprint(1,obj);
cl_shutdown();
}

For MSVC, the program must be linked against ecl.lib. The ecl.dll
is linked against the mutlithreaded release runtime, for both debug
and release builds of ecl.

[On Linux, you will have compiled your C program with "-lecl",
see <http://ecls.wikispaces.com/Linux>, so "libecl.so" will be
dynamically linked when your C program starts up.]


-Rob

-----
Rob Warnock <rp...@rpw3.org>
627 26th Avenue <http://rpw3.org/>
San Mateo, CA 94403

Polos Ruetz

unread,
Jun 22, 2011, 3:27:37 AM6/22/11
to
On 22 Giu, 01:13, Eric Schulte <schulte.e...@gmail.com> wrote:
> Could anyone point me to documentation or examples of how this could be
> done?

An example of something similar can be found here:
(shameless plug to EQL, Embedded Qt Lisp)

http://gitorious.org/eql/eql/trees/master/src

Some functions are defined in lisp/ini.lisp (e.g. %GET-FUNCTION),
compiled to a library (see make-eql-lib.lisp), and then called from C+
+ (see ecl_fun.cpp).

Paul

Message has been deleted

Francogrex

unread,
Jun 22, 2011, 1:05:05 PM6/22/11
to
On Jun 22, 1:13 am, Eric Schulte <schulte.e...@gmail.com> wrote:
> I've written a common lisp library for reading/manipulating/writing ELF
> files [1], and now I need to use this library from C code.  Using ecl I
> was able to fairly easily compile the ASDF package into a static library
> by following the instructions on the ecl wiki [2].  I now have no idea
> how to use this code from a C file, for example how would one call a
> lisp function, or instantiate a pointer to an object defined in the
> compiled lisp library?

I've written you an example in a previous post but google 'swallowed'
it (maybe it will reappear again later, who knows) here is the essence
of it again:

I don't think you can 'directly" call lisp functions without a little
bit of preparations first.

Start with a lisp file where your function(s) is/are:
;;test.lisp
(defun add (x y) (+ x y))

Compile it and output the needed files as such:
(compile-file "c:/test.lisp" :c-file t :h-file t :data-file t)

Your c file will look something like this:

#include "c:/test.c" // this contains the lisp functions compiled
above

__declspec (dllexport) double output (double x, double y)
{
char *s="N";
cl_boot(1, &s);
read_VV(OBJNULL, init_fas_CODE);
cl_object cl_x=ecl_make_doublefloat(x);
cl_object cl_y=ecl_make_doublefloat(y);
cl_object vec = cl_eval(cl_list(3, c_string_to_object("add"), cl_x,
cl_y));
return (ecl_to_float(vec));
}

compile it with all needed info added:
gcc -g -shared library.c -o library.dll -L"c:/ECL" "-Ic:/ECL" -lecl -
lm -lws2_32 -Wl,--enable-auto-import

and now you can test from any application that calls the C. I use CFFI
of course:
(cffi:load-foreign-library "C:/library.dll")
(cffi:defcfun ("output" output) :double (x :double) (y :double))
(output 12.47d0 17.89d0)
> 30.360000610351563d0
etc..

Tell me how it works out for you. HTH

Eric Schulte

unread,
Jun 24, 2011, 2:43:41 PM6/24/11
to
Francogrex <fra...@grex.org> writes:

> On Jun 22, 1:13 am, Eric Schulte <schulte.e...@gmail.com> wrote:

>> I've written a common lisp library for reading/manipulating/writing ELF
>> files [1], and now I need to use this library from C code.  Using ecl I
>> was able to fairly easily compile the ASDF package into a static library
>> by following the instructions on the ecl wiki [2].  I now have no idea
>> how to use this code from a C file, for example how would one call a
>> lisp function, or instantiate a pointer to an object defined in the
>> compiled lisp library?
>> Could anyone point me to documentation or examples of how this could be
>> done?
>

> First a question are you sure you are compile your ASDF as a 'static'
> library, then it must contain all of ECL ~ 5 MB of size. I always
> compile it as a dynamic library (dll). I don't think you can


> 'directly" call lisp functions without a little bit of preparations
> first.
>

No satisfactory answer here, I first tried to build a .dll using the
asdf:make-build command, but during the compilation of libelf.a an error
was thrown [1]. When compiling as a static library no error was thrown.

>
> I'll be happy to give you a simple example; here goes:
>

Thanks for this example, it was illuminating of the degree to which ecl
simply /translates/ into C files with similar structure to the original
lisp. I was able to translate a number of simple files to C and then
compile them to executables, however when I try to use my elf package I
run into problems, for example...

I write the following simple wrapper in wrapper.lisp

(require 'elf)
(in-package :elf)
(defun mem-layout (path) (show-memory-layout (read-elf path)))

compile it to c with

(compile-file "simple.lisp" :c-file t :h-file t :data-file t)

compile that to wrapper.dll with

gcc -g -shared wrapper.c -o wrapper.dll -lecl -fPIC

and then attempt to use that library from a C file do.c with

#include <ecl/ecl.h>
#include "wrapper.eclh"

int main(int argc, char **argv) {
cl_boot(argc, argv);

cl_eval(cl_list(2,
c_string_to_object("mem-layout"),
c_string_to_object("hello64")));
cl_shutdown();
}

however compilation of do.c results in the following error.

wrapper.eclh:11:18: warning: ‘L1mem_layout’ used but never defined
/tmp/cc0izO6R.o:(.rodata+0x18): undefined reference to `L1mem_layout'
collect2: ld returned 1 exit status

I feel that I'm quite close to a working solution, and it seems likely
that I need to explicitly load the mem-layout function, or somehow "step
into" the elf package in my final do.c file, however I have no idea
how/where this should be done.

Any ideas?

Thanks -- Eric

>
> compile it with all needed info added:
> gcc -g -shared library.c -o library.dll -L"c:/ECL" "-Ic:/ECL" -lecl -
> lm -lws2_32 -Wl,--enable-auto-import
>

> and now you can test from any application that calls the C library. I


> use CFFI of course:
> (cffi:load-foreign-library "C:/library.dll")
> (cffi:defcfun ("output" output) :double (x :double) (y :double))
> (output 12.47d0 17.89d0)
>> 30.360000610351563d0
> etc..

Footnotes:
[1] Error compiling elf.lisp as a :dll
--8<---------------cut here---------------start------------->8---
In function COPY-TO-SIMPLE-BASE-STRING, the value of the first argument is
("/home/eschulte/.cache/common-lisp/ecl-11.1.1-f0ace..."
"/home/eschulte/.cache/common-lisp/ecl-11.1.1-f0ace..."
"/home/eschulte/.cache/common-lisp/ecl-11.1.1-f0ace..."
"/home/eschulte/.cache/common-lisp/ecl-11.1.1-f0ace..."
"/home/eschulte/.cache/common-lisp/ecl-11.1.1-f0ace..."
"/home/eschulte/.cache/common-lisp/ecl-11.1.1-f0ace..."
"/home/eschulte/.cache/common-lisp/ecl-11.1.1-f0ace...")
which is not of the expected type STRING
[Condition of type SIMPLE-TYPE-ERROR]
--8<---------------cut here---------------end--------------->8---


Eric Schulte

unread,
Jun 24, 2011, 2:46:30 PM6/24/11
to
Polos Ruetz <polos...@gmail.com> writes:

Thanks for the link Paul, I noticed EQL is also mentioned in some of the
ECL documentation. I tried to parse ecl_fun.cpp, however I was quickly
overwhelmed by the number of new cl_* function names, and a general lack
of any idea as to what was going on.

I believe that my main stumbling block may be centered around loading a
lisp package from within C. If you have any simpler examples of that
process I would be interested to see them.

Thanks -- Eric

Francogrex

unread,
Jun 26, 2011, 1:35:02 AM6/26/11
to
On Jun 24, 8:43 pm, Eric Schulte <eschu...@bagel.i-did-not-set--mail-

host-address--so-tickle-me> wrote:
> No satisfactory answer here, I first tried to build a .dll using the
> asdf:make-build command, but during the compilation of libelf.a an error
> was thrown [1].  When compiling as a static library no error was thrown....

> Thanks for this example, it was illuminating of the degree to which ecl
> simply /translates/ into C files with similar structure to the original
> lisp.  I was able to translate a number of simple files to C and then
> compile them to executables, however when I try to use my elf package I
> run into problems, for example...
>
> I write the following simple wrapper in wrapper.lisp
>
>     (require 'elf)
>     (in-package :elf)
>     (defun mem-layout (path) (show-memory-layout (read-elf path)))
>
> compile it to c with
>
>     (compile-file "simple.lisp" :c-file t :h-file t :data-file t)
>
> compile that to wrapper.dll with
>
>     gcc -g -shared wrapper.c -o wrapper.dll -lecl -fPIC

Please read the example I provided more carefully. What you have tried
shows that you didn't pay attention to many details, especially
inclusion of the "simple.c" in your c program and the "-Ic:/ECL" (and
others) when building the shared library. Before you try your own
codes make sure you can run the provided example successfully.

Eric Schulte

unread,
Jun 26, 2011, 4:59:06 PM6/26/11
to
Francogrex <fra...@grex.org> writes:

Thanks for pointing out where I botched my reproduction of your example.
I tried once more to follow your example staying more faithful to the
original and have indeed had more success (although I am still running
into problems). I had to make a number of small changes to your example
do mainly to the fact that I am not using a windows machine so some
compiler directives to not apply.

In order to successfully compile library.dll I had to remove

__declspec (dllexport)

from the original source file, and I was forced to change the gcc
command from

gcc -g -shared library.c -o library.dll -L"c:/ECL" "-Ic:/ECL" -lecl -lm -lws2_32 -Wl,--enable-auto-import

to

gcc -g -shared library.c -o library.dll -L/usr/local/lib -I/usr/local/lib -lecl -lm -fPIC

I believe these changes are all appropriate given my running on linux
rather than windows.

I am able to load the resulting file using cffi:load-foreign-library,
however upon calling the "output" function, I get the following stream
of warning messages...

CL-USER> (cffi:load-foreign-library "/home/eschulte/Desktop/another/library.dll")
#<a CFFI:FOREIGN-LIBRARY>
CL-USER> (cffi:defcfun ("output" output) :double (x :double) (y :double))
OUTPUT
CL-USER> (output 8.9 7.2)
;;; Warning: Duplicate proclamation for COMPILE
;;; Warning: Duplicate proclamation for COMPILER-MACRO-FUNCTION
;;; Warning: Duplicate proclamation for CONSTANTP
...
ADD ; Evaluation aborted.

followed by an error that the "add" function is undefined.

It seems that somewhere in the translation between operating systems I
have broken your example. Also, I wonder what would be required to use
this library from a short C file, rather than at the ECL repl.

I've been receiving help on the ECL mailing list, and appear to have
found a workable solution.
http://sourceforge.net/mailarchive/forum.php?thread_name=87sjqwz5ah.fsf%40gmail.com&forum_name=ecls-list

Thanks for your help -- Eric

0 new messages