■まず最初に、調べて分かった結論
- 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・・・が、動きません。なにやらImagingMathが見つからないだのなんだのとエラーが出てしまいます。これだけではよく分からないので、直接PILのモジュールをPythonからimportしてみることにしました。
python selftest.py
akisute PIL$ python2.5ふむふむ、どうやらこの_imaging.soというのがなにやら悪さをしているようです。@tokibito先生にお尋ねしたところ、このsoファイルというのはC言語のソースをコンパイルしたライブラリで、Pythonから動的にインポートできるようにpython.hというヘッダをインクルードしてつくられているらしいということが分かりました。なるほど、それでPythonから直接C言語で書かれてビルドされたライブラリをimportできるんですね。凄いなPython。
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
>>>
となると怪しいのは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/うん、なるほど、原因が分かりました。-arch i386と -arch ppcでしかビルドされていないのがまずそうですね。Snow Leopardは64bitですから、-arch x86_64を追加してビルドしなければならないはずです。
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
ためしにPython 2.6.1でこの_imaging.soを読み込もうとしてみた結果がこちら。
akisute PIL$ pythonビンゴ!間違いなさそうです!あとは、どうすれば64bitでビルド出来るかを調べるだけです。
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)
>>>
■distutilとの戦い
とは言ってみたものの、そもそも一体全体どういうカラクリでpython setup.py installコマンドがgccビルドを実行しているのかが分かりません。まずはsetup.pyのソースを読んでみることにしました。するとdistutils.command.build_extなるモジュールをimportして使っていることが判明。怪しい。Python2.5のシステムライブラリをあさってみると、ありましたありました。
さっそくコードを読んでみると・・・
475 objects = self.compiler.compile(sources,おおっといきなり発見、self.compiler.compileとか怪しさ抜群です。こいつはどこからやってきたのかとソースをたどると、なにやらunixccompiler.pyというモジュールを発見。いかにも私がコンパイラだと言わんばかり。犯人はこいつに違いない。さっそくコードを開いて-archとかで検索をかけてみましたが、i386とかppcとか直接指定している箇所は見あたりませんでした。その代わり別の収穫を発見。
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)
def _darwin_compiler_fixup(compiler_so, cc_args):環境変数ARCHFLAGSとかいうのを見てるみたいです。なるほど、じゃこいつに"-arch x86_64"とか追加すればきちんと64bitビルドしてくれるのでしょうか?
"""
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()
----
後略
----
■そしてあっけない幕切れ
ここまでなんとか一人で調査していたものの、たまりかねた隣の席の皆さんからアドバイス。
「Python 2.6じゃないのがまずいんじゃね?」
え、何、そういうこと?まぁ念のために試してみるか、ということでPythonを2.6に切り替えて再度PILをビルド。
あ、-arch x86_64がビルドオプションについてる。
あ、python selftest.py一発で通った。
あ、Google App Engine SDKがPILの警告吐かなくなった。
終了。
なにそれ。俺の苦労、何よ。
■あれ?
・・・おかしいな、今日作るはずだったGoogle App Engineのアプリ、まだ10行ぐらいしか書いてないよ><