4.3 The C-to-FFI facility

4.3.1 Reference pages

translate-c-file Function

Syntax:translate-c-file c-filename&key:output-file :case-sensitive :defines-too :compile :thing :loud :ansi-c

Translates a C file into declarations used by the Foreign Function Interface.

Returns the truename of the Lisp file written, or the binary file if the value of the:compile keyword is non-nil.

Produces Lisp code which makes the functions, variables, and structures defined in the c-filename accessible from the Lisp world using the Foreign Function Interface.

If a value is not supplied for:output-file, it defaults to the C filename ending in .lisp, as in foo.c becoming foo.lisp. If it is the symbolt, then output is written to*standard-output* instead of a file.

If the value of the keyword:case-sensitive is non-nil, the Lisp code produced will have exactly the same case as the original C code, and that case will be preserved by the Lisp reader. This means that most symbols will be printed surrounded by vertical bars. If the value of:case-sensitive isnil (the default), the Lisp code produced will have the same case as the original C code, but that case will not be preserved by the Lisp reader.

If a value for:include is supplied, it should be a list of directory names that would normally be passed tocc as-I arguments when compiling the given C file. This is where the#include'd files exist. (We need this because we invoke the C preprocessorcpp on the file.) If a value for:include is not supplied, it defaults to the directory of c-filename.

If the value of the keyword:translate-includes is non-nil, the translation will contain text from files included using#include. If it isnil, only the text within the file specified will be translated. The value of:translate-includes defaults tonil. (Note that the include search path specified by:include is still needed even if the value of:translate-includes isnil, because the include files may contain definitions that are necessary to process the file.)

If the value of the keyword:defines-too ist (the default), then we translate simplecpp#define statements intodefconstant calls. This does not attempt to translate C macros that take arguments.

You must supply the correct#include directories. If calls totypedef are not made before the defined types are first used, then ambiguity arises and we cannot reliably parse C. Likewise, unexpanded preprocessor macros will cause parse errors.

If the value of the keyword:compile ist, we callcompile-file on the Lisp file after writing it.

