HOME  >  Ruby

Windows で Nokogiri のビルドエラー解決法 再び

久しぶりにアクセスログを見たら、
nokogiri のインストール方法で検索してくる方が結構いらっしゃるようなので、
最新の情報を書いておこうと思います。

# nokogiri に限った問題ではないので、条件によっては他の gem であっても解決するかも。

2015/4/27 追記
本稿は、Ruby 2.1.X までを使用している方が対象です。
Ruby 2.2.X 以降の場合は、本稿は役に立ちません。たぶん。

TL;DR 原因 & 解決法まとめ

原因: 古いバージョンの rubygems に不具合があり、環境に適した gem を取得できないため
[解決法1] 手動でインストールする gem をダウンロードする
または
[解決法2] rubygems をアップグレードする (おすすめ)

[解決法1] 手動でインストールする gem をダウンロードする

nokogiri | RubyGems.org | your community gem host
↑このページの VERSIONS から自分の環境にあったものをクリックしてから、
Download をクリックして gem をダウンロードしてください。
(Windows x64 なら x64-mingw32、Windows x86 なら x86-mingw32)
で、そのダウンロードした gem を以下のコマンドでインストールしてください。
gem install -l nokogiri-1.6.6.2-x64-mingw32.gem
1.6.6.2-x64-mingw32 の箇所はダウンロードした gem のファイル名に合わせて変更してください。

[解決法2] rubygems をアップグレードする (おすすめ)

gem -v
で、rubygems のバージョンを調べてください。
それが 2.3.0 未満の場合は、以下のコマンドで解決できると思います。
gem update --system
gem install nokogiri
ただし、Ruby 1.9系のようにしてください。
gem update --system 2.3.0
gem install nokogiri
gem install の挙動が変わるため、場合によっては、nokogiri インストール後に、
gem update --system 2.2.2
のようにして rubygems のバージョンを戻すことも考慮にいれてください。
2.2.2 の箇所は自分が使用していたバージョンを入力してください。
# ちなみに bundler を使用すると、こんなことしなくてもインストールできるみたいです。

何故 nokogiri をインストールできないのか

現在は、Windows 64bit 向けのバイナリ(すなわち、ビルド済みのもの)を含む gem が
正式に公開されています。
nokogiri | RubyGems.org | your community gem host
gem list --remote nokogiri
...
nokogiri (1.6.6.2 ruby java x64-mingw32 x86-mingw32, 1.6.1 x86-mswin32-60, 1.4.4.1 x86-mswin32)
...
x64-mingw32とか書いてあるのがソレです。
なので、gem install nokogiriとすると、
Nokogiri is built with the packaged libraries: libxml2-2.9.2, libxslt-1.1.28, zlib-1.2.8, libiconv-1.14.
とか表示されて、本来であれば問題無くインストールできるはずです。
(必須のライブラリを静的リンクしたビルド済みのバイナリが gem に含まれているのです)
ですが、rubygems (gem コマンドで呼びだすアレ)が古いと、
別プラットフォーム用の gem を取得してしまいビルドエラーになります。
Extracting libiconv-1.14.tar.gz into tmp/x86_64-w64-mingw32/ports/libiconv/1.14... OK
Running 'configure' for libiconv 1.14... ERROR, review
'C:/ruby/lib/.../nokogiri/tmp/x86_64-w64-mingw32/ports/libiconv/1.14/configure.log' to see what happened.
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers.  Check the mkmf.log file for more details.  You may
need configuration options.
で、 Windows 用の RubyInstaller に含まれている rubygems のバージョンが古い (たぶん 2.2.2) ので
多くの方が困っているみたいです。
gem -v
2.2.2
なので rubygems を最新版にしてから nokogiri をインストールしましょう。
gem update --system
gem install nokogiri
ただし、Ruby 1.9系の場合は rubygems 2.3.0 を使用してください。
gem update --system 2.3.0
gem install nokogiri
なぜ 2.3.0 なのかというと、最新の 2.4.X は、Ruby 1.9 系だと動かないみたいなので。
Native gem installation doesn't work on Windows with >= 2.4.0 · Issue #977 · rubygems/rubygems
# マイルストーンを見ると、2.5.0 でこの問題を解決する予定みたいです。

以上で問題は解決しますが、
場合によっては別の問題が発生する可能性が出てくるので、以下に 2 つほど記載します。
# それらが致命的な問題になることは滅多に無いとは思いますが、
# 頭の片隅にでもいれておくと、いざというとき役立つと思います。

# ちなみに RubyInstaller に、古いバージョンの rubygems が入っている理由ですが、
# 大元の Ruby(2.1.X) 本体に含まれている rubygems が古いためです。
# RubyInstaller 自体は Ruby 本体のものをそのまま使用しているだけなので。
# それに加えて、上であげた Ruby 1.9 系での不具合を RubyInstaller のメンテナさんが
# 気にしているというのもあるようです。
# 個人的にソースを見た限りでは、Ruby 2.0 以降の場合は
# 最新版の rubygems で問題ないと思っています。
# ですが、どのバージョンの rubygems を使うかは、各自それぞれ判断してください。

