2012-06-27 40 views
6

Tôi gặp sự cố khi tạo tiện ích mở rộng ruby ​​để xuất thư viện C++ mà tôi đã viết thành ruby ​​trong OSX. Ví dụ đơn giản:không thể tạo phần mở rộng ruby ​​C++

#include <boost/regex.hpp> 

extern "C" void Init_bayeux() 
{ 
    boost::regex expression("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?"); 
} 

kết quả trong một ngoại lệ bad_cast bị ném:

#0 0x00000001014663bd in __cxa_throw() 
#1 0x00000001014cf6b2 in __cxa_bad_cast() 
#2 0x00000001014986f9 in std::use_facet<std::collate<char> >() 
#3 0x0000000101135a4f in boost::re_detail::cpp_regex_traits_base<char>::imbue (this=0x7fff5fbfe4d0, [email protected]) at cpp_regex_traits.hpp:218 
#4 0x0000000101138d42 in cpp_regex_traits_base (this=0x7fff5fbfe4d0, [email protected]) at cpp_regex_traits.hpp:173 
#5 0x000000010113eda6 in boost::re_detail::create_cpp_regex_traits<char> ([email protected]) at cpp_regex_traits.hpp:859 
#6 0x0000000101149bee in cpp_regex_traits (this=0x101600200) at cpp_regex_traits.hpp:880 
#7 0x0000000101142758 in regex_traits (this=0x101600200) at regex_traits.hpp:75 
#8 0x000000010113d68c in regex_traits_wrapper (this=0x101600200) at regex_traits.hpp:169 
#9 0x000000010113bae1 in regex_data (this=0x101600060) at basic_regex.hpp:166 
#10 0x000000010113981e in basic_regex_implementation (this=0x101600060) at basic_regex.hpp:202 
#11 0x0000000101136e1a in boost::basic_regex<char, boost::regex_traits<char, boost::cpp_regex_traits<char> > >::do_assign (this=0x7fff5fbfe710, p1=0x100540ae0 "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?", p2=0x100540b19 "", f=0) at basic_regex.hpp:652 
#12 0x0000000100540a66 in boost::basic_regex<char, boost::regex_traits<char, boost::cpp_regex_traits<char> > >::assign (this=0x7fff5fbfe710, p1=0x100540ae0 "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?", p2=0x100540b19 "", f=0) at basic_regex.hpp:379 
#13 0x0000000100540a13 in boost::basic_regex<char, boost::regex_traits<char, boost::cpp_regex_traits<char> > >::assign (this=0x7fff5fbfe710, p=0x100540ae0 "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?", f=0) at basic_regex.hpp:364 
#14 0x000000010054096e in basic_regex (this=0x7fff5fbfe710, p=0x100540ae0 "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?", f=0) at basic_regex.hpp:333 
#15 0x00000001005407e2 in Init_bayeux() at bayeux.cpp:10 
#16 0x0000000100004593 in dln_load (file=0x1008bc000 "/Users/todi/sioux/lib/debug/rack/bayeux.bundle") at dln.c:1293 

Tôi biên dịch phần mở rộng với:

g++ ./source/rack/bayeux.cpp -o /Users/todi/sioux/obj/debug/rack/bayeux.o -Wall -pedantic -Wno-parentheses -Wno-sign-compare -fno-common -c -pipe -I/Users/todi/sioux/source -ggdb -O0 

Và cuối cùng liên kết các thư viện năng động với:

g++ -o /Users/todi/sioux/lib/debug/rack/bayeux.bundle -bundle -ggdb /Users/todi/sioux/obj/debug/rack/bayeux.o -L/Users/todi/sioux/lib/debug -lrack -lboost_regex-mt-d -lruby 

Tôi đã đã tìm kiếm trên web và thử tất cả các loại chuyển đổi liên kết và trình biên dịch. Nếu tôi xây dựng một tệp thực thi thì không có vấn đề gì như vậy. Có ai khác đã có một vấn đề như vậy và tìm thấy một giải pháp?

