The following example shows how to use the FLI to call a C function. The function to interface with, FahrenheitToCelsius
, takes one integer as its argument (the temperature in Fahrenheit) and returns the result as a single float (the temperature in Celsius).
The example consists of three stages: defining a foreign language interface to the C function, loading the foreign code into the Lisp image, and calling the C function to obtain the results.
The FLI provides the macro define-foreign-function for creating interfaces to foreign functions. It takes the name of the function you wish to interface to, the argument types the function accepts, and the result type the function returns.
Given the following C declaration to FahrenheitToCelsius
:
float FahrenheitToCelsius( int );
The FLI interface is as follows:
(fli:define-foreign-function
(fahrenheit-to-celsius "FahrenheitToCelsius" :source)
((fahrenheit :int))
:result-type :float
:language :ansi-c
)
The first argument to define-foreign-function declares that fahrenheit-to-celsius
is the name of the Lisp function that is generated to interface with the C function FahrenheitToCelsius
. The :source
keyword is a directive to define-foreign-function that FahrenheitToCelsius
is the name of the C function as seen in the source files. On some platforms the actual symbol name available in the foreign object file we are interfacing with could include character prefixes such as ".
" and "_
", and so the :source
keyword encoding allows you to write cross-platform portable foreign language interfaces.
The second argument to define-foreign-function, ((fahrenheit :int))
, is the argument list for the foreign function. In this case, only one argument is required. The first part of each argument descriptor is the lambda argument name. The rest of the argument describes the type of argument we are trying to interface to and how the conversion from Lisp to C is performed. In this case the foreign type :int
specifies that we are interfacing between a Lisp integer and a C type "int".
The :result-type
keyword tells us that the conversion required between the C function and Lisp uses the foreign type :float
. This tells Lisp that C will return a result of type "float", which needs to be converted to a Lisp single-float.
The final keyword argument, :language
, specifies which language the foreign function was written in. In this case the example uses ANSI C. This keyword determines how single-floating point values are passed to and returned from C functions as described for define-foreign-function.
Once an interface has been created, the object code defining those functions (and indeed any variables) must be made available to LispWorks.
LispWorks for Windows can load Windows Dynamic Link Libraries (.DLL
files).
LispWorks for Linux, LispWorks for x86/x64 Solaris and LispWorks for FreeBSD can load shared libraries (typically .so
files).
LispWorks for Macintosh can load Mach-O dynamically-linked shared libraries (typically .dylib
files).
LispWorks for AIX can load shared libraries such as /usr/lib/libz.a
.
LispWorks for UNIX can either load object files (usually suffixed with ".o
") directly into the Lisp image, extract any required object files from the available archive libraries (usually suffixed with ".a
"), or load in shared libraries (usually suffixed with ".so
").
Throughout this manual we shall refer to these dynamic libraries as DLLs.
On all platforms the function register-module is the main LispWorks interface to DLL files. It is used to specify which DLLs are looked up when searching for foreign symbols. Here are example forms to register a connection to a DLL.
(fli:register-module "MYDLL.DLL")
(fli:register-module "mylib.so")
(fli:register-module "mylib.dylib")
(fli:register-module "mylib.a")
Note: LispWorks for UNIX also provides the loader function link-load:read-foreign-modules
familiar to users of LispWorks 4.3 and earlier. However, this is now deprecated in favor of register-module.
Note: It is also possible to embed a DLL in the Lisp image. See Incorporating a foreign module into a LispWorks image.
Calling the foreign code is the simplest part of using the FLI. The interface to the C function, defined using define-foreign-function, is called like any other Lisp function. In our example, the fahrenheit-to-celsius
function takes the temperature in Fahrenheit as its only argument, and returns the temperature in Celsius.
LispWorks Foreign Language Interface User Guide and Reference Manual - 29 Sep 2017