Package cffi
CFFI is the Common Foreign Function Interface for ANSI Common Lisp
systems. By foreign function we mean a function written in another programming
language and having different data and calling conventions than Common Lisp,
namely, C. CFFI allows you to call foreign functions and access foreign
variables, all without leaving the Lisp image.
About This PackageIntroduction Installation Implementation Support An Introduction to Foreign Interfaces and CFFI Wrapper generators Foreign Types Pointers Strings Variables Functions Libraries Callbacks The Groveller Limitations Platform-specific features Footnotes LicenseCopyright (c) 2005 James Bielman <jamesjb at jamesjb.com>Copyright (c) 2005-2010 Luís Oliveira <loliveira at common-lisp.net> Copyright (c) 2005-2006 Dan Knapp <danka at accela.net> Copyright (c) 2005-2006 Emily Backes <lucca at accela.net> Copyright (c) 2006 Stephen Compall <s11 at member.fsf.org> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. The software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or the use or other dealings in the software. IntroductionCFFI is the Common Foreign Function Interface for ANSI Common Lisp systems. By foreign function we mean a function written in another programming language and having different data and calling conventions than Common Lisp, namely, C. CFFI allows you to call foreign functions and access foreign variables, all without leaving the Lisp image.We consider this manual ever a work in progress. If you have difficulty with anything CFFI-specific presented in the manual, please contact the developers with details. Motivation See "What makes Lisp different",
for an argument in favor of FFI in general. CFFI's primary role in any image is to mediate between Lisp developers and the widely varying FFIs present in the various Lisp implementations it supports. With CFFI, you can define foreign function interfaces while still maintaining portability between implementations. It is not the first Common Lisp package with this objective; however, it is meant to be a more malleable framework than similar packages. Design Philosophy
Pointers do not carry around type information. Instead, type information is
supplied when pointers are dereferenced.
A type safe pointer interface can be developed on top of an untyped one. It
is difficult to do the opposite.
Functions are better than macros. When a macro could be used for
performance, use a compiler-macro instead. InstallationCFFI can be obtained through one of the following means available through its website: In addition, you will need to obtain and install the following dependencies:
You may find mechanisms such as clbuild (recommended) or ASDF-Install (not as recommendable) helpful in getting and managing CFFI and its dependencies. Implementation SupportCFFI supports various free and commercial Lisp implementations: Allegro CL, Corman CL, clisp, CMUCL, ECL, LispWorks, Clozure CL, SBCL and the Scieneer CL.In general, you should work with the latest versions of each implementation since those will usually be tested against recent versions of CFFI more often and might include necessary features or bug fixes. Reasonable patches for compatibility with earlier versions are welcome nevertheless. Limitations
An Introduction to Foreign Interfaces and CFFIUsers of many popular languages bearing semantic similarity to Lisp, such as Perl and Python, are accustomed to having access to popular C libraries, such as GTK, by way of "bindings". In Lisp, we do something similar, but take a fundamentally different approach. This tutorial first explains this difference, then explains how you can use CFFI, a powerful system for calling out to C and C++ and access C data from many Common Lisp implementations.The concept can be generalized to other languages; at the time of writing, only CFFI's C support is fairly complete, but C++ support is being worked on. Therefore, we will interchangeably refer to foreign functions and foreign data, and "C functions" and "C data". At no time will the word "foreign" carry its usual, non-programming meaning. This tutorial expects you to have a working understanding of both Common Lisp and C, including the Common Lisp macro system. What makes Lisp different
The following sums up how bindings to foreign libraries are usually
implemented in other languages, then in Common Lisp:
Perhaps the greatest advantage is that using an FFI doesn't obligate you to become a professional binding developer. Writers of bindings for other languages usually end up maintaining or failing to maintain complete bindings to the foreign library. Using an FFI, however, means if you only need one or two functions, you can write bindings for only those functions, and be assured that you can just as easily add to the bindings if need be. The removal of the C compiler, or C interpretation of any kind, creates the main disadvantage: some of C's "abstractions" are not available, violating information encapsulation. For example, structs that must be passed on the stack, or used as return values, without corresponding functional abstractions to create and manage the structs, must be declared explicitly in Lisp. This is fine for structs whose contents are "public", but is not so pleasant when a struct is supposed to be "opaque" by convention, even though it is not so defined (see footnote [1]). Without an abstraction to create the struct, Lisp needs to be able to lay out the struct in memory, so must know its internal details. In these cases, you can create a minimal C library to provide the missing abstractions, without destroying all the advantages of the Common Lisp approach discussed above. In the case of structs, you can write simple, pure C functions that tell you how many bytes a struct requires or allocate new structs, read and write fields of the struct, or whatever operations are supposed to be public (see footnote [2]). Implementor's note: cffi-grovel, a project not yet part of CFFI, automates this and other processes. Another disadvantage appears when you would rather use the foreign language than Lisp. However, someone who prefers C to Lisp is not a likely candidate for developing a Lisp interface to a C library. Getting a URLPlease note that there are many other ways to download files from the web, not least the cl-curl project to provide bindings to libcurl via a similar FFI (see footnote [3]). libcurl-tutorial(3) is a tutorial for libcurl programming in C. We will follow that to develop a binding to download a file. We will also use curl.h, easy.h, and the man pages for the libcurl function, all available in the curl-dev package or equivalent for your system, or in the cURL source code package. If you have the development package, the headers should be installed in /usr/include/curl/, and the man pages may be accessed through your favorite man facility. Loading foreign libraries(asdf:oos 'asdf:load-op :cffi)Using define-foreign-library and use-foreign-library, we have loaded libcurl into Lisp, much as the linker does when you start a C program, or cl:load does with a Lisp source file or FASL file. We special-cased for Unix machines to always load a particular version, the one this tutorial was tested with; for those who don't care, the define-foreign-library clause (t (:default "libcurl")) should be satisfactory, and will adapt to various operating systems. Initializing libcurlCURLcode curl_global_init(long flags);Let's pick this apart into appropriate Lisp code: ;;; A CURLcode is the universal error code. curl/curl.h says ;;; no return code will ever be removed, and new ones will be ;;; added to the end. (defctype curl-code :int)Implementor's note: By default, CFFI assumes the Unix viewpoint that there is one C symbol namespace, containing all symbols in all loaded objects. This is not so on Windows and Darwin, but we emulate Unix's behaviour there. See defcfun for more details. Note the parallels with the original C declaration. We've defined curl-code as a wrapping type for :int; right now, it only marks it as special, but later we will do something more interesting with it. The point is that we don't have to do it yet. Looking at curl.h, CURL_GLOBAL_NOTHING, a possible value for flags above, is defined as 0. So we can now call the function: cffi-user> (curl-global-init 0) => 0Looking at curl.h again, 0 means CURLE_OK, so it looks like the call succeeded. Note that CFFI converted the function name to a Lisp-friendly name. You can specify your own name if you want; use ("curl_global_init" your-name-here) as the name argument to defcfun. The tutorial goes on to have us allocate a handle. For good measure, we should also include the deallocator. Let's look at these functions: CURL *curl_easy_init( ); void curl_easy_cleanup(CURL *handle);Advanced users may want to define special pointer types; we will explore this possibility later. For now, just treat every pointer as the same: (defcfun "curl_easy_init" :pointer)Now we can continue with the tutorial: cffi-user> (defparameter *easy-handle* (curl-easy-init)) => *EASY-HANDLE* cffi-user> *easy-handle* => #<FOREIGN-ADDRESS #x09844EE0>Note the print representation of a pointer. It changes depending on what Lisp you are using, but that doesn't make any difference to CFFI. Setting download optionsCURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...);We've introduced a new twist: variable arguments. There is no obvious translation to the defcfun form, particularly as there are four possible argument types. Because of the way C works, we could define four wrappers around curl_easy_setopt, one for each type; in this case, however, we'll use the general-purpose macro foreign-funcall to call this function. To make things easier on ourselves, we'll create an enumeration of the kinds of options we want to set. The enum CURLoption isn't the most straightforward, but reading the CINIT C macro definition should be enlightening. (defmacro define-curl-options (name type-offsets &rest enum-args) "As with CFFI:DEFCENUM, except each of ENUM-ARGS is as follows:With some well-placed Emacs query-replace-regexps, you could probably similarly define the entire CURLoption enumeration. I have selected to transcribe a few that we will use in this tutorial. If you're having trouble following the macrology, just macroexpand the curl-option definition, or see the following macroexpansion, conveniently downcased and reformatted: (progn (defcenum curl-option (:noprogress 43) (:nosignal 99) (:errorbuffer 10010) (:url 10002)) 'curl-option)That seems more than reasonable. You may notice that we only use the type to compute the real enumeration offset; we will also need the type information later. First, however, let's make sure a simple call to the foreign function works: cffi-user> (foreign-funcall "curl_easy_setopt" :pointer *easy-handle* curl-option :nosignal :long 1 curl-code) => 0foreign-funcall, despite its surface simplicity, can be used to call any C function. Its first argument is a string, naming the function to be called. Next, for each argument, we pass the name of the C type, which is the same as in defcfun, followed by a Lisp object representing the data to be passed as the argument. The final argument is the return type, for which we use the curl-code type defined earlier. defcfun just puts a convenient façade on foreign-funcall (See footnote [4]). Our earlier call to curl-global-init could have been written as follows: cffi-user> (foreign-funcall "curl_global_init" :long 0 curl-code) => 0Before we continue, we will take a look at what CFFI can and can't do, and why this is so. Breaking the abstractionStrictly speaking, the curl-option enumeration is not necessary; we could have used :int 99 instead of curl-option :nosignal in our call to curl_easy_setopt above. We defined it anyway, in part to hide the fact that we are breaking the abstraction that the C enum provides. If the cURL developers decide to change those numbers later, we must change the Lisp enumeration, because enumeration values are not provided in the compiled C library, libcurl.so.3. CFFI works because the most useful things in C libraries — non-static functions and non-static variables — are included accessibly in libcurl.so.3. A C compiler that violated this would be considered a worthless compiler. The other thing define-curl-options does is give the "type" of the third argument passed to curl_easy_setopt. Using this information, we can tell that the :nosignal option should accept a long integer argument. We can implicitly assume t == 1 and nil == 0, as it is in C, which takes care of the fact that CURLOPT_NOSIGNAL is really asking for a boolean. The "type" of CURLOPT_WRITEDATA is objectpoint. However, it is really looking for a FILE*. CURLOPT_ERRORBUFFER is looking for a char*, so there is no obvious CFFI type but :pointer. The first thing to note is that nowhere in the C interface includes this information; it can only be found in the manual. We could disjoin these clearly different types ourselves, by splitting objectpoint into filepoint and charpoint, but we are still breaking the abstraction, because we have to augment the entire enumeration form with this additional information (see footnote [5]). The second is that the CURLOPT_WRITEDATA argument is completely incompatible with the desired Lisp data, a stream (see footnote [6]). It is probably acceptable if we are controlling every file we might want to use as this argument, in which case we can just call the foreign function fopen. Regardless, though, we can't write to arbitrary streams, which is exactly what we want to do for this application. Finally, note that the curl_easy_setopt interface itself is a hack, intended to work around some of the drawbacks of C. The definition of Curl_setopt, while long, is far less cluttered than the equivalent disjoint-function set would be; in addition, setting a new option in an old libcurl can generate a run-time error rather than breaking the compile. Lisp can just as concisely generate functions as compare values, and the "undefined function" error is just as useful as any explicit error we could define here might be. Option functions in Lisp;;; We will use this type later in a more creative way. For ;;; now, just consider it a marker that this isn't just any ;;; pointer. (defctype easy-handle :pointer)Now we define a function for each kind of argument that encodes the correct value-type in the above. This can be done reasonably in the define-curl-options macroexpansion; after all, that is where the different options are listed! We could make cl:defun forms in the expansion that simply call curl-easy-setopt; however, it is probably easier and clearer to use defcfun. define-curl-options was becoming unwieldy, so I defined some helpers in this new definition. (defun curry-curl-option-setter (function-name option-keyword) "Wrap the function named by FUNCTION-NAME with a version that curries the second argument as OPTION-KEYWORD.Macroexpanding our define-curl-options form once more, we see something different: (progn (defcenum curl-option (:noprogress 43) (:nosignal 99) (:errorbuffer 10010) (:url 10002)) (define-curl-option-setter set-curl-option-noprogress curl-option :noprogress :long) (define-curl-option-setter set-curl-option-nosignal curl-option :nosignal :long) (define-curl-option-setter set-curl-option-errorbuffer curl-option :errorbuffer :pointer) (define-curl-option-setter set-curl-option-url curl-option :url :pointer) 'curl-option)Macroexpanding one of the new define-curl-option-setter forms yields the following: (progn (defcfun ("curl_easy_setopt" set-curl-option-nosignal) curl-code (easy-handle easy-handle) (option curl-option) (new-value :long)) (curry-curl-option-setter 'set-curl-option-nosignal ':nosignal))Finally, let's try this out: cffi-user> (set-curl-option-nosignal *easy-handle* 1) => 0Looks like it works just as well. This interface is now reasonably high-level to wash out some of the ugliness of the thinnest possible curl_easy_setopt FFI, without obscuring the remaining C bookkeeping details we will explore. Memory managementThe first reason also applies to CURLOPT_URL, which we will use to illustrate the point. Assuming we have changed the type of the third argument underlying set-curl-option-url to :string, look at these two equivalent forms. (set-curl-option-url *easy-handle* "http://www.cliki.net/CFFI")The latter, in fact, is mostly equivalent to what a foreign function call's macroexpansion actually does. As you can see, the Lisp string "http://www.cliki.net/CFFI" is copied into a char array and null-terminated; the pointer to beginning of this array, now a C string, is passed as a CFFI :pointer to the foreign function. Unfortunately, the C abstraction has failed us, and we must break it. While :string works well for many char* arguments, it does not for cases like this. As the curl_easy_setopt documentation explains, "The string must remain present until curl no longer needs it, as it doesn't copy the string." The C string created by with-foreign-string, however, only has dynamic extent: it is "deallocated" when the body (above containing the foreign-funcall form) exits. If we are supposed to keep the C string around, but it goes away, what happens when some libcurl function tries to access the URL string? We have reentered the dreaded world of C "undefined behavior". In some Lisps, it will probably get a chunk of the Lisp/C stack. You may segfault. You may get some random piece of other data from the heap. Maybe, in a world where "dynamic extent" is defined to be "infinite extent", everything will turn out fine. Regardless, results are likely to be almost universally unpleasant (see footnote [7]). Returning to the current set-curl-option-url interface, here is what we must do: (let (easy-handle) (unwind-protect (with-foreign-string (url "http://www.cliki.net/CFFI") (setf easy-handle (curl-easy-init)) (set-curl-option-url easy-handle url) #|do more with the easy-handle, like actually get the URL|#) (when easy-handle (curl-easy-cleanup easy-handle))))That is fine for the single string defined here, but for every string option we want to pass, we have to surround the body of with-foreign-string with another with-foreign-string wrapper, or else do some extremely error-prone pointer manipulation and size calculation in advance. We could alleviate some of the pain with a recursively expanding macro, but this would not remove the need to modify the block every time we want to add an option, anathema as it is to a modular interface. Before modifying the code to account for this case, consider the other reason we can't simply use :string as the foreign type. In C, a char * is a char *, not necessarily a string. The option CURLOPT_ERRORBUFFER accepts a char *, but does not expect anything about the data there. However, it does expect that some libcurl function we call later can write a C string of up to 255 characters there. We, the callers of the function, are expected to read the C string at a later time, exactly the opposite of what :string implies. With the semantics for an input string in mind — namely, that the string should be kept around until we curl_easy_cleanup the easy handle — we are ready to extend the Lisp interface: (defvar *easy-handle-cstrings* (make-hash-table) "Hashtable of easy handles to lists of C strings that may be safely freed after the handle is freed.")Here we have redefined the interface to create and free handles, to associate a list of allocated C strings with each handle while it exists. The strategy of using different function names to wrap around simple foreign functions is more common than the solution implemented earlier with curry-curl-option-setter, which was to modify the function name's function slot (see footnote [8]). Incidentally, the next step is to redefine curry-curl-option-setter to allocate C strings for the appropriate length of time, given a Lisp string as the new-value argument: (defun curry-curl-option-setter (function-name option-keyword) "Wrap the function named by FUNCTION-NAME with a version that curries the second argument as OPTION-KEYWORD.A quick analysis of the code shows that you need only reevaluate the curl-option enumeration definition to take advantage of these new semantics. Now, for good measure, let's reallocate the handle with the new functions we just defined, and set its URL: cffi-user> (curl-easy-cleanup *easy-handle*) => NIL cffi-user> (setf *easy-handle* (make-easy-handle)) => #<FOREIGN-ADDRESS #x09844EE0> cffi-user> (set-curl-option-nosignal *easy-handle* 1) => 0 cffi-user> (set-curl-option-url *easy-handle* "http://www.cliki.net/CFFI") => 0For fun, let's inspect the Lisp value of the C string that was created to hold "http://www.cliki.net/CFFI". By virtue of the implementation of add-curl-handle-cstring, it should be accessible through the hash table defined: cffi-user> (foreign-string-to-lisp (car (gethash *easy-handle* *easy-handle-cstrings*))) => "http://www.cliki.net/CFFI"Looks like that worked, and libcurl now knows what URL we want to retrieve. Finally, we turn back to the :errorbuffer option mentioned at the beginning of this section. Whereas the abstraction added to support string inputs works fine for cases like CURLOPT_URL, it hides the detail of keeping the C string; for :errorbuffer, however, we need that C string. In a moment, we'll define something slightly cleaner, but for now, remember that you can always hack around anything. We're modifying handle creation, so make sure you free the old handle before redefining free-easy-handle. (defvar *easy-handle-errorbuffers* (make-hash-table) "Hashtable of easy handles to C strings serving as error writeback buffers.")Be sure to once again set the options we've set thus far. You may wish to define yet another wrapper function to do this. Calling Lisp from CA binding writer without the aid of FFI usually approaches this problem by writing a C function that accepts C data, converts to the language's internal objects, and calls the callback provided by the user, again in a reverse of usual practices. The CFFI approach to callbacks precisely mirrors its differences with the non-FFI approach on the "calling C from Lisp" side, which we have dealt with exclusively up to now. That is, you define a callback function in Lisp using defcallback, and CFFI effectively creates a C function to be passed as a function pointer. Implementor's note: This is much trickier than calling C functions from Lisp, as it literally involves somehow generating a new C function that is as good as any created by the compiler. Therefore, not all Lisps support them. See Implementation Support, for information about CFFI support issues in this and other areas. You may want to consider changing to a Lisp that supports callbacks in order to continue with this tutorial. Defining a callback is very similar to defining a callout; the main difference is that we must provide some Lisp forms to be evaluated as part of the callback. Here is the signature for the function the :writefunction option takes: size_t function(void *ptr, size_t size, size_t nmemb, void *stream);Implementor's note: size_t is almost always an unsigned int. You can get this and many other types using feature tests for your system by using cffi-grovel. The above signature trivially translates into a CFFI defcallback form, as follows. ;;; Alias in case size_t changes. (defctype size :unsigned-int)First, note the correlation of the first few forms, used to declare the C function's signature, with the signature in C syntax. We provide a Lisp name for the function, its return type, and a name and type for each argument. In the body, we call the dynamically-bound *easy-write-procedure* with a "finished" translation, of pulling together the raw data and size into a Lisp string, rather than deal with the data directly. As part of calling curl_easy_perform later, we'll bind that variable to a closure with more useful lexical bindings than the top-level defcallback form. Finally, we make a halfhearted effort to prevent non-local exits from unwinding the C stack, covering the most likely case with an error handler, which is usually triggered unexpectedly (see footnote [9]). The reason is that most C code is written to understand its own idiosyncratic error condition, implemented above in the case of curl_easy_perform, and more "undefined behavior" can result if we just wipe C stack frames without allowing them to execute whatever cleanup actions as they like. Using the CURLoption enumeration in curl.h once more, we can describe the new option by modifying and reevaluating define-curl-options. (define-curl-options curl-option (long 0 objectpoint 10000 functionpoint 20000 off-t 30000) (:noprogress long 43) (:nosignal long 99) (:errorbuffer objectpoint 10) (:url objectpoint 2) (:writefunction functionpoint 11)) ;new item hereFinally, we can use the defined callback and the new set-curl-option-writefunction to finish configuring the easy handle, using the callback macro to retrieve a CFFI :pointer, which works like a function pointer in C code. cffi-user> (set-curl-option-writefunction *easy-handle* (callback easy-write)) => 0 A complete FFI?(defcfun "curl_easy_perform" curl-code (handle easy-handle))Of course, that itself is slightly unwieldy, so you may want to define a function around it that simply retrieves a URL. I will leave synthesis of all the relevant REPL forms presented thus far into a single function as an exercise for the reader. The remaining sections of this tutorial explore some advanced features of CFFI; the definition of new types will receive special attention. Some of these features are essential for particular foreign function calls; some are very helpful when trying to develop a Lispy interface to C. Defining new typesHowever, all of these are mostly sugar for the powerful underlying foreign type interface called type translators. You can easily define new translators for any simple named foreign type. Since we've defined the new type curl-code to use as the return type for various libcurl functions, we can use that to directly convert cURL errors to Lisp errors. defctype's purpose is to define simple typedef-like aliases. In order to use type translators we must use the define-foreign-type macro. So let's redefine curl-code using it. (define-foreign-type curl-code-type () () (:actual-type :int) (:simple-parser curl-code))define-foreign-type is a thin wrapper around defclass. For now, all you need to know in the context of this example is that it does what (defctype curl-code :int) would do and, additionally, defines a new class curl-code-type which we will take advantage of shortly. The CURLcode enumeration seems to follow the typical error code convention of 0 meaning all is well, and each non-zero integer indicating a different kind of error. We can apply that trivially to differentiate between normal exits and error exits. (define-condition curl-code-error (error) (($code :initarg :curl-code :reader curl-error-code)) (:report (lambda (c stream) (format stream "libcurl function returned error ~A" (curl-error-code c)))) (:documentation "Signalled when a libcurl function answers a code other than CURLE_OK."))The heart of this translator is the new method translate-from-foreign. By specializing the type parameter on curl-code-type, we immediately modify the behavior of every function that returns a curl-code to pass the result through this new method. To see the translator in action, try invoking a function that returns a curl-code. You need to reevaluate the respective defcfun form so that it picks up the new curl-code definition. cffi-user> (set-curl-option-nosignal *easy-handle* 1) => :CURLE-OKAs the result was 0, the new method returned :curle-ok, just as specified (see footnote [10]). I will leave disjoining the separate CURLcodes into condition types and improving the :report function as an exercise for you. The creation of *easy-handle-cstrings* and *easy-handle-errorbuffers* as properties of easy-handles is a kluge. What we really want is a Lisp structure that stores these properties along with the C pointer. Unfortunately, easy-handle is currently just a fancy name for the foreign type :pointer; the actual pointer object varies from Common Lisp implementation to implementation, needing only to satisfy pointerp and be returned from make-pointer and friends. One solution that would allow us to define a new Lisp structure to represent easy-handles would be to write a wrapper around every function that currently takes an easy-handle; the wrapper would extract the pointer and pass it to the foreign function. However, we can use type translators to more elegantly integrate this "translation" into the foreign function calling framework, using translate-to-foreign. (defclass easy-handle () ((pointer :initform (curl-easy-init) :documentation "Foreign pointer from curl_easy_init") (error-buffer :initform (foreign-alloc :char :count *curl-error-size* :initial-element 0) :documentation "C string describing last error") (c-strings :initform '() :documentation "C strings set as options")) (:documentation "I am a parameterization you may pass to curl-easy-perform to perform a cURL network protocol request."))While we changed some of the Lisp functions defined earlier to use CLOS slots rather than hash tables, the foreign functions work just as well as they did before. The greatest strength, and the greatest limitation, of the type translator comes from its generalized interface. As stated previously, we could define all foreign function calls in terms of the primitive foreign types provided by CFFI. The type translator interface allows us to cleanly specify the relationship between Lisp and C data, independent of where it appears in a function call. This independence comes at a price; for example, it cannot be used to modify translation semantics based on other arguments to a function call. In these cases, you should rely on other features of Lisp, rather than the powerful, yet domain-specific, type translator interface. What's next?Implementor's note: There are some other things in CFFI that might deserve tutorial sections, such as free-translated-object, or structs. Let us know which ones you care about. Wrapper generatorsCFFI's interface is designed for human programmers, being aimed at aesthetic as well as technical sophistication. However, there are a few programs aimed at translating C and C++ header files, or approximations thereof, into CFFI forms constituting a foreign interface to the symbols in those files.These wrapper generators are known to support output of CFFI forms.
When is more accuracy an unreasonable expectation? As described in the tutorial (see "Breaking the abstraction"), the information in C declarations is insufficient to completely describe every interface. In fact, it is quite common to run into an interface that cannot be handled automatically, and generators should be excused from generating a complete interface in these cases. As further described in the tutorial, the thinnest Lisp interface to a C function is not always the most pleasant one. In many cases, you will want to manually write a Lispier interface to the C functions that interest you. Wrapper generators should be treated as time-savers, not complete automation of the full foreign interface writing job. Reports of the amount of work done by generators vary from 30% to 90%. The incremental development style enabled by CFFI generally reduces this proportion below that for languages like Python. Foreign TypesForeign types describe how data is translated back and forth between C and Lisp. CFFI provides various built-in types and allows the user to define new types.This is an external interface to the type translation facility. In the
implementation, all foreign functions are ultimately defined as type translation wrappers around primitive foreign function invocations. ... This is an external interface to the type translation facility. In the
implementation, all foreign functions are ultimately defined as type translation wrappers around primitive foreign function invocations. ... The function foreign-bitfield-symbols returns a possibly shared list of symbols that correspond to value in type. ... The function foreign-bitfield-value returns the value that corresponds to the symbols in the symbols list. ... The function foreign-enum-keyword returns the keyword symbol that corresponds to value in type. ... The function foreign-enum-value returns the value that
corresponds to keyword in type. ... The function foreign-slot-names returns a potentially shared
list of slot names for the given structure type. This list has no particular order. ... The function foreign-slot-offset returns the offset in bytes of a slot in a foreign struct type. ... Returns a pointer to the location of the slot slot-name in a foreign
object of type type at ptr. The returned pointer points inside the
structure. Both the pointer and the memory it points to have the same extent as ptr. ... For simple slots, foreign-slot-value returns the value of the
object, such as a Lisp integer or pointer. In C, this would be expressed as ptr->slot. ... This is an external interface to the type translation facility. In the
implementation, all foreign functions are ultimately defined as type translation wrappers around primitive foreign function invocations. ... Built-In Types
Other Types
Defining Foreign Types;;; Define MY-INT as an alias for the built-in type :INT. (defctype my-int :int)With this type definition, one can, for instance, declare arguments to foreign functions as having the type my-int, and they will be passed as integers. More complex types(define-foreign-type my-string-type () ((encoding :reader string-type-encoding :initarg :encoding)) (:actual-type :pointer))The :actual-type class option tells CFFI that this type will ultimately be passed to and received from foreign code as a :pointer. Now you need to tell CFFI how to parse a type specification such as (my-string :encoding :utf8) into an instance of my-string-type. We do that with define-parse-method: (define-parse-method my-string (&key (encoding :utf-8)) (make-instance 'my-string-type :encoding encoding))The next section describes how make this type actually translate between C and Lisp strings. Foreign Type Translators
;;; Define a method that converts Lisp strings to C strings. (defmethod translate-to-foreign (string (type my-string-type)) (foreign-string-alloc string :encoding (string-type-encoding type)))From now on, whenever an object is passed as a my-string to a foreign function, this method will be invoked to convert the Lisp value. To perform the inverse operation, which is needed for functions that return a my-string, specialize the translate-from-foreign generic function in the same manner: ;;; Define a method that converts C strings to Lisp strings. (defmethod translate-from-foreign (pointer (type my-string-type)) (foreign-string-to-lisp pointer :encoding (string-type-encoding type)))When a translate-to-foreign method requires allocation of foreign memory, you must also define a free-translated-object method to free the memory once the foreign object is no longer needed, otherwise you'll be faced with memory leaks. This generic function is called automatically by CFFI when passing objects to foreign functions. Let's do that: ;;; Free strings allocated by translate-to-foreign. (defmethod free-translated-object (pointer (type my-string-type) param) (declare (ignore param)) (foreign-string-free pointer))In this specific example, we don't need the param argument, so we ignore it. See free-translated-object, for an explanation of its purpose and how you can use it. A type translator does not necessarily need to convert the value. For example, one could define a typedef for :pointer that ensures, in the translate-to-foreign method, that the value is not a null pointer, signalling an error if a null pointer is passed. This would prevent some pointer errors when calling foreign functions that cannot handle null pointers. Please note: these methods are meant as extensible hooks only, and you should not call them directly. Use convert-to-foreign, convert-from-foreign and free-converted-object instead. See "Defining new types", for another example of type translators. Optimizing Type TranslatorsA good way to understand this issue is to look at the code generated by defcfun. Consider the following example using the previously defined my-string type: CFFI> (macroexpand-1 '(defcfun foo my-string (x my-string))) ;; (simplified, downcased, etc...) (defun foo (x) (multiple-value-bind (#:G2019 #:PARAM3149) (translate-to-foreign x #<MY-STRING-TYPE {11ED5A79}>) (unwind-protect (translate-from-foreign (foreign-funcall "foo" :pointer #:G2019 :pointer) #<MY-STRING-TYPE {11ED5659}>) (free-translated-object #:G2019 #<MY-STRING-TYPE {11ED51A79}> #:PARAM3149))))In order to get rid of those generic function calls, CFFI has another set of extensible generic functions that provide functionality similar to CL's compiler macros: expand-to-foreign-dyn, expand-to-foreign and expand-from-foreign. Here's how one could define a my-boolean with them: (define-foreign-type my-boolean-type () () (:actual-type :int) (:simple-parser my-boolean))And here's what the macroexpansion of a function using this type would look like: CFFI> (macroexpand-1 '(defcfun bar my-boolean (x my-boolean))) ;; (simplified, downcased, etc...) (defun bar (x) (let ((#:g3182 (if x 1 0))) (not (zerop (foreign-funcall "bar" :int #:g3182 :int)))))No generic function overhead. Let's go back to our my-string type. The expansion interface has no equivalent of free-translated-object; you must instead define a method on expand-to-foreign-dyn, the third generic function in this interface. This is especially useful when you can allocate something much more efficiently if you know the object has dynamic extent, as is the case with function calls that don't save the relevant allocated arguments. This exactly what we need for the my-string type: (defmethod expand-from-foreign (form (type my-string-type)) `(foreign-string-to-lisp ,form))So let's look at the macro expansion: CFFI> (macroexpand-1 '(defcfun foo my-string (x my-string))) ;; (simplified, downcased, etc...) (defun foo (x) (with-foreign-string (#:G2021 X :encoding ':utf-8) (foreign-string-to-lisp (foreign-funcall "foo" :pointer #:g2021 :pointer))))Again, no generic function overhead. Other detailsThe expand-* methods have precedence over their translate-* counterparts and are guaranteed to be used in defcfun, foreign-funcall, defcvar and defcallback. If you define a method on each of the expand-* generic functions, you are guaranteed to have full control over the expressions generated for type translation in these macros. They may or may not be used in other CFFI operators that need to translate between Lisp and C data; you may only assume that expand-* methods will probably only be called during Lisp compilation. expand-to-foreign-dyn has precedence over expand-to-foreign and is only used in defcfun and foreign-funcall, only making sense in those contexts. Important note: this set of generic functions is called at macroexpansion time. Methods are defined when loaded or evaluated, not compiled. You are responsible for ensuring that your expand-* methods are defined when the foreign-funcall or other forms that use them are compiled. One way to do this is to put the method definitions earlier in the file and inside an appropriate eval-when form; another way is to always load a separate Lisp or FASL file containing your expand-* definitions before compiling files with forms that ought to use them. Otherwise, they will not be found and the runtime translators will be used instead. Foreign Structure TypesFor example, consider this fictional C structure declaration holding some personal information: struct person { int number; char* reason; };The equivalent defcstruct form follows: (defcstruct person (number :int) (reason :string))Please note that this interface is only for those that must know about the values contained in a relevant struct. If the library you are interfacing returns an opaque pointer that needs only be passed to other C library functions, by all means just use :pointer or a type-safe definition munged together with defctype and type translation. See defcstruct for more details. PointersAll C data in CFFI is referenced through pointers. This includes defined C variables that hold immediate values, and integers.To see why this is, consider the case of the C integer. It is not only an arbitrary representation for an integer, congruent to Lisp's fixnums; the C integer has a specific bit pattern in memory defined by the C ABI. Lisp has no such constraint on its fixnums; therefore, it only makes sense to think of fixnums as C integers if you assume that CFFI converts them when necessary, such as when storing one for use in a C function call, or as the value of a C variable. This requires defining an area of memory [11], represented through an effective address, and storing it there. Due to this compartmentalization, it only makes sense to manipulate raw C data in Lisp through pointers to it. For example, while there may be a Lisp representation of a struct that is converted to C at store time, you may only manipulate its raw data through a pointer. The C compiler does this also, albeit informally. The foreign-free function frees a ptr previously allocated by foreign-alloc. The consequences of freeing a given pointer twice are undefined. ... The foreign-alloc function allocates enough memory to hold count objects of type type and returns a pointer. This memory must be explicitly freed using foreign-free once it is no longer needed. ... The function foreign-symbol-pointer will return a foreign
pointer corresponding to the foreign symbol denoted by the string foreign-name. If a foreign symbol named foreign-name doesn't exist, nil is returned. ... The mem-aref function is similar to mem-ref but will automatically calculate the offset from an index. ... The function null-pointer returns a null pointer. ... The function null-pointer-p returns true if ptr is a null pointer and false otherwise. ... The function pointer-address will return the address of a foreign pointer ptr. ... The function pointer-eq returns true if ptr1 and ptr2 point to the same memory address and false otherwise. ... Basic Pointer Operations— Lisp Type: foreign-pointer The pointers' representations differ from implementation to implementation and have different types. foreign-pointer provides a portable type alias to each of these types. Allocating Foreign MemoryThis should not be confused with what C calls "dynamic" allocation, or that done with malloc and friends. This sort of heap allocation is done with foreign-alloc, creating objects that exist until freed with foreign-free. Accessing Foreign MemoryC values are accessed as the setf-able places defined by mem-aref and mem-ref. Given a pointer and a CFFI type (see Foreign Types), either of these will dereference the pointer, translate the C data there back to Lisp, and return the result of said translation, performing the reverse operation when setf-ing. To decide which one to use, consider whether you would use the array index operator [n] or the pointer dereference * in C; use mem-aref for array indexing and mem-ref for pointer dereferencing. StringsAs with many languages, Lisp and C have special support for logical arrays of characters, going so far as to give them a special name, "strings". In that spirit, CFFI provides special support for translating between Lisp and C strings.The :string type and the symbols related below also serve as an example of what you can do portably with CFFI; were it not included, you could write an equally functional strings.lisp without referring to any implementation-specific symbols. This special variable holds the default foreign encoding. ... The foreign-string-alloc function allocates foreign memory
holding a copy of string converted using the specified encoding. start specifies an offset into string and end marks the position following the last element of the foreign string. ... The foreign-string-free function frees a foreign string allocated by foreign-string-alloc. ... The foreign-string-to-lisp function converts at most count octets from ptr into a Lisp string, using the defined encoding. ... The lisp-string-to-foreign function copies at most bufsize-1 octets
from a Lisp string using the specified encoding into buffer+offset. The foreign string will be null-terminated. ... VariablesThe function get-var-pointer will return a pointer to the foreign global variable symbol previously defined with defcvar. ... FunctionsLibraries Closes library which can be a symbol designating a library define through define-foreign-library or an instance of foreign-library as returned by load-foreign-library. ...
A list, in which each element is a string, a pathname, or a simple Lisp
expression. ... You should not have to use this variable. ... Load the library indicated by library. ... Defining a libraryBringing one of these libraries into the Lisp image is normally a two-step process. Describe to CFFI how to load the library at some future point, depending on platform and other factors, with a define-foreign-library top-level form. Load the library so defined with either a top-level use-foreign-library form or by calling the function load-foreign-library. See Loading foreign libraries, for a working example of the above two steps. Library definition style(define-foreign-library libcurl (t (:default "libcurl")))Indeed, this would work just as well on the computer on which I tested the tutorial. There are a couple of good reasons to provide the .so's current version number, however. Namely, the versionless .so is not packaged on most Unix systems along with the actual, fully-versioned library; instead, it is included in the "development" package along with C headers and static .a libraries. The reason CFFI does not try to account for this lies in the meaning of the version numbers. A full treatment of shared library versions is beyond this manual's scope; see Library interface versions, for helpful information for the unfamiliar. For our purposes, consider that a mismatch between the library version with which you tested and the installed library version may cause undefined behavior.[12] Implementor's note: Maybe some notes should go here about OS X, which I know little about. –stephen CallbacksThis is the functional version of the callback macro. It returns a pointer to the callback named by symbol suitable, for example, to pass as arguments to foreign functions. ... The GrovellerCFFI-Grovel is a tool which makes it easier to write CFFI declarations for libraries that are implemented in C. That is, it grovels through the system headers, getting information about types and structures, so you do not have to. This is especially important for libraries which are implemented in different ways by different vendors, such as the unix/posix functions. The CFFI declarations are usually quite different from platform to platform, but the information you give to CFFI-Grovel is the same. Hence, much less work is required!If you use ASDF, CFFI-Grovel is integrated, so that it will run automatically when your system is building. This feature was inspired by SB-Grovel, a similar SBCL-specific project. CFFI-Grovel can also be used without ASDF. Building FFIs with CFFI-GrovelCFFI-Grovel provides an ASDF component for handling the necessary calls to the C compiler and resulting file management. Specification File SyntaxThere are several forms recognized by CFFI-Grovel:
ASDF IntegrationThe ASDF file defines the system and its dependencies. Notice the use of eval-when to ensure CFFI-Grovel is present and the use of (cffi-grovel:grovel-file name &key cc-flags) instead of (:file name). ;;; CFFI-Grovel is needed for processing grovel-file components (cl:eval-when (:load-toplevel :execute) (asdf:operate 'asdf:load-op 'cffi-grovel))The "package.lisp" file would contain several defpackage forms, to remove circular dependencies and make building the project easier. Note that you may or may not want to :use your internal package. Implementor's note: Mention that it's a not a good idea to :USE when names may clash with, say, CL symbols. (defpackage #:example-internal (:use) (:nicknames #:exampleint))The internal package is created by Lisp code output from the C program written by CFFI-Grovel; if your specification file is exampleint.lisp, the exampleint.cffi.lisp file will contain the CFFI definitions needed by the rest of your project. See Groveller Syntax. Implementation NotesFor foo-internal.lisp, the resulting foo-internal.c, foo-internal, and foo-internal.cffi.lisp are all platform-specific, either because of possible reader-macros in foo-internal.lisp, or because of varying C environments on the host system. For this reason, it is not helpful to distribute any of those files; end users building CFFI-Grovel based software will need cffi-Grovel anyway. If you build with multiple architectures in the same directory (e.g. with NFS/AFS home directories), it is critical to remove these generated files or the resulting constants will be very incorrect. Implementor's note: Maybe we should tag the generated names with something host or OS-specific? Implementor's note: For now, after some experimentation with clisp having no long-long, it seems appropriate to assert that the generated .c files are architecture and operating-system dependent, but lisp-implementation independent. This way the same .c file (and so the same .grovel-tmp.lisp file) will be shareable between the implementations running on a given system. LimitationsThese are CFFI's limitations across all platforms; for information on the warts on particular Lisp implementations, see Implementation Support.The tutorial includes a treatment of the primary, intractable limitation of CFFI, or any FFI: that the abstractions commonly used by C are insufficiently expressive. See Breaking the abstraction, for more details. C structs cannot be passed by value. Platform-specific featuresWhenever a backend does not support one of CFFI's features, a specific symbol is pushed onto cl:*features*. The meanings of these symbols follow.
Footnotes[1] Admittedly, this is an advanced issue, and we encourage you to leave this text until you are more familiar with how CFFI works.[2] This does not apply to structs whose contents are intended to be part of the public library interface. In those cases, a pure Lisp struct definition is always preferred. In fact, many prefer to stay in Lisp and break the encapsulation anyway, placing the burden of correct library interface definition on the library. [3] Specifically, UFFI, an older FFI that takes a somewhat different approach compared to CFFI. I believe that these days (December 2005) CFFI is more portable and actively developed, though not as mature yet. Consensus in the free unix Common Lisp community seems to be that CFFI is preferred for new development, though UFFI will likely go on for quite some time as many projects already use it. CFFI includes the UFFI-COMPAT package for complete compatibility with UFFI. [4] This isn't entirely true; some Lisps don't support foreign-funcall, so defcfun is implemented without it. defcfun may also perform optimizations that foreign-funcall cannot. [5] Another possibility is to allow the caller to specify the desired C type of the third argument. This is essentially what happens in a call to the function written in C. [6] See Other Kinds of Streams, for a GNU-only way to extend the FILE* type. You could use this to convert Lisp streams to the needed C data. This would be quite involved and far outside the scope of this tutorial. [7] “But I thought Lisp was supposed to protect me from all that buggy C crap!” Before asking a question like that, remember that you are a stranger in a foreign land, whose residents have a completely different set of values. [8] There are advantages and disadvantages to each approach; I chose to (setf symbol-function) earlier because it entailed generating fewer magic function names. [9] Unfortunately, we can't protect against all non-local exits, such as returns and throws, because unwind-protect cannot be used to "short-circuit" a non-local exit in Common Lisp, due to proposal minimal in ANSI issue Exit-Extent. Furthermore, binding an error handler prevents higher-up code from invoking restarts that may be provided under the callback's dynamic context. Such is the way of compromise. [10] It might be better to return (values) than :curle-ok in real code, but this is good for illustration. [11] The definition of memory includes the CPU registers. [12] Windows programmers may chafe at adding a unix-specific clause to define-foreign-library. Instead, ask why the Windows solution to library incompatibility is “include your own version of every library you use with every program”. [13] See Using asdf to load systems, for information on asdf:*central-registry*. [14] See mini-eval in libraries.lisp for the source of this definition. As is always the case with a Lisp eval, it's easier to understand the Lisp definition than the english. [15] Namely, CMUCL. See use-foreign-library in libraries.lisp for details. | Exported Symbol Index |