Tôi đã điều tra thêm này và thấy rằng các chức năng gây ra ngoại lệ trông như thế này:

std::locale loc = std::locale("C"); 
std::use_facet< std::collate<char> >(loc); 

Trong nguồn std :: chiếu <> Tôi tìm thấy Statment ném:

use_facet(const locale& __loc) 
{ 
    const size_t __i = _Facet::id._M_id(); 
    const locale::facet** __facets = __loc._M_impl->_M_facets; 
    if (__i >= __loc._M_impl->_M_facets_size || !__facets[__i]) 
    __throw_bad_cast(); 
#ifdef __GXX_RTTI 
     return dynamic_cast<const _Facet&>(*__facets[__i]); 
#else 
     return static_cast<const _Facet&>(*__facets[__i]); 
#endif 
} 

Điều này có hợp lý với bạn không?

Cập nhật: Tôi đã thử gợi ý của Jan:

Todis-MacBook-Pro:rack todi$ g++ -shared -fpic -o bayeux.bundle bayeux.cpp 
Todis-MacBook-Pro:rack todi$ ruby -I. -rbayeux -e 'puts :ok' 
terminate called after throwing an instance of 'std::bad_cast' 
    what(): std::bad_cast 
Abort trap 

phiên bản:

Todis-MacBook-Pro:rack todi$ ruby -v 
ruby 1.9.2p136 (2010-12-25 revision 30365) [x86_64-darwin10.6.0] 
Todis-MacBook-Pro:rack todi$ gcc -v 
Using built-in specs. 
COLLECT_GCC=gcc 
COLLECT_LTO_WRAPPER=/opt/local/libexec/gcc/x86_64-apple-darwin10/4.5.2/lto-wrapper 
Target: x86_64-apple-darwin10 
Configured with: ../gcc-4.5.2/configure --prefix=/opt/local --build=x86_64-apple-darwin10 --enable-languages=c,c++,objc,obj-c++,fortran,java --libdir=/opt/local/lib/gcc45 --includedir=/opt/local/include/gcc45 --infodir=/opt/local/share/info --mandir=/opt/local/share/man --datarootdir=/opt/local/share/gcc-4.5 --with-local-prefix=/opt/local --with-system-zlib --disable-nls --program-suffix=-mp-4.5 --with-gxx-include-dir=/opt/local/include/gcc45/c++/ --with-gmp=/opt/local --with-mpfr=/opt/local --with-mpc=/opt/local --enable-stage1-checking --disable-multilib --enable-fully-dynamic-string 
Thread model: posix 
gcc version 4.5.2 (GCC) 

Cập nhật:

Nó không phải là ràng buộc kiểm tra trong use_facet() mà ném, nhưng dòng tiếp theo, thực sự có dàn diễn viên năng động. Ví dụ này nhét nó xuống để có thể một cái gì đó với RTTI:

#define private public 
#include <locale> 
#include <iostream> 
#include <typeinfo> 

extern "C" void Init_bayeux() 
{ 
    std::locale loc = std::locale("C"); 
    printf("size: %i\n", loc._M_impl->_M_facets_size); 
    printf("id: %i\n", std::collate<char>::id._M_id()); 

    const std::locale::facet& fac = *loc._M_impl->_M_facets[ std::collate<char>::id._M_id() ]; 

    printf("name: %s\n", typeid(fac).name()); 
    printf("name: %s\n", typeid(std::collate<char>).name()); 

    const std::type_info& a = typeid(fac); 
    const std::type_info& b = typeid(std::collate<char>); 

    printf("equal: %i\n", !a.before(b) && !b.before(a)); 
    dynamic_cast< const std::collate<char>& >(fac); 
} 

Tôi đã sử dụng printf() vì việc sử dụng cout cũng không thành công. Sản lượng của các mã trên là:

