diff options
author | William S Fulton <wsf@fultondesigns.co.uk> | 2022-10-06 23:12:38 +0100 |
---|---|---|
committer | William S Fulton <wsf@fultondesigns.co.uk> | 2022-10-06 23:29:33 +0100 |
commit | cea25abca535fa27b89eedaf2dd978991b42e1a5 (patch) | |
tree | 85e669698ad41a576e5ccdf52eef8de35340e92e /Doc | |
parent | 7b0f7caaf2c4d8e863b38a88099ea9dd7e3df0e5 (diff) | |
download | swig-cea25abca535fa27b89eedaf2dd978991b42e1a5.tar.gz |
Completely remove CFFI
No meaningful progress to update CFFI to experimental status
has been made since CFFI was disabled in SWIG-4.0.0 as the first
stage to removal. This commit is the final stage to remove it.
See issue #1966 for an attempt at updating CFFI to experimental
status. Anyone wishing for SWIG to support CFFI again might
want to utilise this work.
Diffstat (limited to 'Doc')
-rw-r--r-- | Doc/Manual/Lisp.html | 604 |
1 files changed, 0 insertions, 604 deletions
diff --git a/Doc/Manual/Lisp.html b/Doc/Manual/Lisp.html deleted file mode 100644 index 6d8463beb..000000000 --- a/Doc/Manual/Lisp.html +++ /dev/null @@ -1,604 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -<html> -<head> -<title>SWIG and Common Lisp</title> -<link rel="stylesheet" type="text/css" href="style.css"> -<meta http-equiv="content-type" content="text/html; charset=UTF-8"> -</head> - -<body bgcolor="#ffffff"> -<H1><a name="Lisp">29 SWIG and Common Lisp</a></H1> -<!-- INDEX --> -<div class="sectiontoc"> -<ul> -<li><a href="#Lisp_nn3">Common Foreign Function Interface(CFFI)</a> -<ul> -<li><a href="#Lisp_nn4">Additional Commandline Options </a> -<li><a href="#Lisp_nn5">Generating CFFI bindings</a> -<li><a href="#Lisp_nn6">Generating CFFI bindings for C++ code</a> -<li><a href="#Lisp_nn7">Inserting user code into generated files</a> -</ul> -<ul> -<li><a href="#Lisp_nn9">Additional Commandline Options </a> -</ul> -</ul> -</div> -<!-- INDEX --> - - - -<p> - Common Lisp is a high-level, all-purpose, object-oriented, - dynamic, functional programming language with long history. - Common Lisp is used in many fields, ranging from web development to - finance, and also common in computer science education. - There are more than 9 different implementations of common lisp which - are available, all have different foreign function - interfaces. SWIG currently supports the - Common Foreign Function Interface(CFFI). -</p> - -<H2><a name="Lisp_nn3">29.2 Common Foreign Function Interface(CFFI)</a></H2> - - -<p> - CFFI, the Common Foreign Function Interface, is a portable foreign - function interface for ANSI Common Lisp systems. - CFFI requires only a small set of - low-level functionality from the Lisp implementation, such as - calling a foreign function by name, allocating foreign memory, - and dereferencing pointers. -</p> - -<p> - To run the cffi module of SWIG requires very little effort, you - just need to run: -</p> -<div class="code"><pre> -swig -cffi -module <i>module-name</i> <i>file-name</i> - -</pre></div> - -<p> - But a better was of using all the power of SWIG is to write SWIG - interface files. Below we will explain how to write interface - files and the various things which you can do with them. -</p> - -<H3><a name="Lisp_nn4">29.2.1 Additional Commandline Options </a></H3> - - -<table summary="CFFI specific options"> -<tr> - <th> CFFI specific options</th> -</tr> - -<tr> -<td>-generate-typedef</td> -<td>If this option is given then defctype will be used to generate<br/> - shortcuts according to the typedefs in the input. -</td> -</tr> - -<tr> -<td>-[no]cwrap</td> -<td>Turn on or turn off generation of an intermediate C file when<br/> - creating a C interface. By default this is only done for C++ code. -</td> -</tr> - -<tr> -<td>-[no]swig-lisp</td> -<td>Turns on or off generation of code for helper lisp macro, functions, - etc. which SWIG uses while generating wrappers. These macros, functions - may still be used by generated wrapper code. -</td> -</tr> - -</table> - -<H3><a name="Lisp_nn5">29.2.2 Generating CFFI bindings</a></H3> - - -<p> - -As we mentioned earlier the ideal way to use SWIG is to use interface - files. To illustrate the use of it, let's assume that we have a - file named <i>test.h</i> with the following C code: -</p> - -<div class="code"><pre> -#define y 5 -#define x (y >> 1) - -typedef int days; - -struct bar { - short p, q; - char a, b; - int *z[1000]; - struct bar * n; -}; - -struct bar * my_struct; - -struct foo { - int a; - struct foo * b[100]; -}; - -int pointer_func(void (*ClosureFun)( void* _fun, void* _data, void* _evt ), int p); - -int func123(div_t * p, int **q[100], int r[][1000][10]); - -void lispsort_double (int n, double * array); - -enum color { RED, BLUE, GREEN}; -</pre></div> - -<p> -Corresponding to this we will write a simple interface file: -</p> - -<div class="code"><pre> -%module test - -%include "test.h" - -</pre></div> - -<p> -The generated SWIG Code will be: -</p> - -<div class="targetlang"><pre> -;;;SWIG wrapper code starts here - -(cl:defmacro defanonenum (&body enums) - "Converts anonymous enums to defconstants." - `(cl:progn , @(cl:loop for value in enums - for index = 0 then (cl:1+ index) - when (cl:listp value) do (cl:setf index (cl:second value) - value (cl:first value)) - collect `(cl:defconstant , value , index)))) - -(cl:eval-when (:compile-toplevel :load-toplevel) - (cl:unless (cl:fboundp 'swig-lispify) - (cl:defun swig-lispify (name flag cl:&optional (package cl:*package*)) - (cl:labels ((helper (lst last rest cl:&aux (c (cl:car lst))) - (cl:cond - ((cl:null lst) - rest) - ((cl:upper-case-p c) - (helper (cl:cdr lst) 'upper - (cl:case last - ((lower digit) (cl:list* c #\- rest)) - (cl:t (cl:cons c rest))))) - ((cl:lower-case-p c) - (helper (cl:cdr lst) 'lower (cl:cons (cl:char-upcase c) rest))) - ((cl:digit-char-p c) - (helper (cl:cdr lst) 'digit - (cl:case last - ((upper lower) (cl:list* c #\- rest)) - (cl:t (cl:cons c rest))))) - ((cl:char-equal c #\_) - (helper (cl:cdr lst) '_ (cl:cons #\- rest))) - (cl:t - (cl:error "Invalid character: ~A" c))))) - (cl:let ((fix (cl:case flag - ((constant enumvalue) "+") - (variable "*") - (cl:t "")))) - (cl:intern - (cl:concatenate - 'cl:string - fix - (cl:nreverse (helper (cl:concatenate 'cl:list name) cl:nil cl:nil)) - fix) - package)))))) - -;;;SWIG wrapper code ends here - - -(cl:defconstant y 5) - -(cl:defconstant x (cl:ash 5 -1)) - -(cffi:defcstruct bar - (p :short) - (q :short) - (a :char) - (b :char) - (z :pointer) - (n :pointer)) - -(cffi:defcvar ("my_struct" my_struct) - :pointer) - -(cffi:defcstruct foo - (a :int) - (b :pointer)) - -(cffi:defcfun ("pointer_func" pointer_func) :int - (ClosureFun :pointer) - (p :int)) - -(cffi:defcfun ("func123" func123) :int - (p :pointer) - (q :pointer) - (r :pointer)) - -(cffi:defcfun ("lispsort_double" lispsort_double) :void - (n :int) - (array :pointer)) - -(cffi:defcenum color - :RED - :BLUE - :GREEN) -</pre></div> - -<p> - The <i>SWIG wrapper</i> code refers to the special code which SWIG - may need to use while wrapping C code. You can turn on/off the - generation of this code by using the <i>-[no]swig-lisp</i> - option. You must have noticed that SWIG goes one extra step to - ensure that CFFI does not do automatic lispification of the C - function names. The reason SWIG does this is because quite often - developers want to build a nice CLOS based lispy API, and this one - to one correspondence between C function names and lisp function - name helps. -</p> - -<p> Maybe you want to have your own convention for generating lisp - function names for corresponding C function names, or you just - want to lispify the names, also, before we forget you want to - export the generated lisp names. To do this, we will use the - SWIG <a - href="Customization.html#Customization_features">feature directive</a>. -Let's edit the interface file such that the C type "div_t*" is changed - to Lisp type ":my-pointer", we lispify all names, - export everything, and do some more stuff. - -</p> -<div class="code"><pre> -%module test - -%typemap(cin) div_t* ":my-pointer" - -%feature("intern_function", "1"); -%feature("export"); - -%feature("inline") lispsort_double; -%feature("intern_function", "my-lispify") lispsort_double; -%feature("export", package="'some-other-package") lispsort_double; - -%rename func123 renamed_cool_func; - -%ignore "pointer_func"; - -%include "test.h" - -</pre></div> - -<p> -The <i>typemap(cin)</i> ensures that for all arguments which are input - to C with the type "div_t*", the ":my-pointer" type be - used. Similarly <i>typemap(cout)</i> are used for all types which - are returned from C. -</p> -<p> -The feature <i>intern_function</i> ensures that all C names are - interned using the <b>swig-lispify</b> function. The "1" given - to the feature is optional. The use of feature like - <i>%feature("intern_function", "1");</i> globally enables - interning for everything. If you want to target a single - function, or declaration then use the targeted version of - feature, <i>%feature("intern_function", "my-lispify") - lispsort_double;</i>, here we are using an additional feature - which allows us to use our lispify function. -</p> -<p>The <i>export</i> feature allows us to export the symbols. If - the <i>package</i> argument is given, then the symbol will be exported to - the specified Lisp package. The <i>inline</i> feature declaims the - declared function as inline. The <i>rename</i> directive allows us to - change the name(it is useful when generating C wrapper code for handling - overloaded functions). The <i>ignore</i> directive ignores a certain - declaration. -</p> -<p>There are several other things which are possible, to see some - example of usage of SWIG look at the Lispbuilder and wxCL - projects. The generated code with 'noswig-lisp' option is: -</p> - -<div class="targetlang"><pre> -(cl:defconstant #.(swig-lispify "y" 'constant) 5) - -(cl:export '#.(swig-lispify "y" 'constant)) - -(cl:defconstant #.(swig-lispify "x" 'constant) (cl:ash 5 -1)) - -(cl:export '#.(swig-lispify "x" 'constant)) - -(cffi:defcstruct #.(swig-lispify "bar" 'classname) - (#.(swig-lispify "p" 'slotname) :short) - (#.(swig-lispify "q" 'slotname) :short) - (#.(swig-lispify "a" 'slotname) :char) - (#.(swig-lispify "b" 'slotname) :char) - (#.(swig-lispify "z" 'slotname) :pointer) - (#.(swig-lispify "n" 'slotname) :pointer)) - -(cl:export '#.(swig-lispify "bar" 'classname)) - -(cl:export '#.(swig-lispify "p" 'slotname)) - -(cl:export '#.(swig-lispify "q" 'slotname)) - -(cl:export '#.(swig-lispify "a" 'slotname)) - -(cl:export '#.(swig-lispify "b" 'slotname)) - -(cl:export '#.(swig-lispify "z" 'slotname)) - -(cl:export '#.(swig-lispify "n" 'slotname)) - -(cffi:defcvar ("my_struct" #.(swig-lispify "my_struct" 'variable)) - :pointer) - -(cl:export '#.(swig-lispify "my_struct" 'variable)) - -(cffi:defcstruct #.(swig-lispify "foo" 'classname) - (#.(swig-lispify "a" 'slotname) :int) - (#.(swig-lispify "b" 'slotname) :pointer)) - -(cl:export '#.(swig-lispify "foo" 'classname)) - -(cl:export '#.(swig-lispify "a" 'slotname)) - -(cl:export '#.(swig-lispify "b" 'slotname)) - -(cffi:defcfun ("renamed_cool_func" #.(swig-lispify "renamed_cool_func" 'function)) :int - (p :my-pointer) - (q :pointer) - (r :pointer)) - -(cl:export '#.(swig-lispify "renamed_cool_func" 'function)) - -(cl:declaim (cl:inline #.(my-lispify "lispsort_double" 'function))) - -(cffi:defcfun ("lispsort_double" #.(my-lispify "lispsort_double" 'function)) :void - (n :int) - (array :pointer)) - -(cl:export '#.(my-lispify "lispsort_double" 'function) 'some-other-package) - -(cffi:defcenum #.(swig-lispify "color" 'enumname) - #.(swig-lispify "RED" 'enumvalue :keyword) - #.(swig-lispify "BLUE" 'enumvalue :keyword) - #.(swig-lispify "GREEN" 'enumvalue :keyword)) - -(cl:export '#.(swig-lispify "color" 'enumname)) - -</pre></div> - -<H3><a name="Lisp_nn6">29.2.3 Generating CFFI bindings for C++ code</a></H3> - - -<p>This feature to SWIG (for CFFI) is very new and still far from - complete. Pitch in with your patches, bug reports and feature - requests to improve it. -</p> -<p> Generating bindings for C++ code, requires <i>-c++</i> option to be - present and it first generates C binding which will wrap the C++ - code, and then generates the - corresponding CFFI wrapper code. In the generated C wrapper - code, you will often want to put your own C code, such as the - code to include various files. This can be done by making use of - "%{" and "%}" as shown below. -</p> -<div class="code"><pre> -%{ - #include "Test/test.h" -%} -</pre></div> -<p> -Also, while parsing the C++ file and generating C wrapper code SWIG - may need to be able to understand various symbols used in other - header files. To help SWIG in doing this while ensuring that - wrapper code is generated for the target file, use the "import" - directive. The "include" directive specifies the target file for - which wrapper code will be generated. -</p> -<div class="code"><pre> - -%import "ancillary/header.h" - -%include "target/header.h" - -</pre></div> -<p> -Various features which were available for C headers can also be used - here. The target header which we are going to use here is: -</p> -<div class="code"><pre> -namespace OpenDemo { - class Test - { - public: - float x; - // constructors - Test (void) {x = 0;} - Test (float X) {x = X;} - - // vector addition - Test operator+ (const Test& v) const {return Test (x+v.x);} - - // length squared - float lengthSquared (void) const {return this->dot (*this);} - - static float distance (const Test& a, const Test& b){return(a-b).length();} - - inline Test parallelComponent (const Test& unitBasis) const { - return unitBasis * projection; - } - - Test setYtoZero (void) const {return Test (this->x);} - - static const Test zero; - }; - - inline Test operator* (float s, const Test& v) {return v*s;} - - inline std::ostream& operator<< (std::ostream& o, const Test& v) - { - return o << "(" << v.x << ")"; - } - - inline Test RandomUnitVectorOnXZPlane (void) - { - return RandomVectorInUnitRadiusSphere().setYtoZero().normalize(); - } -} -</pre></div> -<p>The interface used is: </p> -<div class="code"><pre> -%module test -%include "test.cpp" -</pre></div> - -<p> -SWIG generates 3 files, the first one is a C wrap which we don't show, - the second is the plain CFFI wrapper which is as shown below: -</p> -<div class="targetlang"><pre> -(cffi:defcfun ("_wrap_Test_x_set" Test_x_set) :void - (self :pointer) - (x :float)) - -(cffi:defcfun ("_wrap_Test_x_get" Test_x_get) :float - (self :pointer)) - -(cffi:defcfun ("_wrap_new_Test__SWIG_0" new_Test) :pointer) - -(cffi:defcfun ("_wrap_new_Test__SWIG_1" new_Test) :pointer - (X :float)) - -(cffi:defcfun ("_wrap_Test___add__" Test___add__) :pointer - (self :pointer) - (v :pointer)) - -(cffi:defcfun ("_wrap_Test_lengthSquared" Test_lengthSquared) :float - (self :pointer)) - -(cffi:defcfun ("_wrap_Test_distance" Test_distance) :float - (a :pointer) - (b :pointer)) - -(cffi:defcfun ("_wrap_Test_parallelComponent" Test_parallelComponent) :pointer - (self :pointer) - (unitBasis :pointer)) - -(cffi:defcfun ("_wrap_Test_setYtoZero" Test_setYtoZero) :pointer - (self :pointer)) - -(cffi:defcvar ("Test_zero" Test_zero) - :pointer) - -(cffi:defcfun ("_wrap_delete_Test" delete_Test) :void - (self :pointer)) - -(cffi:defcfun ("_wrap___mul__" __mul__) :pointer - (s :float) - (v :pointer)) - -(cffi:defcfun ("_wrap___lshift__" __lshift__) :pointer - (o :pointer) - (v :pointer)) - -(cffi:defcfun ("_wrap_RandomUnitVectorOnXZPlane" RandomUnitVectorOnXZPlane) :pointer) -</pre></div> - -<p> -The output is pretty good but it fails in disambiguating overloaded - functions such as the constructor, in this case. One way of - resolving this problem is to make the interface use the rename - directiv, but hopefully there are better solutions. - In addition SWIG also generates, a CLOS file -</p> - - -<div class="targetlang"><pre> -(clos:defclass test() - ((ff :reader ff-pointer))) - -(clos:defmethod (cl:setf x) (arg0 (obj test)) - (Test_x_set (ff-pointer obj) arg0)) - -(clos:defmethod x ((obj test)) - (Test_x_get (ff-pointer obj))) - -(cl:shadow "+") -(clos:defmethod + ((obj test) (self test) (v test)) - (Test___add__ (ff-pointer obj) (ff-pointer self) (ff-pointer v))) - -(clos:defmethod length-squared ((obj test) (self test)) - (Test_lengthSquared (ff-pointer obj) (ff-pointer self))) - -(clos:defmethod parallel-component ((obj test) (self test) (unitBasis test)) - (Test_parallelComponent (ff-pointer obj) (ff-pointer self) (ff-pointer unitBasis))) - -(clos:defmethod set-yto-zero ((obj test) (self test)) - (Test_setYtoZero (ff-pointer obj) (ff-pointer self))) -</pre></div> - -<p>I agree that the CFFI C++ module needs lot more work. But I hope it - provides a starting point, on which you can base your work of - importing C++ libraries to Lisp. -</p> -<p> -If you have any questions, suggestions, patches, etc., related to CFFI - module feel free to contact us on the SWIG mailing list, and - also please add a "[CFFI]" tag in the subject line. - -<H3><a name="Lisp_nn7">29.2.4 Inserting user code into generated files</a></H3> - - -<p> -It is often necessary to <a href="SWIG.html#SWIG_nn40">include user-defined code</a> -into the automatically generated interface files. For example, when building -a C++ interface, example_wrap.cxx will likely not compile unless -you add a <tt>#include "header.h"</tt> directive. This can be done -using the SWIG <tt>%insert(section) %{ ...code... %}</tt> directive: -</p> - -<div class="code"> -<pre> -%module example - -%{ -#include "header.h" -%} - -%include "header.h" - -int fact(int n); -</pre> -</div> - -<p> -Additional sections have been added for inserting into the -generated lisp interface file: -</p> -<ul> - <li><tt>lisphead</tt> - inserts before type declarations</li> - <li><tt>swiglisp</tt> - inserts after type declarations according to - where it appears in the .i file</li> -</ul> -<p> -Note that the block <tt>%{ ... %}</tt> is effectively a shortcut for -<tt>%insert("header") %{ ... %}</tt>. -</p> - - -</body> -</html> |