32.3. The Foreign Function Call Facility

Platform Dependent: Many UNIX, Win32 platforms only.

32.3.1. Introduction
32.3.2. Overview
32.3.3. (Foreign) C types
32.3.4. The choice of the C flavor
32.3.5. Foreign variables
32.3.6. Operations on foreign places
32.3.7. Foreign functions
32.3.7.1. Callbacks and memory management
32.3.8. Argument and result passing conventions
32.3.9. Parameter Mode
32.3.10. Examples
32.3.10.1. More examples

List of Examples

32.2. Simple declarations and access
32.3. External C variable and some accesses
32.4. Calling an external function
32.5. Another example for calling an external function
32.6. Accessing cpp macros
32.7. Calling Lisp from C
32.8. Calling Lisp from C dynamically
32.9. Variable size arguments: calling gethostname from CLISP
32.10. Accessing variables in shared libraries
32.11. Controlling validity of resources
32.12. Floating point arrays

32.3.1. Introduction

This facility, also known as “Foreign Language Interface”, allows one to call a function implemented in C from inside CLISP and to do many related things, like inspect and modify foreign memory, define a “callback” (i.e., make a lisp function available to the C world), etc. To use this facility, one writes a foreign function description into an ordinary Lisp file, which is then compiled and loaded as usual; or just evaluates the appropriate form in the read-eval-print loop.

There are two basic ways to do define a foreign function:

  1. Use dlopen and dlsym to get to the location of the function code in a dynamic library. To access this facility, pass the :LIBRARY option to FFI:DEF-CALL-OUT and FFI:DEF-C-VAR.

    Unfortunately, this functionality is not available on some operating systems, and, also, it offers only a part of the foreign functionality: cpp macros and inline functions cannot be accessed this way. On the other hand, this functionality is available in the read-eval-print loop and does not require a C compiler.

  2. Use a somewhat less direct way: when you do not use the :LIBRARY argument, COMPILE-FILE produces a #P".c" file (in addition to a #P".fas" and a #P".lib"). Then you compile (with a C compiler) and link it into CLISP (statically, linking it into lisp.a, or dynamically, loading it into a running CLISP using dlopen and dlsym). This way you can use any functionality your foreign library exports, whether using ordinary functions, inline functions, or cpp macros (see Example 32.6, “Accessing cpp macros”).

All symbols relating to the foreign function interface are exported from the package FFI. To use them, (USE-PACKAGE FFI).

Special FFI forms may appear anywhere in the Lisp file.

32.3.2. Overview

These are the special FFI forms. We have taken a pragmatic approach: the only foreign languages we support for now are C and ANSI C.

Note

Unless specifically noted otherwise, type specification parameters are not evaluated, so that they can be compiled by FFI:PARSE-C-TYPE into the internal format at macroexpansion time.

High-level FFI forms; name is any Lisp SYMBOL; c-name is a STRING

(FFI:DEF-C-TYPE name &OPTIONAL c-type)

This form makes name a shortcut for c-type. Note that c-type may already refer to name. Forward declarations of types are not possible, however.

When c-type is omitted, the type is assumed to be an integer, and its size and signedness are determined at link time, e.g., (FFI:DEF-C-TYPE size_t).

(FFI:DEF-C-VAR name {option}*)

This form defines a FFI:FOREIGN-VARIABLE. name is the Lisp name, a regular Lisp SYMBOL.

Options for FFI:DEF-C-VAR

(:NAME c-name)
specifies the name as seen from C, as a STRING. If not specified, it is derived from the print name of the Lisp name.
(:TYPE c-type)
specifies the variable's foreign type.
(:READ-ONLY BOOLEAN)
If this option is specified and non-NIL, it will be impossible to change the variable's value from within Lisp (using SETQ or similar).
(:ALLOC ALLOCATION)
This option can be either :NONE or :MALLOC-FREE and defaults to :NONE. If it is :MALLOC-FREE, any values of type FFI:C-STRING, FFI:C-PTR, FFI:C-PTR-NULL, FFI:C-ARRAY-PTR within the foreign value are assumed to be pointers to malloc-allocated storage, and when SETQ replaces an old value by a new one, the old storage is freed using free and the new storage allocated using malloc. If it is :NONE, SETQ assumes that the pointers point to good storage (not NULL!) and overwrites the old values by the new ones. This is dangerous (just think of overwriting a string with a longer one or storing some data in a NULL pointer...) and deprecated.
(:LIBRARY name)
Specifies the (optional) dynamic library which contains the variable, the default is set by FFI:DEFAULT-FOREIGN-LIBRARY.
(:VERSION version)
Specifies the (optional) symbol version in the library (therefore, if :VERSION is supplied, :LIBRARY must also be supplied)
(:DOCUMENTATION string)
Specifies the (optional) VARIABLE documentation.
(FFI:DEF-C-CONST name {option}*)

