I'm new to SWIG and if my question is documented, feel free to just post the link and I'll read through it.
I have a C function that takes the form:
int myFunc(char *output, const char *input)
I generated the Python wrapper, and I tried calling this function (in Python) with:
m=""
n="valid input string"
myFunc(m,n)
This simply prints the (int) return code, and m is still "". What am I doing wrong?
Thanks!
From the SWIG manual section 8.3.4:
If your C function is declared like this:
int myFunc(char *myOutput, const char *myInput);
Then you can use the following SWIG interface syntax:
%include "cstring.i"
%cstring_bounded_output(char *myOutput, 1024);
int myFunc(char *myOutput, const char *myInput);
This should result in a Python wrapper function taking a single string argument (myInput) and returning a tuple of an integer (the C function's return value) and a string (myOutput). Memory for the string will be allocated by SWIG and be 1024 bytes in length, in this example.
OK, it is not recommended practice (see my comment), and YMMV, but this seems to work for me with Python 2.4:
#pre-allocate enough space for m
m = "\x00"*100
n = "valid input string"
myFunc(m,n)
# now m.rstrip("\x00") has what you want
Related
I have a fairly simple C routine I would like to access via Python, using SWIG:
int routine(char *instring, char *outstring);
The input string is just passed in, and that seems to work. The outstring return is a pointer to a fixed array within the C routine, and my problem is how to pass a python parameter to it using the python interface.
When I use python, I get:
>>retstring = "foo"
>>retval = routine("Hello world", retstring)
This (obviously) doesn't work because the value is lost when the scope returns to the prompt level. But the routine doesn't fail. The problem is, any OTHER parameter I pass in fails because it is not considered a char *.
Other than not returning the string, the routine seems to be working.
I'm not sure what to do. Do I have to modify with typemaps to produce a second return? Is there an example somewhere that shows this?
Okay, I got it to work like this (.i file):
%module example
%include cstring.i
%cstring_bounded_output(char *outcs, 1024); // large magic number...
%{
#include "routine.h"
%}
int routine(char *instring, char *outcs);
The call is then (in Python):
import example
retval, restring = example.routine("Hello World")
This (I hope) is quite a simple issue, but despite doing some reading (I'm v. new to SWIG, and fairly green C-wise) I'm just not able to make the "connection" in my head.
I have a function from a library (legacy code, keen not to edit):
extern int myfunction(char *infile, char *maskfile, int check, float *median, char *msg)
My aim is to create a wrapper for this in Python using SWIG.
The values of the median and msg variables are changed by the C function. When the return int != 0 then there will be some error information in the msg arg. Where the return int == 0, then median variable will contain a float with value assigned from myfunction.
This generally runs OK where the return value is 0. I use %array_functions and %pointer_functions to create the pointers needing to be passed, as per this .i file:
%module test
%include "cpointer.i"
%include "carrays.i"
%{
#include <stdint.h>
%}
extern int myfunction(char *infile, char *maskfile, int check, float *median, char *msg)
%pointer_functions(float, floatp);
%pointer_functions(char, charp);
%array_functions(char, charArray);
After swig-ing, compiling and linking, I can call the function in python:
import test
errmsg_buffer = 1024
_infile = 'test2.dat'
infile = imstat.new_charArray(len(_infile))
for i in xrange(len(_infile)):
imstat.charArray_setitem(infile,i,_infile[i])
maskfile = imstat.new_charArray(1)
imstat.charArray_setitem(maskfile,0,'')
check = 0
med = imstat.new_floatp()
errmsg = imstat.new_charArray(errmsg_buffer)
out = test.myfunction(infile,maskfile,check,med,errmsg)
median = test.floatp_value(med)
This works sometimes, but often not - I get a lot of segfaults which are generally fixed by changing the errmsg_buffer length (clearly not a useful fix!). The C code that changes the msg string is:
(void)sprintf(errmsg,"file not found");
My main issue is in proper handling of msg string, which I suspect is causing the segfaults (and might be due to incorrect implementation via new_charArray?).
What is the best way to do this?
Can I add something to the .i that converts the char *msg into a python str?
Can this be done without "pre-initialising" with new_CharArray? I'd presumably get a buffer overflow if errmsg_buffer is too small.
I hope this is clear - happy to add comments for further discussion.
Your wrapper can be much simplified using SWIG. Try this SWIG interface file (details below):
%module test
%include "typemaps.i"
%include "cstring.i"
%apply float *OUTPUT { float *median };
%cstring_bounded_output(char *msg, 1024);
extern int myfunction(char *infile, char *maskfile, int check, float *median, char *msg);
Then, from python, use the module in the following way:
import test
infile = 'test2.dat'
maskfile = ''
check = 0
out, median, errmsg = test.myfunction(infile,maskfile,check)
if out == 0: print(errmsg)
...
However, from what you write, it is not quite clear to me why your approach segfaults.
Details
The typemaps.i file contains the float *OUTPUT typemap, which is then applied to the float *median argument and turns this from an argument into a float output value. See the SWIG docs on argument handling for details.
The cstrings.i file contains SWIG macros to deal with C strings. Here, I used the %cstring_bounded_output macro. This creates a char * buffer of the given size 1024 and passes this as the argument for char *msg automatically. Then, the contents after the function complete are converted into a python string and appended to the output. See here for details.
SWIG handles the first two char * arguments by default, that is converting python strings to appropriate char * and passing these. Note that the passed char * for these arguments are immutable, i.e., if your myfunction attempts to modify these, bad things will happen. Read about how SWIG handles C strings here.
So, your wrapped myfunction then is used as shown above and has the following signature in python:
myfunction(infile, maskfile, check) -> (out, median, msg)
EDIT:
The SWIG docs about carrays.i state:
Note: %array_functions() and %array_class() should not be used with types of char or char *.
I think your code is not creating correctly NULL-terminated C char *, so perhaps this could be causing the segfaults.
I am not learn SWIG very deeply.But I try give you some suggestions.
1.
If your program modifies the input parameter or uses it to return data, consider using the cstring.i library file described in the SWIG Library chapter.
Data is copied into a new Python string and returned.
If your program needs to work with binary data, you can use a typemap to expand a Python string into a pointer/length argument pair. As luck would have it, just such a typemap is already defined. Just do this:
%apply (char *STRING, int LENGTH) { (char *data, int size) };
...
int parity(char *data, int size, int initial);
Python:
parity("e\x09ffss\x00\x00\x01\nx", 0)
If you need to return binary data, you might use the cstring.i library file. The cdata.i library can also be used to extra binary data from arbitrary pointers.
2.I think "pre-initialising" maybe necessary.
I am writing a Cython wrapper around a C library we are maintaining. I am getting the following error message:
analog.pyx:6:66: Cannot convert 'unsigned short (*)' to Python object
Here's the code I am trying to write:
cimport company as lib
def get_value(device, channel, index):
cdef unsigned short aValue
err = library_get_data_val(device, channel, index, &aValue) # line 6
# Ignore the err return value for StackOverflow.
return aValue
The prototype of the C function I am trying to use is:
unsigned long library_get_data_val(unsigned long device, int channel,
int index, unsigned short *pValue);
The library function returns the requested value in the aValue parameter. It's just an unsigned short primitive. What's the expected way of returning primitives (i.e. not struct) from these type of functions? I am new to Cython so the answer may be quite simple but I didn't see anything obvious through Google.
I think the problem is that you haven't defined library_get_data_val properly, so Cython thinks it's a Python type function you're calling, and doesn't know what to do with the pointer to aValue
Try:
cdef extern from "header_containing_library_get_data_val.h":
# I've taken a guess at the signature of library_get_data_val
# Update it to match reality
int library_get_data_val(int device, int channel, int index, int* value)
That way Cython knows it's a C-function that expects a pointer, and will be happy.
(Edited to be significantly changed from my original answer, where I misunderstood the problem!)
I found out what my problem was. You can probably tell what it is now that I've edited the question. There's a company.pxd file that's cimported by the .pyx file. Once I copied the C prototype into company.pxd it worked.
I also needed to use the lib prefix in my call:
err = lib.library_get_data_val(device, channel, index, &aValue) # line 6
I was wondering what is the correct way to wrap an array of strings in C to a Python list using SWIG.
The array is inside a struct :
typedef struct {
char** my_array;
char* some_string;
}Foo;
SWIG automatically wraps some_string to a python string.
What should I put in the SWIG interface file so that I can access my_array in Python as a regular Python string list ['string1', 'string2' ] ?
I have used typemap as sugested :
%typemap(python,out) char** {
int len,i;
len = 0;
while ($1[len]) len++;
$result = PyList_New(len);
for (i = 0; i < len; i++) {
PyList_SetItem($result,i,PyString_FromString($1[i]));
}
}
But that still didn't work. In Python, the my_array variable appears as SwigPyObject: _20afba0100000000_p_p_char.
I wonder if that is because the char** is inside a struct? Maybe I need to inform SWIG that?
Any ideas?
I don't think there is a option to handle this conversion automatically in SWIG. You need use Typemap feature of SWIG and write type converter manually. Here you can find a conversion from Python list to char** http://www.swig.org/Doc1.3/Python.html#Python_nn59 so half of job is done. What you need to do right now is to check rest of documentation of Typemap and write converter from char** to Python list.
I am not an expert on this but I think:
%typemap(python,out) char** {
applies to a function that returns char **. Your char ** is inside a structure.. have a look at the code generated by swig to confirm the map got applied or not.
You might have to use something like:
%typemap(python,out) struct Foo {
To have a map that works on a structure Foo that gets returned.
Background: I used the same typemap definition as you used, but then for a char ** successfully.
I am sorry for being slightly off-topic, but if it is an option for you I would strongly recommend using ctypes instead of swig. Here is a related question I asked previously in ctypes context: Passing a list of strings to from python/ctypes to C function expecting char **
I'd like to use some existing C++ code, NvTriStrip, in a Python tool.
SWIG easily handles the functions with simple parameters, but the main function, GenerateStrips, is much more complicated.
What do I need to put in the SWIG interface file to indicate that primGroups is really an output parameter and that it must be cleaned up with delete[]?
///////////////////////////////////////////////////////////////////////////
// GenerateStrips()
//
// in_indices: input index list, the indices you would use to render
// in_numIndices: number of entries in in_indices
// primGroups: array of optimized/stripified PrimitiveGroups
// numGroups: number of groups returned
//
// Be sure to call delete[] on the returned primGroups to avoid leaking mem
//
bool GenerateStrips( const unsigned short* in_indices,
const unsigned int in_numIndices,
PrimitiveGroup** primGroups,
unsigned short* numGroups,
bool validateEnabled = false );
FYI, here is the PrimitiveGroup declaration:
enum PrimType
{
PT_LIST,
PT_STRIP,
PT_FAN
};
struct PrimitiveGroup
{
PrimType type;
unsigned int numIndices;
unsigned short* indices;
PrimitiveGroup() : type(PT_STRIP), numIndices(0), indices(NULL) {}
~PrimitiveGroup()
{
if(indices)
delete[] indices;
indices = NULL;
}
};
Have you looked at the documentation of SWIG regarding their "cpointer.i" and "carray.i" libraries? They're found here. That's how you have to manipulate things unless you want to create your own utility libraries to accompany the wrapped code. Here's the link to the Python handling of pointers with SWIG.
Onto your question on getting it to recognize input versus output. They've got another section in the documentation here, that describes exactly that. You lable things OUTPUT in the *.i file. So in your case you'd write:
%inline{
extern bool GenerateStrips( const unsigned short* in_dices,
const unsigned short* in_numIndices,
PrimitiveGroup** OUTPUT,
unsigned short* numGroups,
bool validated );
%}
which gives you a function that returns both the bool and the PrimitiveGroup* array as a tuple.
Does that help?
It's actually so easy to make python bindings for things directly that I don't know why people bother with confusing wrapper stuff like SWIG.
Just use Py_BuildValue once per element of the outer array, producing one tuple per row. Store those tuples in a C array. Then Call PyList_New and PyList_SetSlice to generate a list of tuples, and return the list pointer from your C function.
I don't know how to do it with SWIG, but you might want to consider moving to a more modern binding system like Pyrex or Cython.
For example, Pyrex gives you access to C++ delete for cases like this. Here's an excerpt from the documentation:
Disposal
The del statement can be applied to a pointer to a C++ struct
to deallocate it. This is equivalent to delete in C++.
cdef Shrubbery *big_sh
big_sh = new Shrubbery(42.0)
display_in_garden_show(big_sh)
del big_sh
http://www.cosc.canterbury.ac.nz/greg.ewing/python/Pyrex/version/Doc/Manual/using_with_c++.html