2011-11-25 82 views
1

我剛開始使用Linux上的gcc。我遵循教程here,除了我正在使用g ++編譯器。使用ctypes.cdll.LoadLibrary從Python加載庫時無效的ELF標頭

hello_fn.cpp

#include <stdio.h> 
#include "hello.h" 

void 
hello (const char * name) 
{ 
    printf ("Hello, %s!\n", name); 
} 

bye_fn.cpp

#include <stdio.h> 
#include "hello.h" 

void 
bye (void) 
{ 
    printf ("Goodbye!\n"); 
} 

hello.h

void hello (const char * name); 
void bye (void); 

我然後運行shell執行以下操作:

$ g++ -Wall -c hello_fn.cpp 
$ g++ -Wall -c bye_fn.cpp 
$ ar cr libhello.a hello_fn.o bye_fn.o 

然後我試着從蟒蛇如下:

Python 2.7.1+ (r271:86832, Apr 11 2011, 18:05:24) 
[GCC 4.5.2] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import ctypes 
>>> test = ctypes.cdll.LoadLibrary(r'/home/oob/development/libtest/libhello.a') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/usr/lib/python2.7/ctypes/__init__.py", line 431, in LoadLibrary 
    return self._dlltype(name) 
    File "/usr/lib/python2.7/ctypes/__init__.py", line 353, in __init__ 
    self._handle = _dlopen(self._name, mode) 
OSError: /home/jeff/development/libtest/libhello.a: invalid ELF header 

我的想法是寫一些功能在C++和Python的從調用它們。有任何想法嗎?

更新:我能夠讓事情「工作」。根據Cat Plus Plus的說法,我可能不會爲新代碼走這個方向,但我可以將它與我從Windows移植到Linux的大型傳統C++庫一起工作。我們需要一個前端從這個庫中調用一些長時間運行的函數,所以我認爲Python可能是最簡單的。這些函數創建了很多輸出,並且只返回一個整型返回碼,所以也許我可以避免Cat Plus Plus所說的「痛苦」的東西。

這是我做的。

改性hello_fn.cpp

#include <stdio.h> 
#include "hello.h" 

extern "C" int 
hello (void) 
{ 
    return 16; 
}                     

改性by_fn.cpp

#include <stdio.h> 
#include "hello.h" 

extern "C" void 
bye (void) 
{ 
    printf ("Goodbye!\n"); 
} 

改性hello.h

extern "C" int hello (void); 
extern "C" void bye (void); 

buildscript.sh

#!/bin/bash 

rm *.o 
rm *.so 

g++ -fpic -g -c -Wall hello_fn.cpp 
g++ -fpic -g -c -Wall bye_fn.cpp 
#make a shared library, not a static library (thanks cat plus plus) 
g++ -shared -o libhello.so hello_fn.o bye_fn.o 

test.py

#!/usr/bin/python 

import ctypes 

c = ctypes.cdll.LoadLibrary(r'/home/jeff/development/libtest/libhello.so') 
a = c.hello() 
print 'hello was ' + str(a) 
c.bye() 

嘗試在終端....

[email protected]:~/development/libtest$ ./build_script.sh 
[email protected]:~/development/libtest$ python test.py 
hello was 16 
Goodbye! 

我們的傳統圖書館並沒有真正使用任何Windows的特定C++的東西(感謝誰寫的傢伙該代碼),所以它是一個非常容易的端口。我們有幾個使用extern「C」來暴露函數的函數。對於端口,我已經做了以下修改:

#ifdef LINUX 
#define __stdcall 
#endif 
#ifdef WINDOWS 
#define __stdcall __stdcall 
#endif 

而對於我們的功能之一,我可以離開它不變,例如:

extern "C" long __stdcall reform_proj { 
    //do a bunch of stuff 
    return 0; 
} 

回答

4

​​是加載共享庫。 ar創建目標文件的存檔,也稱爲靜態庫。您無法使用​​加載該文件,只能通過鏈接器進行理解。

另一個問題是,使用C++共享庫通過​​是痛苦的,如果不是完全不可能的話。不要。改爲使用Cython,然後編寫一個適當的Python擴展,與您的C++代碼進行交互(然後您可以靜態或動態鏈接它,並且它會工作)。

另一個選項是Boost.Python,但它的記錄較少,但有直接在C++代碼中定義Python模塊的好處,而不是使用其他語言編寫的包裝器。

第三個是SWIG,但我從來沒有用過它,所以不能告訴你它在實際中的效果如何。

+0

謝謝。靜態vs共享是我需要開始的。查看我的更新,瞭解我如何爲這個小例子工作。我一定會接受你的建議(關於cython),以便我將來編寫任何代碼。 – oob