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

define-foreign-function Macro

Summary

Defines a Lisp function which acts as an interface to a foreign function.

Package

fli

Signature

define-foreign-function name ({arg}*) &key lambda-list documentation result-type result-pointer language no-check calling-convention module variadic-num-of-fixed => lisp-name

name ::= lisp-name | (lisp-name foreign-name [encoding])

encoding ::= :source | :object | :lisp | :dbcs

arg ::= arg-name | (arg-name arg-type) | (:constant value value-type) | &optional | &key | ((arg-name default) arg-type) | (:ignore arg-type)

language ::= :c | :ansi-c

Arguments
lambda-list
The lambda list to be used for the defined Lisp function.
documentation
A string.
result-type
A foreign type.
result-pointer
The name of the keyword argument that is added to the lambda-list of the Lisp function when result-type is an aggregate type.
language
The language in which the foreign source code is written. The default is :ansi-c.
no-check
A boolean.
calling-convention
Specifies the calling convention used.
module
A symbol or string naming the module in which the foreign symbol is defined.
variadic-num-of-fixed
nil or a non-negative integer.
lisp-name
A symbol naming the defined Lisp function.
foreign-name
A string or a symbol specifying the foreign name of the function.
arg-name
A variable.
arg-type
A foreign type name.
value
A Lisp object.
value-type
A foreign type name.
default
A Lisp object.
Values
lisp-name
A symbol naming the defined Lisp function.
Description

The macro define-foreign-function defines a Lisp function lisp-name which acts as an interface to a foreign language function, for example a C function. When the Lisp function is called its arguments are converted to the appropriate foreign representation before being passed to the specified foreign function. Once the foreign function exits, any return values are converted back from the foreign format into a Lisp format.

encoding specifies how lisp-name is translated into the function name in the foreign object code. Its values are interpreted as follows:

:source
foreign-name is the name of the function in the foreign source code. This is the default value of encoding 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 encoding 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.

The number and types of the arguments of lisp-name must be given. Lisp arguments may take any name, but the types must be accurately specified and listed in the same order as in the foreign function, unless otherwise specified using lambda-list.

If arg is a symbol arg-name, then define-foreign-function assumes that it is of type :int. Otherwise arg-type or value-type specifies the foreign type of the argument.

If arg is of the form (:constant value value-type) then value is always passed through to the foreign code, and arg is omitted from the lambda list of lisp-name.

If arg is &optional or &key, then the lambda list of the Lisp function lisp-name will contain these lambda-list-keywords too. Any argument following &optional or &key can use the
((arg-name default) arg-type) syntax to provide a default value default for arg-name.

If arg is of the form (:ignore arg-type) then nil is always passed through to the foreign code and arg is omitted from the lambda list of lisp-name. This is generally only useful when arg-type is a :reference-return type, where the value nil will be ignored.

If documentation is supplied then it is set as the function documentation for lisp-name.

When language is :ansi-c the foreign code is expected to be written in ANSI C. In particular single floats are passed through as single-floats whereas language :c causes them to be passed through as double floats. Similarly :c causes double floats to be returned from C and :ansi-c causes a single-floats to be returned. In both cases the type returned to Lisp is determined by result-type.

If no-check is nil, then the types of the arguments provided when lisp-name is called are compared with the expected types 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. If the compilation safety level is set to 0 then no-check defaults to t, otherwise it defaults to nil.

lambda-list allows you to define the order in which the Lisp function lisp-name takes its arguments to be different from the order in which the foreign function takes them, and to use standard lambda list keywords such as &optional even if they do not appear in args. If lambda-list is not supplied, the lambda list of lisp-name is generated from the list of args.

If arg-type is a struct then the value arg-name can be either a foreign struct object or a pointer to a foreign struct object.

The :reference, :reference-pass and :reference-return types are useful with define-foreign-function. It is fairly common for a C function to return a value by setting the contents of an argument passed by reference (that is, as a pointer). This can be handled conveniently by using the :reference-return type, which dynamically allocates memory for the return value and passes a pointer to the C function. On return, the pointer is dereferenced and the value is returned as an extra multiple value from the Lisp function.

The :reference-pass type can be used to automatically construct an extra level of pointer for an argument. No extra results are returned.

The :reference type is like :reference-return but allows the initial value of the reference argument to be set.

result-type optionally specifies the type of the foreign function's return value. When result-type is an aggregate type, an additional keyword argument is placed in the lambda-list of the Lisp function. This keyword is named after result-pointer or is called :result-pointer if unspecified. When calling the Lisp function, a foreign pointer must be supplied as the value of this keyword argument, pointing to an object of type result-type. The result of the foreign call is written into this object and the foreign pointer is returned as the primary value from the Lisp function. This allows the caller to maintain control over the lifetime of this object (in C this would typically be stored in a local variable). If result-type is :void or is omitted, then no value is returned.

calling-convention is ignored on some platforms, 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.

On 32-bit x86 platforms (including 32-bit Windows), the :fastcall calling convention can be use (see 4.2.4 Fastcall on 32-bit x86 platforms for details).

If module is the name of a module registered using register-module then that module is used to look up the symbol. Otherwise module should be a string, and a module named module is automatically registered and used to look up the symbol. Such automatically-registered modules have connection-style :manual - this prevents them being used by other define-foreign-function forms which do not specify a module.

When variadic-num-of-fixed a non-negative integer, it specifies that the foreign function that it is calling is variadic (like printf). The integer must be the number of fixed arguments that the foreign function takes. For printf, for example, you need to pass :variadic-num-of-fixed 1, and for sprintf you need :variadic-num-of-fixed 2. When variadic-num-of-fixed is nil (the default), then the function is specified to be not variadic. Calls to variadic function without using variadic-num-of-fixed work on some platforms, but not all. Thus you should always use it when calling variadic functions.

Compatibility notes

In LispWorks 4.4 and previous versions, the default value for language is :c. In LispWorks 5.0 and later, the default value is :ansi-c.

The :fastcall calling-convention was added in LispWorks 7.1.

variadic-num-of-fixed was added in LispWorks 7.1.

Examples

A simple example of the use of define-foreign-function is given in 1.2.2 Defining a FLI function. More detailed examples are given in 5 Advanced Uses of the FLI.

Here is an example using the :reference-return type.

Non-Windows version:

int cfloor(int x, int y, int *remainder)
{
  int quotient = x/y;
  *remainder = x - y*quotient;
  return quotient;
}

Windows version:

__declspec(dllexport) int __cdecl cfloor(int x, int y, int *remainder)
{
  int quotient = x/y;
  *remainder = x - y*quotient;
  return quotient;
}

In this foreign function definition the main result is the quotient and the second return value is the remainder:

(fli:define-foreign-function cfloor 
    ((x :int) 
     (y :int) 
     (rem (:reference-return :int)))
 :result-type :int)
 
(cfloor 11 5 t)
=> 
2,1

This example illustrates a use of the lambda list keyword &optional and a default value for the optional argument:

(define-foreign-function one-or-two-ints
    ((arg-one :int)
     &optional
     ((arg-two 42) :int)))

The call (one-or-two-ints 1 2) passes 1 and 2.

The call (one-or-two-ints 1) passes 1 and 42.

See also

define-foreign-callable
define-foreign-funcallable
define-foreign-variable
register-module
4 Defining foreign functions and callables


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