2015-02-06 41 views
6

我已经完全复制了Cython documentation for wrapping C++ classes中给出的示例代码。我可以成功地建立和导入使用distutilscythonize()方法rect.so延伸,通过即:如何手动编译使用C++的Cython代码?

# distutils: language = c++ 
# distutils: sources = Rectangle.cpp 
  • setup.py文件,其中包含:

    1. rect.pyx顶部把下面的指令这个:

      from distutils.core import setup 
      from Cython.Build import cythonize 
      
      setup(
          name = "rectangleapp", 
          ext_modules = cythonize('*.pyx'), 
      ) 
      
    2. 打电话

      $ python setup.py build_ext --inplace 
      

    然而,当我包装C代码用Cython我经常发现它更方便手动命令行编译单个扩展,即:

    1. 生成.c代码使用命令行Cython编译器

      $ cython foo.pyx 
      
    2. 使用手动编译它:

      $ gcc -shared -fPIC -O3 -I /usr/lib/python2.7 -L /usr/lib/python2.7 \ 
           foo.c -lpython2.7 -o foo.so 
      

    我已经尝试采用同样的工艺打造的rect.so上面的例子:

    $ cython --cplus rect.pyx 
    $ g++ -shared -fPIC -O3 -I /usr/lib/python2.7 -L /usr/lib/python2.7 \ 
         rect.cpp -lpython2.7 -o rect.so 
    

    无论是用Cython和g ++编译步骤似乎成功 - 我不明白任何命令行输出,并在最后我有一个rect.so内置。然而,当我再尝试导入模块我得到一个错误undefined symbol

    In [1]: import rect 
    --------------------------------------------------------------------------- 
    ImportError        Traceback (most recent call last) 
    <ipython-input-1-ba16f97c2145> in <module>() 
    ----> 1 import rect 
    
    ImportError: ./rect.so: undefined symbol: _ZN6shapes9Rectangle9getLengthEv 
    

    什么是手动编译一个封装C++类用Cython代码正确的程序?

  • 回答

    6

    这里的问题是,你说的地方,你会提供一个名为Rectangle类的定义 - 在示例代码中指出

    cdef extern from "Rectangle.h" namespace "shapes": 
        cdef cppclass Rectangle: 
         ... 
    

    然而,当你编译你没有提供的库代码为Rectangle或包含它的库,所以rect.so不知道在哪里可以找到这个Rectangle类。

    要运行您的代码,您必须先创建Rectangle对象文件。

    gcc -c Rectangle.cpp # creates a file called Rectangle.o 
    

    现在,您可以创建动态对抗链接库,或静态目标文件链接到rect.so。我会首先介绍静态链接,因为它最简单。

    gcc -shared -fPIC -I /usr/include/python2.7 rect.cpp Rectangle.o -o rect.so 
    

    请注意,我没有包含python库。这是因为你期望你的库被python解释器加载,所以当你的库被加载时,python库已经被加载。除了提供rect.cpp作为来源,我还提供Rectangle.o。所以让我们试着用你的模块来运行一个程序。

    run.py

    import rect 
    print(rect.PyRectangle(0, 0, 1, 2).getLength()) 
    

    不幸的是,这将产生另一个错误:

    ImportError: /home/user/rectangle/rect.so undefined symbol: _ZTINSt8ios_base7failureE 
    

    这是因为用Cython需要C++标准库,但是Python有没有装好了。您可以通过添加C++标准库所需的库rect.so

    gcc -shared -fPIC -I/usr/include/python2.7 rect.cpp Rectangle.o -lstdc++ \ 
        -o rect.so 
    

    运行run.py再解决这个问题,所有应该工作。但是,rect.so的代码比需要的大,尤其是如果您生成依赖于相同代码的多个库。你可以动态链接矩形代码,也可以将它作为一个库。

    gcc -shared -fPIC Rectangle.o -o libRectangle.so 
    gcc -shared -fPIC -I/usr/include/python2.7 -L. rect.cpp -lRectangle -lstdc++ \ 
        -o rect.so 
    

    我们编译矩形代码到当前目录中的共享库,并提供-L.以使gcc知道如何寻找当前目录和库-lRectangle以使gcc知道如何寻找的矩形库。最后,为了能够运行你的代码,你必须告诉python Rectangle库在哪里。运行蟒蛇之前进入

    export LD_LIBRARY_PATH="/home/user/rectangle" # where libRectangle.so lives 
    

    您可以使用shell脚本,以确保你运行程序之前这样做,每次,但它使事情混乱。最好只是坚持静态链接矩形。