2010-01-20 103 views
16

我是Cython的新手,我正在使用Cython來包裝C/C++靜態庫。我做了一個簡單的例子如下。用Cython包裝C++庫

Test.h:

#ifndef TEST_H 
#define TEST_H 

int add(int a, int b); 
int multipy(int a, int b); 

#endif 

Test.cpp的

#include "test.h" 
int add(int a, int b) 
{ 
    return a+b; 

} 

int multipy(int a, int b) 
{ 
    return a*b; 
} 

然後我用克++編譯並生成它。

g++ -c test.cpp -o libtest.o 
ar rcs libtest.a libtest.o 

所以現在我有一個名爲libtest.a的靜態庫。

Test.pyx:

cdef extern from "test.h": 
     int add(int a,int b) 
     int multipy(int a,int b) 

print add(2,3) 

Setup.py:

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

ext_modules = [Extension("test", 
        ["test.pyx"], 
        language='c++', 
        include_dirs=[r'.'], 
        library_dirs=[r'.'], 
        libraries=['libtest'] 
        )] 

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

的我叫:

python setup.py build_ext --compiler=mingw32 --inplace 

產量爲:

running build_ext 
cythoning test.pyx to test.cpp 
building 'test' extension 
creating build 
creating build\temp.win32-2.6 
creating build\temp.win32-2.6\Release 
C:\Program Files\pythonxy\mingw\bin\gcc.exe -mno-cygwin -mdll -O -Wall -I. -IC:\ 
Python26\include -IC:\Python26\PC -c test.cpp -o build\temp.win32-2.6\Release\test.o 
writing build\temp.win32-2.6\Release\test.def 
C:\Program Files\pythonxy\mingw\bin\g++.exe -mno-cygwin -mdll -static --entry _D 
[email protected] --output-lib build\temp.win32-2.6\Release\libtest.a --def build\temp.w 
in32-2.6\Release\test.def -s build\temp.win32-2.6\Release\test.o -L. -LC:\Python 
26\libs -LC:\Python26\PCbuild -ltest -lpython26 -lmsvcr90 -o test.pyd 
g++: build\temp.win32-2.6\Release\libtest.a: No such file or directory 
error: command 'g++' failed with exit status 1 

我也嘗試使用libraries = ['test']而不是libraries = ['libtest']。它給了我同樣的錯誤。

有關這些的任何線索?

謝謝!

回答

2

我想你可以通過指定正確的library_dirs(你實際上 libtest.a - 顯然它沒有得到發現)解決這個特定的問題,但我想,那麼你就面臨着另一個問題 - 您進入點沒有被正確地聲明爲extern "C",所以函數的名字已經被C++編譯器(看你從libtest.a中導出的名字,你會看到!),所以除了C++之外的任何其他語言(包括C ,Cython等)將會遇到問題。解決方法是將其聲明爲extern "C"

+0

我應該在哪裏聲明extern「C」?不過,我認爲現在的問題是,構建抱怨它找不到libtest.a而不是其中的一個函數,即add()或mulitpy()。所以我不確定這是否會起作用。 這對我來說很怪,它抱怨'build \ temp.win32-2.6 \ Release'中沒有libtest.a。是不是由Cython本身生成的生成文件夾?爲什麼Cython試圖在那裏尋找libtest.a? – 2010-01-21 09:36:58

+0

'extern「C」'進入'.h'中的函數聲明中,正如我所說的那樣,在修正不正確的'library_dirs'(您說庫在當前目錄中)後,您將遇到的下一個問題「和'Release'恰好是編譯器/鏈接器查找庫時的當前目錄)。 – 2010-01-21 16:06:52

23

如果你的C++代碼僅用於包裝,另一種選擇是讓安裝編譯.cpp文件,就像這樣:

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

ext_modules = [Extension("test", 
        ["test.pyx", "test.cpp"], 
        language='c++', 
        )] 

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

鏈接到一個靜態庫,你必須使用extra_objects爭論在Extension

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

ext_modules = [Extension("test", 
        ["test.pyx"], 
        language='c++', 
        extra_objects=["libtest.a"], 
        )] 

setup(
    name = 'test', 
    cmdclass = {'build_ext': build_ext}, 
    ext_modules = ext_modules 
) 
+1

不,我爲測試製作了'test.cpp'。在真實的項目中,我只有一個頭文件和一個靜態庫。 – 2010-01-21 09:37:57

+3

看起來你想要的是'extra_objects'選項,編輯答案。 – 2010-01-21 14:20:44

+0

@zyq那麼一旦.so文件被創建後我們該如何繼續? – PascalVKooten 2013-05-22 12:31:55

4

Test.pyx文件沒有做你的期望。 print add(2,3)不會調用add() C++函數;你必須明確地創建一個包裝函數來做到這一點。 Cython不會自動爲你創建包裝。

像這樣的東西可能是你想要什麼:

cdef extern from "test.h": 
     int _add "add"(int a,int b) 
     int _multiply "multiply"(int a,int b) 

def add(a, b): 
    return _add(a, b) 

def multiply(a, b): 
    return _multiply(a, b) 

print add(2, 3) 

你可以看一下用Cython的documentation瞭解更多詳情。