2017-07-31 11 views
0

documentationによれば、Cythonから生成されたCヘッダファイルを使用することができます。私は問題なしでHello Worldの例を続けてきましたが、今は違うことを試してみたいと思います。私は、カスタムメソッドを使用できるように公開宣言を使用したいと思います。Cythonから生成されたヘッダファイルを使用する

  • hello.pyx
  • setup.py
  • main.cの

hello.pyx

cdef public void say_hello(): 
    print("Hello World") 

setup.py:私のコードの構造は以下のとおりです。

from distutils.core import setup 
from distutils.extension import Extension 
from Cython.Distutils import build_ext 

ext_modules = [ 
    Extension("hello", ["hello.pyx", "main.c"]), 
] 

setup(
    name='Hello app', 
    cmdclass={'build_ext': build_ext}, 
    ext_modules=ext_modules 
) 

main.cの

#include "hello.h" 

int main(void){ 
    say_hello(); 
} 

意図したとおりsay_hello()方法が機能することを確認するためのテストファイルとしてmain.c働きます。 セットアップファイルpython3 setup.py build_extをビルドすると、次の出力が生成されます。

running build_ext 
    skipping 'hello.c' Cython extension (up-to-date) 
    building 'hello' extension 
    x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -I/usr/include/python3.5m -c hello.c -o build/temp.linux-x86_64-3.5/hello.o 
    x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -I/usr/include/python3.5m -c main.c -o build/temp.linux-x86_64-3.5/main.o 
    In file included from main.c:1:0: 
    hello.h:26:1: error: unknown type name ‘PyMODINIT_FUNC’ 
    PyMODINIT_FUNC inithello(void); 
    ^
    error: 

command 'x86_64-linux-gnu-gcc' failed with exit status 1 

hello.hファイルは、私の理解するには、以下の

/* Generated by Cython 0.25.2 */ 

#ifndef __PYX_HAVE__hello 
#define __PYX_HAVE__hello 


#ifndef __PYX_HAVE_API__hello 

#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 DL_IMPORT(void) say_hello(void); 

#endif /* !__PYX_HAVE_API__hello */ 

#if PY_MAJOR_VERSION < 3 
PyMODINIT_FUNC inithello(void); // <-- Line 26 
#else 
PyMODINIT_FUNC PyInit_hello(void); 
#endif 

#endif /* !__PYX_HAVE__hello */ 

が含まれ、GCCは、Pythonの正しいバージョンを取得することができませんで(私は、Python 3.5を使っている)ようです。何とかそれを設定する方法はありますか?また、実際にそうであれば、python3 setup.py build_extコマンドを実行すると、が世話をするのはなぜですか?

私はCの経験が豊富なので、何か不足している可能性があります。

答えて

1

私は問題があなたの誤解であり、distutilsが実行ファイルをビルドすると思います。そうではありません。

目標は、Cプログラムの一部のPython機能を使用することです。のは、自分で必要な手順を実行してみましょう:

  1. を与えPYXファイルからhello.hhello.cを生成するためにcythonを使用しました。
  2. 作成したhello.hを使用して、Cプログラム(main.c)でPythonの機能をインポートします。
  3. コンパイラを使用してファイルhello.cmain.cの両方をコンパイルします。
  4. リンカを使用して、最後のステップで作成したオブジェクトファイルを実行可能ファイルにリンクします。

最初のステップは簡単です:

​​

今、私たちは私たちの作業ディレクトリにhello.chello.hを持っています。あなたのmain.cは間違っていると、次のようになります。

//main.c 
#include <Python.h> //needed 
#include "hello.h" 

int main(void){ 
    Py_Initialize(); //Needed! 
    inithello();  //Needed! called PyInit_hello() for Python3 
    say_hello(); 
    Py_Finalize(); //Needed! 
} 

私は(これはその自己完結型になるだろう)cythonの結果はPython.hが含まれていない理由はわからないんだけど、これは方法それでありますあなたはhello.hの前にそれを含める必要があります。また、Py_Initialize()Py_Finalize()は、hello.hの機能を使用する前後で呼び出す必要があります。helloinithello()で初期化する必要があります。そうしないと、セグメント化エラーが実行ファイルの先頭に表示されます。

コンパイルするためのフラグを見つける必要があります。それでは、それを構築しましょう

>>> /usr/bin/python-config --cflags 
-I/usr/include/python2.7 -I/usr/include/x86_64-linux-gnu/python2.7 
-fno-strict-aliasing -Wdate-time -D_FORTIFY_SOURCE=2 -g -fstack-protector-strong 
-Wformat -Werror=format-security -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes 

>>>gcc -c hello.c -o hello.o <our cflags> 
>>>gcc -c main.c -o main.o <our cflags> 

今、私たちは持っているこれは、ユーティリティ/usr/bin/python-config(私はpython2.7を使用し、あなたがのpython3のために同じことを行う必要がある)とオプション--cflagsで行うことができます両方のオブジェクトファイルhello.omain.oが作業ディレクトリにあります。

>>> /usr/bin/python-config --ldflags 
--L/usr/lib/python2.7/config-x86_64-linux-gnu -L/usr/lib -lpython2.7 
-lpthread -ldl -lutil -lm -Xlinker -export-dynamic -Wl,-O1 -Wl,-Bsymbolic-functions 

意味:私たちはそれらをリンクし、再び--ldflags -optionとユーティリティが、今回我々が使用権フラグを見つけるためにする必要が

>>> gcc main.o hello.o -o prog <our ldflags> 

をそして今、我々は持っていますついに実行可能!


実は、それがために求められているまさにではなく、オプション--embedを使用することにより、cythonコードから実行ファイルを生成するための別の可能性があります。このスイッチをオンにするだけでなく、モジュールがサイモスタライズされるだけでなく、メイン関数も作成されます。このために、次のようにあなたのhello.pyxになります:

#hello.pyx: 
cdef public void say_hello(): 
    print("Hello World") 
##main: 
say_hello() 

をそれは__name__=="__main__"トリックを使用することも可能ですが、必要ありません。ランニング後の今

>>>python -m cython hello.pyx --embed 

main機能はPython環境を初期化/設定の世話をする結果hello.cに作成されます。だから我々は単に構築し、それをリンクすることができます。

>>> gcc hello.c -o prog <our cflags> <our ldflags> 

をそして、我々が行っている - 必要は全体のpython-ものを右に初期化する方法を、知らないために!

+0

あなたの答えが@eadのおかげで、フラグを見つける上でのヒントは非常に便利でした。 ああ、 'main.c'のコンパイル中に、私は' inithello() 'メソッドの暗黙の宣言を受け取り、後でリンクを試みているときに' undefined reference to inithello'というエラーをスローします。 Python2.7を使用するとうまくいきます! – BitWhyz

+0

@BitWhyz hello.hコードを調べると、Python3では 'inithello()'の代わりに 'PyInit_hello()'を使うべきだと思います。 – ead

+0

それは働いた!ありがとうございました。私はなぜドキュメンテーションに言及していないのか理解していない。もっと掘り下げるための良い資源に感謝します。 – BitWhyz

関連する問題