gpt4 book ai didi

ruby - 链接到 OS X 上特定的 Oracle 即时客户端动态库

转载 作者:太空宇宙 更新时间:2023-11-03 16:53:46 25 4
gpt4 key购买 nike

有一个广泛使用的 Ruby gem (ruby-oci8),它使用 C 扩展来调用 Oracle C 库(Oracle Instant Client)。它创建一个包 (oci8lib_191.bundle),它调用 Oracle 库 (libclntsh.dylib.11.1) 中的例程。

但是,如果使用 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()链接呢?

我使用的是 OS X 10.8.2 和 Xcode 版本 4.6 (4H127)。

最佳答案

更新:

我给提问者发了邮件,通过在他的应用程序顶部添加“require 'oci8'”,崩溃消失了。

根据DYLD_PRINT_LIBRARIES=1 和DYLD_PRINT_BINDINGS=1 输出的日志,这个问题是由函数插入引起的。 libclntsh.dylib 和 OS X LDAP 库导出 _ldap_first_entry,其实现不同。当 OS X LDAP 库在 libclntsh.dylib 之前加载到进程内存中并且 libclntsh.dylib 中的函数尝试使用 libclntsh.dylib 中的 _ldap_first_entry 时,它错误地使用了 OS X LDAP 库中的 _ldap_first_entry。它通常可能发生在 Unix(OS X 除外)上,并且仅当库与 flat_namespace 链接时才会发生在 OS X 上。

IMO,他没有明确使用 OS X LDAP 库。他使用了一种授权模块,内部依赖库。

其余不变。


我有一个想法。但我还没有测试过。

IMO,ruby 不直接使用 OS X 版本库。像 ruby​​-ldap 这样的扩展库使用它。如果是这样,在扩展库之前“需要'oci8'”可能会解决问题。

require 'oci8' # This must be before any other extension libraries using LDAP.
require 'ldap' # for example

但这会导致另一个问题。当 ruby​​-ldap 库尝试使用 OS X 版本 _ldap_first_entry 时,调用 Oracle 版本 _ldap_first_entry 并且进程崩溃。您需要自定义 oci8 以避免它。

改变ext/oci8/oci8lib.c中的DLOPEN_FLAG如下,

#define DLOPEN_FLAG (RTLD_NOW|RTLD_LOCAL)

然后安装如下

gem build ruby-oci8.gemspec
gem install ruby-oci8-2.1.5.gem -- --with-runtime-check

并使用它。

require 'oci8' # This must be before any other extension libraries using LDAP.
require 'ldap'

RTLD_LOCAL 从其他扩展库中隐藏 libclntsh.dylib 中的符号。RTLD_NOW 立即解析符号并防止 libclntsh.dylib 在成功加载的库中使用符号。--with-runtime-check 强制 ruby​​-oci8 使用 dlopen()。

我希望 OS X dlopen() 规范与 Linux 相同并且可以正常工作。

关于ruby - 链接到 OS X 上特定的 Oracle 即时客户端动态库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15205743/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com