Calling Lisp Functions from Go Language

Written by on June 10, 2018 in Golang, LISP, Programming with 0 Comments

In the previous post, we saw how to invoke a Go function from Lisp. In today’s post, I would like to explain how to go in the other direction, namely, how to call Lisp functins from Go.

There are two ways to do this. The first approach is to load the Lisp DLL (like any other DLL) in Go and make calls to functions in that DLL. The other, preferred approach, is to use a LIB (“.o”) file to statically bind to the DLL functions. Let me show both the approaches.

Building the Lisp DLL

Let us start with the Lisp side. As in the previous article, I am using LispWorks Lisp (Windows – 64 bit) for the demo. 

Here is a simple function that adds two 64-bit integers and returns the corresponding value:

(fli:define-foreign-callable (“addIntLisp” :language :ansi-c :result-type :int64 :calling-convention :cdecl)

    ( (arg1 :int64) (arg2 :int64) )   

  (+ arg1 arg2))

define-foreign-callable enables a Lisp function to be called from a foreign language, in this case, Go. Let us suppose that this function is defined in the file Exported Functions.lisp. Now we have to compile this function (plus the necessary Lisp runtime) into a DLL.

We create another file called Generate DLL.lisp with the following code:

(in-package “CL-USER”)

(load-all-patches)

(compile-file “Exported Functions.lisp”)

(load “Exported Functions”)

(defun dummy ())

(compile ‘dummy)

(deliver #’dummy “Lisp-functions” 1 :startup-bitmap-file nil :keep-eval t :keep-load-function t :dll-exports ‘(“addIntLisp”))

 (quit)

I urge you to lookup the documentation of deliver function to understand the different parameters. 

We are now ready to generate the DLL. Open a Command prompt and switch to the directory where these two files are located. Then run:

>  “C:\Program Files\LispWorks7.1\lispworks-7-1-0-x64-windows.exe” -build “Generate DLL.lisp”

This will result in a file called Lisp-functions.Dll in the current directory. We need this file to use with our Go program.

Using the DLL in Go

Approach-1a (Using the DLL directly):

Here we use syscall.LoadLibrary() function in Go to load our DLL, followed by a call to syscall.GetProcAddress() to get the address of the desired function within the DLL. Finally, we use syscall.Syscall() to call into the loaded function and get the result. See the image below:

Direct DLL Call

Direct DLL Call

You can see a deferred call to a function named QuitLispWorks. This is the recommended way to terminate the LispWorks Lisp runtime as part of unloading the DLL. To run the Go program, do this:

 > go run LispCall.go

Approach-1b (Using the DLL directly):

There is a simpler way to load the DLL and call its functions. This is shown below:

Direct DLL Call 2

Direct DLL Call 2

I wanted to show both approaches for the sake of documentation, but I guess most developers would prefer the simpler variant. To run the Go program, do this:

 > go run LispCall2.go

Approach-2 (Using “.o” file):

If you have the LIB file corresponding to the DLL, along with the C header for the exported functions, then calling Lisp functions via the DLL becomes much easier.

Since LispWorks does not create the LIB file as part of DLL generation, I looked around for some utility to generate the LIB from the DLL. Fortunately, I remembered that Embarcadero’s RAD Studio comes with implib utility, so I used it thus:

> implib Lisp-functions.o Lisp-functions.dll

Note that the LIB file is named “.o” for compatibility with Go build system.

I then created the Header file manually:

#ifndef __LISP_FUNCTIONS_H__

#define __LISP_FUNCTIONS_H__

long addIntLisp(long arg1, long arg2);

int __stdcall QuitLispWorks(int Force , int MilliTimeOut);

#endif

Here is the Go program (LispCall3.go) that calls the Lisp function:

Lisp Call via LIB

Lisp Call via LIB

Take note of the comments before import “C”. These are required.

For the second approach, we have the following files:

– Lisp-functions.dll

– Lisp-functions.o

– Lisp-functions.h

– LispCall3.go

To build the Go executable from these files, run:

> go build LispCall3.go

This creates LispCall3.exe. We have to distribute our DLL along with the executable if we are planning to run the program elsewhere. To run the program, enter:

 > LispCall3

Lisp addInt: 300

Good, the program works as expected! That completes today’s discussion on how to call LispWorks Lisp functions from Go. You can download the relevant files here.

Although I have not tried, I think the procedure should be similar for other Lisp environments on Windows.

Hope you found today’s post useful.

Tags: , ,

Subscribe

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.

Top