diff --git a/src/doc/new-doc/extensions/ffi.txi b/src/doc/new-doc/extensions/ffi.txi index b5d330324..825003d54 100644 --- a/src/doc/new-doc/extensions/ffi.txi +++ b/src/doc/new-doc/extensions/ffi.txi @@ -49,13 +49,13 @@ sections. @node Two kinds of FFI @subsection Two kinds of FFI +@cindex Two kinds of FFI ECL allows for two different appraoches when building a FFI. Both approaches have a different implementation philosophy and affect the places where you can use the FFI and how. @table @dfn @item Static FFI (SFFI) -@cindex Static FFI For every foreign function and variable you might need to use, a wrapper is automatically written in C with the help of ffi:c-inline. These wrappers are compiled using an ordinary C compiler and linked against @@ -68,7 +68,6 @@ user may directly invoked. @c @item Library FFI (LFFI) @item Dynamic FFI (DFFI) -@cindex Dynamic FFI First of all, the foreign libraries are loaded in memory using the facilities of the operating system. Similar routines are used to find out and register the memory location of all the functions and variables diff --git a/src/doc/new-doc/extensions/ffi_sffi.txi b/src/doc/new-doc/extensions/ffi_sffi.txi index 65d79d44d..fefc63319 100644 --- a/src/doc/new-doc/extensions/ffi_sffi.txi +++ b/src/doc/new-doc/extensions/ffi_sffi.txi @@ -1,6 +1,9 @@ @node SFFI Reference @subsection SFFI Reference @cindex C/C++ code inlining +@cindex Static foreign function interface + +@subsubheading Reference @lspindex ffi:clines @defspec ffi:clines c/c++-code* diff --git a/src/doc/new-doc/extensions/ffi_uffi.txi b/src/doc/new-doc/extensions/ffi_uffi.txi index fd04d5fc8..dd64315ee 100644 --- a/src/doc/new-doc/extensions/ffi_uffi.txi +++ b/src/doc/new-doc/extensions/ffi_uffi.txi @@ -1,12 +1,13 @@ @node UFFI Reference @subsection UFFI Reference +@cindex Universal foreign function interface @menu * Primitive Types :: * Aggregate Types :: -* UFFI Objects :: -@c * Strings -@c * Functions and Libraries +* Foreign Objects :: +* Foreign Strings :: +* Functions and Libraries @end menu @node Primitive Types @@ -89,6 +90,7 @@ Points to a generic object. Used to declare a pointer to an object. @end table +@subsubheading Reference @lspindex ffi:def-constant @defmac ffi:def-constant name value &key (export nil) @@ -192,7 +194,8 @@ return a integer whence dereferencing a C character pointer. @subsubheading Overview Aggregate types are comprised of one or more primitive types. - +@subsubheading Reference + @lspindex ffi:def-enum @defmac ffi:def-enum name fields &key separator-key @@ -422,17 +425,15 @@ Defines a foreign union type. Defines a new foreign type. @end defmac - - -@node UFFI Objects -@subsubsection Objects +@node Foreign Objects +@subsubsection Foreign Objects @cindex Foreign objects @subsubheading Overview Objects are entities that can allocated, referred to by pointers, and can be freed. - +@subsubheading Reference @lspindex ffi:allocate-foreign-object @defun ffi:allocate-foreign-object type &optional size @@ -464,8 +465,6 @@ object. @end lisp @end defun - - @lspindex ffi:free-foreign-object @defun ffi:free-foreign-object ptr @@ -480,8 +479,6 @@ A pointer to the allocated foreign object to free. Frees memory that was allocated for a foreign object. @end defun - - @lspindex ffi:with-foreign-object @defmac ffi:with-foreign-object (var type) &body body @@ -515,8 +512,6 @@ foreign object around the body of code. @end lisp @end defmac - - @lspindex ffi:size-of-foreign-type @defmac ffi:size-of-foreign-type ftype @@ -543,8 +538,6 @@ does not include any Lisp storage overhead. @end lisp @end defmac - - @lspindex ffi:pointer-address @defun ffi:pointer-address ptr @@ -561,8 +554,6 @@ An integer representing the pointer's address. Returns the address as an integer of a pointer. @end defun - - @lspindex ffi:deref-pointer @defun ffi:deref-pointer ptr ftype @@ -595,7 +586,6 @@ together with the @code{DEREF-POINTER}/@code{DEREF-ARRAY}. ;; => 10 @end lisp @end defun - @lspindex ffi:ensure-char-character @defun ffi:ensure-char-character object @@ -627,7 +617,6 @@ Ensures that an objects obtained by dereferencing @code{:char} and Depending upon the implementation and what UFFI expects, this macro may signal an error if the object is not a character or integer. @end defun - @lspindex ffi:ensure-char-integer @defun ffi:ensure-char-integer object @@ -659,7 +648,6 @@ Ensures that an objects obtained by dereferencing @code{:char} and Depending upon the implementation and what UFFI expects, this macro may signal an error if the object is not a character or integer. @end defun - @lspindex ffi:make-null-pointer @defun ffi:make-null-pointer ftype @@ -674,8 +662,6 @@ The NULL pointer of type @var{ftype}. @end table @end defun - - @lspindex ffi:null-pointer-p @defun ffi:null-pointer-p ptr @@ -689,16 +675,12 @@ The boolean flag. @end table @end defun - - @lspindex ffi:+null-cstring-pointer+ @defvr {FFI} {+null-cstring-pointer+} A NULL cstring pointer. This can be used for testing if a cstring returned by a function is NULL. @end defvr - - @lspindex ffi:with-cast-pointer @defmac ffi:with-cast-pointer (var ptr ftype) &body body @@ -736,8 +718,6 @@ execution of @var{BODY}. @end lisp @end defmac - - @lspindex ffi:def-foreign-var @defmac ffi:def-foreign-var name type module @@ -764,8 +744,9 @@ Defines a symbol macro which can be used to access (get and set) the value of a variable in foreign code. @subsubheading Examples -@exindex @code{ffi:def-foreign-var} +@exindex @code{ffi:def-foreign-var} places in foreign world +C code defining foreign structure, standalone integer and the accessor: @example @verbatim int baz = 3; @@ -783,8 +764,10 @@ int foo () { @end verbatim @end example +Lisp code defining C structure, function and a variable: @lisp -(ffi:def-struct foo-struct (x :int) +(ffi:def-struct foo-struct + (x :int) (y :double)) (ffi:def-function ("foo" foo) () @@ -800,59 +783,299 @@ int foo () { @end lisp @end defmac - +@node Foreign Strings +@subsubsection Foreign Strings +@cindex Foreign strings -@lspindex ffi: -@defmac ffi: +@subsubheading Overview +@cindex @code{cstring} and @code{foreign string} differences -desc +UFFI has functions to two types of C-compatible strings: @code{cstring} +and foreign strings. @code{cstrings} are used only as parameters to and +from functions. In some implementations a @code{cstring} is not a +foreign type but rather the Lisp string itself. On other platforms a +cstring is a newly allocated foreign vector for storing characters. The +following is an example of using cstrings to both send and return a +value. +@exindex @code{cstring} used to send and return a value +@lisp +(ffi:def-function ("getenv" c-getenv) + ((name :cstring)) + :returning :cstring) + +(defun my-getenv (key) + "Returns an environment variable, or NIL if it does not exist" + (check-type key string) + (ffi:with-cstring (key-native key) + (ffi:convert-from-cstring (c-getenv key-native)))) +@end lisp + +In contrast, foreign strings are always a foreign vector of characters +which have memory allocated. Thus, if you need to allocate memory to +hold the return value of a string, you must use a foreign string and not +a cstring. The following is an example of using a foreign string for a +return value. + +@exindex @code{foreign string} used to send and return a value +@lisp +(ffi:def-function ("gethostname" c-gethostname) + ((name (* :unsigned-char)) + (len :int)) + :returning :int) + +(defun gethostname () + "Returns the hostname" + (let* ((name (ffi:allocate-foreign-string 256)) + (result-code (c-gethostname name 256)) + (hostname (when (zerop result-code) + (ffi:convert-from-foreign-string name)))) + ;; UFFI does not yet provide a universal way to free + ;; memory allocated by C's malloc. At this point, a program + ;; needs to call C's free function to free such memory. + (unless (zerop result-code) + (error "gethostname() failed.")))) +@end lisp + +Foreign functions that return pointers to freshly allocated strings +should in general not return @code{cstring}s, but @code{foreign +strings}. (There is no portable way to release such @code{cstring}s from +Lisp.) The following is an example of handling such a function. + +@exindex Conversion between @code{foreign string} and @code {cstring} +@lisp +(ffi:def-function ("readline" c-readline) + ((prompt :cstring)) + :returning (* :char)) + +(defun readline (prompt) + "Reads a string from console with line-editing." + (ffi:with-cstring (c-prompt prompt) + (let* ((c-str (c-readline c-prompt)) + (str (ffi:convert-from-foreign-string c-str))) + (ffi:free-foreign-object c-str) + str))) +@end lisp + +@subsubheading Reference + +@lspindex ffi:convert-from-cstring +@defmac ffi:convert-from-cstring object +Converts a @code{cstring} to a Lisp string @table @var -@item arg-1 -description -@item arg-2 -description +@item object +@code{cstring} @item returns -One value? More? +Lisp string @end table @subsubheading Description -Description here - -@subsubheading Examples -@exindex @code{ffi:} sample run -@lisp - -@end lisp - -@subsubheading Side effects -foo bar +Converts a Lisp string to a cstring. This is most often used when +processing the results of a foreign function that returns a cstring. @end defmac - - -@lspindex ffi: -@defmac ffi: - -desc +@lspindex ffi:convert-to-cstring +@defmac ffi:convert-to-cstring object +Converts a Lisp string to a @code{cstring} @table @var -@item arg-1 -description -@item arg-2 -description +@item object +Lisp string @item returns -One value? More? +@code{cstring} @end table @subsubheading Description -Description here - -@subsubheading Examples -@exindex @code{ffi:} sample run -@lisp - -@end lisp - -@subsubheading Side effects -foo bar +Converts a Lisp string to a cstring. The cstring should be freed with +free-cstring. +@subsubheading Side Effects +This function allocates memory. @end defmac + + +@lspindex ffi:free-cstring +@defmac ffi:convert-from-cstring cstring +Free memory used by @var{cstring} +@table @var +@item cstring +@code{cstring} to be freed. +@end table +@subsubheading Description +Frees any memory possibly allocated by convert-to-cstring. On ECL, a +cstring is just the Lisp string itself. +@end defmac + + +@lspindex ffi:with-cstring +@defmac ffi:with-cstring (cstring string) &body body +Binds a newly created @code{cstring} +@table @var +@item cstring +A symbol naming the @code{cstring} to be created. +@item string +A Lisp string that will be translated to a @code{cstring}. +@item body +The body of where the @var{cstring} will be bound. +@item returns +Result of evaluating the @var{body}. +@end table +@subsubheading Description +Binds a symbol to a @code{cstring} created from conversion of a +@var{string}. Automatically frees the @var{cstring}. +@subsubheading Examples +@exindex @code{with-cstring} +@lisp +(ffi:def-function ("getenv" c-getenv) + ((name :cstring)) + :returning :cstring) + +(defun getenv (key) + "Returns an environment variable, or NIL if it does not exist" + (check-type key string) + (ffi:with-cstring (key-cstring key) + (ffi:convert-from-cstring (c-getenv key-cstring)))) +@end lisp +@end defmac + +@lspindex ffi:with-cstrings +@defmac ffi:with-cstrings bindings &body body +Binds a newly created @code{cstrings} +@table @var +@item bindings +List of pairs @var{(cstring string)}, where @var{cstring} is a name +for a @code{cstring} translated from Lisp string @var{string}. +@item body +The body of where the @var{bindings} will be bound. +@item returns +Result of evaluating the @var{body}. +@end table +@subsubheading Description +Binds a symbols to a @code{cstring}s created from conversion of a +@var{string}s. Automatically frees the @var{cstring}s. This macro works +similar to @code{LET*}. Based on @code{with-cstring}. +@end defmac + +@lspindex ffi:convert-from-foreign-string +@defmac ffi:convert-from-foreign-string foreign-string &key length (null-terminated-p t) +Converts a foreign string into a Lisp string +@table @var +@item foreign-string +A foreign string. +@item length +The length of the foreign string to convert. The default is the length +of the string until a NULL character is reached. +@item null-terminated-p +A boolean flag with a default value of T When true, the string is +converted until the first NULL character is reached. +@item returns +A Lisp string. +@end table +@subsubheading Description +Returns a Lisp string from a foreign string. Can translated ASCII and +binary strings. +@end defmac + +@lspindex ffi:convert-to-foreign-string +@defmac ffi:convert-to-foreign-string +Converts a Lisp string to a foreign string +@table @var +@item string +A Lisp string. +@item returns +A foreign string. +@end table +@subsubheading Description +Converts a Lisp string to a foreign string. Memory should be freed with +free-foreign-object. +@end defmac + +@lspindex ffi:allocate-foreign-string +@defmac ffi:allocate-foreign-string size &key unsigned +Allocates space for a foreign string +@table @var +@item size +The size of the space to be allocated in bytes. +@item unsigned +A boolean flag with a default value of T. When true, marks the pointer +as an :unsigned-char. +@item returns +A foreign string which has undefined contents. +@end table +@subsubheading Description +Allocates space for a foreign string. Memory should be freed with +free-foreign-object. +@end defmac + +@lspindex ffi:with-foreign-string +@defmac ffi:with-foreign-string (foreign-string string) &body body +Binds a newly allocated @code{foreign-string} +@table @var +@item foreign-string +A symbol naming the @code{foreign string} to be created. +@item string +A Lisp string that will be translated to a @code{foreign string}. +@item body +The body of where the @var{foreign-string} will be bound. +@item returns +Result of evaluating the @var{body}. +@end table +@subsubheading Description +Binds a symbol to a @code{foreign-string} created from conversion of a +@var{string}. Automatically deallocates the @var{foreign-string}. +@subsubheading Examples +@end defmac + +@lspindex ffi:with-foreign-strings +@defmac ffi:with-foreign-strings bindings &body body +Binds a newly created @code{foreign string} +@table @var +@item bindings +List of pairs @var{(foreign-string string)}, where @var{foreign-string} +is a name for a @code{foreign string} translated from Lisp string +@var{string}. +@item body +The body of where the @var{bindings} will be bound. +@item returns +Result of evaluating the @var{body}. +@end table +@subsubheading Description +Binds a symbols to a @code{foreign-string}s created from conversion of a +@var{string}s. Automatically frees the @var{foreign-string}s. This macro +works similar to @code{LET*}. Based on @code{with-foreign-string}. +@end defmac + +@node Functions and Libraries +@subsubsection Functions and Libraries +@cindex Foreign functions and libraries + +@c def-function +@c load-foreign-library +@c find-foreign-library + + + +@c @lspindex ffi: +@c @defmac ffi: + +@c desc + +@c @table @var +@c @item arg-1 +@c description +@c @item arg-2 +@c description +@c @item returns +@c One value? More? +@c @end table + +@c @subsubheading Description +@c Description here + +@c @subsubheading Examples +@c @exindex @code{ffi:} sample run +@c @lisp + +@c @end lisp + +@c @subsubheading Side effects +@c foo bar +@c @end defmac diff --git a/src/lsp/ffi.lsp b/src/lsp/ffi.lsp index db263cd6c..42124674e 100644 --- a/src/lsp/ffi.lsp +++ b/src/lsp/ffi.lsp @@ -407,21 +407,38 @@ Ensures that a dereferenced char or integer is a lisp integer." (si::foreign-data-pointer obj 0 1 '(* :unsigned-char))) (defmacro convert-from-cstring (object) + "Syntax: (convert-from-cstring object) + +Converts a Lisp string to a cstring. This is most often used when +processing the results of a foreign function that returns a cstring." object) (defmacro convert-to-cstring (object) + "Syntax: (convert-to-cstring object) + +Converts cstring OBJECT to a Lisp string. Allocates memory." ;; This enforces that the string contains only as many characters as the ;; fill-pointer determines Since ECL always sets a 0 character after the ;; last element of a string, this way, the string is always zero-terminated `(si:copy-to-simple-base-string ,object)) -(defmacro free-cstring (object) - object) +(defmacro free-cstring (cstring) + "Syntax: (free-cstring cstring) + +Free memory used by CSTRING." + cstring) (defmacro with-cstring ((cstring string) &body body) + "Syntax: (with-cstring (cstring string) &body body) + +Binds CSTRING to a cstring created from conversion of a STRING and +evaluated the BODY. Automatically frees the CSTRING." `(let ((,cstring (convert-to-cstring ,string))) ,@body)) (defmacro with-cstrings (bindings &rest body) + "Syntax: (with-cstrings ((cstring string)*) &body body) + +See: WITH-CSTRING. Works similar to LET*." (if bindings `(with-cstring ,(car bindings) (with-cstrings ,(cdr bindings) @@ -436,6 +453,11 @@ Ensures that a dereferenced char or integer is a lisp integer." (defun convert-from-foreign-string (foreign-string &key length (null-terminated-p t)) + "Syntax: (convert-from-foreign-string + foreign-string &key length (null-terminated-p t) + +Returns a Lisp string from a foreign string FOREIGN-STRING. Can +translated ASCII and binary strings." (cond ((and (not length) null-terminated-p) (setf length (foreign-string-length foreign-string))) ((not (integerp length)) @@ -451,6 +473,10 @@ Ensures that a dereferenced char or integer is a lisp integer." :side-effects t)) (defun convert-to-foreign-string (string-designator) + "Syntax: (convert-to-foreign-string string-designator) + +Converts a Lisp string to a foreign string. Memory should be freed +with free-foreign-object." (let ((lisp-string (string string-designator))) (c-inline (lisp-string) (t) t "{ @@ -465,11 +491,19 @@ Ensures that a dereferenced char or integer is a lisp integer." :side-effects t) )) -(defun allocate-foreign-string (size &key unsigned) +(defun allocate-foreign-string (size &key (unsigned T)) + "Syntax: (allocate-foreign-string size &key (unsigned t)) + +Allocates space for a foreign string. Memory should be freed with +FREE-FOREIGN-OBJECT. Initial contents of the string are undefined." (si::allocate-foreign-data `(* ,(if unsigned :unsigned-char :char)) (1+ size))) (defmacro with-foreign-string ((foreign-string lisp-string) &rest body) + "Syntax: (with-foreign-string ((foreign-string lisp-string) &rest body) + +Binds FOREIGN-STRING to a foreign string created from conversion of a +STRING and evaluated the BODY. Automatically frees the FOREIGN-STRING." (let ((result (gensym))) `(let* ((,foreign-string (convert-to-foreign-string ,lisp-string)) (,result (progn ,@body))) @@ -477,6 +511,9 @@ Ensures that a dereferenced char or integer is a lisp integer." ,result))) (defmacro with-foreign-strings (bindings &rest body) + "Syntax: (with-foreign-strings ((foreign-string string)*) &body body) + +See: WITH-FOREIGN-STRING. Works similar to LET*." (if bindings `(with-foreign-string ,(car bindings) (with-foreign-strings ,(cdr bindings)