MacroPackage: ffToCDocOverviewCGDocRelNotesFAQIndexPermutedIndex
Allegro CL version 10.1
Unrevised from 10.0 to 10.1.
10.0 version


Arguments: lispname &key entry-point unconverted-entry-name arguments pass-types arg-checking prototype return-type language convert-symbol print address remember-address call-direct callback strings-convert

This operator is obsolete and maintained for backwards compatibility only. It has been replaced by the macro def-foreign-call. All new code should use that macro.

This macro defines the calling convention which allows Lisp to call a foreign function correctly, passing arguments of the correct type, and interpreting the returned value correctly. lisp-name is the name (a symbol) by which lisp will refer to the foreign function.

If the entry point (either the value of entry-point or determined by other arguments as described below) does not exist, no error will be signaled when defforeign is called. Instead, the error will be signaled when the function defined by defforeign is called. This makes foreign functions more like Lisp functions -- if you define foo to call the undefined function bar, the error is signaled when foo is called, not when foo is defined.

The function defforeign creates a function identified by lisp-name, which passes its arguments through to the foreign code and returns the return-value of the foreign function to Lisp. The default passing convention (which can be overridden by using the pass-types keyword argument to defforeign) depends on the type of arguments and the language. For example, C normally expects its arguments to be passed by value, Fortran expects arguments to be passed by address.

defforeign returns t if it successfully defines the foreign function. It returns nil if it fails.

You can test whether or not an entry point exists with the function get-extern-code-address.

The following are the keyword arguments to defforeign.

Argument Value Description
entry-point foreign-name This keyword's value foreign-name is the name of the entry point as found in the loaded foreign namespace. If no value is specified, the default depends on other arguments. The determination of the entry-point need not happen until the defforeign form is loaded into (or evaluated within) Lisp and not when a file containing a defforeign form is compiled into a fasl file. If determination of the entry-point is delayed until a fasl file is loaded, the same fasl file can be used on different platforms despite different conventions for naming entry points (some platforms prepend a _, some append, and some do not add _'s).

The entry-point name is determined as follows:

If entry-point is specified, it is used at compile time.

If entry-point is not specified but convert-symbol is,

(convert-symbol lisp-name)

where convert-symbol is the conversion function given in the keyword argument convert-symbol described below, is used as the entry point at compile time.

If neither entry-point nor convert-symbol are specified, unconverted-entry-name is stored at compile time and converted (with convert-to-lang) only when the resulting fasl file is loaded. This allows the same fasl files to be used on various platforms. unconverted-entry-name defaults to the symbol name of lisp-name.

Late conversion is the recommended behavior, so neither this argument nor convert-symbol should be specified. This argument and unconverted-entry-name should not both be specified.

unconverted-entry-name unconverted-entry-name unconverted-entry-name should evaluate to a string. The method for determining the entry point name is given in the description of entry-point just above. If a value for this argument is specified, it is stored until the defforeign form defining the foreign function is loaded (or evaluated). At that time, unconverted-entry-name is converted with convert-to-lang to produce the entry-point name.
arguments (argument-type+) This specifies the types of arguments that will be passed to the foreign function. Its value must be a list of valid lisp types (e.g. the expressions integer, string, (simple-array double-float), etc.), or t, which converts arguments according to their type, whatever they are, or nil, which means no arguments. When unspecified, this argument defaults to t.

The special type :lisp is also accepted as an argument-type. Arguments specified :lisp are passed to foreign code unconverted. The format of Lisp objects is given in the sys:;misc;lisp.h file. Please be aware that if a Lisp object is modified inappropriately by foreign code, Lisp will likely fail unrecoverably. Also note that the Lisp object may be moved by the garbage collector so the reference may not be valid if it is stored by C for later processing.

pass-types pass-convention+ This keyword specifies the passing convention of each argument. The choices are :by-address, meaning pass by address (Fortran style) and :by-value, meaning pass by value (C style). The default is the style of the language specified, so users will rarely have to use this keyword. If the C code passes arguments by address, however, then this keyword should be used and its value should be a list of the same length as the argument list with elements :by-value if the corresponding argument is passed by value and :by-address if it is passed by address.

In addition to :by-value and :by-address, one can specify :normal and :non-array-by-address. :normal means to use the normal pass-type based on the value of the :language argument. :non-array-by-address means to pass the argument by address if the corresponding argument specified in the arguments list is not an array.

arg-checking t-or-nil This argument defaults to t, in which case Lisp will check that the arguments passed through to the foreign function are of the types specified in arguments. This argument is ignored if arguments is t. This argument must be nil if call-direct is specified t (otherwise the call will not be inlined).
prototype proto This keyword is now effective on most platforms. This keyword supports argument passing for machines with ANSI C compilers which use function argument prototyping. C functions written with ANSI C prototyping expect arguments to be passed in a specific format. Before the advent of ANSI C prototyping, one did not know what format the callee function expected, so functions always passed in the largest value.