This form defines a Lisp constant variable name whose value is determined at build time using an internal FFI:FOREIGN-FUNCTION.

Options for FFI:DEF-C-CONST

(:NAME c-name)
specifies the name as seen from C, as a STRING. If not specified, it is derived from the print name of the Lisp name.
(:TYPE c-type)

specifies the constant's foreign type, one of

FFI:INT
FFI:C-STRING
FFI:C-POINTER
(:GUARD string)

specifies the cpp check to wrap around c-name, defaults to "defined(c-name)"; can be NIL to omit the test. When the test fails, name is unbound.

(:DOCUMENTATION string)
Specifies the (optional) VARIABLE documentation.

See also Example 32.6, “Accessing cpp macros”.

(FFI:DEF-CALL-OUT name {option}*)

This form defines a named call-out function (a foreign function called from Lisp: control flow temporarily leaves Lisp).

Options for FFI:DEF-CALL-OUT

(:NAME c-name)
Any Lisp function call to #'name is redirected to call the C function c-name.
(:ARGUMENTS {(argument c-type [PARAM-MODE [ALLOCATION]])}*)
(:RETURN-TYPE c-type [ALLOCATION])
Argument list and return value, see Section 32.3.8, “Argument and result passing conventions” and Section 32.3.9, “Parameter Mode”.
(:LANGUAGE language)
See Section 32.3.4, “The choice of the C flavor”.
(:BUILT-IN BOOLEAN)
When the function is a C built-in, the full prototype will be output (unless suppressed by FFI:*OUTPUT-C-FUNCTIONS*).
(:LIBRARY name)
Specifies the (optional) dynamic library which contains the function, the default is set by FFI:DEFAULT-FOREIGN-LIBRARY.
(:VERSION version)
Specifies the (optional) symbol version in the library (therefore, if :VERSION is supplied, :LIBRARY must also be supplied)
(:DOCUMENTATION string)
Specifies the (optional) FUNCTION documentation.

See also Section 32.3.7, “Foreign functions”.

(FFI:DEF-CALL-IN function {option}*)

This form defines a callback - a named call-in function (i.e., a Lisp function called from the foreign language: control flow temporary enters Lisp)

Options for FFI:DEF-CALL-IN

(:NAME c-name)
Any C function call to the C function c-name is redirected to call the Common Lisp function function, which should be a function name.
(:ARGUMENTS {(argument c-type [PARAM-MODE [ALLOCATION]])}*)
(:RETURN-TYPE c-type [ALLOCATION])
Argument list and return value, see Section 32.3.8, “Argument and result passing conventions” and Section 32.3.9, “Parameter Mode”.
(:LANGUAGE language)
See Section 32.3.4, “The choice of the C flavor”.

See also Section 32.3.7, “Foreign functions”.

(FFI:OPEN-FOREIGN-LIBRARY name)

Open (load) a shared foreign library.

This is only needed if you want to test for presence of a library without creating a foreign object. When you create a FFI:FOREIGN-VARIABLE or a FFI:FOREIGN-FUNCTION using FFI:DEF-C-VAR or FFI:DEF-CALL-OUT with a :LIBRARY argument, the library name is opened automatically.

(FFI:CLOSE-FOREIGN-LIBRARY name)

Close (unload) a shared foreign library (opened by FFI:OPEN-FOREIGN-LIBRARY or the :LIBRARY argument to FFI:DEF-CALL-OUT or FFI:DEF-C-VAR).

If you modify your shared library, you need to use close it using FFI:CLOSE-FOREIGN-LIBRARY first. When you use the FFI:FOREIGN-VARIABLE or the FFI:FOREIGN-FUNCTION which resides in the library name, it will be re-opened automatically.

