A file Globals.h contains the following definition of a constant:
namespace MyNameSpace {
/** Constants **/
constexpr index none = std::numeric_limits<index>::max();
}
... where index is a typedef for uint64_t.
How can I expose it to Cython and Python?
A failed attempt:
cdef extern from "../cpp/Globals.h" namespace "MyNamespace":
cdef index _none "MyNamespace::none"
none = _none
The syntax for exposing (global) constants is similar to the syntax for exposing simple attributes and the syntax for exposing static members, in your example the syntax is almost right except that you need to omit the cdef statement, the cdef statement is only for declaring new variables in Cython, not for adding information about externally declared variables.
cdef extern from "../cpp/Globals.h" namespace "MyNamespace":
index _none "MyNamespace::none"
none = _none
Then you can use none in Python, if your Cython module is named mymodule, the import statement could be
from mymodule import none
if you want to make none available as global name in your Python code.
Related
I have some C code that I have to port to C++. The code has a structure
struct A {
...
struct A * myPtr;
}
And now two global arrays are declared and initialized like this:
//Forward declaration of Unit
struct A Unit[10];
struct A* ptrUnit[2] = { Unit, Unit+7 };
struct A Unit[10] = { { .., &ptrUnit[0] },
... };
Now while this works fine in C, it gives an error in C++ (variable redeclared).
Aren't variables allowed to be forward-declared in C++?
struct A Unit[10] is not a forward declaration of a variable. The term "forward declaration" normally refers to non-defining declarations, while struct A Unit[10] is a definition. So in your code you are defining Unit multiple times in the same source file. In C language it is allowed, since in C definitions without an initializer are tentative definitions. They may occur many times in the same translation unit. In C++ there's no such thing as tentative definition. In C++ multiple definitions are always illegal.
If you want a genuine forward declaration for a variable, you have to use the keyword extern
extern struct A Unit[10];
This will work in both C and C++. However, as a side effect, this will give Unit external linkage. If you need a variable with internal linkage, then you are out of luck in C++, since in C++ it is not possible to forward-declare a variable with internal linkage. Meanwhile, in C tentative definitions will still help you to achieve that.
In C++, a variable declaration must be prefixed with extern:
extern A Unit[10];
// ...
A Unit[10] = { ... };
(Note that in C++ you can omit the leading struct.)
C allows variables to be tenatively declared (I guess). C++ does not. Once 'Unit' has been defined, it cannot be redefined in the same scope
Make Unit a function that returns a reference to to A[10] and have the actual array be a static variable in the function.
// in hpp file
A[10]& Unit();
// in cpp file
A[10]& Unit() {
static A[10] value;
return value;
}
I am working on a C++ project that needs to be wrapped in Cython to ultimately use in integration tests in Python. I have a global variable used to default a value in a function in my C++ header file that looks like
header file
const uint8_t kAudioLevel = 0x5a;
This is used in a function in the c++ files like
void func(uint audioLevel=kAudioLevel)
I am wrapping this function in Cython, and currently have another variable with the same name used in my .pyx file like
DEF kAudioLevel
This default value is passed into the func() wrapper in C++ to allow that value to be defaulted. However, I would really like to have this variable used in the wrapper be imported directly from the header file, so I have a single source of truth and dont have to change this variable twice every time. I have tried adding the following:
pxd file
cdef extern from "header.h":
cdef cppclass Class:
int kAudioLevel
And then attempt to use kAudioLevel directly in the .pyx like so
def func(audioLevel = kAudioLevel):
return client.func(audioLevel)
This is to allow us to have the value be defaulted across Cython and C++, and not have to edit it twice. However, the variable is not found when I try this. Not sure if I have to add the header class to both the pxd and pyx files and how to do this. I looked over the Cython documentation but didnt find anything useful.
For a const member like cpy.hh:
#ifndef CPY_HH
#define CPY_HH
#include <cstdint>
const uint8_t kAudioLevel = 5;
#endif
with cytest.pyx:
from libc.stdint cimport uint8_t
cdef extern from "cpy.h":
cdef uint8_t kAudioLevel
Allows me to use kAudioLevel within my .pyx file. With a exposedKAudioLevel = kAudioLevel I can expose this to outside the module.
If you wanted a truly global variable, that is a bit more complicated, but with cpy.hh:
#ifndef CPY_HH
#define CPY_HH
#include <cstdint>
extern uint8_t kAudioLevel;
#endif
cpy.cc:
#include "cpy.hh"
uint8_t kAudioLevel = 5;
and the same cytest.pyx as above, I could create a variable I could access and modify, from both .pyx and .cc.
Unfortunately kAudioLevel is not exposed to the outside importer, so to access/modify, helper functions would be needed, like getVal(), setVal(newVal), as far as I saw.
I've got a use case I'm testing where, for performance, it's convenient to write a Cython wrapper class for C++'s unordered_map<int, int> type up front, then pass the wrapper to a bunch of Cython functions that use it, rather than always passing around Python dict (keyed and valued by Python ints that fit in C int) and converting on the fly over and over. I'm also trying to bake in some basic functionality to make it behave like a dict at the Python layer, so it can be worked with without converting en masse from Python dict to Cython unordered_map<int, int> wrapper and back.
My problem occurs in trying to implement __eq__ efficiently in the simplest case (comparing one wrapper instance to another). AFAICT, in theory Cython's libcpp.unordered_map pxd definition pretends unordered_map has a member operator==. This answer claims it should be fine, even though the operator== is actually a non-member function, since the definition only needs to exist so Cython knows it can just put a literal == in the code; the C++ compiler will look up the real overload when compiling the extension module.
But in practice, I can't seem to get it to work without additional manual (and hacky) intervention. For experimenting, I've just been using ipython %%cython magic. Right now what I'm doing is (minimized as much as possible while still exhibiting problem):
>>> %load_ext cython
>>> %%cython -+ --verbose --compile-args=/std:c++latest
... from libcpp.unordered_map cimport unordered_map
... from cython.operator cimport dereference as deref
... cdef extern from "<unordered_map>" namespace "std":
... bint operator==(unordered_map[int, int]&, unordered_map[int, int]&)
... cdef class UII(object):
... cdef unordered_map[int, int] c_map
... def __cinit__(self, dict py_map):
... cdef int k, v
... for k, v in py_map.iteritems():
... self.c_map[k] = v
... def __eq__(UII self, other):
... if isinstance(other, UII):
... return self.c_map == (<UII>other).c_map
... return NotImplemented
...
To be clear, this works right now, e.g.:
>>> pydict = {1:2, 3:4}; ui = UII(pydict); uieq = UII(pydict); uine = UII({1: 2, 4: 3})
>>> ui == uieq # Compares equal for same value UIIs
True
>>> ui == uine # Correctly determines different valued UII not-equal
False
but it only works because I included:
cdef extern from "<unordered_map>" namespace "std":
bint operator==(unordered_map[int, int]&, unordered_map[int, int]&)
to explicitly define the non-member overload of operator== for the <int, int> template specifically (because Cython doesn't support generically templated functions, only generically templated classes and explicitly declared templates of functions). If I omit those lines, I get the following error from Cython:
[1/1] Cythonizing C:\Users\ShadowRanger\.ipython\cython\_cython_magic_ea9bfadf105ac88c17e000476fd582dc.pyx
Error compiling Cython file:
------------------------------------------------------------
...
cdef int k, v
for k, v in py_map.iteritems():
self.c_map[k] = v
def __eq__(UII self, other):
if isinstance(other, UII):
return self.c_map == (<UII>other).c_map
^
------------------------------------------------------------
C:\Users\ShadowRanger\.ipython\cython\_cython_magic_ea9bfadf105ac88c17e000476fd582dc.pyx:13:30: Invalid types for '==' (unordered_map[int,int], unordered_map[int,int])
indicating that it believes there is no overload for operator== available. Am I doing something wrong that I can fix, or is Cython broken for non-member operator== (and possibly other non-member functions, despite what this answer claims)? I hate explicitly defining every template specialization for non-member functions; it's not a huge burden for this specific case, but it seems odd that Cython would define member overloads, presumably to solve this specific problem, but not actually be able to use them. I checked the actual text of unordered_map.pxd, and it's definitely defined there:
cdef extern from "<unordered_map>" namespace "std" nogil:
cdef cppclass unordered_map[T, U]:
# ... irrelevant stuff expunged ...
bint operator==(unordered_map&, unordered_map&) # Looks properly defined...
Two things are broken about Cython's handling of non-member operators:
Non-member operators defined in a .pxd file outside a class aren't correctly cimported to Cython (the workround is to do from something cimport *) and thus aren't used. This is what I think I said in my previous answer
Non-member operators defined within a class with two arguments (as in the code you showed in unordered_map.pxd) aren't recognised by Cython and aren't used (despite being defined like that all over the C++ standard library wrappers included in Cython). At one point I tried to submit a patch for this but it was ignored. This is no longer true. Only point 1 now applies.
What does work is to tell Cython that it's a member operator (even if C++ implements it as a non-member operator). Therefore a simple patch to unordered_map.pxd would work. Note that I'm changing it to be defined with one argument and the C++ implicit this/self:
cdef extern from "<unordered_map>" namespace "std" nogil:
cdef cppclass unordered_map[T, U]:
# ... irrelevant stuff expunged ...
bint operator==(unordered_map&)
Alternatively, you can define it yourself before you need to use it (like you're doing currently) but as a template. This at least saves you having to define every specialization
cdef extern from "<unordered_map>" namespace "std":
bint operator==[R,S](unordered_map[R, S]&, unordered_map[R, S]&)
i.e. the statement in your question
(because Cython doesn't support generically templated functions, only generically templated classes and explicitly declared templates of functions)
isn't true.
It is all a bit of a mess though
I have a Cython extension type, let's call it Foo, and I'd like to be able to pass an 'instance' of it (isn't it like a struct?) in to a pure-C function so I can call a method of the extension type from C. I've tried piecing together how I might do this from various SO and mailing list posts but haven't been able to get it to work. My C skills are fairly rusty...
I know the below is wrong for a number of reasons, but hopefully it at least illustrates what I'd like to do...Thanks for your patience!
test.c:
#include <stdlib.h>
#include <stdio.h>
void cfunc(void* foo, double derp) {
double r = foo.bar(derp);
printf("%f", r);
}
cy_test.pyx:
import cython
cimport cython
cdef extern from "/tmp/test.c":
void cfunc(void*, double)
cdef public class Foo[type FooType, object Foo]:
cdef double spam
def __init__(self, spam):
self.spam = spam
cdef public double bar(self, double q) nogil:
q *= 15. + self.spam
return q
cpdef call_func():
foo = Foo(1.5)
cfunc(&foo, 10.)
call_func()
Python objects are of type PyObject*, which can be manipulated via the Python/C API. You'll probably find PyObject_CallMethod() and its relatives most useful here.
You may find it easier to write a C function in Cython that does what you want (i.e. a cdef function), and then call that from C code. That way, Cython does all the annoying PyObject* fiddling (including reference counting) and you just get your desired result.
myPythonClient (below) wants to invoke a ringBell function (loaded from a DLL using ctypes). However, attempting to access ringBell via its name results in an AttributeError. Why?
RingBell.h contains
namespace MyNamespace
{
class MyClass
{
public:
static __declspec(dllexport) int ringBell ( void ) ;
} ;
}
RingBell.cpp contains
#include <iostream>
#include "RingBell.h"
namespace MyNamespace
{
int __cdecl MyClass::ringBell ( void )
{
std::cout << "\a" ;
return 0 ;
}
}
myPythonClient.py contains
from ctypes import *
cdll.RingBell[1]() # this invocation works fine
cdll.RingBell.ringBell() # however, this invocation errors out
# AttributeError: function 'ringBell' not found
Your C++ compiler is mangling the names of all externally visible objects to reflect (as well as their underlying names) their namespaces, classes, and signatures (that's how overloading becomes possible).
In order to avoid this mangling, you need an extern "C" on externally visible names that you want to be visible from non-C++ code (and therefore such names cannot be overloaded, nor in C++ standard can they be inline, within namespaces, or within classes, though some C++ compilers extend the standard in some of these directions).
All is working now :) To summarize your posts:
Write DLL in C++:
// Header
extern "C"
{ // Name in DLL will be "MyAdd" - but you won't be able to find parameters etc...
__declspec(dllexport) int MyAdd(int a, int b);
}
// Name will be with lot of prefixes but some other info is provided - IMHO better approach
__declspec(dllexport) int MyAdd2(int a, int b);
//.cpp Code
__declspec(dllexport) int MyAdd(int a, int b)
{ return a+b;
}
__declspec(dllexport) int MyAdd2(int a, int b)
{ return a+b;
}
Then you can use program link.exe to see real function name in dll.
link.exe is for example in MSVC2010 here:
c:\program files\microsoft visual studio 10.0\VC\bin\link.exe
use:
link /dump /exports yourFileName.dll
you see Something like:
ordinal hint RVA name
1 0 00001040 ?MyAdd2##YAHHH#Z = ?MyAdd2##YAHHH#Z (int __cdecl MyAdd2(int,int))
2 1 00001030 MyAdd = _MyAdd
Then in python you can import it as:
import ctypes
mc = ctypes.CDLL('C:\\testDll3.dll')
#mc.MyAdd2(1,2) # this Won't Work - name is different in dll
myAdd2 = getattr(mc,"?MyAdd2##YAHHH#Z") #to find name use: link.exe /dump /exports fileName.dll
print myAdd2(1,2)
#p1 = ctypes.c_int (1) #use rather c types
print mc[1](2,3) # use indexing - can be provided using link.exe
print mc.MyAdd(4,5)
print mc[2](6,7) # use indexing - can be provided using link.exe
Perhaps because the C++ name is mangled by the compiler and not exported from the DLL as RingBell. Have you checked that it appears in the exported names exactly like that?