The default is nil. If proto is t, then all arguments will be prototyped. If the arguments are only partially prototyped (e.g. only the first few are prototyped), then the value of the prototype argument should be a list containing t's in the prototyped positions.

For example:

(ff:defforeign 'blarg 
      :arguments (integer single-float single-float)
     :prototype (t t))

would say that the first two args are prototyped and the third is not.

To use defforeign on a function defined with a prototype, one must list the argument type with the argument keyword and have the prototype keyword argument true.

If one has argument checking enabled with the arg-checking keyword argument, then foreign function calling will be strict about getting the correct floating point type.

return-type return-type The value of return-type must be one of the keywords

:integer :fixnum :single-float :double-float :character :lisp :boolean :void

:void indicates no value is returned; :lisp indicates a Lisp value is returned (normally used only if a C program returns a value accessed by the C routine lisp_value()). The other keywords indicate values of the type named by the keyword. If the value is :boolean, the function will return t or nil as the foreign code returned a non-zero or 0 value.

When unspecified, this argument defaults to :integer.

language language-name The language-name must be either of the keywords :c, for C, or :fortran, for Fortran. When unspecified, this argument defaults to :c. This argument is ignored if entry-point is specified.
print t-or-nil If t, information useful for debugging will be printed to *terminal-io*. This argument defaults to nil.
convert-symbol con-function Note: specifying a value for this argument is not recommended. See the description of entry-point above for information on how Lisp determines the entry-point name for a foreign function. If a value for this argument is specified (and no value is specified for entry-point or unconverted-entry-name), the entry-point name will be determined at compile time by applying the function which is the value of this argument to lisp-name. The benefits of determining the entry point only when the fasl file containing the defforeign form is loaded (which allows for portability) is lost.

This keyword's value con-function is the name of the function that does the conversion of the Lisp name to an entry-point name. The function must take as arguments a symbol and the keyword :language, and must return a string recognizable to the operating system as an entry-point name.

call-direct t-or-nil The default value of this argument is nil. If this value is t, then the compiler will attempt to inline calls to the foreign function being defined by this call to defforeign. If the value of :call-direct is t then the :arguments keyword argument must be a list of arguments rather than t and arg-checking must be nil (otherwise :call-direct's value will be ignored). :callback may be t or nil but if it is t, extra code must be included to allow for the callback so the inlined call is slower.

A :call-direct foreign function will return the type specified by :return-type. In earlier releases, a double-float was sometimes returned when :return-type was :single-float. because the C routine returned a double and Lisp did not convert it. Starting in 4.3, Lisp converts the value returned by C if necessary.

Argument types and return types :long-long and :unsigned-long-long (which are 64-bit values) are not supported for :call-direct foreign calls on 32- or 64-bit Windows or in 32-bit Lisps. (In other 64-bit Lisps, they are okay because they are the same as :long and :unsigned-long).

callback callback Because Allegro CL uses (on some platforms) the :os-threads model of multiprocessing, it is not possible to guarantee that Lisp code will not run while a foreign function defined to Lisp with defforeign is running (essentially what :callback nil did in earlier relases on Unix). Therefore, whatever is specified for this argument, t is the value used. See the release-heap keyword argument of def-foreign-call.
method-index nil (the default) or an index into C++ table, as described at right. This argument allows for calling of C++ style member-methods. The value, if specified, must be an integer index into the virtual table of the C++ class. Symbolic index specifications are not directly supported.
strings-convert nil or t. Default is t. This argument is only supported on 16-bit character Lisps. (Allegro CL can run with 8-bit characters or 16-bit characters. See this section of startup.htm for the various Allegro CL images.) This argument assists in having the foreign-function interface handle Allegro CL's 16-bit strings automatically. When the strings-convert is true, then when any of the specified arguments at defforeign time are declared directly or indirectly as (* :char), defforeign augments the function wrapping the low-level foreign function call so that for each (* :char) declared argument, a check is made at runtime to see if that declaration's corresponding value is a string. If it is, then that value is converted at runtime to native-string format using a dynamic-extent array, and this new array is passed in place of the original string argument to low-level foreign function call. See Foreign-Functions in iacl.htm for full details and examples (the examples use def-foreign-call).

See ftype.htm for information on foreign types in Allegro CL and foreign-functions.htm for general information on foreign functions in Allegro CL.

Copyright (c) 1998-2022, Franz Inc. Lafayette, CA., USA. All rights reserved.
This page was not revised from the 10.0 page.
Created 2019.8.20.

Allegro CL version 10.1
Unrevised from 10.0 to 10.1.
10.0 version