I want to wrap a quite long C function published by a scientist with Cython. I am following
http://scipy-lectures.github.io/advanced/interfacing_with_c/interfacing_with_c.html#interfacing-with-c
and I am able to replicate the examples with numpy support.
I am confused about what to do (or to do anything at all) about variables declared as extern in the library.cpp. Obviously, I will have a main.py that will call this function, not a main.cpp. How should I declare ini_flag and A and pass to func? Is there any other way than making them arguments to the function? If possible I would prefer not to edit original library.cpp file.
// main.cpp:
int ini_flag=0, *A;
void main(){
func(...)
...
}
// library.cpp:
extern int ini_flag, *A;
void func(...){
if (ini_flag==0){
// malloc and initialize A
ini_flag=1;
}
// use A and do other stuff
}
You should create a corresponding library.hpp file:
int ini_flag, *A;
void func(...)
And then in Cython:
cdef extern from "library.hpp":
int ini_flag, *A
void func(...)
Then you can then use them normally in Cython.
Related
How can I perform the equivalent of the following C++ code in Cython?
typedef vector<double> dvec;
dvec *arr = new dvec[n]; // n is an unsigned int (unknown at compile time)
// do something with arr; for example...
arr[0].push_back(10);
cout << arr[0][0] << endl;
I've tried to malloc the memory for the n vectors, but then I do not know how to do a placement new in Cython. Any help would be greatly appreciated.
It doesn't seem like you can do array new (new something[n]) in Cython. The simplest solution would be to create 1-line C++ function to do array new and array delete, and call those instead.
template <typename T>
T* array_new(int n) {
return new T[n];
}
template <typename T>
void array_delete(T* x) {
delete [] x;
}
Called from the following Cython file
# distutils: language = c++
from libcpp.vector cimport vector
ctypedef vector[double] dvec
cdef extern from "cpp_funcs.hpp":
T* array_new[T](int)
void array_delete[T](T* x)
def example(int n):
cdef dvec* arr = array_new[dvec](n)
try:
if n>0:
arr[0].push_back(10)
print(arr[0][0])
finally:
array_delete(arr)
Given that Cython's C++ support is limited, and awkward in places (and given that you have to have a pretty good understanding of C++ to use it anyway) I think that writing a small amount of C++ code is usually a reasonable solution, and can save quite a bit of time. Some people seem to want to avoid this at all costs though....
I'd still recommend using a vector of vectors (vector<vector<double>>) instead since you get the memory management for free. Even better would be to stick with Python types and use a list of numpy arrays, but that might not be suitable if you want to interface with external C++ code.
As an addition to #DavidW's answer: Since Cython 0.28 there is a new feature which allows verbatim C-code. Its advantage is a seamless usage of such small C/C++-wrappers:
cdef extern from *:
"""
template <typename T>
T* array_new(int n) {
return new T[n];
}
template <typename T>
void array_delete(T* x) {
delete [] x;
}
"""
T* array_new[T](int)
void array_delete[T](T* x)
from libcpp.vector cimport vector
.... and so on
without the need for creating an extern header-file.
I am trying to wrap a C++ function that has arguments of type uint32_t, which can be found in the cstdint library. Let's say the C++ file looks like
cppfile.cpp:
#include <cstdint>
int foo(uint32_t x){
return 1;
}
How do I wrap this in a Cython .pxd file? If x was just a normal integer, I would do
cdef extern from "cppfile.cpp":
cdef int foo(int x)
But how do I do this when x is of type uint32_t? How do I obtain the uint32_t as a type in cython?
This is a question answered in the FAQ of cython
from libc.stdint cimport uint32_t
cdef extern from "cppfile.cpp":
cdef int foo(uint32_t x)
I am using swig, which is wrapping one of my C++ function:
get(unsigned int a, unsigned int &b);
but i am failing to call this function from python, the error i get is TypeError that it should be unsigned int&
how call to this function from python ? should i add something special to the .i file ?
Yes,you should add typemaps.
example:
export.i:
%module my_mod
%include "typemaps.i"
%apply unsigned int &OUTPUT {unsigned int&}; //this map you output
%include "export.h"
export.h
void get(unsigned int a, unsigned int& b);
test
print(my_mod.get(10))
I have header (fingisdk.h) file like this:
#ifndef FINGISDK_H_
#define FINGISDK_H_
#include "fingienum.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*fingi_event)(FINGI_EVENT_ID eventId, char* msg);
FINGI_EVENT_ID start_fingi_sdk(char* ini_file_location);
FINGI_EVENT_ID download_room_info(char** roominfo);
void register_fingi_sdk_status_event_listener(fingi_event pointer_to_listener_fnc);
#ifdef __cplusplus
}
#endif
#endif
And then i have written a python Wrapper for this one:
#include <fingisdk.h>
#include <fingienum.h>
#include <boost/python.hpp>
BOOST_PYTHON_MODULE(libpythonWrapper)
{
using namespace boost::python;
def("start_fingi_sdk", start_fingi_sdk);
}
And python file for calling it is like this:
import libpythonWrapper
print libpythonWrapper.start_fingi_sdk('file_location.ini')
So far this works fine. However, i can not find out how to expose double the double pointer
function :
FINGI_EVENT_ID download_room_info(char** roominfo);
And callback function :
void register_fingi_sdk_status_event_listener(fingi_event pointer_to_listener_fnc);
Can anyone point me to some documentation or help me solve it
Thankyou
EDIT 1:
After messing around a bit, i figured out how to do the pointer to pointer function . Python does not support pointer , so have to wrap the download_room_info(char** roominfo) to return simple string:
std::string download_room_info_python_wrapper() {
char * value;
FINGI_EVENT_ID result = download_room_info(&value);
return std::string(value);
}
And then:
def("download_room_info", download_room_info_python_wrapper);
Still looking for solution for callback function
So you want to bind this API to Python:
typedef void (*fingi_event)(FINGI_EVENT_ID eventId, char* msg);
void register_fingi_sdk_status_event_listener(fingi_event);
That's a register function which takes a function which takes an eventId and a string. OK, let's define one of our own (in extern "C" of course, as the API is):
void my_callback(FINGI_EVENT_ID eventId, char* msg)
{
// do something
}
Now we can write a wrapper for the register function:
void my_register()
{
register_fingi_sdk_status_event_listener(my_callback);
}
And bind it:
def("my_register", my_register);
That should all work. But it's useless, because we didn't actually do anything in the callback. So this leads to a sub-question, which is how can you possibly do anything in the callback? One idea I have is that you should make your own function registration mechanism which lets you register a Python callback function into something like a global PyObject which will be set to a Python function and invoked using Boost Python:
boost::python::object g_callback;
void my_callback(FINGI_EVENT_ID eventId, char* msg)
{
if (g_callback)
g_callback(eventId, msg);
}
Now it's just a matter of letting the user assign the global callback:
void set_callback(boost::python::object func)
{
g_callback = func;
register_fingi_sdk_status_event_listener(my_callback);
}
def("set_callback", set_callback);
Then in Python:
def callback(eventId, msg):
print eventId, msg
set_callback(callback)
That should be about it, I think. This whole thing would be a ton easier if your callback API supported a "void* userData" argument like many callback APIs do. We'd then use that to store a PyObject or something useful. But the API lacks that, so we're stuck with a global somewhere to remember which function to call.
In Cython glue declarations, how do I represent a C struct type containing an anonymous union? For example, if I have a C header file mystruct.h containing
struct mystruct
{
union {
double da;
uint64_t ia;
};
};
then, in the corresponding .pyd file
cdef extern from "mystruct.h":
struct mystruct:
# what goes here???
I tried this:
cdef extern from "mystruct.h":
struct mystruct:
union {double da; uint64_t ia;};
but that only gave me "Syntax error in C variable declaration" on the union line.
For those who got here via Google, I found a solution to this. If you have a struct:
typedef struct {
union {
int a;
struct {
int b;
int c;
};
}
} outer;
You can flatten it all out in the Cython declaration, like so:
ctypedef struct outer:
int a
int b
int c
Cython isn't generating any code that makes any suppositions about the memory layout of your struct; you're only telling it the de facto structure of what you're calling by telling it what syntax to generate to call it. So if your structure has a member of size int that can be accessed as ((outer) x).a, then you can throw a on the struct definition and it will work. It's operating on textual substitution, not memory layout, so it doesn't care about whether these things are in anonymous unions or structs or what have you.
You can't nest declarations to the best of my knowledge, and Cython doesn't support anonymous unions AFAIK.
Try the following:
cdef union mystruct_union:
double lower_d
uint64_t lower
cdef struct mystruct:
mystruct_union un
Now access the union members as un.lower_d and un.lower.