5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[Ruby] mini_portile を使って依存ライブラリのコンパイルを簡略化する

Posted at

はじめに

mini_portile という拡張ライブラリ作者向けの gem がある。
拡張ライブラリが依存しているものを事前にコンパイルし、拡張ライブラリをコンパイルする際にそちらを参照するようにしてくれる gem だ。
nokogiri や sqlite3 でも使われているが、 mini_portile 自体の情報が日本語では見つけられなかったので紹介したい。

なお、筆者は本来想定されている使い方とは違う用途で利用してみたので、そちらについても軽く触れてみたいと思う。

mini_portile の使い方

使い方は README に詳しく載っているが、「そちらを見て欲しい」では紹介記事にならないので利用例を上げたいと思う。

基本的な使用方法

require "mini_portile"
recipe = MiniPortile.new("libiconv", "1.13.1")
recipe.files = ["http://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.13.1.tar.gz"]
recipe.cook
recipe.activate

READMEに載っているものをそのまま持ってきた形だが、 iconv をコンパイルして拡張ライブラリのビルド時に使用するようにするには上記のコードのみでよい。
MiniPortile#cook でファイルの取得から展開、 ./configure の実行、make までを自動で行ってくれる。
インストール先は <BASEDIR>/port/<platform>/<ライブラリ名>/<バージョン> となり、その後の MiniPortile#activate で環境変数にこのパスを追加するようになっている。
パッケージ管理システムの代替を目指している訳ではないためシステムワイドにインストールする機能は提供されていないが、拡張ライブラリをコンパイルする用途であれば問題ない。

パッチを当てる

mini_portile にはダウンロードしてきたソースにパッチを当てるための機能が存在する。

require "mini_portile"
recipe = MiniPortile.new("libiconv", "1.14")
recipe.files = ["http://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.14.tar.gz"]
recipe.patch_files = [File.expand_path("path/to/libiconv-1.14-ja-1.patch")]
recipe.cook
recipe.activate

libiconv-1.14 日本語パッチ にて公開されている日本語エンコーディングに関するパッチを当てる場合などは上記のようにすればよい。
ただし、 MiniPortile#patch_filesMiniPortile#files と違い自動でダウンロードしてくれないため事前にダウンロードしておく必要があることと、相対パスを指定した場合うまくいかなかったため File.expand_path で絶対パスにしてやる必要があった。
さらに内部的に git-apply を呼び出しているため、 git のインストールが必須となっている。

mini_portile デフォルトでは対応できない場合

基本的には ./configure が色々と吸収してくれるはずだが、 zlib のように Windows にインストールする場合は別の手順を行う必要があったりと、 mini_portile が想定している方法通りではうまく行かないケースが多々存在する。
ではどうするかというと、 利用例のRakefile を見る限り mini_portile を継承したクラスを作成し、その中にライブラリ固有の処理を書く必要があるようだ。

MiniPortile#cook は下記メソッドを呼ぶだけの処理のため、これらを適時オーバーライドしてやればよい。

  • MiniPortile#download
  • MiniPortile#extract
  • MiniPortile#patch
  • MiniPortile#configure
  • MiniPortile#compile
  • MiniPortile#install

サンプルは長くなりそうなので、上記の Rakefile を参照してほしい。

おまけ:mini_portileをあえて任意の場所にインストールする用途に使ってみる

話は変わるが、筆者は eucJP-ms が適切に処理出来なければならない環境にいるため、 iconv に上記日本語パッチを当てたものを度々コンパイルする。
shell script で書いてもいいのだが、今回あえて mini_portile を使ってやってみようと思った。
mini_portile は任意の場所にインストールすることを想定していないため、そのあたりに手を入れてやる必要がある。
また、前述の通りパッチファイルは自動でダウンロードしてくれないため、自動でダウンロードしてくれるように手を入れた。

require "mini_portile"

class PatchedPortile < MiniPortile
  attr_writer :port_path
  attr_accessor :patch_urls

  def initialize name, version
    super name, version
    @patch_urls = []
  end

  def download_patch
    @patch_urls.each do |url|
      filename = File.basename(url)
      download_file(url, File.join(patches_path, filename))
      @patch_files.push File.expand_path(File.join(patches_path, filename))
    end
  end

  def cook
    download_patch
    super
  end

  private

  def port_path
    @port_path.nil? ? super : @port_path
  end

  def patches_path
    "#{@target}/patches"
  end
end

class LibiconvRecipe < PatchedPortile
  def initialize version
    super "libiconv", version
    @files << "http://ftp.gnu.org/pub/gnu/#{@name}/#{@name}-#{@version}.tar.gz"
  end
end

recipe = LibiconvRecipe.new "1.14"
recipe.patch_urls << "http://apolloron.org/software/libiconv-1.14-ja/libiconv-1.14-ja-1.patch"
recipe.port_path = ENV['LIBICONV_INSTALL_DIR'] || "/usr/local/#{recipe.name}-#{recipe.version}"
recipe.configure_options = [
  "--host=#{recipe.host}",
  "--enable-shared"
]
recipe.cook
recipe.activate

これで LIBICONV_INSTALL_DIR=/path/to/libiconv ruby script.rb とすれば /path/to/libiconv にインストールされ、環境変数 LIBICONV_INSTALL_DIR を指定しなければ /usr/local/libiconv-1.14 にインストールされる。
アンインストールコマンドが提供されていないため簡単に入れ替えが出来るようなデフォルトインストール先としているが、環境変数をごにょごにょ弄りたくないという場合であれば LIBICONV_INSTALL_DIR=/usr/local としてもよいのかもしれない。

実際に使ってから思ったのだが、やはりこういう用途で使用するならば Ruby で書くよりも shell scriptで書いたほうがよいようである。
筆者環境では Windows でコンパイルすることもあるため Ruby でやったほうが便利ではないか?とも思ったが、この方法では Cygwin や MinGW/MSYS、さらに Git for Windows をインストールする必要があるため、それならば bash も入っているから shell script で充分ではないか?という話であった...。
自動でパッチをダウンロードするぐらいは mini_portile で対応してくれたら嬉しそうなので、気が向いたら修正して PR するかもしれない。

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?