I have two swig modules that share some common headers. I only want to %include the header in one but I want the other to be able to still treat the enums as integers (rather than classes) without fully %including it. Something kind of like this:
MyEnum.h
typedef enum {
One,
Two
} MyEnum;
LibOne.i
module() libOne
%{
#include "MyEnum.h"
%}
%include "MyEnum.h"
HeaderUsingMyEnum.h
#include <MyEnum.h>
MyEnum DoSomething(MyEnum &anEnum);
MyEnum &DoAnotherThing(MyEnum *anEnum);
LibTwo.i
module() libTwo
%{
#include "MyEnum.h"
#include "HeaderUsingMyEnum.h"
%}
%include "HeaderUsingMyEnum.h"
The problem is that swig then turns around and creates swig objects in LibTwo whereas LibOne just automatically treats the enums as unsigned ints. Then I have a mismatch between the two modules on what they think a MyEnum is.
Obviously simply %including MyEnum.h in libTwo works perfectly well but it's a lot of duplication. I also know I can write a bunch of MyEnum typemaps for LibTwo but I want to know if there is an 'automatic' way to do it, maybe with %apply or some such thing?
There are quite a few enumerated types in the main library and I'd love to have a simply way to just tell SWIG to just treat them as ints.
I guess I've been struggling to solve esoteric SWIG problems and didn't recognize when one came along that was actually simple. This seems to do the trick.
%include "typemaps.i"
%apply unsigned int { MyEnum };
Related
I have a C++ method declared as follow:
std::tuple<std::vector<int>, std::size_t, std::size_t> get_state(); // Should I use a struct and expose the struct instead?
And I would like to declare a cython extension to interface it in Python
cdef extern from "cpp_sources/CClass.hpp":
cdef cppclass CClass nogil:
tuple[vector[int], size_t, size_t] get_state()
Unfortunately, I don't see an easy import to make to have access to a C++ tuple.
I also checked here with no success.
My question is, is there an easy way to have access to a c++ tuple? Or maybe there is a better way to have access to some elements?
(We don't care about performances for this exact method)
Unfortunately this is not supported. More generally variadic templates are not supported - that's why you have pair for example, but not a generic tuple.
In the github issue I linked they have their own version of a workaround, which is what I would come up with first - for every amount of N arguments I will actually use,
template<typename T_1, ... typename T_N>
using tupleN = std::tuple<T_1, ..., TN>;
and exporting each tupleN individually. There is no magic I'm aware of to make a general variadic template here.
Most of my library is written with Cython in the "normal" C mode. Up to now I rarely needed any C++ functionality, but always assumed (and sometimes did!) I could just switch to C++-mode for one module if I wanted to.
So I have like 10+ modules in C-mode and 1 module in C++-mode.
The problem is now how Cython seems to handle complex numbers definitions. In C-mode it assumes I think C complex numbers, and in C++-mode it assumes I think C++ complex numbers. I've read they might be even the same by now, but in any case Cython complains that they are not:
openChargeState/utility/cheb.cpp:2895:35: error: cannot convert ‘__pyx_t_double_complex {aka std::complex<double>}’ to ‘__complex__ double’ for argument ‘1’ to ‘double cabs(__complex__ double)’
__pyx_t_5 = ((cabs(__pyx_v_num) == INFINITY) != 0);
In that case I'm trying to use cabs defined in a C-mode module, and calling it from the C++-mode module.
I know there are some obvious workarounds (right now I'm just not using C++-mode; I'd like to use vectors and instead use the slower Python lists for now).
Is there maybe a way to tell my C++-mode module to use C complex numbers, or tell it that they are the same? If there is I couldn't find a working way to ctypedef C complex numbers in my C++-mode module... Or are there any other solutions?
EDIT: Comments of DavidW and ead suggested some reasonable things. First the minimum working example.
setup.py
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
from Cython.Build import cythonize
extra_compile_args=['-O3']
compdir = {'language_level' : '3'}
extensions = cythonize([
Extension("cmod", ["cmod.pyx"]),
Extension("cppmod", ["cppmod.pyx"], language='c++')
],
compiler_directives = compdir
)
setup(cmdclass = {'build_ext': build_ext},
ext_modules = extensions
)
import cppmod
cmod.pyx
cdef double complex c_complex_fun(double complex xx):
return xx**2
cmod.pxd
cdef double complex c_complex_fun(double complex xx)
cdef extern from "complex.h":
double cabs(double complex zz) nogil
cppmod.pyx
cimport cmod
cdef double complex cpp_complex_fun(double complex xx):
return cmod.c_complex_fun(xx)*abs(xx) # cmod.cabs(xx) doesn't work here
print(cpp_complex_fun(5.5))
Then just compile with python3 setup.py build_ext --inplace.
Now the interesting part is that (as written in the code) only "indirectly" imported c functions have a problem, in my case cabs. So the suggestion to just use abs actually does help, but I still don't understand the underlying logic. I hope I don't encounter this in another problem. I'm leaving the question up for now. Maybe somebody knows what's happening.
Your problem has nothing to do with the fact, that one module is compiled as a C-extension and the other as a C++-extension - one can easily reproduce the issue in a C++-extension alone:
%%cython -+
cdef extern from "complex.h":
double cabs(double complex zz) nogil
def cpp_complex_fun(double complex xx):
return cabs(xx)
results in your error-message:
error: cannot convert __pyx_t_double_complex {aka
std::complex<double>} to __complex__ double for argument 1 to
double cabs(__complex__ double)
The problem is that the complex numbers are ... well, complex. Cython's strategy (can be looked up here and here) to handle complex numbers is to use an available implementation from C/CPP and if none is found a hand-written fallback is used:
#if !defined(CYTHON_CCOMPLEX)
#if defined(__cplusplus)
#define CYTHON_CCOMPLEX 1
#elif defined(_Complex_I)
#define CYTHON_CCOMPLEX 1
#else
#define CYTHON_CCOMPLEX 0
#endif
#endif
....
#if CYTHON_CCOMPLEX
#ifdef __cplusplus
typedef ::std::complex< double > __pyx_t_double_complex;
#else
typedef double _Complex __pyx_t_double_complex;
#endif
#else
typedef struct { double real, imag; } __pyx_t_double_complex;
#endif
In case of a C++-extension, Cython's double complex is translated to std::complex<double> and thus cannot be called with cabs( double complex z ) because std::complex<double> isn't double complex.
So actually, it is your "fault": you lied to Cython and told him, that cabs has the signature double cabs(std::complex<double> z), but it was not enough to fool the c++-compiler.
That means, in c++-module std::abs(std::complex<double>) could be used, or just Cython's/Python's abs, which is automatically translated to the right function (this is however not possible for all standard-function).
In case of the C-extension, because you have included complex.h as an so called "early include" with cdef extern from "complex.h", thus for the above defines _Complex_I becomes defined and Cython's complex becomes an alias for double complex and thus cabs can be used.
Probably the right thing for Cython would be to always use the fallback per default and that the user should be able to choose the desired implementation (double complex or std::complex<double>) explicitly.
Since SWIG can't parse the __attribute__((packed)) on some C structs I'd like to wrap, I work around this by putting a
#define __attribute__(x)
in my .i file.
When will this come and bite me?
This is actually perfectly sane. SWIG doesn't need to know anything about the layout of the structs you're wrapping in order to be able to generate correct code. (It doesn't even need to know about all the members they contain even).
The reason for this is that the code which is generated is largely just marshaling data. In C you can legally write:
void show_a(const struct foo *instance) {
printf("%s", instance->b);
}
Regardless of whether foo was defined as:
struct foo {
double a;
char *b;
}
or
struct foo {
char *b;
double a,c;
int xyz;
}
The only place where the packing/alignment matters is when creating new structs. This is handled correctly though also, provided you don't also hide the attribute from the C compiler itself, because the generated C wrapper code will be using the real definition and not the pseudo one that you showed in the interface file.
It's a little bit clunky, but you can convince yourself of this as required by reading through the generated wrapper.
The general answer is that you can lie to SWIG itself quite a lot and it'll all work out alright in the end when the C compiler sees the generated code and reconciles it with the real definitions/declarations.
In the specific case the short answer is: so long as you only put that #define in the .i file and then only in a place where it doesn't get passed out to your generated module_wrap.c you're fine.
I have some C source code and want to wrap it in Cython. Now, the problem is, that there is a structure called print, and externing it throws a syntax error.
cdef extern from "foo.h":
struct print:
# ...
Same problem would appear when an attribute or a function or alike is called like a keyword.
cdef extern from "foo.h":
struct foo:
bint print
print(char*, int)
Is there a way to work around this, without modifieng the source? Maybe some technique that replaces a proxy-name with the real-name in the source-file ?
I think the solution you are looking for is something along the lines of:
cdef extern from "foo.h":
struct print "MY_print":
double var "MY_var"
print.var will then be defined by:
MY_print.MY_var
This way you can rename structs, functions, unions and enums from the header file. The names are converted when Cython compiles your code into C code.
The relevant part of Cython documentation can be found here.
I have the below SWIG Interface file structure that I feel is invalid. The int func(usigned char key[20]) resides in headerThree.h. When I leave in the %include "HeaderThree.h" I get a duplicate int func(SWIGTYPE_p_unsigned_char key);. If I remove the %include "HeaderThree.h", the other functions do not show up in the generated Example.java file..only the int func(short[] key) does. I would like to configure the SWIG .i file to not have the
func(SWIGTYPE_p_unsigned_char key) function but to have the rest of the functions included in HeaderThree.h. Any ideas?
%module Example
%{
#include "HeaderOne.h" //has constants and type definitions
#include "HeaderTwo.h" // has an #include "HeaderOne.h" and its own C apis
#include "HeaderThree.h" // has an #include "HeaderOne.h" and its own C apis
%}
%include "arrays_java.i"
int func(unsigned char key[20]);
%include "HeaderOne.h" //has constants and type definitions
%include "HeaderTwo.h" // has an #include "HeaderOne.h" and its own C apis
%include "HeaderThree.h" // has an #include "HeaderOne.h" and its own C apis
The problem here is that when you say %include it is as though you pasted the contents of the file directly at that point (i.e. asked SWIG to wrap it all). This means SWIG has seen both versions of func, the one you explicitly told it about and the one that actually exists in the header you %included.
There's a couple of ways you can fix this, although having the extra overload kicking around doesn't really do any harm, it's just noisy and messy.
Hide the declaration of func in the header file from SWIG using #ifndef SWIG. Your header file would then become:
#ifndef SWIG
int func(unsigned char *key);
#endif
When you %include that header file SWIG won't see this version of func - that's not a problem though because you explicitly told it about another version (which is compatible for the purposes of SWIG)
Use %ignore to instruct SWIG to ignore this version of func specifically. The SWIG module file then becomes:
%module Example
%{
#include "HeaderOne.h"
#include "HeaderTwo.h"
#include "HeaderThree.h"
%}
%include "arrays_java.i"
int func(unsigned char key[20]);
// This ignore directive only applies to things seen after this point
%ignore func;
%include "HeaderOne.h"
%include "HeaderTwo.h"
%include "HeaderThree.h"
You could also change the actual declaration and definition of func in the header file and the place it's actually implemented in your code to use unsigned char[20] instead of unsigned char*.