忘れないようにメモっとく

機械学習とかプログラミングとか。

lxmlが動かない。OS X 10.7でアップデート。

先日書いたScrapyは自分macbook airで動いたけれども、研究室のiMacでscrapyコマンドを使ったときにうまくいかなかったので、追加でインストールのメモ。

pythonのフレームワークでサクッとクローラをつくる。"Python Framework Scrapy" - ケンキュウハック

airもiMacOS X 10.7。発生したエラーは以下の通り。

$ scrapy startproject sample
......
ImportError: dlopen(/Library/Python/2.7/site-packages/lxml/etree.so, 2): Symbol not found: ___xmlStructuredErrorContext
  Referenced from: /Library/Python/2.7/site-packages/lxml/etree.so
  Expected in: flat namespace
 in /Library/Python/2.7/site-packages/lxml/etree.so

pythonライブラリのlxmlでおかしなことになっている様子。(こういうインストールのエラー嫌だなぁ)
困ったときのstackoverflowということで、次の記事を発見。
python - Need help installing lxml on os x 10.7 - Stack Overflow

scrapyに限らず、from lxml import etree とpythonで実行したときに発生するようで、lxmlのサイトでも取り上げられている。

Building lxml on MacOS-X

Apple regularly ships new system releases with horribly outdated system libraries. This is specifically the case for libxml2 and libxslt, where the system provided versions are too old to build lxml.
......

http://lxml.de/build.html#building-lxml-on-macos-x

Mac OSのシステムライブラリが時代遅れで、lxmlをビルドするときに問題が起こると言っている。
macportsとかで管理していても、OSがシステムライブラリを優先する。あとは、Appleが静的ライブラリを非推奨にしているので、ビルドやインストールではstaticなライブラリの使用を明示する必要があるとのこと。

試しに、次のコマンドを実行してみると

$ otool -L /Library/Python/2.7/site-packages/lxml/etree.so
etree.so:
	/usr/lib/libxslt.1.dylib (compatibility version 3.0.0, current version 3.24.0)
	/usr/lib/libexslt.0.dylib (compatibility version 9.0.0, current version 9.13.0)
	/usr/lib/libxml2.2.dylib (compatibility version 10.0.0, current version 10.3.0)
	/usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.5)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 159.1.0)

参照している共有ライブラリを更新すると、どこか別のところで影響があるかもしれないので、更新したい部分は静的ライブラリとしてビルド&インストールする。

以上のことをふまえ、gitでローカルにクローンしてから、次のコマンドを実行。

$ git clone git://github.com/lxml/lxml.git lxml
$ cd lxml
$ python setup.py build --static-deps --libxml2-version=2.7.8 --libxslt-version=1.1.27
$ sudo python setup.py install
$ sudo pip uninstall lxml
$ STATIC_DEPS=true sudo pip install lxml

再び、scrapy startproject sampleを実行して......これがまた同じエラーorz。
確認のためにpython起動。

Python 2.7.4 (v2.7.4:026ee0057e2d, Apr  6 2013, 11:43:10) 
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from lxml import etree
>>> etree.__file__
'/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/lxml-3.1.2-py2.7-macosx-10.6-intel.egg/lxml/etree.so'

うーんインポートも実行もできているけど、scrapyのコマンド打ったときとlxmlのパスが違う。。。

/Library/Python/2.7/site-packages/lxml/etree.so

のときは動かないけど、

/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/lxml-3.1.2-py2.7-macosx-10.6-intel.egg/lxml/etree.so

のときは動く。

ということで、動くlxmlを動かないlxmlに上書きコピー(邪道!!)。
このとき、otoolコマンドを実行すると、共有ライブラリへの参照が外れていることが分かる。

$ otool -L etree.so
etree.so:
	/usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.5)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 159.1.0)

このあと、scrapy startproject sampleを実行してうまく動いた。