【发布时间】:2019-07-25 17:44:07
【问题描述】:
Ruby 扩展 davenport-ruby 到 C 库 davenport 无法在 Ubuntu 和 Debian 上正确加载。它可以在开发机器 (MacOS) 上正常工作,正如烟雾测试 Ruby 项目的 README 所证明的那样,dvt
RubyGems 加载器(通过捆绑器)编译并安装扩展如下:
~/dvt$ rm -rf ~/.bundle
~/dvt$ bundle install
Fetching gem metadata from https://rubygems.org/.
Using bundler 2.0.2
Fetching davenport 1.0.2.pre
Installing davenport 1.0.2.pre with native extensions
Bundle complete! 1 Gemfile dependency, 2 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
~/dvt$ bundle info davenport
* davenport (1.0.2.pre)
Summary: Ruby binding for the Davenport library
Homepage: https://github.com/wbreeze/davenport-ruby
Path: /home/deploy/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0\
/gems/davenport-1.0.2.pre
~/dvt$ ls /home/deploy/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0\
/gems/davenport-1.0.2.pre/lib/davenport_ruby/
davenport_ruby.so
~/dvt$
但是尝试运行程序会产生:
deploy@localhost:~/dvt$ ruby test.rb
Traceback (most recent call last):
6: from test.rb:1:in `<main>'
5: from /home/deploy/.rbenv/versions/2.6.3/lib/ruby/2.6.0/rubygems\
/core_ext/kernel_require.rb:34:in `require'
...
1: from /home/deploy/.rbenv/versions/2.6.3/lib/ruby/2.6.0/rubygems\
/core_ext/kernel_require.rb:54:in `require':\
libdavenport.so.0: cannot open shared object file: No such file or\
directory - /home/deploy/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0\
/gems/davenport-1.0.2.pre/lib/davenport_ruby/davenport_ruby.so\
(LoadError)
库文件libdavenport.so.0 存在于/usr/local/lib 中。使用ruby -I /usr/local/lib test.rb 制作加载路径的那一部分会产生相同的结果。
库文件davenport_ruby.so 存在于/home/deploy/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/davenport-1.0.2.pre/lib/davenport_ruby 中,如下所示:
/home/deploy/.rbenv/versions/2.6.3/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require': libdavenport.so.0: cannot open shared\
object file: No such file or directory - /home/deploy/.rbenv/versions/2.6.3\
/lib/ruby/gems/2.6.0/gems/davenport-1.0.2.pre/lib/davenport_ruby\
/davenport_ruby.so (LoadError)
~/dvt$ ls -l ~/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/\
davenport-1.0.2.pre/lib/davenport_ruby/
total 72
-rwxr-xr-x 1 deploy deploy 69640 Jul 25 17:02 davenport_ruby.so
~/dvt$
已发布的1.0.2.pre Ruby davenport 扩展版本来自this PR,该链接显示了所有代码位(以及大量实验)。是不是扩展 gem 的一些细节或部分不太正确?
davenport_ruby.so
.so 文件是安装 gem 时编译的共享库文件。它不存在于 gem 的内容中:
~/davenport-ruby/dltem[i1]$ gem unpack davenport-1.0.2.pre.gem
Unpacked gem: '/Users/dcl/davenport-ruby/dltem/davenport-1.0.2.pre'
~/davenport-ruby/dltem[i1]$ ls -R
davenport-1.0.2.pre davenport-1.0.2.pre.gem
./davenport-1.0.2.pre:
History.txt README.rdoc Rakefile ext lib
./davenport-1.0.2.pre/ext:
davenport_ruby
./davenport-1.0.2.pre/ext/davenport_ruby:
davenport_ruby.c extconf.rb
./davenport-1.0.2.pre/lib:
davenport.rb
~/davenport-ruby/dltem[i1]$
当 RubyGems 安装 gem 时,它是否检测到 gem 规范中的 s.extensions << 'ext/davenport_ruby/extconf.rb' 并使用 ruby 执行该文件?它是否为生成的 make 文件运行 make?
什么能使ruby test.rb 运行而不会出现错误?
This gist
包含 libdavenport.so.0 和 davenport_ruby.so 中唯一全局符号的比较,以及 gem environment 和 ruby -e 'puts $:.join("\n")' 命令的输出。
ldd
This question 关于not found (LoadError) 问题建议使用ldd 来验证链接。 (有一个 related question 未得到答复,但在评论中有类似的建议。)
确实,扩展库虽然构建了,但并没有链接到已安装的libdavenport.so.0:
~/dvt$ bundle install
Fetching gem metadata from https://rubygems.org/.
Using bundler 2.0.2
Fetching davenport 1.0.2.pre
Installing davenport 1.0.2.pre with native extensions
Bundle complete! 1 Gemfile dependency, 2 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
~/dvt$ ldd ~/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/davenport-1.0.2.pre/lib/davenport_ruby/davenport_ruby.so
linux-vdso.so.1 (0x00007fff2d3e3000)
libdavenport.so.0 => not found
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f9a5be42000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9a5baa3000)
/lib64/ld-linux-x86-64.so.2 (0x00007f9a5c349000)
~/dvt$
ldconfig
This very old question over on AskUbuntu 建议使用ldconfig 命令。由于libdavenport.so.0 安装在/usr/local/lib 中,因此命令为ldconfig /usr/local/lib。但是,要运行它需要一个不同的登录名,该登录名可以获得 root 权限。切换回正在安装 Ruby 程序的 deploy 帐户:
~/dvt$ ruby test.rb
Hola
[1, 3, 2, 4]
~/dvt$
瞧。它现在正在工作。问题变成了如何让它与部署/安装以及没有root权限的用户一起使用。 (安装库 libdavenport 也需要 root 权限,尽管它是从源代码编译和安装的。)
【问题讨论】:
-
为什么 C 库
libdavenport.so.0会调用扩展库davenport_ruby.so(存在),而不是相反? C 库在扩展中没有引用任何内容,而是扩展引用了 C 库。这可能是链接的名称冲突问题吗?
标签: c rubygems linker-errors dynamic-linking ruby-c-extension