Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
335 views
in Technique[技术] by (71.8m points)

python - Calling a cython library with multiple pyx files through c++

I have a python project that I want to call from a c++ application. I would like to bundle all python sources together in a single shared library and link the c++ application to that library. Right now my cython setup.py creates one *.so per python source, which is very inconvenient.

Here is the setup.py file:

from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize

sourcefiles = ['project_interface.pyx', 'impl_file1.pyx']

setup(
    ext_modules = cythonize(sourcefiles)
)

project_interface.pyx :

# distutils: language = c++

import impl_file1

cdef public void HelloWorld():
    print "Calling Hello World"
    impl_file1.helloworld_func()

impl_file1.pyx :

def helloworld_func():
    print 'Hello World'

I tried to modify setup.py to bundle all python code in a single library like this:

setup(
      ext_modules = cythonize([Extension("my_project", sourcefiles, language='c++')])
)

Unfortunately, when executing void HelloWorld(), the application cannot file impl_file1 anymore. I get :

Calling Hello World
NameError: name 'impl_file1' is not defined
Exception NameError: "name 'impl_file1' is not defined" in 'project_interface.HelloWorld' ignored

The c++ program driving this is:

#include <Python.h>
#include "project_interface.h"

int main(int argc, const char** argv){
    Py_Initialize();
    initproject_interface();
    HelloWorld();
    Py_Finalize();


    return 0;
}

This application works correctly when compiling with multiple *.so files.

Compilation is very straightforward in either cases:

python setup.py build_ext --inplace
mv my_project.so libmy_project.so
g++ main.cpp -o main `python2-config --cflags --ldflags` -L. -lmy_project

Is there any way to get the single shared library solution to work?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

There's a number of similar looking questions about bundling multiple Cython modules together (e.g. 1, 2) which isn't really viable because Python uses file paths to handle modules. However, this question isn't quite the same because you're calling it from C++, which gives you an extra option.

You need to use the C API function PyImport_AppendInittab to Python to treat impl_file1 as a builtin module so it doesn't search the path for a file to import. Start by providing a declaration of the import function (since you won't get that from your header file):

extern "C" {
// PyObject* PyInit_impl_file1(); // Python 3
void initimpl_file1(); // Python 2
}

Then, in main, before Py_Initialize, add:

PyImport_AppendInittab("impl_file1", initimpl_file1); // change the name for Python 3

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...