Exploring the embedding and interop features of ECL. Continued.
[ Check out all posts in “lisp” series here. ]
The initial integration into a C/C++ library is pretty straightforward:1
- There are various ways to build the lisp code, but I focused on the
asdfbased method. You just add a build rule that’s a few lines long. It triggers
eclto build a (static or shared) library from an ASDF based system you point at.
- As part of the build rule, you also declare an “entry point” to generate. This entry point will be used to initialize the library later.
- On the C/C++ side, you boot ecl, and call the library init function you just created.
- You are now ready to interact with the system.
- While building your C/C++ code, you link against the library you created earlier.
The API that ecl exports is pretty rich. It has:
- C versions of many CL functions, which are
- Functions for interop-related functionality, convenience etc. These are
The naming conventions page in docs have the details.
One interesting concept is the
cl_object, which is the box for CL values. The definition:
typedef union cl_lispunion *cl_object;
Internals are detailed here. The type
cl_lispunion is essentially a tagged
union. But I am planning to start a series on methods used for boxing values in dynamic languages, anyway. So I will move on for now.
cl_object is the input and the return type of most C side APIs. Obviously, the requirement to explicitly generate
cl_objects for values makes it a slightly verbose to use the APIs from C side, but that is expected.
I am currently trying to have a better grasp of the memory management aspect.
While navigating the ECL codebase, I noticed that the
src/c directory is full of files with
.d extension. It took me a while to figure out that these source files are intended to be processed by the tool called “defun preprocessor” (
dpp), which generates the corresponding C sources.
So those files are mostly normal C, with some parts that use special syntax to be expanded by this preprocessor, to C. Here is an example line from “src/c/file.d”:
if (b == @':eof') b = ECL_NIL;
Above expands to a C form:
if (b == ECL_SYM(":EOF",1256)) b = ECL_NIL;
ECL_SYM macro just indexes an array called
cl_symbols using the index (second argument) arg.
Another example: this
defun declaration expands to a function with the prototype below:
cl_object cl_read(cl_narg narg, ...)
Thanks for reading! If you find technical errors, please report in the blog’s Issues page.
At least for the method I focused on. ↩