18.11.2009Сборка руби-билиотеки в заданной среде
Постановка задачи
Как разработчику gphoto4ruby мне приходится сталкиваться с особыми задачами. Связано это с тем, что этот gem является оболочкой поверх ещё одной библиотеки. И как у всякой более-менее развитой сторонней библиотеки, у libgphoto2 есть версия, распространяемая через системные репозитории и порты и есть, так сказать, последний писк моды (bleeding edge).
Отсюда вытекает необходимость:
- Иметь разные версии библиотеки не конфликтующие между собой, установленные не одной системе,
- Компилировать свою руби-библиотеку под любую из версий.
Установка двух gphoto2 :)
Проделаю весь путь с самого начала. Для пущей целостности. Для начала установка из системного репозитория:
sudo apt-get install libgphoto2-2-dev gphoto2
gphoto2 --version
Теперь можно скачать нужную версию и установить её отдельно. Поскольку я в основном использую две версии, то версию из исходников нужно установить в /opt. Предположим, что исходники libgphoto2 и gphoto2 скачаны:
tar zxvf libgphoto2-x.x.x.tar.gz
cd libgphoto2-x.x.x.tar.gz
./configure --prefix=/opt
make
sudo make install
tar zxvf gphoto2-x.x.x.tar.gz
cd gphoto2-x.x.x.tar.gz
./configure --prefix=/opt --with-libgphoto2=/opt
make
sudo make install
/opt/bin/gphoto2 --version
Теперь мы имеем две библиотеки и две утилиты командной строки, поставленные раздельно и правильно залинкованные. Каждая утилита командной строки знает, где искать свою библиотеку. Надо, чтобы это же умел и gem
Компиляция джема
Если скачать исходник библиотеки, то можно проделать руками то, что делает команда gem install. Для создания Makefile используется утилита mkmf, которая входит в ruby-dev и с которой работает файл extconf.rb. В моём случае последовательность действий установщика такая:
cd ext
ruby extconf.rb
make
Теперь в папке ext мы имеем скомпилированную библиотеку (*.so или *.bundle в зависимости от системы). Установщик потом копирует её в папку lib, но мы пока остановимся. Мы можем посмотреть, какие другие библиотеки использует эта:
ldd gphoto4ruby.so
По выводу этой команды видно, что используется библиотека установленная из центрального репозитория. Теперь попробуем скомпилировать под версию «по последней моде». Поскольку я написал в extconf.rb
dir_config("gphoto2")
То это означает, что пользователю будет доступен целый ряд опций, позволяющих сказать компилятору, где искать libgphoto2. Попробуем:
ruby extconf.rb --with-gphoto2-dir=/opt
make
ldd gphoto4ruby.so
Но что это? Вывод показывает нам, что библиотека привязалась опять к тому, что установлено из репозиториев, а не тому, что в /opt. То есть компилятор, конечно, находит нужные ему заголовки (*.h), но ничего в них не говорит о том, где искать соответствующие им библиотеки. Об этом ему должны сказать мы:
ruby extconf.rb --with-gphoto2-dir=/opt --with-dldflags="-Wl,-rpath,/opt/lib"
make
ldd gphoto4ruby.so
Вуаля!
Теперь, собственно, главное. Как это сделать при установке джема. Чтобы передать ключи для extconf нужно задать их после дополнительного «--»:
sudo gem i gphoto4ruby -- --with-gphoto2-dir=/opt --with-dldflags="-Wl,-rpath,/opt/lib"
Вот такой экскурс в жизнь разработчиков библиотек. Как это звучало в школьные времена: «Спэтсыално дла джэма».
Материалы для самостоятельного изучения
Руководство по расширению руби с помощью C (см. главу про extconf.rb)