[問題1] gem install の挙動が変わる

ざっくりな説明ですが、以下のように rubygems の振舞いが変わります。
  • rubygems のバージョン < 2.3.0
    • platform = ruby の gem が優先される
  • rubygems のバージョン >= 2.3.0
    • platform = ユーザのプラットフォームの gem が優先される

例えば、nokogiri の例だと、
  • rubygems 2.2.2
    • nokogiri-1.6.6.2.gem (自前でビルドする必要がある gem) がインストールされる
  • rubygems 2.4.6
    • nokogiri-1.6.6.2-x64-mingw32.gem (ビルド済みで配布されている gem)がインストールされる
となります。

なので、最新の rubygems で不都合があれば、
以下のコマンドで使用していたバージョンに rubygems を戻してあげてください。
gem update --system 2.2.2
2.2.2 の箇所は自分が使用していたバージョンを入力してください。

[問題2] 依存ライブラリのバージョン

例えば、nokogiri の場合であれば、
自前でビルドする時は、依存ライブラリ(libxml2 とか)は、動的リンクされます。
一方、ビルド済みで配布されている gem の場合は、依存ライブラリは、静的リンクされています。

依存ライブラリのバージョンが重要とされるような場合は、
この辺りを気にしてあげる必要がありそうです。
スポンサーサイト



2015/03/01 | カテゴリ:Ruby | トラックバック(1) | コメント(0)

RMagick 2.13.4 が公開されてます

もう過去の記事は不要ですね。
ImageMagick 6.X 最新バージョンでもコマンド一発でインストール、ビルドが可能です
※ Ruby1.8 だとビルドできない不具合があるみたいです

gem install rmagick -- '--with-opt-lib="C:/Program Files/ImageMagick-6.8.9-7-Q16/lib" --with-opt-include="C:/Program Files/ImageMagick-6.8.9-7-Q16/include"'
6.8.9-7-Q16 とかパスの部分はご自分の環境、バージョンに合わせてください。
2014/12/06 | カテゴリ:Ruby | トラックバック(0) | コメント(0)

RMagick が入らない問題と対策3 ImageMagick 6.8.9 に対応

2014/12/6 追記
RMagick 2.13.4 にて下記の内容は取り込まれています。
2.13.4 をインストールできない場合は、下記の内容とは別の問題ということになります。
RMagick を ImageMagick 6.8.9 に対応させました。
# Windows x64 以外でもインストール可能だと思います。

インストール方法は変わっていないので、過去記事を参照ください。

Windows 7 に Ruby 2.0 x64 を その3 ~RMagick が入らない問題と対策2~|Ruby と iPhone と UI と

プルリクエスト投げたら取り込まれたので、近いうちに公式からでもインストールできるようになる……と思います。
# 少し前にプルリクエスト投げていたのに、記事にするのを忘れてた……。
2014/09/14 | カテゴリ:Ruby | トラックバック(0) | コメント(0)

Windows 7 に Ruby 2.0 x64 を その5 ~EventMachine の問題と対策~

2014/5/13 追記 公式に修正が取り込まれました。gem も公開されていました。
なのでこの記事はもはや *無意味* です。

Windows 7, Ruby2.0 で guard-livereload を使おうと思い、インストールしようとしたら
EventMachine が必要といわれ、入れようとしたらビルドエラー発生。

ということで、EventMachine を修正してみました。
GitHub 上にソースをおいたので、以下のコマンドでインストールできます。
# プルリクエストしたので、そのうち取り込まれる……といいな。
2014/5/13 追記 マージされました。
gem specific_install -l 'git://github.com/u338steven/eventmachine.git'
specific_install をインストールしていない方は、以下のコマンドで用意してください。
gem install specific_install
# ビルドエラーを修正しただけだと、guard-livereload が変な挙動をしたので、
# 他にも、ちょこっと直しています。

修正した内容

以下 4 つのエラーに対処。
  1. undefined method `each' for "i386-mingw32":String
  2. error: conflicting declaration 'typedef _pid_t pid_t'
  3. rubyeventmachine.so (LoadError)
  4. guard-livereload の妙な動き(EventMachine が原因)
以下、修正内容をざっくりと記載します。
修正したソースの詳細を見たい方は、 GitHub 上のソース差分 をどうぞ。

1. undefined method `each' for "i386-mingw32":String

ある変数に配列が入ったり、配列以外が入ったりしていたのが原因でした。
なので、事前に配列かどうかチェックします。
    if ext.cross_platform.is_a?(Array) then
      ext.cross_platform.each do |platform|
        (略)
    end

