0

I'm trying to translate some simple cython to c++ :

cdef public int G = 1

and then use it in my c++ code :

#include <Python.h>
#include "test.h" // The file generated by the cython command
#include <iostream>
int main(int argc, char **argv) {
    std::cout << "G : " << G << std::endl;
}

Output is :

G : 0

I've looked into the test.cpp cython-generated file, and on line 897, I have

  G = 1;

So why is G evaluated to 0 in the main ?

Here are the commands used to compile :

cython.exe test.pyx -3 --cplus
g++ test.cpp test_main.cpp -IC:\Python36-32\include -LC:\Python36-32\libs -lpython36
B. Barbieri
  • 1,055
  • 13
  • 16

1 Answers1

2

What you generate when you use cython is a python extension module. You cannot link it directly into an executable, as it needs to be dynamically imported and linked to libpython. In that process, your extension's initialization function is run, which will cause your G to be set to 1.

So you should:

  • Build a python extension from your cython (using -shared and outputting a DLL).
  • Load python interpreter in your main. In your program, you don't even initialize python at the moment.
  • Import it in your main using PyImport_ImportModule("mymodule").

Untested, but your main should look like this:

#include <Python.h>

int main(int argc, char * argv[])
{
    Py_Initialize();
    PyObject * test_module = PyImport_ImportModule("test");

    // do something with test_module

    Py_Finalize();
    return 0;
}

You can get G from python using PyObject_GetAttrString(), or since you declared it as cdef, you can access it directly using your OS's symbol resolution tools, such as GetProcAddress() for windows.

It may be possible to link dynamically at load time, yet still use importmodule to let python do its initialization magic, but I have no idea how to do that or if it's even possible.

spectras
  • 13,105
  • 2
  • 31
  • 53
  • Thanks for your answer. It feels like a lot more complicated than what I expected ... I've done the same thing for a function, and everything was just fine without importing the module, only calling `Py_Initialize` and `Py_Finalize` – B. Barbieri Apr 21 '17 at 13:17
  • 2
    The Cython documentation [specifies a couple of different way of doing import/initialization](http://cython.readthedocs.io/en/latest/src/userguide/external_C_code.html#using-cython-declarations-from-c) which you might find slightly simpler. The basic idea is very much the same as this answer though. – DavidW Apr 21 '17 at 13:36
  • @DavidW Just perfect. G is 1 after a call to `PyInit_test` (because i'm using python3, the documentation you provided has examples for python2) – B. Barbieri Apr 21 '17 at 13:44
  • @B.Barbieri> great! Yeah now you mention it, this is what ImportModule does: it looks for `PyInit_modulename` inside the module and calls it. So if you do it yourself it should replace the DLL + importmodule just fine. – spectras Apr 21 '17 at 13:56