(FFI:DEFAULT-FOREIGN-LIBRARY library-name)

This macro sets the default :LIBRARY argument for FFI:DEF-CALL-OUT and FFI:DEF-C-VAR. library-name should be NIL (meaning use the C file produced by COMPILE-FILE), a STRING, or, depending on the underlying dlsym or dlvsym implementation, :DEFAULT or :NEXT.

The default is set separately in each compilation unit, so, if you are interfacing to a single library, you can set this variable in the beginning of your lisp file and omit the :LIBRARY argument throughout the file.

(FFI:DEF-C-STRUCT name (symbol c-type)*)

This form defines name to be both a STRUCTURE-CLASS and a foreign C type with the given slots. If this class representation overhead is not needed one should consider writing (FFI:DEF-C-TYPE name (FFI:C-STRUCT {LIST | VECTOR} (symbol c-type)*)) instead. name is a SYMBOL (structure name) or a LIST whose FIRST element is the structure name and the REST is options. Two options are supported at this time:

Options for FFI:DEF-C-STRUCT

:TYPEDEF
means that the name of this structure is a C type defined with typedef elsewhere.
:EXTERNAL
means that this structure is defined in a C header file that you include with, e.g., (FFI:C-LINES "#include <filename.h>~%").

These options determine how the struct is written to the #P".c".

(FFI:DEF-C-ENUM name {symbol | (symbol [value])}*)

This form defines symbols as constants, similarly to the C declaration enum { symbol [= value], ... };

You can use (FFI:ENUM-FROM-VALUE name value) and (FFI:ENUM-TO-VALUE name symbol) to convert between the numeric and symbolic representations (of course, the latter function boils down to SYMBOL-VALUE plus a check that the symbol is indeed a constant defined in the FFI:DEF-C-ENUM name).

(FFI:C-LINES format-string {argument}*)

This form outputs the string (FORMAT NIL format-string {argument}*) to the C output file's top level. This is usually used to include the relevant header files, see :EXTERNAL and FFI:*OUTPUT-C-FUNCTIONS*.

When format-string is not a STRING, is should be a SYMBOL, and then the STRING (FORMAT NIL {argument}*) is added to the appropriate C function:

