Calling External DLL Functions from Julia

Written by on February 16, 2023 in Julia, LISP, Programming with 0 Comments

Julia supports calling external functions, especially those written in “C” language. As Julia documentation says, such calls do not involve any “boilerplate” code and hence are efficient. In today’s article, I am going to show how to call functions defined in a DLL (Windows 64 bit). Instead of using direct “C” functions, I will discuss how to compile LispWorks Lisp code into a DLL and then interface it with Julia.

My environment:

1) Windows 10 (64 bit)
2) LispWorks Enterprise Edition 8.0.1 (64 bit, for Windows)

Let us start with the Lisp code first. I have written a function “lispEval” that takes a string, evaluates it as a sequence of S-Expressions and returns the result as a string. It uses LispWorks “FLI” package. Here is the code:

The "lispEval" Function

The “lispEval” Function

To make the Julia interaction more interesting, I have defined another Lisp function “juliaCallBack”, which takes a “pointer” to a Julia function and then calls it with two integer arguments. The Julia function is expected to return an integer, which is then returned as it is from the Lisp function. Nothing fancy here, except that this allows 2-way communication between Lisp and Julia. Here is the second function:

The "juliaCallBack" Function

The “juliaCallBack” Function

Both the functions are exported from the Lisp code.

Exporting the Functions from Lisp DLL

Exporting the Functions from Lisp DLL

Now, to compile this Lisp code and generate the DLL, we execute the following command on Windows prompt:

CMD>”G:\Program Files\LispWorks8\lispworks-8-0-0-x64-windows.exe” -build lisp-call.lisp

This completes the DLL creation. Next, we copy the DLL to the Julia project directory so that it is accessible from our Julia environment.

I have already installed Julia 1.8.5 on my Windows machine. It includes “IJulia” package that allows me to work conveniently with JupyterLab IDE. Here is how I launch it:

Launching JupyterLab IDE

Launching JupyterLab IDE

The notebook interface provides an interactive session with Julia. First we need to open the Lisp DLL and bind a variable to the “lispEval” function in the DLL. The Julia function by the same name, defined in cell [5], acts as a wrapper by allocating the required buffer and passing it to Lisp.

Calling the Lisp Function

Calling the Lisp Function 

Cells [6] and [7] show that when the DLL function “lispEval” is called with a string representing an S-Expression, we get the corresponding answer as a string.

The second example shows the other Lisp function “juliaCallBack” in action.

Testing the "juliaCallBack" Function

Testing the “juliaCallBack” Function

As before, we need to bind the DLL function to a Julia variable. Then we define a Julia function “fooBar” whose pointer will be passed to the Lisp function. We need to use the “@cfunction” macro to generate a c-callable function pointer from a Julia function. The “testCallBack” function is a simple wrapper around the underlying “ccall”. Cells [12] and [13] show that the call works correctly.

Just to make sure that the Lisp call back is general enough, let us define another Julia function “findMax”, whose pointer will be passed to the Lisp function.

Another Callback Function

Another Callback Function

The cells [16] and [17] show that this also works as expected.

As the above examples demonstrate, calling external functions available in shared libraries is straightforward. You can download the Lisp code from here. The “Jupyterlab” notebook is available here.

Have a nice day and a great weekend!

Tags: , , ,


If you enjoyed this article, subscribe now to receive more just like it.

Subscribe via RSS Feed

Leave a Reply

Your email address will not be published. Required fields are marked *