2015-06-22 12 views
5

Tôi có một chức năng kiểm tra đơn giản trên C++:ctypes biểu tượng lỗi AttributeError không tìm thấy, OS X 10.7.5

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
#include <locale.h> 
#include <wchar.h> 

char fun() { 
    printf("%i", 12); 

    return 'y'; 
} 

biên dịch:

gcc -o test.so -shared -fPIC test.cpp 

và sử dụng nó trong python với ctypes:

from ctypes import cdll 
from ctypes import c_char_p 

lib = cdll.LoadLibrary('test.so') 
hello = lib.fun 
hello.restype = c_char_p 

print('res', hello()) 

nhưng sau đó tôi gặp lỗi:

Traceback (most recent call last): File "./sort_c.py", line 10, in <module> 
    hello = lib.fun File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ctypes/__init__.py", line 366, in __getattr__ 
    func = self.__getitem__(name) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ctypes/__init__.py", line 371, in __getitem__ 
    func = self._FuncPtr((name_or_ordinal, self)) 
AttributeError: dlsym(0x100979b40, fun): symbol not found 

Sự cố ở đâu?

sử dụng:

Mac Os X 10.7.5 and Python 2.7

Trả lời

8

vấn đề đầu tiên của bạn là C++ tên mangling. Nếu bạn chạy nm trong hồ sơ .so của bạn, bạn sẽ nhận được một cái gì đó như thế này:

nm test.so 
0000000000000f40 T __Z3funv 
       U _printf 
       U dyld_stub_binder 

Nếu bạn đánh dấu nó như C phong cách khi biên dịch với C++:

#ifdef __cplusplus 
extern "C" char fun() 
#else 
char fun(void) 
#endif 
{ 
    printf("%i", 12); 

    return 'y'; 
} 

nm cho:

0000000000000f40 T _fun 
       U _printf 
       U dyld_stub_binder 

Vấn đề thứ hai của bạn là con trăn sẽ chết với Segmentation fault: 11 (trên OS X). C++ trả về một char, trong khi bạn đang đánh dấu nó trong python như một con trỏ tới một char. Sử dụng:

hello.restype = c_char 

thay vì (thay đổi import tuyên bố khớp).

EDIT: như @eryksun đã chỉ ra, bạn không nên sử dụng gcc, bạn nên sử dụng g++ để thay thế. Nếu không, thời gian chạy C++ chính xác sẽ không được liên kết. Để kiểm tra trên OS X:

otool -L test.so 

(ldd, công cụ thường được sử dụng trên UNIX/Linux, không được phân phối với OS X)

+1

Liệu sử dụng 'gcc' liên kết một chương trình C++ với C thích hợp ++ runtime trong hệ điều hành X? Tôi mong đợi nó yêu cầu 'g ++'. Tôi biết nó không quan trọng trong trường hợp này vì mã mẫu chỉ sử dụng các hàm thư viện chuẩn của C. – eryksun

+0

@eryksun: 'gcc' biên dịch nó thành C++ nếu tệp nguồn có hậu tố' .cpp', nhưng bạn đúng, 'g ++' được ưu tiên. Tôi đã không đề cập đến nó trong câu trả lời của tôi bởi vì có một bình luận về nó (của bạn?). Nó giống như C++ bởi vì tên mangling là khác nhau với điều kiện 'extern" C "' (xem phần thân của bài viết). – cdarke

+1

'gcc' biên dịch nguồn là C++, nhưng trên Linux nó không liên kết với libstdC++ .vì vậy, do đó tải thư viện không thành công nếu nó yêu cầu lib C++. – eryksun

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