Snow Leopardに
PIL(Python Imaging Library)をインストールしようとして見事にハマりましたので、後学のために事の顛末を記しておきます。
■まず最初に、調べて分かった結論- Snow LeopardでPythonを使うときは、デフォルトで付属しているPython 2.6.1を使用すること。
- Snow LeopardにはPython 2.5.4も付属しているが、こちらは使用するべきではない。
- Snow LeopardのPython 2.5.4のdistutilには不具合?があり、UnixCCompilerクラスがC言語のモジュールを64bitでビルドしてくれないため、Snow Leopardでは動作しなくなる
- したがって、C言語のモジュールを使用しているPILはSnow LeopardのPython 2.5.4を使うとビルド出来ない
- どうしても2.5.4を使いたいときには、環境変数にARCHFLAGS "-arch x86_64"を追加してからPILをビルドするとうまくいくかもしれない(未確認)
- MacPortやMacPythonからのインストールは実験していないため未確認
※ あくまで2009年9月8日現在での断片的な情報です。皆様がごらんになっている時点では既にMacPort上のPythonやMacPythonも対応を完了しているかもしれませんので、参考程度にご覧ください。でもSnow Leopard上のPython 2.5.4はほんとお勧めしません。
■ことのはじまりLeopardのころはきちんと動いていたGoogle App Engine SDKが、Snow Leopardにアップグレードしたとたん突然PILモジュールがないと警告を出すようになってしまいました。確認してみると/Library/Python/Python2.5/site-packages/以下に確かにインストールされているのですが、何度試しても警告が消えません。Pythonのバージョンも以前から使っているPython 2.5のままです。これは何かがおかしい、再インストールした方がいいだろうと判断し、
http://www.pythonware.com/products/pil/から1.1.6のソースコードを落としてきていざビルド。
sudo python setup.py install
python selftest.py
・・・が、動きません。なにやらImagingMathが見つからないだのなんだのとエラーが出てしまいます。これだけではよく分からないので、直接PILのモジュールをPythonからimportしてみることにしました。
akisute PIL$ python2.5
Python 2.5.4 (r254:67916, Jul 7 2009, 23:51:24)
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import Imaging
>>> # 問題なくインポートできました
>>> import _imaging
Traceback (most recent call last):
File "", line 1, in
ImportError: dlopen(./_imaging.so, 2): Symbol not found: _jpeg_resync_to_restart
Referenced from: /Library/Python/2.5/site-packages/PIL/_imaging.so
Expected in: flat namespace
in /Library/Python/2.5/site-packages/PIL/_imaging.so
>>>
ふむふむ、どうやらこの_imaging.soというのがなにやら悪さをしているようです。
@tokibito先生にお尋ねしたところ、このsoファイルというのはC言語のソースをコンパイルしたライブラリで、Pythonから動的にインポートできるようにpython.hというヘッダをインクルードしてつくられているらしいということが分かりました。なるほど、それでPythonから直接C言語で書かれてビルドされたライブラリをimportできるんですね。凄いなPython。
となると怪しいのはPILのビルド工程。先ほどのエラーを見ると_jpeg_resync_to_restartというシンボルが見つからないと表示されていたため、インストールに使った
libjpeg(MacPortよりインストール)に何か問題があったのではないかと推測したのですが、特に問題は見つからず。
次にPILのビルドログを調査。細かいwarningが出まくるのはいつものことなので無視して調べてみますが、一見何もエラーは出ていません。するとあることに気づきました。
gcc-4.2 -Wl,-F. -bundle -undefined dynamic_lookup -arch i386 -arch ppc build/temp.macosx-10.6-i386-2.5/_imaging.o build/
temp.macosx-10.6-i386-2.5/decode.o build/temp.macosx-10.6-i386-2.5/encode.o build/temp.macosx-10.6-i386-2.5/map.o build/
----
中略
----
-L/o
pt/local/lib -L/System/Library/Frameworks/Python.framework/Versions/2.5/lib -L/usr/lib -ljpeg -lz -o build/lib.macosx-10
.6-i386-2.5/_imaging.so
うん、なるほど、原因が分かりました。-arch i386と -arch ppcでしかビルドされていないのがまずそうですね。Snow Leopardは64bitですから、-arch x86_64を追加してビルドしなければならないはずです。
ためしにPython 2.6.1でこの_imaging.soを読み込もうとしてみた結果がこちら。
akisute PIL$ python
Python 2.6.1 (r261:67515, Jul 7 2009, 23:51:51)
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import _imaging
Traceback (most recent call last):
File "", line 1, in
ImportError: ./_imaging.so: no appropriate 64-bit architecture (see "man python" for running in 32-bit mode)
>>>
ビンゴ!間違いなさそうです!あとは、どうすれば64bitでビルド出来るかを調べるだけです。
■distutilとの戦いとは言ってみたものの、そもそも一体全体どういうカラクリでpython setup.py installコマンドがgccビルドを実行しているのかが分かりません。まずはsetup.pyのソースを読んでみることにしました。するとdistutils.command.build_extなるモジュールをimportして使っていることが判明。怪しい。Python2.5のシステムライブラリをあさってみると、ありましたありました。
さっそくコードを読んでみると・・・
475 objects = self.compiler.compile(sources,
476 output_dir=self.build_temp,
477 macros=macros,
478 include_dirs=ext.include_dirs,
479 debug=self.debug,
480 extra_postargs=extra_args,
481 depends=ext.depends)
おおっといきなり発見、self.compiler.compileとか怪しさ抜群です。こいつはどこからやってきたのかとソースをたどると、なにやらunixccompiler.pyというモジュールを発見。いかにも私がコンパイラだと言わんばかり。犯人はこいつに違いない。さっそくコードを開いて-archとかで検索をかけてみましたが、i386とかppcとか直接指定している箇所は見あたりませんでした。その代わり別の収穫を発見。
def _darwin_compiler_fixup(compiler_so, cc_args):
"""
This function will strip '-isysroot PATH' and '-arch ARCH' from the
compile flags if the user has specified one them in extra_compile_flags.
This is needed because '-arch ARCH' adds another architecture to the
build, without a way to remove an architecture. Furthermore GCC will
barf if multiple '-isysroot' arguments are present.
"""
----
中略
----
if stripArch or 'ARCHFLAGS' in os.environ:
while 1:
try:
index = compiler_so.index('-arch')
# Strip this argument and the next one:
del compiler_so[index:index+2]
except ValueError:
break
if 'ARCHFLAGS' in os.environ and not stripArch:
# User specified different -arch flags in the environ,
# see also distutils.sysconfig
compiler_so = compiler_so + os.environ['ARCHFLAGS'].split()
----
後略
----
環境変数ARCHFLAGSとかいうのを見てるみたいです。なるほど、じゃこいつに"-arch x86_64"とか追加すればきちんと64bitビルドしてくれるのでしょうか?
■そしてあっけない幕切れここまでなんとか一人で調査していたものの、たまりかねた隣の席の皆さんからアドバイス。
「Python 2.6じゃないのがまずいんじゃね?」
え、何、そういうこと?まぁ念のために試してみるか、ということでPythonを2.6に切り替えて再度PILをビルド。
あ、-arch x86_64がビルドオプションについてる。
あ、python selftest.py一発で通った。
あ、Google App Engine SDKがPILの警告吐かなくなった。
終了。
なにそれ。俺の苦労、何よ。
■あれ?・・・おかしいな、今日作るはずだったGoogle App Engineのアプリ、まだ10行ぐらいしか書いてないよ><