All Manuals > Foreign Language Interface User Guide and Reference Manual > 7 Function, Macro and Variable Reference

define-foreign-callable Macro

Summary

Defines a Lisp function which can be called from a foreign language.

Package

fli

Signature

define-foreign-callable (foreign-name &key encode language result-type result-pointer no-check calling-convention) ({arg}*) &body body => lisp-name

arg ::= arg-name | (arg-name arg-type)

language ::= :c | :ansi-c

Arguments
foreign-name
A string or symbol naming the Lisp callable function created.
encode
One of :source, :object, :lisp or dbcs.
language
The language in which the foreign calling code is written. The default is :ansi-c.
result-type
The FLI type of the Lisp foreign callable function's return value which is passed back to the calling code.
result-pointer
A variable which will be bound to a foreign pointer into which the result should be written when the result-type is an aggregate type.
no-check
A boolean.
calling-convention
Specifies the calling convention used on Windows and ARM.
arg
The arguments of the Lisp foreign callable function. Each argument can consist either of an arg-name, in which case LispWorks assumes it is an :int, or an arg-name and an arg-type, which is a FLI type.
body
A list of forms which make up the Lisp foreign callable function.
arg-name
A Lisp symbol.
arg-type
A FLI type.
Values
lisp-name
A string or symbol naming the Lisp callable function created.
Description

The macro define-foreign-callable defines a Lisp function that can be called from a foreign language, for example from a C function. When the C function is called, data passed to it is converted to the appropriate FLI representation, which is translated to an appropriate Lisp representation for the Lisp part of the function. Once the callable function exits, any return values are converted back into a FLI format to be passed back to the calling language.

When you use :reference with :lisp-to-foreign-p t as an arg-type, you need to set arg-name to the value that you want to return in that reference. That value is then converted and stored into the pointer supplied by the calling foreign function. This is done after the visible body of your define-foreign-callable form returns.

If no-check is nil, the result of the foreign callable function, produced by body, is checked to see if matches result-type, and an error is raised if they do not match. If no-check is t then this check is not done and the effect will be undefined if the types do not match.

calling-convention is ignored on platforms other than Windows and ARM, where there is no calling convention issue. On 32-bit Windows, :stdcall is the calling convention used to call Win32 API functions and matches the C declarator "__stdcall". This is the default value. :cdecl is the default calling convention for C/C++ programs and matches the C declarator "__cdecl". See 4.2.1 Windows 32-bit calling conventions for details.

On ARM platforms, there is also more than one calling convention, but normally you do not need to specify it. See 4.2.2 ARM 32-bit calling conventions and 4.2.3 ARM 64-bit calling conventions for details.

When result-type is an aggregate type, an additional variable is bound in the body to allow the value of the function to be returned (the value returned by the body is ignored). This argument is named after result-pointer or is named result-pointer in the current package if unspecified. While the body is executing, the variable will be bound to a foreign pointer that points to an object of the type result-type. The body must set the slots in this foreign object in order for the value to be returned to the caller.

To make a function pointer referencing a foreign callable named "Foo", use:

(make-pointer :symbol-name "Foo")

By default, LispWorks performs automatic name encoding to translate foreign-name. If you want to explicitly specify an encoding, encode can be one of the following:

:source
foreign-name is the name of the function in the foreign source code. This is the default value of encode when foreign-name is a string.
:object
foreign-name is the literal name of the function in the foreign object code.
:lisp
If foreign-name is a Lisp symbol, it must be translated and encoded. This is the default value of encode if foreign-name is a symbol.
:dbcs
A suffix is automatically appended to the function name depending on the Windows operating system that LispWorks runs in. The suffix is "A" for Windows 95-based systems and "W" for Windows NT-based systems.
Notes
  1. For a delivered application where the string name of your foreign callable is not passed in dll-exports, be aware that a call to make-pointer like that above will not retain the foreign callable in a delivered application. Internally a Lisp symbol named |%FOREIGN-CALLABLE/Foo| is used so you could retain that explicitly (see the Delivery User Guide for details, and take care to specify the package). However it is simpler to name the foreign callable with your Lisp symbol, and pass that to make-pointer. This call will keep your foreign callable in the delivered application:
    (make-pointer :symbol-name 'foo :functionp t)
    
  2. If you specify any of the FLI float types :float, :double, :lisp-float, :lisp-single-float and so on, then the value of language should be :ansi-c.
Compatibility note

64-bit integer types such as (:long :long), :int64 and :uint64 are now supported for arg-type in define-foreign-callable in 32-bit LispWorks. In 32-bit LispWorks 6.1 and earlier versions, these types could only be used by define-foreign-function.

Examples

The following example demonstrates the use of foreign callable. A foreign callable function, square, is defined, which takes an integer as its argument, and returns the square of the integer.

(fli:define-foreign-callable 
  ("square" :result-type :int)
  ((arg-1 :int)) (* arg-1 arg-1))

The foreign callable function, square, can now be called from a foreign language. We can mimic a foreign call by using the define-foreign-function macro to define a FLI function to call square.

(fli:define-foreign-function (call-two "square")
  ((in-arg :int)) :result-type :int)

The call-two function can now be used to call square. The next command is an example of this.

(call-two 9)

This last example shows how the address of a foreign callable can be passed via a pointer object, which is how you use foreign callables in practice. The foreign library in this example is libgsl:

(fli:define-foreign-callable ("gsl-error-handler")
    ((reason (:reference-return :ef-mb-string))
     (file (:reference-return :ef-mb-string))
     (lineno :integer)
     (gsl-errno :integer))
  (error 
   "Error number ~a inside GSL [file: ~a, lineno ~a]: ~a"
   gsl-errno file lineno reason))
(fli:define-foreign-function gsl-set-error-handler 
    ((func :pointer))
  :result-type :pointer)

To set the error handler, you would do:

(gsl-set-error-handler 
 (fli:make-pointer :symbol-name "gsl-error-handler"))
See also

define-foreign-function
define-foreign-variable
make-pointer
4 Defining foreign functions and callables
5.7.2 Operations on foreign blocks


Foreign Language Interface User Guide and Reference Manual - 01 Dec 2021 19:34:58