:thing is what to extract from c-filename; it defaults to:all, meaning that it produces FFI calls for everything in the C file (and in the files#include'd by it, if the value of:translate-includes is non-nil). It may be a string or list of strings, which are the names of structures, functions, or variables which we should translate. However, we also translate all user-defined structures and types which are referenced by the specified thing--if a function returns a pointer to a structure, then the definition of that structure will be translated as well.

If:loud ist, then some progress messages will be written on*standard-output*. If it is:very, then a C-syntax representation of everything being parsed will be printed. This can be useful for debugging.

:ansi-c reflects whether you use an ANSI C compiler. The value should bet if you do andnil if you don't. It defaults to the value of*ansi-c*.

Note that before loading the Lisp file written bytranslate-c-file, you must uselcl:load-foreign-files orlcl:load-foreign-libraries to read in the.o or.a file corresponding to the C code which you have translated. If you don't do this, then Lisp can't determine the addresses of the global variables referenced declared in C and can't make pointers to them.

It will often be necessary to run this program on.c files as well as.h files, even if all of the functions you wish to use are declared in the.h files. Non-ANSI header files do not contain type declarations for the arguments of functions, and Lisp needs to know them.

Since we parse the output of the C preprocessor, it is not necessary to run this on every.hfile in your system--simply running it on a file which#include's the header files you wish to translate will do, since#include'd files are spliced in bycpp.

;;; Assume we begin with the C function:
;;;       int ThisIsATest ();
;;; defined in the file test.c
;;; The default case-sensitive value of nil produces 
;;; more readable code, but has the potential of producing
;;; ambiguous results, since C is strictly case-sensitive.
;;; Then the following Lisp code will be produced:
(def-foreign-function (ThisIsATest
                        (:name "_ThisIsATest")
                        (:return-type :signed-32bit)))

;;; Now we call translate-c-file with :case-sensitive true. (translate-c-file "test.c" :case-sensitive t)

(def-foreign-function (|ThisIsATest| (:name "_ThisIsATest") (:return-type :signed-32bit)))

*cpp-command* Variable

Syntax:*cpp-command*

Gives the name of the C preprocessor to use during a translation.

Default value is "/lib/cpp".

See Also: *cpp-arguments*, *prefer-multidimensional-arrays*, *make-linker-name*, *pointer-to-character-becomes-string*

*cpp-arguments* Variable

Syntax:*cpp-arguments*

Gives a list of arguments to pass to the program that is the value of the*cpp-command* variable.

The default value is-E. Do not include in this list the switch that inhibits line numbering (normally-P).

See Also: *cpp-command*, *prefer-multidimensional-arrays*, *make-linker-name*, *pointer-to-character-becomes-string*

*prefer-multidimensional-arrays* Variable

Syntax:*prefer-multidimensional-arrays*

Specifies a preference for the multidimensional idiom for arrays.

The C declarationint a[5][10]; says that the variablea holds storage for 50 integers. The expressiona[3] treatsa as a one-dimensional array of arrays, and refers to the array in the third row. The expressiona[3][3] can be viewed as either accessing slot (3, 3) in a 5x10 array, or accessing slot 3 of the array in slot 3 of a one-dimensional array.

The Foreign Function Interface lets you look at C array data in either way; this variable controls whether the multidimensional idiom should be preferred over the single-dimensional idiom. If*prefer-multidimensional-arrays* ist (the default), then the type ofint a[5][10] will be(:array :signed-32bit (5 10)). If it isnil, then the Foreign Function Interface type will instead be(:array (:array :signed-32bit (10)) (5)).

See Also:lcl:foreign-aref, *cpp-arguments*, *cpp-command*, *make-linker-name*, *pointer-to-character-becomes-string*

*make-linker-name* Variable

Syntax:*make-linker-name*

Returns the platform-dependent name of a C function.

This variable is bound to a Lisp function of one argument, a string, that returns a string. Given the name of a C function, it should return the name as it would be specified in the:name option ofdef-foreign-function. On Solaris, this function is an identity. This may have to be changed to match your C compiler.

> (apply c-to-ffi:*make-linker-name* '("my-function"))
"my-function"

See Also: *cpp-arguments*, *cpp-command*, *prefer-multidimensional-arrays*, *pointer-to-character-becomes-string*

*pointer-to-character-becomes-string* Variable

Syntax:*pointer-to-character-becomes-string*

Directs Lisp to use type:string instead of(:pointer :character).

The value of this variable is a list of none, any, or all of the keywords:function,:argument, and:struct-slot. Each of these three keywords represents a context where one can specify:

type char *
in C. Thus we have:

For each item in the list, Lisp will use type:string instead of(:pointer :character) in the corresponding C context.

Having a(:pointer :character) become:string allows you to use a Lisp string in a context where a foreign pointer would otherwise be necessary.

The default value of this variable isnil.

For the ANSI C function declaration:

int vowel_count (char * word);
the default form generated is:

(def-foreign-function (vowel_count
(:name "vowel_count")
   (:return-type :signed-32bit))
  (word (:pointer : character)))

However, if the value of*pointer-to-character-becomes-string* is'(:argument) instead ofnil, the result is:

(def-foreign-function (vowel_count
   (:name "vowel_count")
   (:return-type :signed-32bit))
  (word :string))

which allows ordinary Lisp strings to be passed as arguments.

See Also: *cpp-arguments*,*cpp-command*, *make-linker-name*,*prefer-multidimensional-arrays*

*default-archive-directories* Variable

Syntax:*default-archive-directories*

The variable*default-archive-directories* contains a list of directories that are searched by the functionsload-foreign-files andload-foreign-libraries for library(.a) files. When a library name, such as-lc, is specified, the full library name is formed by removing-l from the name, prepending the directory name, and appending the suffix.a.

> (pprint *default-archive-directories*)
("/usr/lib/lib" "/opt/SUNWspro/SC2.0.1/lib" 
 "/opt/SUNWspro/SC2.0/lib" "/usr/ccs/lib/lib"
 "/usr/ucblib/lib" "/usr/local/lib/lib")

;; Note that /opt/SUNWspro/SC2.0/libm.a is a symbolic link to ;; ./cg89/libm.a > (let ((*default-archive-directories* '("/usr/lib/lib" "/opt/SUNWspro/SC2.0/lib" "/optf77/SUNWspro/SC2.0.1/lib"))) (load-foreign-files '("ftnf.o" "ftng.o") '("-lM77" "-lF77" "-lV77" "-lm" "-lc"))) ;;; Loading foreign object file "ftnf.o" ;;; Loading foreign object file "ftng.o" ;;; Reading library file "/optf77/SUNWspro/SC2.0.1/libM77.a" ;;; Reading library file "/optf77/SUNWspro/SC2.0.1/libF77.a" ;;; Reading library file "/optf77/SUNWspro/SC2.0.1/libV77.a" ;;; Reading library file "/opt/SUNWspro/SC2.0/cg89/libm.a" ;;; Reading library file "/usr/lib/libc.a" T

*ansi-c* Variable

Syntax:*ansi-c*

This variable tells Lisp whether you are using an ANSI C compiler or not.

Give*ansi-c* the valuet (the default) if you are using an ANSI C compiler; otherwise, usenil. Liquid Common Lisp needs to know whether you are using an ANSI C compiler or not, as some non-ANSI compilers are known to have problems with single floats. Using this variable will avoid those problems.

See Also: translate-c-file


The Advanced User's Guide - 9 SEP 1996

Generated with Harlequin WebMaker