Python Cookbook (3rd edition) Chinese version: 15.9 packing C code with WSIG

Source: Internet
Author: User
Tags gcd

15.9 Packing C code with WSIG?

You want to write the C code as a C extension module to access and want to do it by using the Swig wrapper generator.

Solution?

Swig operates by parsing the C header file and automatically creating extension code.
To use it, you first need to have a C header file. For example, the header file for our example is as follows:

/*Sample.H*/#include <math.h>externIntgcd(Int,Int);externIntIn_mandel(DoubleX0,DoubleY0,IntN);externIntDivide(IntA,IntB,Int*remainder); extern double avg (double *aint n span class= "n" >typedef struct point {double x,y;} point; extern double distance (point *< span class= "n" >p1point *p2   

Once you have this header file, the next step is to write a swig "interface" file.
By convention, these files are suffixed with ". I" and resemble the following:

Sample.i-swig interface%module sample%{#include "sample.h"%}/* customizations */%extend Point {/* Constructor for        Point objects */point (double x, double y) {point *p = (point *) malloc (sizeof);        p->x = x;        P->y = y;   return p; };};/  * Map int *remainder as an output argument */%include typemaps.i%apply int *output {int * remainder};/* Map the argument  Pattern (double *a, int n) to arrays */%typemap (in) (double *a, int n) (Py_buffer view) {view.obj = NULL; if (Pyobject_getbuffer ($input, &view, pybuf_any_contiguous |  Pybuf_format) = =-1) {swig_fail;    } if (strcmp (View.format, "D")! = 0) {pyerr_setstring (Pyexc_typeerror, "expected an array of doubles");  Swig_fail;  } $ = (double *) view.buf; $ = view.len/sizeof (double);}  %typemap (Freearg) (double *a, int n) {if (view$argnum.obj) {pybuffer_release (&view$argnum); }}/* C declarations to is included in the extension module */extern int gcd (int, int); extern int In_mandel (double x0, double y0, int n), extern int divide (int a, int b, int *remainder), extern double avg (double *a, I NT n); typedef struct Point {double x, y;} Point;extern double Distance (point *p1, point *p2);

Once you have written the interface file, you can call swig in the command-line tool:

--sample.  I%    

The output of Swig is two files, sample_wrap.c and sample.py.
The file that follows is what the user needs to import.
The sample_wrap.c file is the C code that needs to be compiled into the _sample support module called.
This can be done with the same technology as the normal expansion module.
For example, you create a file that resembles the following setup.py :

# setup.pyFromDistutils.coreImportSetup,ExtensionSetup(Name=' Sample ',py_modules=[ ' sample.py ' ], span class= "n" >ext_modules=[extension (  _sample ' [ ' sample_wrap.c '  include_dirs = [], define_macros = [], undef_macros = [], library_ dirs = [], libraries = [  ' sample ' ] ) ]     

To compile and test, execute Python3 on setup.py, as follows:

Bash% python3 setup.py build_ext--inplacerunning build_extbuilding ' _sample ' extensiongcc-fno-strict-aliasing- Dndebug-g-fwrapv-o3-wall-wstrict-prototypes-i/usr/local/include/python3.3m-c Sample_wrap.c-o build/ temp.macosx-10.6-x86_64-3.3/sample_wrap.osample_wrap.c:in function ' Swig_initializemodule ': sample_wrap.c:3589: Warning:statement with no effectgcc-bundle-undefined dynamic_lookup BUILD/TEMP.MACOSX-10.6-X86_64-3.3/SAMPLE.O Build /temp.macosx-10.6-x86_64-3.3/sample_wrap.o-o _sample.so-lsamplebash%

If all goes well, you will find it convenient to use the generated C extension module. For example:

>>>ImportSample>>>Sample.gcd(42,8)2>>>Sample.Divide(42,8)[5, 2]>>>P1=Sample.Point(2,3)>>>P2=Sample.Point(4,5)>>>Sample.Distance(P1,P2)2.8284271247461903>>>p1.  X2.0>>> p1.  Y3.0>>> import array>>> a = array.  Array(' d ', [1,2,3])>>> sample.  Avg(a)2.0>>>           
Discuss?

Swig is one of the oldest tools for building extension modules in Python history.
Swig can automate the processing of many packaging generators.

All swig interfaces begin with a similar following:

%Sample%{#include "sample.h"%}     

This simply declares the name of the extension module and specifies the C header file.
In order to be able to compile through the code that must contain these header files (located in%{and%}),
Copy and paste them into the output code, which is where you want to place all the definitions that contain files and other compilation needs.

The bottom part of the Swig interface is a list of C declarations that you need to include in the extension.
This is usually copied from the scratch file. In our case, we just paste it directly into the header file as follows:

%ModuleSample%{#include "sample.h"%}...externIntgcd(Int,Int);externIntIn_mandel(DoubleX0,DoubleY0,IntN);externIntDivide(IntA,IntB,Int*remainder); extern double avg (double *aint n span class= "n" >typedef struct point {double x,y;} point; extern double distance (point *< span class= "n" >p1point *p2   

One thing to emphasize is that these statements tell swig what you want to include in the Python module.
Usually you need to edit this statement list or modify it accordingly.
For example, if you don't want certain declarations to be included, you'll remove them from the declaration list.

The most complicated thing about using swig is that it can provide a lot of custom operations to C code.
This theme is too big to unfold here, but we have some custom things left in this section.

The first customization is that the %extend instruction allows the method to be appended to the existing struct and class definitions.
In my example, this constructor method is used to add a point struct.
It allows you to use this structure as follows:

Sample.  Point(2,3)>>>       

If omitted, the point object must be created in a more complex way:

 >>> # Usage if%extend point is Omitted>>> span class= "n" >p1 = sample. Point () >>> p1. x = 2.0>>> p1. Y = 3           

The second customization involves the typemaps.i introduction and instruction of the library %apply ,
It indicates that the Swig parameter signature int *remainder is to be treated as an output value.
This is actually a pattern matching rule.
In all the subsequent statements, whenever it int  *remainder happens, he will be output.
This custom method allows divide() a function to return two values.

Sample.  Divide(8)[5, 2]>>>        

The last customization that involves %typemap directives is probably the most advanced feature shown here.
A typemap is a rule in a particular parameter pattern in the input.
In this section, a typemap is defined as a matching parameter pattern (double *a, int n) .
Inside Typemap is a C code fragment that tells Swig how to convert a Python object to the corresponding C parameter.
This section of code uses Python's caching protocol to match any input parameter that looks like a double-precision array
(such as numpy arrays, arrays created by array modules, etc.), refer to section 15.3 for more information.

Inside the TYPEMAP code, variable substitution such as $ and $ will get the C parameter value of Typemap mode
(for example, map to double *a ). $input point to a parameter as input PyObject * ,
And $argnum it represents the number of parameters.

Writing and understanding Typemaps is the most basic prerequisite for using swig.
Not only is the code more cryptic, but you need to understand how the Python C API and swig interact with it.
Swig documentation for more details on this, you can refer to the following.

However, if you have a lot of C code that needs to be exposed as an extension module.
Swig is a very powerful tool. The key point is that Swig is a compiler that handles C declarations,
Powerful pattern matching and custom components let you change the way declarations are specified and typed.
For more information, please refer to the Swig website,
There are also Python-specific related documents

Albert (http://www.aibbt.com/) The first artificial intelligence portal in China

Python Cookbook (3rd edition) Chinese version: 15.9 packing C code with WSIG

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.