[英]link cython module in a c++ program
Is it possible to build a cython module with some cdef
functions and link the resulting shared library into a C++ program? 是否可以使用一些
cdef
函数构建cython模块并将生成的共享库链接到C ++程序中?
I tried a proof of concept: 我尝试了一个概念验证:
cymod.pyx: cymod.pyx:
# distutils: language=c++
from libcpp.string cimport string
cdef public string simple_echo(string test_string):
return test_string
cpp_test.cpp: cpp_test.cpp:
#define PyMODINIT_FUNC void
#include <iostream>
#include "cymod.h"
int main(int argc, char const *argv[])
{
std::cout << simple_echo("test") << std::endl;
return 0;
}
setup.py: setup.py:
from setuptools import setup, Extension
from Cython.Build import cythonize
setup(
name='cymod',
ext_modules=cythonize(
Extension(
"cymod", ["cymod.pyx"],
),
)
)
The cython module builds fine, but when I try to build the c++ code that will use the cython function I get: cython模块构建正常,但是当我尝试构建将使用cython函数的c ++代码时,我得到:
$ g++ -L. -l:cymod.so cpp_test.cpp -o cpp_test
/tmp/cc48Vc2z.o: In function `main':
cpp_test.cpp:(.text+0x51): undefined reference to `simple_echo'
collect2: error: ld returned 1 exit status
Which is odd. 这很奇怪。 The generated header file has it:
生成的头文件包含它:
cymod.h: cymod.h:
/* Generated by Cython 0.29.1 */
#ifndef __PYX_HAVE__cymod
#define __PYX_HAVE__cymod
#ifndef __PYX_HAVE_API__cymod
#ifndef __PYX_EXTERN_C
#ifdef __cplusplus
#define __PYX_EXTERN_C extern "C"
#else
#define __PYX_EXTERN_C extern
#endif
#endif
#ifndef DL_IMPORT
#define DL_IMPORT(_T) _T
#endif
__PYX_EXTERN_C std::string simple_echo(std::string);
#endif /* !__PYX_HAVE_API__cymod */
/* WARNING: the interface of the module init function changed in CPython 3.5. */
/* It now returns a PyModuleDef instance instead of a PyModule instance. */
#if PY_MAJOR_VERSION < 3
PyMODINIT_FUNC initcymod(void);
#else
PyMODINIT_FUNC PyInit_cymod(void);
#endif
#endif /* !__PYX_HAVE__cymod */
and I see my function in cymod.so
: 我在
cymod.so
看到了我的功能:
nm cymod.so| grep simple_echo
0000000000001e50 T simple_echo
NOTE: I realize that to actually get this working I'll need to link against the python libraries and initialize the interpreter etc. I left that out to make this a tad shorter and I get the same error either way. 注意:我意识到要真正实现这个工作,我需要链接python库并初始化解释器等。我把它留下来使这一点更短,我得到相同的错误。
The short answer is that I was putting the -l
argument too early in the compilation command. 简短的回答是我在编译命令中过早地放置
-l
参数。 It is also important to handle the library lookup path. 处理库查找路径也很重要。 The simplest way is to use
rpath
. 最简单的方法是使用
rpath
。 I set the rpath
to the directory that the executable is in, ie, .
我将
rpath
设置为可执行文件所在的目录,即.
Additionally, it is necessary to link against the python libraries and set the include and library paths. 此外,有必要链接python库并设置包含和库路径。 These can be determined at compile time by using the output of the
python-config
utility. 这些可以在编译时通过使用
python-config
实用程序的输出来确定。 Here is the compilation command that ultimately did the trick: 这是最终完成这个技巧的编译命令:
g++ cpp_test.cpp -o cpp_test -L. -l:cymod.so $(python-config --libs) $(python-config --includes) $(python-config --cflags) -Wl,-rpath,"\$ORIGIN"
I also updated the c++ file to #include "Python.h"
and added calls to Py_Initialize()
, Py_Finalize()
, and initcymod()
: 我还将c ++文件更新为
#include "Python.h"
并添加了对Py_Initialize()
, Py_Finalize()
和initcymod()
:
#include <iostream>
#include "Python.h"
#include "cymod.h"
int main(int argc, char *argv[])
{
Py_Initialize();
initcymod();
std::cout << simple_echo("test") << std::endl;
Py_Finalize();
return 0;
}
NOTE: the call to initcymod()
is necessary, but python2 specific. 注意:调用
initcymod()
是必要的,但python2是特定的。 On python3 you should call PyImport_AppendInittab("cymod", PyInit_cymod);
在python3上你应该调用
PyImport_AppendInittab("cymod", PyInit_cymod);
prior to Py_Initialize()
. 在
Py_Initialize()
之前。 The cymod
part is the module name, substitute your module name. cymod
部分是模块名称,替换您的模块名称。
Thanks to @ead for the informative link to the docs on this topic https://cython.readthedocs.io/en/latest/src/userguide/external_C_code.html#using-cython-declarations-from-c and his answer to a related question https://stackoverflow.com/a/45424720/2069572 感谢@ead提供有关此主题的文档的信息链接https://cython.readthedocs.io/en/latest/src/userguide/external_C_code.html#using-cython-declarations-from-c以及他对相关问题https://stackoverflow.com/a/45424720/2069572
While reading the linked docs, I came across this: 在阅读链接文档时,我遇到了这个:
Note On some operating systems like Linux, it is also possible to first build the Cython extension in the usual way and then link against the resulting .so file like a dynamic library.
注意在某些操作系统(如Linux)上,也可以首先以常规方式构建Cython扩展,然后将链接到生成的.so文件,如动态库。 Beware that this is not portable, so it should be avoided.
请注意,这不是便携式的,所以应该避免。
So it turns out that you should not do what I was trying to do. 事实证明,你不应该做我想做的事情。
Instead, what I should have done was run: 相反,我应该做的是运行:
cython --cplus cymod.pyx
And then compiled cpp_test.cpp
with the generated cymod.cpp
file. 然后用生成的
cymod.cpp
文件编译cpp_test.cpp
。 No need to link the cython shared library, and it turns out that it is not a good idea to do so. 无需链接cython共享库,事实证明这样做并不是一个好主意。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.