How can a #defined C value be exposed to Python in a Cython module?
Asked Answered
H

3

35

I'd like to make the integer constants (ACTIVE_TAG, etc) defined here:

//island management, m_activationState1
#define ACTIVE_TAG 1
#define ISLAND_SLEEPING 2
#define WANTS_DEACTIVATION 3
#define DISABLE_DEACTIVATION 4
#define DISABLE_SIMULATION 5

available as normal attributes of a Cython defined module I'm working on, so that Python application code can access them (to pass them in to wrapped APIs which are defined in terms of them).

I've looked at defining these with cdef as integers or enums, but neither of these approaches actually binds the value to an an attribute in the Cython module. What other options are there?

Huba answered 18/4, 2011 at 0:35 Comment(0)
D
36

Here's one way, which, while seemingly tedious, could feasibly be automated for any given .h file as input:

Step 1. Get all the constants you want into a file, say bulletdefs.h, which has the #defines but with leading underscores, e.g:

#define _ACTIVE_TAG 1
#define _ISLAND_SLEEPING 2
#define _WANTS_DEACTIVATION 3
#define _DISABLE_DEACTIVATION 4
#define _DISABLE_SIMULATION 5

Step 2. Insert a section into the pyx file for your module, say bullet.pyx:

cdef extern from "bulletdefs.h":
    cdef int _ACTIVE_TAG
    cdef int _ISLAND_SLEEPING
    cdef int _WANTS_DEACTIVATION
    cdef int _DISABLE_DEACTIVATION
    cdef int _DISABLE_SIMULATION

ACTIVE_TAG = _ACTIVE_TAG
ISLAND_SLEEPING = _ISLAND_SLEEPING
WANTS_DEACTIVATION = _WANTS_DEACTIVATION
DISABLE_DEACTIVATION = _DISABLE_DEACTIVATION
DISABLE_SIMULATION = _DISABLE_SIMULATION

Then, when you compile your module, you should get the intended effect:

Python 2.7.1+ (r271:86832, Apr 11 2011, 18:05:24) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import bullet
>>> bullet.ACTIVE_TAG
1
>>> bullet.DISABLE_SIMULATION
5
>>>
Dowdell answered 18/4, 2011 at 16:20 Comment(4)
Thanks. This works, and there's even one more shortcut that can be taken (which is where I got stuck before). I can use the defines straight from bullet and rename them in the Cython namespace by doing things like cdef int _ACTIVE_TAG "ACTIVE_TAG". The name in quotes is what Cython looks for on the C side of things, the name to the left of that is how its value is exposed to Python.Huba
@Jean-PaulCalderone I guess you meant cdef int ACTIVE_TAG "_ACTIVE_TAG".Alsace
There's some disagreement in spelling between my comments and Vinay's, I guess. The Bullet defined constants do not have a leading _.Huba
Here are a couple links to what I ended up doing - bazaar.launchpad.net/~exarkun/pybullet/trunk/view/head:/bullet/… and bazaar.launchpad.net/~exarkun/pybullet/trunk/view/head:/bullet/…Huba
M
6

It worked in my case. Maybe can be helpful for someone too:

In my case I needed to export a #define from a linux kernel library. And it worked for my:

# your_pxd_file.pxd
cdef extern from "sched.h": #here are lots of `#define`'s clauses. something like the link: https://github.com/spotify/linux/blob/master/include/linux/sched.h
    cdef enum:
        CLONE_NEWNS

In your .pyx file:

from your_compiled_cython_package cimport CLONE_NEWNS

print(CLONE_NEWNS)

I hope this can be helpful for someone as it was for me =)

Mammilla answered 26/11, 2019 at 18:35 Comment(0)
C
1

Example header:

// myheader.hh
#ifndef MYHEADER
#define MYHEADER

#define NONE 0

#endif

An answer from my experience for my similar case, without const keyword, a variable is created and it's not constant as of #define. I found some assignment to NONE at the end of the generated C++ file by Cython and it's not allowed to assign to macro.

cdef extern from "myheader.hh":
    int NONE

This is a real constant:

cdef extern from "myheader.hh":
    const int NONE

Bug in Cython without const keyword: https://github.com/cython/cython/issues/2621

Christchurch answered 7/1, 2022 at 10:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.