2015-02-06 12 views
6

Tôi đã sao chép chính xác mã ví dụ được đưa ra trong Cython documentation for wrapping C++ classes. Tôi có thể xây dựng thành công và nhập phần mở rộng rect.so sử dụng distutilscythonize() phương pháp, tức là bằng cách:Làm cách nào tôi có thể biên dịch mã Cython theo cách thủ công sử dụng C++?

  1. Đưa các chỉ dẫn sau ở đầu rect.pyx:

    # distutils: language = c++ 
    # distutils: sources = Rectangle.cpp 
    
  2. Viết một tập tin setup.py có chứa này:

    from distutils.core import setup 
    from Cython.Build import cythonize 
    
    setup(
        name = "rectangleapp", 
        ext_modules = cythonize('*.pyx'), 
    ) 
    
  3. Gọi

    $ python setup.py build_ext --inplace 
    

Tuy nhiên, khi tôi đang gói mã C trong Cython tôi thường thấy nó thuận tiện hơn để biên dịch các phần mở rộng cá nhân bằng tay từ dòng lệnh, ví dụ:

  1. Tạo mã .c bằng cách sử dụng dòng lệnh Cython biên dịch

    $ cython foo.pyx 
    
  2. thủ biên dịch nó bằng cách sử 012.306.:

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

Tôi đã thử áp dụng quá trình tương tự để xây dựng các ví dụ rect.so trên:

$ 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 

Cả Cython và g ++ bước biên soạn dường như thành công - Tôi không nhận được bất kỳ đầu ra dòng lệnh nào và cuối cùng tôi đã xây dựng rect.so. Tuy nhiên, khi tôi sau đó cố gắng nhập module Tôi nhận được một lỗi 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ác thủ tục chính xác cho tay biên dịch mã Cython rằng kết thúc tốt đẹp các lớp C++ là gì?

Trả lời

6

Vấn đề ở đây là bạn nói rằng ở đâu đó bạn sẽ cung cấp định nghĩa của một lớp được gọi là Rectangle - nơi mã ví dụ khẳng định

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

Tuy nhiên, khi bạn biên soạn các thư viện bạn đã không cung cấp mã cho Rectangle, hoặc một thư viện chứa nó, vì vậy rect.so không có ý tưởng nơi để tìm thấy lớp hình chữ nhật này.

Để chạy mã của bạn, trước tiên bạn phải tạo tệp đối tượng Hình chữ nhật.

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

Bây giờ bạn có thể tạo thư viện để liên kết động hoặc liên kết tĩnh tệp đối tượng vào rect.so. Tôi sẽ bao gồm liên kết tĩnh đầu tiên vì nó đơn giản nhất.

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

Lưu ý rằng tôi đã không bao gồm các thư viện cho python.Điều này là do bạn mong đợi thư viện của bạn được nạp bởi trình thông dịch python, do đó các thư viện python sẽ được nạp bởi quá trình khi thư viện của bạn được tải. Ngoài việc cung cấp rect.cpp làm nguồn tôi cũng cung cấp Rectangle.o. Vì vậy, hãy thử chạy một chương trình bằng cách sử dụng mô-đun của bạn.

run.py

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

Thật không may, điều này tạo ra một lỗi khác:

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

Điều này là do cython cần Thư viện chuẩn C++, nhưng trăn chưa nạp nó. Bạn có thể khắc phục điều này bằng cách thêm vào Thư viện chuẩn C++ với thư viện cần thiết cho rect.so

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

Run run.py một lần nữa và tất cả phải làm việc. Tuy nhiên, mã cho rect.so lớn hơn mức cần thiết, đặc biệt nếu bạn tạo nhiều thư viện phụ thuộc vào cùng một mã. Bạn có thể liên kết động mã Rectangle, bằng cách làm cho nó trở thành một thư viện.

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

Chúng tôi biên dịch mã Rectangle thành một thư viện chia sẻ trong thư mục hiện và cung cấp -L. để gcc biết để tìm kiếm các thư viện trong thư mục hiện và -lRectangle để gcc biết để tìm kiếm các thư viện Rectangle. Cuối cùng, để có thể chạy mã của bạn, bạn phải nói với python nơi thư viện Rectangle sống. Trước khi chạy python nhập

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

Bạn có thể sử dụng một kịch bản để đảm bảo điều này được thực hiện mỗi lần trước khi bạn chạy chương trình của bạn, nhưng nó làm cho mọi thứ hỗn độn. Tốt nhất chỉ cần dính với hình chữ nhật liên kết tĩnh.

Các vấn đề liên quan