使用Cython将Python链接到共享库

jos*_*iti 35 c python linker distutils cython

我正在尝试C使用我的python应用程序集成第三方库Cython.我有为测试编写的所有python代码.我找不到设置它的例子.

我有一个pyd/pyx手动创建的文件.第三方给了我一个header file (*.h)和一个shared library (*.so).据我所知,没有其他依赖.有人可以提供一个如何使用Cython和设置此示例的示例disutils吗?

谢谢

Gau*_*lio 55

好的!

(在下文中,我假设你已经知道如何处理cimport和之间的相互作用.pxd.pyx,如果这不是完全的情况下,只问我会开发部分以及)

样本(从我的C++项目中获取,但C项目的工作方式基本相同):

1. Distutils设置文件:

假设将要调用要创建的扩展myext并且第三方共享库是libexternlib.so(注意lib*前缀,这里)...

# 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/"]
             )
        ]
)           
Run Code Online (Sandbox Code Playgroud)

注意:您的外部.so文件通过以下libraries选项链接:

libraries=["externlib"]   # Without the 'lib' prefix and the '.so' extension...
Run Code Online (Sandbox Code Playgroud)

注意:该sources选项可用于获取编译的其他源文件.

重要:( myext.pxd不要混淆.pyd--Windows的东西),myext.pyx应该在同一目录中.在编译时,首先处理定义文件(如果存在)(更多).

2.然后按如下方式运行:

将目录更改为包含您myext.pxdmyext.pyx,以及上述setup.py脚本的目录后:

# 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
Run Code Online (Sandbox Code Playgroud)

地点:

  • libexternlib.so 假设位于 ./some/path/to/externlib/
  • yourheader.h 假设位于 ./some/path/to/includes/

注意:CFLAGS也可以使用以下extra_compile_args选项进行设置:

extra_compile_args=["-I./some/path/to/includes/", "-fopenmp", "-O3"]
Run Code Online (Sandbox Code Playgroud)

注意:LDFLAGS也可以使用以下extra_link_args选项进行设置:

extra_link_args=["-L./some/path/to/externlib/", "-DSOME_DEFINE_OPT", "-L./some/extra/dependency/dir/"]
Run Code Online (Sandbox Code Playgroud)

一旦使用构建完成了distutils,你会获得一些新文件,特别是myext.cpp,myext.h最重要的是,myext.so.

在那之后,你很高兴去:

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
Run Code Online (Sandbox Code Playgroud)

您可以通过名称导入新创建的Python扩展的位置:

# somescript.py
import myext
from myext import PySomeFeature
...
Run Code Online (Sandbox Code Playgroud)

关于优化的注意事项:默认情况下-O2用于编译扩展,但这可能会重载(请参阅上面的设置-O3指定位置).

关于Cython路径的注意事项:如果Cython安装在自定义目录中,您可能希望将它添加到您的环境中,然后才能:

PYTHONPATH=$PYTHONPATH:../../../DEPENDENCIES/Cython-0.18 export PYTHONPATH;
PATH=$PATH:../../../DEPENDENCIES/Cython-0.18/bin; export PATH;
Run Code Online (Sandbox Code Playgroud)

好吧,希望我涵盖了要点......