Preface:
I have two header files: "Sample.h" and "Sample2.h". Here are the contents of the two headers:
"Sample.h" has:
#include "Sample2.h"
typedef struct {
int c;
sJustFloats sJf;
}sTest;
"Sample2.h" has:
typedef struct {
float a;
float b;
}sJustFloats;
Sample.c just has:
#include "Sample.h"
My SWIG interface file has:
%module Sample
%{
/* Put header files here or function declarations like below */
#include "Sample.h"
%}
%include "Sample.h"
%apply float {float a}; // For sJustFloats.a
%apply float {float b}; // For sJustFloats.b
%apply int {int c}; // For sTest.c
%apply sJustFloats {sJustFloats sJf}; // For sTest.sJf
%apply sTest {sTest test}; //I guess this exposes test struct itself.
Steps followed to get .so file that is imported in Python:
gcc -c -fPIC Sample.c Sample_wrap.c -I /usr/include/python3.6m
ld -shared Sample.o Sample_wrap.o -o _Sample.so
Observations:
I am able to import this as a module in Python and I can access fields of sTest as follows:
test = Sample.sTest()
test.c // To access "c" -- This works fine
Problem: I am not able to access fields of struct sJustFloats
If I do test.sJf(), it gives me TypeError: 'SwigPyObject' object is not callable. Similarly test.sJf.a gives: AttributeError: 'SwigPyObject' object has no attribute 'a'
Can someone please tell me how to access members of the struct, sJustFloats?
Additional observations:
When I do type(Sample.sTest), it gives me <class 'type'>, whereas doing type(Sample.sTest.sJf) gives me <class 'property'>.
If I have both structs in the same file "Sample.h", I am able to access all the fields by doing:
test = Sample.sTest()
sjf = test.sJf()
sjf.a # Works fine
sjf.b # Works fine
Am I missing something in the interface file? Are there are nuances of SWIG that I'm unaware of?
SWIG doesn’t recurse by default, but you need %include "Sample2.h" after %include "Sample.h" and don’t need any of the %apply:
%module Sample
%{
#include "Sample.h"
%}
%include "Sample.h"
%include "Sample2.h"
Related
i have a SWIG C-python interface. I want to make individual functions from test.c available in my python interface. I feel like i am wasting hrs on the documentation without finding the simple way to do it. The only options i know are to either:
%module test
%{
#include "test.h"
//#include "test.c"
%}
%include "stdint.i" # Add support for uint8_t, int32_t, etc...
/** Keep test immutable for now because we have const struct members in the
* header file which can not be reassigned.
*/
%immutable;
%include test.h // Test header for interface debugging
//%include test.c
//%import test.h
%mutable;
I tried either #including 'test.c' in the %{} section of my interface (This section just copies the file content into the target interface), %include 'test.c' or %import 'test.c'
But i have a whole bunch of other functions in 'test.c' that have dependencies to other files and i cannot import the generated interface in python (ImportError: Undefined symbol:)
#include "test.h"
#include "someotherfunctions.h"
#include "specialdefines.h"
int testFunc(int n, int m) // The function i want to use
{
int res = n + m;
return res;
}
int otherFunc(void)
{
otherDifferentFunc(); // Stuff from other header/c files which my interface doesnt know
}
SPECIALMACRO(X) // More stuff from other headers that i dont want in my interface
int foo = someOtherOperation(500);
The header file test.h:
/* Functions ----------------------------------------------------------------*/
int testFunc(int n, int m);
I feel like i am not having the right approach to make single functions available in my Python interface without including all the unwanted stuff from all the headers in my source file. In reality, my 'test.c' is quite large and includes a whole bunch of header for all sorts of symbols and external functions used. If i dont #include all oft those in my %{} interface section, i get the import error. But if i include them, they again require other headers (its a large project) and i am starting a messy chain of includes for just a tiny function, unnecessary bloating my interface. This can't be the SWIG way to go guys?
If someone knows a good way to solve this, please let me know.
%module test
%{
// Whatever goes here is directly copied to the generated wrapper code.
// Put what you need here for the wrapper to build, typically just
// your public headers.
#include "test.h"
%}
// Anything you declare or %import is processed to make the SWIG interface.
// You can %import "test.h" and all the functions *directly* in
// the header (not other #include in the header), are exposed to Python.
//
// If you only want one function, just put its prototype, like:
int testFunc(int n, int m);
When you build the wrapper, swig the .i file to generate test_wrap.c, then compile test.c and test_wrap.c and link them together at the link step.
An example:
test.i
%module test
%{
#include "test.h"
%}
// uncomment to bring in func1 and func2 (not func3, but it's still used by func2)
//%include "test.h"
// only exposes func1
int func1();
test.h
int func1();
int func2();
test.c
#include "test.h"
int func3() { return 3; }
int func2() { return func3() - 1; }
int func1() { return func2() - 1; }
makefile (Windows, Microsoft compiler)
all: _test.pyd
test_wrap.c test.py: test.i test.h
echo swigging...
swig -python test.i
_test.pyd: test_wrap.c test.c test.h
cl /nologo /LD /MD /W3 /Fe_test.pyd /Id:\dev\python310\include test_wrap.c test.c -link /libpath:d:\dev\python310\libs
Output (built as above, only func1() exposed):
>>> import test
>>> test.func1
<function func1 at 0x000001CF6DEF7F40>
>>> test.func1()
1
>>> test.func2()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: module 'test' has no attribute 'func2'. Did you mean: 'func1'?
Output (built uncommenting the %include and commenting the prototype):
>>> import test
>>> test.func1()
1
>>> test.func2()
2
>>> test.func3()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: module 'test' has no attribute 'func3'. Did you mean: 'func1'?
Consider this mcve:
mcve.h
#pragma once
#include <windows.h>
class Windows {
public:
static HWND GetActiveWindow();
static HWND GetForegroundWindow();
};
mcve.cpp
#include "mcve.h"
HWND Windows::GetActiveWindow() {
return ::GetActiveWindow();
}
HWND Windows::GetForegroundWindow() {
return ::GetForegroundWindow();
}
mcve.i
%module mcve
%include <std_string.i>
%include <std_vector.i>
%include <typemaps.i>
%include <windows.i>
%include <cpointer.i>
%include <carrays.i>
%{
#include "mcve.h"
%}
%include "mcve.h"
setup.py
from distutils.core import Extension
from distutils.core import setup
setup(
name="mcve",
ext_modules=[
Extension(
"_mcve",
sources=["mcve.i", "mcve.cpp", "mcve_wrap.cpp"],
swig_opts=["-c++", "-python"],
include_dirs=["."],
library_dirs=[
"D:/software/vcpkg/installed/x86-windows/lib"
],
libraries=["user32"]
)
],
py_modules=["mcve"],
)
In order to run it, make sure you adjust properly the library_dirs variable and then just type:
python setup.py build_ext --inplace
If the extension has been generated succesfully then you just run python test.py and you should see an output similar to this:
>python test.py
swig/python detected a memory leak of type 'HWND *', no destructor found.
swig/python detected a memory leak of type 'HWND *', no destructor found.
I know you can use swig -nodefaultdtor to not generate implicit default destructors, I've tried and that didn't make any difference.
For the sake of completeness, here's roughly how the HWND typedefs would look like:
typedef PVOID HANDLE;
typedef HANDLE HWND;
typedef void *PVOID;
QUESTION: What's the proper way in swig to prevent that memory leak of HWND?
SWIG wasn't provided a definition of HWND and treats it as an opaque class. Note that %include "mcve.h" does NOT recurse into #include <windows.h> and only processes code directly in mcve.h, so SWIG has no definition at all.
There are a couple of solutions:
Give SWIG a definition that it understands. SWIG has a default for void*, and would correctly handle the following definition:
%module mcve
%{
#include "mcve.h"
%}
typedef void* HWND;
%include "mcve.h"
You can make custom typemaps instructing Python how to convert an HWND to and from a Python object. Unlike the previous solution, which returns a SWIG-wrapped void* object, this solution treats handles as integers:
%module mcve
%{
#include "mcve.h"
%}
%typemap(in) HWND %{
$1 = PyLong_AsVoidPtr($input);
%}
%typemap(out) HWND %{
$result = PyLong_FromVoidPtr($1);
%}
%include "mcve.h"
I am trying to create a Python Bluetooth wrapper to wrap C++ classes. This is my SWIG interface file:
%module blsdk
%include "pyabc.i"
%include "std_vector.i"
%include "cstring.i"
%include "cpointer.i"
%include "typemaps.i"
%include serialport.i
%include exploresearch.i
Here is my serialport.i
%module serialport
%{
#include <string>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <termios.h>
#include <sys/poll.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <assert.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
#include <bluetooth/rfcomm.h>
#include "BTSerialPortBinding.h"
%}
%include "BTSerialPortBinding.h"
My BTSerialPortBinding.h has these functions:
static BTSerialPortBinding *Create(std::string address, int channelID);
int Connect();
void Close();
int Read(char *buffer, int length);
void Write(const char *write_buffer, int length);
bool IsDataAvailable();
How can I wrap the int Read(char* buffer, int length) function? I want to have the char* buffer as output and the length as input. I have tried to define the read function as int Read(char* OUTPUT, int length) but this gives an error: TypeError: a bytes-like object is required, not 'str' in my program as I need a byte object in Python. Any help would be very much appreciated.
This is not a complete answer but it might serve to get you started hacking around. As always with SWIG the key is looking at the generated code and monkeying around with it. Writing off the top of my head so again, just a starting point.
One thing you can do is a bit hacky but could work if you have some theoretical limit to how much data you read. A handy way is to 'swallow' the input and return value with a pair like this:
%typemap(in,numinputs=0) char *buffer
{
$1 = malloc(some_arbitrary_large_amount);
// or 'cheat' by looking at swig output and using the value you just happen
// to know is the length (like arg1 or something)
}
%typemap(argout) char *buffer
{
PyObject *tmp = $result;
int len = 0;
int res = SWIG_AsVal_long(tmp, &len);
if(!SWIG_IsOK(res)) {
free($1);
SWIG_fail;
}
$result = SWIG_From_CharPtrAndSize( $1, len );
PyDecRef(tmp); //probably?
free($1);
}
This would change the interface on the python side to just take the length argument and return a python string which may not be what you want. Note that you can return whatever you like so instead of SWIG_From_CharPtr you could create some other python object like a bytearray.
Another approach is to play with multi-arg typemaps. More hazy on the details here but you'd be doing something like:
%typemap(in) (char *buffer, int length)
{
/*
$input is a python object of your choice - bytearray?
Use the various Python/Swig APIs to decode the input object.
Set $1 and $2 to the data pointer and length decoded from
your input object and they will be passed to the C function.
*/
}
Now you have a Read() function on the python side that takes one argument which is up to you to create and set the size of. Could be anything as long as you can figure out how to get access to the internal array and size. Numpy is a pretty good candidate but if you're using Numpy, they already have a really nice set of typemaps for SWIG. Then you'd just do:
%include "numpy.i"
%apply( char *IN_ARRAY1, int DIM1 )
and give it a numpy array.
I am trying to SWIG a C++ library to Python. One of the C++ functions returns a shared_ptr. I am successful at producing a Python module but the object returned by that function to Python appears to have no members. Is this a limitation of SWIG's handling of shared_ptr or am I doing something wrong?
This is roughly the structure of my code:
//foo.h
namespace MyNamespace
{
class Base {};
template <typename T> class Derived : public Base {};
std::shared_ptr<Base> make_obj();
}
SWIG:
//foo.i
%module foo
%include <std_shared_ptr.i>
%{
#define SWIG_FILE_WITH_INIT
#include "foo.h"
%}
%include "foo.h"
%template(FooA) MyNamespace::Derived< MyNamespace::AAA >;
%template(FooB) MyNamespace::Derived< MyNamespace::BBB >;
%shared_ptr(MyNamespace::Base)
%shared_ptr(FooA)
%shared_ptr(FooB)
I think you've got the order of things a little wrong here. Notice that in all the examples in the shared_ptr documentation they call %shared_ptr before any declaration/definition of that type is seen at all.
With the caveats commented about the %shared_ptr directive and the FooA/FooB template instances corrected for I believe something like this ought to work for your example.
//foo.i
%module foo
%include <std_shared_ptr.i>
%{
#define SWIG_FILE_WITH_INIT
#include "foo.h"
%}
%shared_ptr(MyNamespace::Base)
%shared_ptr(FooA) // This should probably be MyNamespace::Derived<...>
%shared_ptr(FooB) // This should probably be the fully qualified C++ type also
%include "foo.h"
%template(FooA) MyNamespace::Derived< MyNamespace::AAA >;
%template(FooB) MyNamespace::Derived< MyNamespace::BBB >;
I have a C header file containing structure definitions with typedef, and an array of char definition with typedef too:
/* File: test.h */
typedef struct
{
char *key;
void *value;
int size;
} cti_pair;
typedef char FOO[CONST];
The SWIG interface file contains the following lines:
/* File: test.i */
%module test
%{
#define SWIG_FILE_WITH_INIT
#include "/home/users/jdoe/workspace/project/src/lib-cti/test.h"
...
%}
#ifndef CTI_TYPES_H_
#define CTI_TYPES_H_
#include "cti_const.h"
typedef char FOO[CONST];
typedef struct
{
char *key;
void *value;
int size;
} cti_pair;
The problem is that I can access the cti_pair struct, but can't use FOO (it's not defined) in my python script.
Ok, just figure out what the problem was.
Actually, I used %extend in another part of the interface file. But this keyword can only be used on structures, not on basic typedef (and SWIG does not display any error message if we use %extend the wrong way).
As a matter of fact, FOO was defined. The problem was not related to this at all. Thanks!