(FFI:ELEMENT c-place index1 ... indexn)
Array element: If c-place is of foreign type (FFI:C-ARRAY c-type (dim1 ... dimn)) and 0 ≤ index1 < dim1, ..., 0 ≤ indexn < dimn, this will be the place corresponding to (AREF c-place index1 ... indexn) or c-place[index1]...[indexn]. It is a place of type c-type. If c-place is of foreign type (FFI:C-ARRAY-MAX c-type dim) and 0 ≤ index < dim, this will be the place corresponding to (AREF c-place index) or c-place[index]. It is a place of type c-type.
(FFI:DEREF c-place)
Dereference pointer: If c-place is of foreign type (FFI:C-PTR c-type), (FFI:C-PTR-NULL c-type) or (FFI:C-POINTER c-type), this will be the place the pointer points to. It is a place of type c-type. For (FFI:C-PTR-NULL c-type), the c-place may not be NULL.
(FFI:SLOT c-place slot-name)
Struct or union component: If c-place is of foreign type (FFI:C-STRUCT class ... (slot-name c-type) ...) or of type (FFI:C-UNION ... (slot-name c-type) ...), this will be of type c-type.
(FFI:CAST c-place c-type)
Type change: A place denoting the same memory locations as the original c-place, but of type c-type.
(FFI:OFFSET c-place offset c-type)
Type change and displacement: return a place denoting a memory locations displaced from the original c-place by an offset counted in bytes, with type c-type. This can be used to resize an array, e.g. of c-type (FFI:C-ARRAY uint16 n) via (FFI:OFFSET c-place 0 '(FFI:C-ARRAY uint16 k)).
(FFI:C-VAR-ADDRESS c-place)
Return the address of c-place as a Lisp object of type FFI:FOREIGN-ADDRESS. This is useful as an argument to foreign functions expecting a parameter of C type FFI:C-POINTER.
(FFI:C-VAR-OBJECT c-place)
Return the FFI:FOREIGN-VARIABLE object underlying the c-place. This is also an acceptable argument type to a FFI:C-POINTER declaration.
(FFI:TYPEOF c-place)
returns the c-type corresponding to the c-place.
(FFI:SIZEOF c-type)
(FFI:SIZEOF c-place)

The first form returns the size and alignment of the C type c-type, measured in bytes.

The second form returns the size and alignment of the C type of c-place, measured in bytes.

(FFI:BITSIZEOF c-type)
(FFI:BITSIZEOF c-place)

The first form returns the size and alignment of the C type c-type, measured in bits.

The second form returns the size and alignment of the C type of c-place, measured in bits.

(FFI:FOREIGN-ADDRESS-UNSIGNED foreign-entity)
(FFI:UNSIGNED-FOREIGN-ADDRESS number)

FFI:FOREIGN-ADDRESS-UNSIGNED returns the INTEGER address embodied in the Lisp object of type FFI:FOREIGN-ADDRESS, FFI:FOREIGN-POINTER, FFI:FOREIGN-VARIABLE or FFI:FOREIGN-FUNCTION.

FFI:UNSIGNED-FOREIGN-ADDRESS returns a FFI:FOREIGN-ADDRESS object pointing to the given INTEGER address.

(FFI:FOREIGN-ADDRESS foreign-entity)

FFI:FOREIGN-ADDRESS is both a type name and a selector/constructor function. It is the Lisp object type corresponding to a FFI:C-POINTER external type declaration, e.g. a call-out function with (:RETURN-TYPE FFI:C-POINTER) yields a Lisp object of type FFI:FOREIGN-ADDRESS.

The function extracts the object of type FFI:FOREIGN-ADDRESS living within any FFI:FOREIGN-VARIABLE or FFI:FOREIGN-FUNCTION object. If the foreign-entity already is a FFI:FOREIGN-ADDRESS, it returns it. If it is a FFI:FOREIGN-POINTER (e.g. a base foreign library address), it encapsulates it into a FFI:FOREIGN-ADDRESS object, as suitable for use with a FFI:C-POINTER external type declaration. It does not construct addresses out of NUMBERs, FFI:UNSIGNED-FOREIGN-ADDRESS must be used for that purpose.

(FFI:FOREIGN-VARIABLE foreign-entity c-type-internal &KEY name)
This constructor creates a new FFI:FOREIGN-VARIABLE from the given FFI:FOREIGN-ADDRESS or FFI:FOREIGN-VARIABLE and the internal C type descriptor (as obtained from FFI:PARSE-C-TYPE). name, a STRING, is mostly useful for documentation and interactive debugging since it appears in the printed representation of the FFI:FOREIGN-VARIABLE object, as in #<FFI:FOREIGN-VARIABLE "foo" #x0ADD4E55>. In effect, this is similar to FFI:CAST (or rather (FFI:OFFSET ... 0 ...) for places), except that it works with FFI:FOREIGN-ADDRESS objects and allows caching of the internal C types.
(FFI:FOREIGN-FUNCTION foreign-entity c-type-internal &KEY name)

This constructor creates a FFI:FOREIGN-FUNCTION from the given FFI:FOREIGN-ADDRESS or FFI:FOREIGN-FUNCTION and the internal C type descriptor (as obtained from (FFI:PARSE-C-TYPE '(FFI:C-FUNCTION ...)), in which case it is important to specify the :LANGUAGE because the expressions are likely to be evaluated at run time, outside the compilation unit). The name, a STRING, is mostly useful for documentation and interactive debugging since it appears in the printed representation of the FFI:FOREIGN-FUNCTION object, e.g., #<FFI:FOREIGN-FUNCTION "foo" #x0052B060>. It is inherited from the given FFI:FOREIGN-FUNCTION object when available.

See also Section 32.3.7, “Foreign functions”.

(FFI:VALIDP foreign-entity)
(SETF (FFI:VALIDP foreign-entity) value)

This predicate returns NIL if the foreign-entity (e.g. the Lisp equivalent of a FFI:C-POINTER) refers to a pointer which is invalid (e.g., because it comes from a previous Lisp session). It returns T if foreign-entity can be used within the current Lisp process (thus it returns T for all non-foreign arguments).

You can invalidate a foreign object using (SETF FFI:VALIDP). You cannot resurrect a zombie, nor can you kill a non-foreign object.

(FFI:FOREIGN-POINTER foreign-entity)
FFI:FOREIGN-POINTER returns the FFI:FOREIGN-POINTER associated with the Lisp object of type FFI:FOREIGN-ADDRESS, FFI:FOREIGN-POINTER, FFI:FOREIGN-VARIABLE or FFI:FOREIGN-FUNCTION.
(FFI:SET-FOREIGN-POINTER foreign-entity {foreign-entity | :COPY})
FFI:SET-FOREIGN-POINTER changes the FFI:FOREIGN-POINTER associated with the Lisp object of type FFI:FOREIGN-ADDRESS, FFI:FOREIGN-VARIABLE or FFI:FOREIGN-FUNCTION to that of the other entity. With :COPY, a fresh FFI:FOREIGN-POINTER is allocated. The original foreign-entity still points to the same object and is returned. This is particularly useful with (SETF FFI:VALIDP), see Example 32.11, “Controlling validity of resources”.
(FFI:WITH-FOREIGN-OBJECT (variable c-type [initarg]) body)
(FFI:WITH-C-VAR (variable c-type [initarg]) body)

These forms allocate space on the C execution stack, bind respectively a FFI:FOREIGN-VARIABLE object or a local SYMBOL-MACRO to variable and execute body.

When initarg is not supplied, they allocate space only for (FFI:SIZEOF c-type) bytes. This space is filled with zeroes. E.g., using a c-type of FFI:C-STRING or even (FFI:C-PTR (FFI:C-ARRAY uint8 32)) (!) both allocate space for a single pointer, initialized to NULL.

When initarg is supplied, they allocate space for an arbitrarily complex set of structures rooted in c-type. Therefore, FFI:C-ARRAY-MAX, #() and "" are your friends for creating a pointer to the empty arrays:

(with-c-var (v '(c-ptr (c-array-max uint8 32)) #())
  (setf (element (deref v) 0) 127) v)

c-type is evaluated, making creation of variable sized buffers easy:

(with-c-var (fv `(c-array uint8 ,(length my-vector)) my-vector)
  (print fv))

(FFI:FOREIGN-VALUE FFI:FOREIGN-VARIABLE)
(SETF (FFI:FOREIGN-VALUE FFI:FOREIGN-VARIABLE) ...)

This functions converts the reference to a C data structure which the FFI:FOREIGN-VARIABLE describes, to Lisp. Such a reference is typically obtained from FFI:ALLOCATE-SHALLOW, FFI:ALLOCATE-DEEP, FFI:FOREIGN-ALLOCATE or via a (FFI:C-POINTER c-type) C type description. Alternatively, macros like FFI:WITH-C-PLACE or FFI:WITH-C-VAR and the concept of foreign place hide many uses of this function.

The SETF form performs conversion from Lisp to C, following to the FFI:FOREIGN-VARIABLE's type description.

(FFI:WITH-FOREIGN-STRING (foreign-address char-count byte-count string &KEY encoding null-terminated-p start end) &BODY body)

This forms converts a Lisp string according to the encoding, allocating space on the C execution stack. encoding can be any EXT:ENCODING, e.g. CHARSET:UTF-16 or CHARSET:UTF-8, whereas CUSTOM:*FOREIGN-ENCODING* must be an ASCII-compatible encoding.

body is then executed with the three variables foreign-address, char-count and byte-count respectively bound to an untyped FFI:FOREIGN-ADDRESS (as known from the FFI:C-POINTER foreign type specification) pointing to the stack location, the number of CHARACTERs of the Lisp string that were considered and the number of (UNSIGNED-BYTE 8) bytes that were allocated for it on the C stack.

When null-terminated-p is true, which is the default, a variable number of zero bytes is appended, depending on the encoding, e.g. 2 for CHARSET:UTF-16, and accounted for in byte-count, and char-count is incremented by one.

The FFI:FOREIGN-ADDRESS object bound to foreign-address is invalidated upon the exit from the form.

A stupid example (a quite costly interface to mblen):

(with-foreign-string (fv elems bytes string
                      :encoding charset:jis... :null-terminated-p nil
                      :end 5)
 (declare (ignore fv elems))
 (format t "This string would take ~D bytes." bytes))

(FFI:PARSE-C-TYPE c-type)
(FFI:DEPARSE-C-TYPE c-type-internal)

Convert between the external (LIST) and internal (VECTOR) C type representations (used by DESCRIBE).

Note

Although you can memoize a c-type-internal (see Section 31.11.3, “Macro EXT:MEMOIZED - but do not expect type redefinitions to work across memoization!), you cannot serialize it (write to disk) because deserialization loses object identity.

(FFI:ALLOCATE-SHALLOW c-type &KEY :COUNT :READ-ONLY)
(FFI:ALLOCATE-DEEP c-type contents &KEY :COUNT :READ-ONLY)
(FFI:FOREIGN-FREE foreign-entity &KEY :FULL)
(FFI:FOREIGN-ALLOCATE c-type-internal &KEY :INITIAL-CONTENTS :COUNT :READ-ONLY)

Macro FFI:ALLOCATE-SHALLOW allocates (FFI:SIZEOF c-type) bytes on the C heap and zeroes them out (like calloc). When :COUNT is supplied, c-type is substituted with (FFI:C-ARRAY c-type count), except when c-type is CHARACTER, in which case (FFI:C-ARRAY-MAX CHARACTER count) is used instead. When :READ-ONLY is supplied, the Lisp side is prevented from modifying the memory contents. This can be used as an indication that some foreign side is going to fill this memory (e.g. via read).

Returns a FFI:FOREIGN-VARIABLE object of the actual c-type, whose address part points to the newly allocated memory.

FFI:ALLOCATE-DEEP will call C malloc as many times as necessary to build a structure on the C heap of the given c-type, initialized from the given contents.

E.g., (FFI:ALLOCATE-DEEP 'FFI:C-STRING "ABCDE") performs 2 allocations: one for a C pointer to a string, another for the contents of that string. This would be useful in conjunction with a char** C type declaration. (FFI:ALLOCATE-SHALLOW 'FFI:C-STRING) allocates room for a single pointer (probably 4 bytes).

(FFI:ALLOCATE-DEEP 'CHARACTER "ABCDEF" :count 10) allocates and initializes room for the type (FFI:C-ARRAY-MAX CHARACTER 10), corresponding to char* or, more specifically, char[10] in C.

Function FFI:FOREIGN-FREE deallocates memory at the address held by the given foreign-entity. If :FULL is supplied and the argument is of type FFI:FOREIGN-VARIABLE, recursively frees the whole complex structure pointed to by this variable.

If given a FFI:FOREIGN-FUNCTION object that corresponds to a CLISP callback, deallocates it. Callbacks are automatically created each time you pass a Lisp function via the FFI.

Use (SETF FFI:VALIDP) to disable further references to this address from Lisp. This is currently not done automatically. If the given pointer is already invalid, FFI:FOREIGN-FREE (currently) SIGNALs an ERROR. This may change to make it easier to integrate with EXT:FINALIZE.

Function FFI:FOREIGN-ALLOCATE is a lower-level interface as it requires an internal C type descriptor as returned by FFI:PARSE-C-TYPE.

(FFI:WITH-C-PLACE (variable foreign-entity) body)

Create a place out of the given FFI:FOREIGN-VARIABLE object so operations on places (e.g. FFI:CAST, FFI:DEREF, FFI:SLOT etc.) can be used within body. FFI:WITH-C-VAR appears as a composition of FFI:WITH-FOREIGN-OBJECT and FFI:WITH-C-PLACE.

Such a place can be used to access memory referenced by a foreign-entity object:

(setq foo (allocate-deep '(c-array uint8 3) rgb))
(with-c-place (place foo) (element place 0))

FFI:*OUTPUT-C-FUNCTIONS*
FFI:*OUTPUT-C-VARIABLES*
CLISP will write the extern declarations for foreign functions (defined with FFI:DEF-CALL-OUT) and foreign variables (defined with FFI:DEF-C-VAR) into the output #P".c" (when the Lisp file is compiled with COMPILE-FILE) unless these variables are NIL. They are NIL by default, so the extern declarations are not written; you are encouraged to use FFI:C-LINES to include the appropriate C headers. Set these variables to non-NIL if the headers are not available or not usable.
FFI:*FOREIGN-GUARD*

When this variable is non-NIL at compile time, CLISP will guard the C statements in the output file with cpp conditionals to take advantage of GNU autoconf feature detection. E.g.,

(EVAL-WHEN (compile) (setq *foreign-guard* t))
(FFI:DEF-CALL-OUT some-function (:name "function_name") ...)

will produce

# if defined(HAVE_FUNCTION_NAME)
  register_foreign_function((void*)&function_name,"function_name",1024);
# endif

and will compile and link on any system.

This is mostly useful for product delivery when you want your module to build on any system even if some features will not be available.

FFI:*FOREIGN-GUARD* is initialized to NIL for backwards compatibility.

FFI:FOREIGN-POINTER-INFO
This is an interface to dladdr and it returns the 4 fields of Dl_info as multiple values.

Low-level FFI forms

(FFI:MEMORY-AS foreign-address c-type-internal &OPTIONAL offset)
(SETF (FFI:MEMORY-AS foreign-address c-type-internal &OPTIONAL offset) value)

This accessor is useful when operating with untyped foreign pointers (FFI:FOREIGN-ADDRESS) as opposed to typed ones (represented by FFI:FOREIGN-VARIABLE). It allows to type and dereference the given pointer without the need to create an object of type FFI:FOREIGN-VARIABLE.

Alternatively, one could use (FFI:FOREIGN-VALUE (FFI:FOREIGN-VARIABLE foreign-entity c-type-internal)) (also SETFable).

Note that c-type-internal is the internal representation of a foreign type, thus FFI:PARSE-C-TYPE is required with literal names or types, e.g. (FFI:MEMORY-AS foreign-address (FFI:PARSE-C-TYPE '(FFI:C-ARRAY uint8 3))) or (SETF (FFI:MEMORY-AS foreign-address (FFI:PARSE-C-TYPE 'uint32)) 0).

32.3.3. (Foreign) C types

Foreign C types are used in the FFI. They are not regular Common Lisp types or CLOS classes.

A c-type is either a predefined C type or the name of a type defined by FFI:DEF-C-TYPE.

the predefined C types (c-type)

simple-c-type

the simple C types

Lisp nameLisp equivalentC equivalentILU equivalentComment
NILNILvoid as a result type only
BOOLEANBOOLEANintBOOLEAN 
CHARACTERCHARACTERcharSHORT CHARACTER 
charINTEGERsigned char  
ucharINTEGERunsigned char  
shortINTEGERshort  
ushortINTEGERunsigned short  
intINTEGERint  
uintINTEGERunsigned int  
longINTEGERlong  
ulongINTEGERunsigned long  
uint8(UNSIGNED-BYTE 8)uint8BYTE 
sint8(SIGNED-BYTE 8)sint8  
uint16(UNSIGNED-BYTE 16)uint16SHORT CARDINAL 
sint16(SIGNED-BYTE 16)sint16SHORT INTEGER 
uint32(UNSIGNED-BYTE 32)uint32CARDINAL 
sint32(SIGNED-BYTE 32)sint32INTEGER 
uint64(UNSIGNED-BYTE 64)uint64LONG CARDINALdoes not work on all platforms
sint64(SIGNED-BYTE 64)sint64LONG INTEGERdoes not work on all platforms
SINGLE-FLOATSINGLE-FLOATfloat  
DOUBLE-FLOATDOUBLE-FLOATdouble  
FFI:C-POINTER
This type corresponds to what C calls void*, an opaque pointer. When used as an argument, NIL is accepted as a FFI:C-POINTER and treated as NULL; when a function wants to return a NULL FFI:C-POINTER, it actually returns NIL.
(FFI:C-POINTER c-type)
This type is equivalent to what C calls c-type *: a pointer to a single item of the given c-type. It differs from (FFI:C-PTR-NULL c-type) (see below) in that no conversion to and from Lisp will occur (beyond the usual one of the C NULL pointer to or from Lisp NIL). Instead, an object of type FFI:FOREIGN-VARIABLE is used to represent the foreign place. It is assimilable to a typed pointer.
FFI:C-STRING
This type corresponds to what C calls char*, a zero-terminated string. Its Lisp equivalent is a string, without the trailing zero character.
(FFI:C-STRUCT class (ident1 c-type1) ... (identn c-typen))

This type is equivalent to what C calls struct { c-type1 ident1; ...; c-typen identn; }. Its Lisp equivalent is: if class is VECTOR, a SIMPLE-VECTOR; if class is LIST, a proper list; if class is a symbol naming a structure or CLOS class, an instance of this class, with slots of names ident1, ..., identn.

class may also be a CONS of a SYMBOL (as above) and a LIST of FFI:DEF-C-STRUCT options.

(FFI:C-UNION (ident1 c-type1) ... (identn c-typen))
This type is equivalent to what C calls union { c-type1 ident1; ...; c-typen identn; }. Conversion to and from Lisp assumes that a value is to be viewed as being of c-type1.
(FFI:C-ARRAY c-type dim1)
(FFI:C-ARRAY c-type (dim1 ... dimn))
This type is equivalent to what C calls c-type [dim1] ... [dimn]. Note that when an array is passed as an argument to a function in C, it is actually passed as a pointer; you therefore have to write (FFI:C-PTR (FFI:C-ARRAY ...)) for this argument's type.
(FFI:C-ARRAY-MAX c-type maxdimension)
This type is equivalent to what C calls c-type [maxdimension], an array containing up to maxdimension elements. The array is zero-terminated if it contains less than maxdimension elements. Conversion from Lisp of an array with more than maxdimension elements silently ignores the extra elements.
(FFI:C-FUNCTION (:ARGUMENTS {(argument a-c-type [PARAM-MODE [ALLOCATION]])}*) (:RETURN-TYPE r-c-type [ALLOCATION]) (:LANGUAGE language))
This type designates a C function that can be called according to the given prototype (r-c-type (*) (a-c-type1, ...)). Conversion between C functions and Lisp functions is transparent, and NULL/NIL is recognized and accepted.
(FFI:C-PTR c-type)
This type is equivalent to what C calls c-type *: a pointer to a single item of the given c-type.
(FFI:C-PTR-NULL c-type)
This type is also equivalent to what C calls c-type *: a pointer to a single item of the given c-type, with the exception that C NULL corresponds to Lisp NIL.
(FFI:C-ARRAY-PTR c-type)
This type is equivalent to what C calls c-type (*)[]: a pointer to a zero-terminated array of items of the given c-type.

The conversion of FFI:C-STRING, (FFI:C-ARRAY CHARACTER dim1), (FFI:C-ARRAY-MAX CHARACTER maxdimension), (FFI:C-ARRAY-PTR CHARACTER) is governed by CUSTOM:*FOREIGN-ENCODING* and dimensions are given in bytes. The conversion of CHARACTER, and as such of (FFI:C-PTR CHARACTER), or (FFI:C-PTR-NULL CHARACTER), as well as that of multi-dimensional arrays (FFI:C-ARRAY CHARACTER (dim1 ... dimn)), are governed by CUSTOM:*FOREIGN-ENCODING* if the latter is a 1:1 encoding, or by the ASCII encoding otherwise.

Note

Remember that the C type char is a numeric type and does not use CHARACTER EXT:ENCODINGs.

32.3.4. The choice of the C flavor

FFI:C-FUNCTION, FFI:DEF-CALL-IN, FFI:DEF-CALL-OUT take a :LANGUAGE argument. The language is either :C (denotes K&R C) or :STDC (denotes ANSI C) or :STDC-STDCALL (denotes ANSI C with the stdcall calling convention). It specifies whether the C function (caller or callee) has been compiled by a K&R C compiler or by an ANSI C compiler, and possibly the calling convention.

The default language is set using the macro FFI:DEFAULT-FOREIGN-LANGUAGE . If this macro has not been called in the current compilation unit (usually a file), a warning is issued and :STDC is used for the rest of the unit.

32.3.5. Foreign variables

Foreign variables are variables whose storage is allocated in the foreign language module. They can nevertheless be evaluated and modified through SETQ, just as normal variables can, except that the range of allowed values is limited according to the variable's foreign type.

Equality of foreign values

For a foreign variable x the form (EQL x x) is not necessarily true, since every time x is evaluated its foreign value is converted to a