有一个广泛使用的 Ruby gem (ruby-oci8),它使用 C 扩展来调用 Oracle C 库 (Oracle Instant Client)。它创建一个调用 Oracle 库 (libclntsh.dylib.11.1) 中的例程的包 (oci8lib_191.bundle)。
但是,如果使用 LDAP 来解析他们的数据库名称,就会出现问题。客户端崩溃:
Assertion failed: (LDAP_VALID( ld )), function ldap_first_entry, file getentry.c, line 35.
Oracle 库包括它自己的 LDAP 例程。
nm /Applications/OracleInstantClient/libclntsh.dylib.11.1 | grep ldap_first_entry
0000000000f0fc50 T _ldap_first_entry
0000000000f15620 T _ora_ldap_first_entry
但是,我已经使用 gdb 验证了当客户端崩溃时,它会在 OS X LDAP 库的代码中崩溃。
(gdb) bt
#0 0x00007fff8403d212 in __pthread_kill ()
#1 0x00007fff8da78af4 in pthread_kill ()
#2 0x00007fff8dabcdce in abort ()
#3 0x00007fff8dabde2a in __assert_rtn ()
#4 0x00007fff86e233e2 in ldap_first_entry ()
(gdb) info symbol 0x00007fff86e233e2
ldap_first_entry + 98 in section LC_SEGMENT.__TEXT.__text of /System/Library/Frameworks/LDAP.framework/Versions/A/LDAP
因此,显然发生的事情是当捆绑包尝试调用 ldap_first_entry() 时,它与 OS X 版本链接,而不是 Oracle 内部的自定义版本 (libclntsh.dylib.11.1)。
我的第一个想法是在存在动态库时使用与链接静态库相同的技巧。也就是说,将绝对路径传递给库。但是,如您所见,这会导致错误:
gcc -dynamic -bundle -o oci8lib_191.bundle oci8lib.o env.o error.o oci8.o ocihandle.o connection_pool.o stmt.o bind.o metadata.o attr.o lob.o oradate.o ocinumber.o ocidatetime.o object.o apiwrap.o encoding.o oranumber_util.o thread_util.o -L. -L/usr/local/lib -L. -L/usr/local/lib -Wl,-undefined,dynamic_lookup -Wl,-multiply_defined,suppress -Wl,-flat_namespace -L/Applications/OracleInstantClient -l/Applications/OracleInstantClient/libclntsh.dylib.11.1 -lpthread -ldl -lobjc
ld: library not found for -l/Applications/OracleInstantClient/libclntsh.dylib.11.1
该库确实存在于列出的路径中:
xanadu:~ wwilliam$ file /Applications/OracleInstantClient/libclntsh.dylib.11.1
/Applications/OracleInstantClient/libclntsh.dylib.11.1: Mach-O 64-bit dynamically linked shared library x86_64
我也试过-rpath:
gcc -dynamic -bundle -o oci8lib_191.bundle oci8lib.o env.o error.o oci8.o ocihandle.o connection_pool.o stmt.o bind.o metadata.o attr.o lob.o oradate.o ocinumber.o ocidatetime.o object.o apiwrap.o encoding.o oranumber_util.o thread_util.o -L. -L/usr/local/lib -L. -L/usr/local/lib -Wl,-undefined,dynamic_lookup -Wl,-multiply_defined,suppress -Wl,-flat_namespace -L/Applications/OracleInstantClient -Wl,-rpath,/Applications/OracleInstantClient -lclntsh -lpthread -ldl -lobjc
仅供参考, DYLD_LIBRARY_PATH 已设置:
DYLD_LIBRARY_PATH=:/Applications/OracleInstantClient
那么,如何才能保证bundle与Oracle版本的ldap_first_entry()链接呢?
我正在使用带有 Xcode 版本 4.6 (4H127) 的 OS X 10.8.2。