web-dev-qa-db-ja.com

Cythonを使用して共有ライブラリにリンクするPython

Cを使用して、pythonで記述されたサードパーティライブラリをCythonアプリケーションと統合しようとしています。すべてのpythonコードをテスト用に作成しました。これを設定する例を見つけるのに苦労しています。

手動で作成した_pyd/pyx_ファイルがあります。サードパーティからheader file (*.h)shared library (*.so)が提供されました。私の知る限り、他の依存関係はありません。誰かがCythondisutilsを使用してこれを設定する方法の例を提供できますか?

ありがとう

37
josephmisiti

承知しました !

(以下では、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/"]
             )
        ]
)           
_

注:外部_.so_ファイルはlibrariesオプションを介してリンクされます:

_libraries=["externlib"]   # Without the 'lib' prefix and the '.so' extension...
_

注:sourcesオプションを使用すると、追加のソースファイルをコンパイルできます。

重要:_myext.pxd_(_.pyd_-Windowsのものと混同しないでください)と_myext.pyx_は同じディレクトリにある必要があります。コンパイル時に、定義ファイルが存在する場合は、最初に処理されます( more )。

2。次に、次のように実行します:

_myext.pxd_、_myext.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
_

どこ :

  • _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"]
_

注:LDFLAGSは、_extra_link_args_オプションを使用して設定することもできます。

_extra_link_args=["-L./some/path/to/externlib/", "-DSOME_DEFINE_OPT", "-L./some/extra/dependency/dir/"]
_

ビルドでdistutilsが完了すると、いくつかの新しいファイル、特に_myext.cpp_、_myext.h_、そして最も重要なのは_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拡張機能は、その名前でインポートできます。

_# somescript.py
import myext
from myext import PySomeFeature
...
_

最適化に関する注意:デフォルトでは、拡張機能のコンパイルに_-O2_が使用されますが、これはオーバーロードされる可能性があります(_-O3_が指定されている上記の設定を参照)。

Cythonパスに関する注意:Cythonがカスタムディレクトリにインストールされている場合は、それを環境に追加してから、次の手順を実行します。

_PYTHONPATH=$PYTHONPATH:../../../DEPENDENCIES/Cython-0.18 export PYTHONPATH;
PATH=$PATH:../../../DEPENDENCIES/Cython-0.18/bin; export PATH;
_

さて、私が主要なポイントをカバーしたことを願っています...

57