【问题标题】:Ruby extension wrapper around C library fails to load installed library围绕 C 库的 Ruby 扩展包装器无法加载已安装的库
【发布时间】: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 &lt;&lt; '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


【解决方案1】:

以 root 身份运行 ldconfig /usr/local/lib 原来是答案。它使加载程序能够在运行时找到已安装的libdavenport.so.0 库。

对于后续问题,答案是make install 可能无法消除在某些系统上运行ldconfig 的需要。有一个针对另一个库的旧问题,该问题仍然开放,位于 esnet/iperf。他们没有弄清楚。如果他们这样做了,他们没有更新问题。一个较新的问题 libcheck/check 也有类似的挣扎。

libtool 的当前 Gnu 文档已在其 implementation issues,

安装 Makefile 目标应该警告包安装程序设置 适当的环境变量(LD_LIBRARY_PATH 或等效变量),或 运行 ldconfig。

本例中的“解决方案”是 Davenport 库的文档解决方案, 对自述文件的更新 this PR.

关于库链接和加载有一个很好的简短解释 Cprogramming.com(得到广告支持,但不那么痛苦;这篇文章值得参考)。

【讨论】:

    【解决方案2】:
    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
    

    这个错误意味着原生扩展davenport_ruby.so无法加载Davenport的共享库libdavenport.so.0。您需要使用 ldconfig 或通过将其路径添加到 LD_LIBRARY_PATH 来确保共享库位于您的加载路径中。


    旧的错误答案:

    Ruby C 扩展必须针对您运行它们的平台进行编译。如果你只是下载一些使用扩展的 Ruby 代码,它不会开箱即用。

    您是否使用gem 或bundle 构建了扩展程序?您是否在尝试运行脚本的 Ubuntu 机器上运行它?

    gem 不应该包含.so。当您安装 gem 时,它应该构建 .so 并将其放在 Ruby 的加载路径中的某个位置,以便脚本可以需要它。

    假设您实际安装了 gem 并且成功构建了 .so,我可以想到两个可能的问题

    1. 您使用错误的工具或选项安装了 gem,所以它把 .so 放在了错误的位置
    2. 您以错误的方式运行 Ruby(您使用的是 rbenv 还是 rvm?)所以它在错误的地方寻找 .so

    运行gem environment 和ruby -e 'p $:' 将您的gem 安装目录与Ruby 的加载路径进行比较。

    【讨论】:

    • 感谢您的浏览。该问题现在列出了 gem 内容以及有关 davenport_ruby.so 和扩展构建的问题。 gem 文件是使用gem build davenport.gemspec 构建的。它是使用 bundler 和 Gemfile 安装的。
    • 非常感谢您提供这些关于验证 gem 安装和本机编译的提示。 ruby -e 'p $:' 命令是 TIL。问题底部链接的要点现在包含两者的输出。它看起来像扩展 gem 安装、编译,并且是由冒烟测试程序加载的。如果 gem 安装和加载看起来不错,则问题可能出在 C 代码本身或链接中。
    • 表示赞赏,因为答案包含用于验证构建和设置的非常好的策略。这样做的可能性很大。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-06
    相关资源
    最近更新 更多