Расширение Ruby davenport-ruby для библиотеки C davenport не будет правильно загружаться в Ubuntu и Debian. Он нормально работает на машине разработки (MacOS), как показано в файле README проекта Smoke test Ruby, 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 взята из этого PR, который ссылка показывает все биты кода (и довольно много экспериментов). Это какая-то деталь или часть жемчужины расширения не совсем правильная?
davenport_ruby.so
Файл .so
— это файл общей библиотеки, скомпилированный при установке драгоценного камня. Его нет в содержимом драгоценного камня:
~/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 устанавливает гем, обнаруживает ли он s.extensions << 'ext/davenport_ruby/extconf.rb'
в спецификации гем и выполняет ли этот файл с ruby
? Запускается ли он make
для результирующего make-файла?
Что позволит ruby test.rb
работать без ошибки?
Этот список содержит сравнение уникальных глобальных символов в libdavenport.so.0 и davenport_ruby.so и вывод команд gem environment
и ruby -e 'puts $:.join("\n")'
.
лдд
В этом вопросе о проблеме not found (LoadError)
предлагается использовать ldd
для проверки связи. (Есть связанный вопрос, на который нет ответа, но с аналогичным предложением в комментарии.)
Действительно, библиотека расширений хоть и построена, но не ссылается на установленный 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
Этот очень старый вопрос на AskUbuntu предлагает использовать команду ldconfig
. Так как libdavenport.so.0
установлен в /usr/local/lib
, команда была ldconfig /usr/local/lib
. Однако для его запуска требуется другой логин, который может получить привилегии root. Вернемся к учетной записи deploy
, которая выполняет установку программы Ruby:
~/dvt$ ruby test.rb
Hola
[1, 3, 2, 4]
~/dvt$
Вуаля. Сейчас это работает. Возникает вопрос, как заставить это работать с развертыванием/установкой и с пользователем, у которого нет привилегий root. (Для установки библиотеки libdavenport
также требовались привилегии суперпользователя, хотя она была скомпилирована и установлена из исходного кода.)
libdavenport.so.0
вызывает библиотеку расширенийdavenport_ruby.so
(которая присутствует), а не наоборот? Библиотека C ничего не ссылается в расширении, скорее расширение ссылается на библиотеку C. Может ли это быть проблемой конфликта имен со ссылкой? - person Douglas Lovell   schedule 26.07.2019