size: 28 
id: 5 
name: St7collateIcE 
name: St7collateIcE 
equal: 1 
terminate called after throwing an instance of 'std::bad_cast' 
    what(): std::bad_cast 
Abort trap 

Xây dựng với:

g++ -shared -fpic -o bayeux.bundle bayeux.cpp && ruby -I. -rbayeux -e 'puts :ok' 

Cập nhật:

Nếu tôi đổi tên Init_bayeux to main() và liên kết nó với một thực thi, đầu ra là giống nhau, nhưng không có cuộc gọi để chấm dứt.

Cập nhật:

Khi tôi viết một chương trình nhỏ để nạp thư viện chia sẻ và để thực hiện Init_bayeux(), một lần nữa, không có ngoại lệ được ném:

#include <dlfcn.h> 

int main() 
{ 
    void* handle = dlopen("bayeux.bundle", RTLD_LAZY|RTLD_GLOBAL); 
    void(*f)(void) = (void(*)(void)) dlsym(handle, "Init_bayeux") ; 
    f(); 
} 

Vì vậy, có vẻ với tôi, rằng nó có thể là một vấn đề với cách ruby.exe được xây dựng. Điều đó có ý nghĩa?

Cập nhật: Tôi đã xem xét các địa chỉ chứa tên của hai đối tượng type_info. Cùng một nội dung, nhưng địa chỉ khác nhau.Tôi đã thêm công tắc -flat_namespace vào lệnh liên kết. Bây giờ các công trình dynamic_cast. Vấn đề ban đầu với thư viện boost regex vẫn còn tồn tại, nhưng tôi nghĩ rằng điều này có thể được giải quyết bằng cách liên kết tăng tĩnh vào thư viện được chia sẻ hoặc bằng cách xây dựng lại các thư viện tăng với chuyển đổi -flat_namespace.

Cập nhật: Bây giờ tôi trở lại với ví dụ đầu tiên với biểu hiện tăng regex, xây dựng với lệnh này:

g++ -shared -flat_namespace -fPIC -o bayeux.bundle /Users/todi/boost_1_49_0/stage/lib/libboost_regex.a bayeux.cpp 

Nhưng khi tải phần mở rộng vào thông dịch viên ruby, khởi tạo các biểu tượng tĩnh thất bại :

ruby(59384,0x7fff712b8cc0) malloc: *** error for object 0x7fff70b19500: pointer being freed was not allocated 
*** set a breakpoint in malloc_error_break to debug 

Program received signal SIGABRT, Aborted. 
0x00007fff8a6ab0b6 in __kill() 
(gdb) bt 
#0 0x00007fff8a6ab0b6 in __kill() 
#1 0x00007fff8a74b9f6 in abort() 
#2 0x00007fff8a663195 in free() 
#3 0x0000000100541023 in boost::re_detail::cpp_regex_traits_char_layer<char>::init (this=0x10060be50) at basic_string.h:237 
#4 0x0000000100543904 in boost::object_cache<boost::re_detail::cpp_regex_traits_base<char>, boost::re_detail::cpp_regex_traits_implementation<char> >::do_get ([email protected]) at cpp_regex_traits.hpp:366 
#5 0x000000010056005b in create_cpp_regex_traits<char> (l=<value temporarily unavailable, due to optimizations>) at pending/object_cache.hpp:69 
#6 0x0000000100544c33 in boost::basic_regex<char, boost::regex_traits<char, boost::cpp_regex_traits<char> > >::do_assign (this=0x7fff5fbfe090, p1=0x100567158 "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?", p2=0x100567191 "", f=0) at cpp_regex_traits.hpp:880 
#7 0x0000000100566280 in boost::basic_regex<char, boost::regex_traits<char, boost::cpp_regex_traits<char> > >::assign() 
#8 0x000000010056622d in boost::basic_regex<char, boost::regex_traits<char, boost::cpp_regex_traits<char> > >::assign() 
#9 0x0000000100566188 in boost::basic_regex<char, boost::regex_traits<char, boost::cpp_regex_traits<char> > >::basic_regex() 
#10 0x0000000100566025 in Init_bayeux() 
#11 0x0000000100003a23 in dln_load (file=0x10201a000 "/Users/todi/sioux/source/rack/bayeux.bundle") at dln.c:1293 
#12 0x000000010016569d in vm_pop_frame [inlined]() at /Users/todi/.rvm/src/ruby-1.9.2-p320/vm_insnhelper.c:1465 
#13 0x000000010016569d in rb_vm_call_cfunc (recv=4303980440, func=0x100042520 <load_ext>, arg=4303803000, blockptr=0x1, filename=<value temporarily unavailable, due to optimizations>, filepath=<value temporarily unavailable, due to optimizations>) at vm.c:1467 
#14 0x0000000100043382 in rb_require_safe (fname=4303904640, safe=0) at load.c:602 
#15 0x000000010017cbf3 in vm_call_cfunc [inlined]() at /Users/todi/.rvm/src/ruby-1.9.2-p320/vm_insnhelper.c:402 
#16 0x000000010017cbf3 in vm_call_method (th=0x1003016b0, cfp=0x1004ffef8, num=1, blockptr=0x1, flag=8, id=<value temporarily unavailable, due to optimizations>, me=0x10182cfa0, recv=4303980440) at vm_insnhelper.c:528 
... 

