Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swig wrapping typedef struct

Tags:

swig

Trying to wrap a binary library where the headerfile defines a typedef struct x x_t where struct x has not been defined. How can i define a interface file that allows python to use the type defed structure in the Functions defined below.

myconnection.h

typedef int myConnectionError;

// Note: this struct does not exist
// The typedef is done to strengthen type checking
typedef struct _myConnectionHandle* myConnectionHandle;

myConnectionError myConnectionOpen( const char *x , const char *y , myConnectionHandle *hand);

myconnection.i

% module myconnection
%{
#include "myconnection.h"
%}

%include "myconnection.h"

Example of Working C/C++ code

myConnectionHandle chandle;
myConnectionError error;
error = myConnectionOpen("foo","bar",&chandle);

Expected Python code

import myconnection
handle = myconnection.myConnectionHandle
err = myconnection.myConnectionOpen("foo","1080",handle)

Python result

Python 2.6.6 (r266:84292, Jan 22 2014, 09:42:36) 
[GCC 4.4.7 20120313 (Red Hat 4.4.7-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import myconnection
>>> handle = myconnection.myConnectionHandle()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'myConnectionnHandle'
like image 800
Markus Jonsson Avatar asked Nov 10 '22 00:11

Markus Jonsson


1 Answers

Since Python doesn't support output parameters, the typical way is to create a set of typemaps that suppress having to pass an output parameter and instead use a temporary value internally that is appended to the return value. Here's a minimal example that converts the handles to and from Python integer objects:

%typemap(in) myConnectionHandle %{
    $1 = (myConnectionHandle)PyLong_AsVoidPtr($input);
%}

%typemap(in,numinputs=0) myConnectionHandle* (void* tmp) %{
    $1 = (myConnectionHandle*)&tmp;
%}
%typemap(argout) myConnectionHandle* %{
    $result = SWIG_Python_AppendOutput($result,PyLong_FromVoidPtr(*$1));
%}

The first typemap converts a Python integer to a myConnectionHandle to be used as an input to a function.

The second typemap tells SWIG to ignore myConnectionHandle* on input since it is an output parameter, and just use a temporary value to store the handle in when calling the function.

The third typemap tells SWIG to append the returned handle value to the return result, converting it to a list of [retval, handle] if necessary.

Here's an example using your myconnection.h but I added a function to take a handle as input as well and added some dummy implementation of the functions to get it to compile.

%module myconnection
%{
    #include "myconnection.h"
    myConnectionError myConnectionOpen( const char *x , const char *y , myConnectionHandle *hand)
    {
        static int something;
        *hand = (myConnectionHandle)&something;
        return 0;
    }
    void useConnection(myConnectionHandle h)
    {
    }
%}

%typemap(in) myConnectionHandle %{
    $1 = (myConnectionHandle)PyLong_AsVoidPtr($input);
%}

%typemap(in,numinputs=0) myConnectionHandle* (void* tmp) %{
    $1 = (myConnectionHandle*)&tmp;
%}

%typemap(argout) myConnectionHandle* %{
    $result = SWIG_Python_AppendOutput($result,PyLong_FromVoidPtr(*$1));
%}

%include "myconnection.h"

Output:

>>> import myconnection
>>> retval, handle = myconnection.myConnectionOpen('foo','bar')
>>> myconnection.useConnection(handle)
>>>
like image 59
Mark Tolonen Avatar answered Dec 14 '22 23:12

Mark Tolonen