问题描述
我正在尝试使用 Cython 将用 C 编写的第三方库与我的 python 应用程序集成.我已经为测试编写了所有 python 代码.我无法找到设置此示例的示例.
I am trying to integrate a third party library written in C with my python application using Cython. I have all of the python code written for a test. I am having trouble finding an example for setting this up.
我有一个手动创建的 pyd/pyx 文件.第三方给了我一个头文件(*.h)和一个共享库(*.so).据我所知,没有其他依赖项.有人可以提供一个如何使用 Cython 和 disutils 进行设置的示例吗?
I have a pyd/pyx file I created manually. The third party has given me a header file (*.h) and a shared library (*.so). As far as I can tell, there are no other dependencies. Can someone provide an example of how to set this up using Cython and disutils?
谢谢
推荐答案
好的!
(以下,我假设你已经知道如何处理cimport以及.pxd和.pyx之间的交互.如果情况不完全如此,请询问,我也会开发该部分)
(In the following, I assume that you already know how to deal with cimport and the interactions between .pxd and .pyx. If this is not completely the case, just ask and I will develop that part as well)
示例(从我的 C++ 项目中获取,但 C 项目的工作方式几乎相同):
The sample (grabbed from a C++ project of mine, but a C project would work pretty much the same) :
1.Distutils 安装文件:
假设要创建的扩展名为myext,第三方共享库为libexternlib.so(注意lib*前缀,这里)...
Assuming that the extension to be created will be called myext and the 3rd party shared library is libexternlib.so (note the lib* prefix, here)...
# setup.py file import sys import os import shutil from distutils.core import setup from distutils.extension import Extension from Cython.Distutils import build_ext # clean previous build for root, dirs, files in os.walk(".", topdown=False): for name in files: if (name.startswith("myext") and not(name.endswith(".pyx") or name.endswith(".pxd"))): os.remove(os.path.join(root, name)) for name in dirs: if (name == "build"): shutil.rmtree(name) # build "myext.so" python extension to be added to "PYTHONPATH" afterwards... setup( cmdclass = {'build_ext': build_ext}, ext_modules = [ Extension("myext", sources=["myext.pyx", "SomeAdditionalCppClass1.cpp", "SomeAdditionalCppClass2.cpp" ], libraries=["externlib"], # refers to "libexternlib.so" language="c++", # remove this if C and not C++ extra_compile_args=["-fopenmp", "-O3"], extra_link_args=["-DSOME_DEFINE_OPT", "-L./some/extra/dependency/dir/"] ) ] )
注意:您的外部 .so 文件通过 libraries 选项链接:
Note : Your external .so file is linked via the libraries option :
libraries=["externlib"] # Without the 'lib' prefix and the '.so' extension...
注意:sources 选项可用于编译一些额外的源文件.
Note : the sources option can be used to get some additional source files compiled.
重要: myext.pxd(不要与 .pyd - Windows 的东西混淆)和 myext.pyx 应该在同一目录中.在编译时,首先处理定义文件(如果存在)(more).
Important : myext.pxd (do not confound with .pyd - Windows stuff) and myext.pyx should be in the same directory. At compile time the definition file, if it exists, is processed first (more).
<强>2.然后运行如下:
将目录更改为包含您的 myext.pxd、您的 myext.pyx 以及上述 setup.py 的目录后脚本:
After having changed directory to the one containing your myext.pxd, your myext.pyx, as well as the above setup.py script :
# setup.sh # Make the "myext" Python Module ("myext.so") CC="gcc" CXX="g++" CFLAGS="-I./some/path/to/includes/ -I../../../DEPENDENCIES/python2.7/inc -I../../../DEPENDENCIES/gsl-1.15" LDFLAGS="-L./some/path/to/externlib/" python setup.py build_ext --inplace
地点:
- libexternlib.so 假定位于 ./some/path/to/externlib/
- yourheader.h 假定位于 ./some/path/to/includes/
- libexternlib.so is assumed to be located at ./some/path/to/externlib/
- yourheader.h is assumed to be located at ./some/path/to/includes/
注意:CFLAGS 也可以使用 extra_compile_args 选项进行设置:
Note : CFLAGS could also have been setup using the extra_compile_args option :
extra_compile_args=["-I./some/path/to/includes/", "-fopenmp", "-O3"]
注意:LDFLAGS 也可以使用 extra_link_args 选项进行设置:
Note : LDFLAGS could also have been setup using the extra_link_args option :
extra_link_args=["-L./some/path/to/externlib/", "-DSOME_DEFINE_OPT", "-L./some/extra/dependency/dir/"]
distutils 构建完成后,您会得到一些新文件,特别是 myext.cpp、myext.h,最重要的是 myext.所以.
Once distutils is done with the build, you get some new files, specially the myext.cpp, myext.h and most importantly, the myext.so.
3.之后,您就可以开始了:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./some/path/to/externlib/ export PYTHONPATH=$PYTHONPATH:./some/path/to/myext/ # Run some script requiring "myext.so" python somescript.py
您新创建的 Python 扩展可以通过其名称导入:
Where your freshly created Python extension can be imported by its name :
# somescript.py import myext from myext import PySomeFeature ...
注意关于优化:默认情况下 -O2 用于编译扩展,但这可以重载(参见上面的设置 -O3 已指定).
Note about Optimization : By default -O2 is used for compiling the extension, but this can be overloaded (see above setup where -O3 is specified).
注意关于 Cython 路径:如果 Cython 安装在自定义目录中,您可能需要先将其添加到您的环境中:
Note about Cython paths : If Cython was installed in a custom directory, you might want to add it to your environment, before all :
PYTHONPATH=$PYTHONPATH:../../../DEPENDENCIES/Cython-0.18 export PYTHONPATH; PATH=$PATH:../../../DEPENDENCIES/Cython-0.18/bin; export PATH;
嗯,希望我能讲到要点……
Well, hope I covered the main points...