nokogiriが(また)インストールできない
2.4.0-prevew3が出たし、そろそろ2.4の準備だねってことでgem install rails
したらコケた。
$ gem install rails
Building native extensions. This could take a while...
ERROR: Error installing rails:
ERROR: Failed to build gem native extension.
[...]
Building nokogiri using packaged libraries.
[...]
************************************************************************
Extracting libxml2-2.9.4.tar.gz into tmp/x86_64-apple-darwin16.1.0/ports/libxml2/2.9.4... OK
Running 'configure' for libxml2 2.9.4... OK
Running 'compile' for libxml2 2.9.4... ERROR, review '/Users/akira/.rbenv/versions/2.4.0-preview3/lib/ruby/gems/2.4.0/gems/nokogiri-1.6.8.1/ext/nokogiri/tmp/x86_64-apple-darwin16.1.0/ports/libxml2/2.9.4/compile.log' to see what happened. Last lines are:
========================================================================
unsigned short* in = (unsigned short*) inb;
^~~~~~~~~~~~~~~~~~~~~
encoding.c:815:27: warning: cast from 'unsigned char *' to 'unsigned short *' increases required alignment from 1 to 2 [-Wcast-align]
unsigned short* out = (unsigned short*) outb;
^~~~~~~~~~~~~~~~~~~~~~
4 warnings generated.
CC error.lo
CC parserInternals.lo
CC parser.lo
CC tree.lo
CC hash.lo
CC list.lo
CC xmlIO.lo
xmlIO.c:1450:52: error: use of undeclared identifier 'LZMA_OK'
ret = (__libxml2_xzclose((xzFile) context) == LZMA_OK ) ? 0 : -1;
^
1 error generated.
make[2]: *** [xmlIO.lo] Error 1
make[1]: *** [all-recursive] Error 1
make: *** [all] Error 2
これはnokogiri.gemに含まれているlibxml2をbuildしようとしている中でエラーが起きている。
nokogiriのドキュメントのMac OS X: Error Message About Undeclared Identifier LZMA_OK
によれば
When using Homebrew, there are several libraries that use a formula called xz (including thesilversearcher and imagemagick), which by default installs a version of liblzma that is incompatible with most Ruby builds. (Homebrew installs only the 64-bit version of the library, but most Ruby builds are universal.)
とのことで、回避策はa)一時的にbrew unlink xz
する、b)brew reinstall xz --universal
する、c)nokogiri.gem同梱libxml2を使わない、のどれか。
a)は後になって忘れてしまいそうなのでb)を試してみるも、やはりコケるしエラーにも変化がない(まあ、なんか違うんじゃ?とは思ったんだけど)。
ではc)を、ということでやってみると、これもダメ。
$ gem install nokogiri -- --use-system-libraries
Building native extensions with: '--use-system-libraries'
This could take a while...
ERROR: Error installing nokogiri:
ERROR: Failed to build gem native extension.
[...]
Building nokogiri using system libraries.
Using pkg-config gem version 1.1.7
checking for libxml-2.0... no
checking for libxslt... no
checking for libexslt... no
ERROR: cannot discover where libxml2 is located on your system. please make sure `pkg-config` is installed.
*** extconf.rb failed ***
libxml2(やlibxslt)を検出できなかったらしい。
libxml2はhomebrewでインストールしていたはずだが、と確認していくと/usr/local/lib
にリンクがないことが分かった。
/usr/local
にリンクを作らない、こういうタイプのformulaがありkeg-onlyと呼ぶらしい。明示的にリンクを作ろうとするとこうなる:
$ brew link libxml2
Warning: libxml2 is keg-only and must be linked with --force
Note that doing so can interfere with building software.
メッセージにある通り、brew link --force
によってリンクを強制することができる。だが、keg-onlyになっているのにも理由があるはずなので避けられるものなら避けておきたい。となると、libxml2のパスを個別に指定すればよいだろうということでやってみる:
$ gem install nokogiri -- --use-system-libraries --with-xml2-dir=$(brew --prefix libxml2)
Building native extensions with: '--use-system-libraries --with-xml2-dir=/usr/local/opt/libxml2'
This could take a while...
ERROR: Error installing nokogiri:
ERROR: Failed to build gem native extension.
[...]
Building nokogiri using system libraries.
Using pkg-config gem version 1.1.7
checking for libxslt... no
checking for libexslt... no
ERROR: cannot discover where libxml2 is located on your system. please make sure `pkg-config` is installed.
*** extconf.rb failed ***
だがこれまたコケた。
ただ、checking for libxml-2.0... no
という出力が消えていることから検出できなかったわけではないようだ。ならばextconf.rb
でのチェックにハネられたということ。mkmf.log
を確認すると、最後はこうなっていた:
"clang -E -I/Users/akira/.rbenv/versions/2.4.0-preview3/include/ruby-2.4.0/x86_64-darwin16 -I/Users/akira/.rbenv/versions/2.4.0-preview3/include/ruby-2.4.0/ruby/backward -I/Users/akira/.rbenv/versions/2.4.0-preview3/include/ruby-2.4.0 -I. -I/usr/local/opt/libxml2/include -I/Users/akira/.rbenv/versions/2.4.0-preview3/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -D_DARWIN_UNLIMITED_SELECT -D_REENTRANT -O3 -Wno-error=shorten-64-to-32 -pipe conftest.c -o conftest.i"
conftest.c:3:10: fatal error: 'libxml/xmlversion.h' file not found
#include <libxml/xmlversion.h>
^
1 error generated.
checked program was:
/* begin */
1: #include "ruby.h"
2:
3: #include <libxml/xmlversion.h>
/* end */
`--with-xml2-dir`で指定したパスが`-I/usr/local/opt/libxml2/include`という形で反映されているのが分かる。しかしその場所に`libxml/xmlversion.h`はない。
$ ls /usr/local/opt/libxml2/include
libxml2
$ ls /usr/local/opt/libxml2/include/libxml2
libxml
$ ls /usr/local/opt/libxml2/include/libxml2/libxml/xmlversion.h
/usr/local/opt/libxml2/include/libxml2/libxml/xmlversion.h
これがhomebrewによるインストールであるためか、そうではないのか分からないが、include/libxml2
まで指定してやる必要があるようだ。
こうなってくると--with-xml2-dir
などではダメで、--with-xml2-include
などでいちいちパスを指定しなければならない。しかしそこまでいくとCFLAGS
やLDFLAGS
を直接指定するようなもので、さすがにめんどうになる。
ここでextconf.rb
からのメッセージを再確認するとpkg-config
をなんとかせよと書かれている。extconf.rb
のその部分を見てみると、こうなっていた:
case
when using_system_libraries?
message "Building nokogiri using system libraries.\n"
[...]
dir_config('xml2').any? or package_config('libxml-2.0')
dir_config('xslt').any? or package_config('libxslt')
dir_config('exslt').any? or package_config('libexslt')
pkg-config
で情報が得られない? と少し疑問に思ったが、今しがた確認した通り libxml2はkeg-onlyである。.pc
ファイルも/usr/local
にはない。
$ pkg-config --cflags libxml-2.0
Package libxml-2.0 was not found in the pkg-config search path.
Perhaps you should add the directory containing `libxml-2.0.pc'
to the PKG_CONFIG_PATH environment variable
No package 'libxml-2.0' found
.pc
ファイルのパスを指定するとよいようだ。
$ PKG_CONFIG_PATH=$(brew --prefix libxml2)/lib/pkgconfig pkg-config --cflags libxml-2.0
-I/usr/local/Cellar/libxml2/2.9.4/include/libxml2
ならばgem install
するときにもPKG_CONFIG_PATH
を指定しておけばよいのではないか。
$ PKG_CONFIG_PATH=$(brew --prefix libxml2)/lib/pkgconfig:$(brew --prefix libxslt)/lib/pkgconfig:$(pkg-config --variable pc_path pkg-config) gem install nokogiri -- --use-system-libraries
Building native extensions with: '--use-system-libraries'
This could take a while...
Successfully installed nokogiri-1.6.8.1
Parsing documentation for nokogiri-1.6.8.1
Installing ri documentation for nokogiri-1.6.8.1
Done installing documentation for nokogiri after 3 seconds
1 gem installed
ようやくうまくいった! これでrails.gemをインストールできる。
なお、--with-xml2-config
や--with-xslt-config
を個別に指定することでの回避も可能かと思ったのだが、実際に試してみると(homebrew環境では?)うまくいかなかった。
これはxml2-configが無効なオプションを指定されても終了コードが0になるためのようだ。
上で引用した中に出てくるpackage_config
は内部でmkmf.rb
のpkg_config
を呼び出している。pkg_config
はpkg-config
と○○-config
の両方に対応していて、その判別はこうなっている。
def pkg_config(pkg, option=nil) # pkgには'libxml-2.0'や'libxslt'が渡されてくる
if pkgconfig = with_config("#{pkg}-config") and find_executable0(pkgconfig)
# iff package specific config command is given
elsif ...
...
else
pkgconfig = nil
end
if pkgconfig
get ||= proc {|opt|
opt = xpopen("#{pkgconfig} --#{opt}", err:[:child, :out], &:read)
Logging.open {puts opt.each_line.map{|s|"=> #{s.inspect}"}}
opt.strip if $?.success?
}
end
orig_ldflags = $LDFLAGS
if get and option
get[option]
elsif get and try_ldflags(ldflags = get['libs'])
if incflags = get['cflags-only-I']
$INCFLAGS
/* end */
なやましい。いや、PKG_CONFIG_PATH
で回避はできたんだけど。