Một lần nữa, điều này không thành công khi tôi tải thư viện được chia sẻ bởi chương trình c từ trên xuống.

Cập nhật: Bây giờ tôi liên kết ví dụ đầu tiên tĩnh:

g++ -shared -fPIC -flat_namespace -nodefaultlibs -o bayeux.bundle -static -lstdc++ -lpthread -lgcc_eh -lboost_regex-mt bayeux.cpp 

Với những lỗi tương tự:

ruby(15197,0x7fff708aecc0) malloc: *** error for object 0x7fff7027e500: pointer being freed was not allocated 

otool -L khẳng định rằng tất cả các thư viện được liên kết tĩnh:

bayeux.bundle: 
bayeux.bundle (compatibility version 0.0.0, current version 0.0.0) 
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 125.2.11) 

gỡ lỗi:

Nếu tôi liên kết với phiên bản gỡ lỗi tăng, thì nó hoạt động như mong đợi.

+4

Tôi không thể tạo lại hành vi bạn mô tả. Tôi đã biên dịch tập tin ví dụ C++ với 'g ++ -shared -fpic -o bayeux.so -lboost_regex bayeux.cpp' và' ruby ​​-I. -rbayeux -e 'đặt: ok'' tải phần mở rộng mà không có bất kỳ vấn đề. Tuy nhiên, tôi đã có một số vấn đề khi tôi bỏ qua '-lboost_regex'. Bên cạnh đó, bạn có thể chỉ định phiên bản Ruby và Boost nào bạn đang sử dụng và cách chúng tôi có thể tạo lại vấn đề này? – Jan

+0

@Jan, Cảm ơn bạn đã thử. Trên OS X, tôi phải thay đổi phần mở rộng 'so' thành 'bundle' (nếu không yêu cầu sẽ không tìm thấy thư viện) nhưng kết quả vẫn như cũ. –

+0

@Jan, bạn có thể bỏ qua thư viện tăng tốc, nó không thành công nếu không có nó. Đó là lệnh gọi use_facet <> không thành công. –

Trả lời

0

Đối với các bản ghi: Tôi hiện đang xây dựng tăng cường và ứng dụng của tôi với trình biên dịch rất giống nhau (phiên bản 4.2.1 [phiên bản chính thức của Apple]). Không có vấn đề cho đến nay. Tại sao nó sẽ không hoạt động như mong đợi khi mở rộng ruby ​​liên kết tất cả các thư viện tĩnh là một phép lạ đối với tôi. Cảm ơn tất cả những người đặt thời gian vào vấn đề này.

Trân trọng Torsten

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