2. error: conflicting declaration 'typedef _pid_t pid_t'

これは、ccoenen さんのパッチをそのまま流用してます。
pid_t が重複して定義されちゃってるので、#ifndef を使って定義済かチェックしてます。
c:\ruby\devkit\mingw\bin\../lib/gcc/x86_64-w64-mingw32/4.7.2/../../../../x86_64-w64-mingw32/include/sys/types.h:68:16: error: conflicting declaration 'typedef _pid_t pid_t'
In file included from ../../../../ext/binder.cpp:20:0:
../../../../ext/project.h:97:13: error: 'pid_t' has a previous declaration as 'typedef int pid_t'
In file included from ../../../../ext/project.h:151:0,
                 from ../../../../ext/binder.cpp:20:
#ifndef _PID_T_
#define	_PID_T_
typedef int pid_t;
#endif
ここまでで、ビルドエラーの修正は終了です。

3. rubyeventmachine.so (LoadError)

次は、実行時のエラー。
やっとビルドできたと思ったらrequire 'eventmachine'するだけでエラーが発生します。
Unable to load the EventMachine C extension; To use the pure-ruby reactor, require 'em/pure_ruby'
C:/ruby/lib/ruby/site_ruby/2.0.0/rubygems/core_ext/kernel_require.rb:55:in `require': 126: 指定されたモジュールが見つかりません。   - C:/ruby/lib/ruby/gems/2.0.0/extensions/x64-mingw32/2.0.0/eventmachine-1.0.3/rubyeventmachine.so (LoadError)
        from C:/ruby/lib/ruby/site_ruby/2.0.0/rubygems/core_ext/kernel_require.rb:55:in `require'
        from C:/ruby/lib/ruby/gems/2.0.0/gems/eventmachine-1.0.3/lib/eventmachine.rb:8:in `'
        from C:/ruby/lib/ruby/site_ruby/2.0.0/rubygems/core_ext/kernel_require.rb:135:in `require'
        from C:/ruby/lib/ruby/site_ruby/2.0.0/rubygems/core_ext/kernel_require.rb:135:in `rescue in require'
        from C:/ruby/lib/ruby/site_ruby/2.0.0/rubygems/core_ext/kernel_require.rb:144:in `require'
        from require.rb:1:in `
'
rubyeventmachine.so は存在してるのですが、依存関係にある libgcc_s_sjlj-1.dll と libstdc++.dll が
実行時に見つからなくてエラーになっています。

というわけで libgcc_s_sjlj-1.dll と libstdc++.dll を読まないようにするため、
ビルド時のオプションに、-static-libgcc, -static-libstdc++を追加します。
    CONFIG['LDSHAREDXX'] = "$(CXX) -shared -static-libgcc -static-libstdc++"
ここまでで、EventMachine が一応使えるようになります。

4. guard-livereload の妙な動き(EventMachine が原因)

やっと EventMachine が動いて guard-livereload を使えると思ったら、 guard-livereload 起動後、最初の数回だけまともに動いて、以降リロードされないという謎現象が発生。

ソースみまくったところ、EventMachine のソケットの後処理に問題がありました。
Windows のソケットは close じゃなく、closesocketで閉じます。
#define close closesocket
これには、なかなか気づかなくて、ものすごくハマりました。
最初の数回だけは動いていたので、GC が悪さしてるのか?とか迷走したり。
# 実際GC.disableすると、何故か普通に動いちゃったし。
# なんで普通に動いちゃったのか、いまだにわからない……。

ここまできて、やっとまともに guard-livereload が動きました……。
2014/02/22 | カテゴリ:Ruby | トラックバック(1) | コメント(0)

実行中の Ruby コマンドのパスを取得する方法

とてもレアなケースだと思われますが、
個人的に必要になったのでメモとして残しておきます。
puts RbConfig.ruby    #=>"C:/ruby/bin/ruby.exe"
Ruby スクリプト内から、別プロセスで既存の Ruby スクリプトを実行したかったので、
こんなことしてます。(IO.popen との組み合わせで)
他のやり方もあるのかなぁ。

# どうせパスが通ってるんだろうから、
# 単純に "ruby" で呼び出してもいいんじゃないかというツッコミもあると思います。
# ですが、僕の環境だと、Ruby2.0 系、Ruby1.9 系、JRuby が共存してるので、
# 例えば、JRuby でも動くよね?っていう確認をしたくて、JRuby で実行したのに、
# 別プロセスとして呼び出されたのが Ruby2.0 系……とか、
# そんな悲劇が起こってしまうのです……。
2014/02/04 | カテゴリ:Ruby | トラックバック(0) | コメント(0)
外部リンク

カンパのお願い
公開しているソフトウェアはフリーウェアなので無料でご利用いただけます。 気に入ってくださった方は、Amazon でお買い物をする際に下記のリンクを経由して頂ければ励みになります。

検索BOX・タグ一覧