I've been having a bit of a headache trying to install PythonMagick (the Python bindings for ImageMagick) on Mac OS X Snow Leopard, so having eventually had a modicum of success I thought I'd post my adventures here.
But first, let me outline the problems I was having. Initially I tried building ImageMagick from source. That meant first downloading and installing Boost, which again I tried doing from source (1.46.1). When it became time to install the Boost::Python module, I tried following the instructions in the documentation:
$ cd libs/python/example/quickstart/ $ bjam toolset=darwin --verbose-test test
However, I'd find it would get so far and then just hang - I left it for about 24 hours with no progress. If I hit Ctrl-C and then tried again, it just sits there saying this:
...patience... ...patience... ...found 1603 targets... ...updating 8 targets...
Since I couldn't get very far that route, I decided to try the MacPorts approach, which makes installing these kinds of things very straightforward.
Again, first I had to try and install Boost, with the Python module enabled:
$ sudo port install boost +python26
So far, so good! That installed the package "boost @1.46.1_0+python26". Next was to install ImageMagick:
$ sudo port install ImageMagick
Again, nice and smooth! That installed "ImageMagick @6.6.8-1_0+q16". Now came the hard part: building PythonMagick. I used v0.9.3 since that seemed the latest version compatible with Python 2.x. The first step is to configure it. Reading around it became clear that I needed to specify the MacPorts include and library directories, like so:
$ ./configure --prefix=/opt/local CPPFLAGS=-I/opt/local/include LDFLAGS=-L/opt/local/lib
But no matter what I tried, I kept getting the message "checking whether the Boost::Python library is available... no". Eventually I figured out that you can get more information by reading the config.log file. I was getting all sorts of error messages like this:
configure:14953: checking whether the Boost::Python library is available
configure:14983: g++ -c -g -O2 -I/opt/local/include conftest.cpp >&5
In file included from /opt/local/include/boost/python/detail/prefix.hpp:13,
from /opt/local/include/boost/python/module.hpp:8,
from conftest.cpp:23:
/opt/local/include/boost/python/detail/wrap_python.hpp:50:23: error: pyconfig.h: No such file or directory
/opt/local/include/boost/python/detail/wrap_python.hpp:75:24: error: patchlevel.h: No such file or directory
/opt/local/include/boost/python/detail/wrap_python.hpp:78:2: error: #error Python 2.2 or higher is required for this version of Boost.Python.
/opt/local/include/boost/python/detail/wrap_python.hpp:142:21: error: Python.h: No such file or directory
These pyconfig.h and Python.h files and so on are usually installed with the Python development package, but supposedly MacPorts just installs everything all together under /opt/local/include/python2.6, so I wondered what was going on. But somebody put me on to a good way to find out where MacPorts has put stuff:
$ port contents python26 | grep pyconfig.h
That revealed that the include files were being installed in /opt/local/Library/Frameworks/Python.framework/Versions/2.6/include/python2.6. So let's try the configure again with that new information:
$ ./configure --prefix=/opt/local CPPFLAGS="-I/opt/local/include -I/opt/local/Library/Frameworks/Python.framework/Versions/2.6/include/python2.6" LDFLAGS=-L/opt/local/lib
Success! All seems to have worked this time - it picked up Boost::Python and no more errors showed up (I have secretly skipped a step where I installed the MacPorts python_select package to make sure that it was definitely using Python 2.6, but hopefully you can figure that one out on your own).
But alas, not so easy. Next I had to actually compile the thing. And of course, it failed:
$ make _Image.cpp: In function 'void Export_pyste_src_Image()': _Image.cpp:89: error: address of overloaded function with no contextual type information _Image.cpp:90: error: address of overloaded function with no contextual type information _Image.cpp:97: error: address of overloaded function with no contextual type information _Image.cpp:114: error: address of overloaded function with no contextual type information ... and many more such errors ...
It would seem that the ImageMagick API has changed a little, but thankfully the PythonMagick guys have patched that in the latest version. So I had to download PythonMagick 0.9.5 and copy the following files from it into the 'pythonmagick_src' directory of 0.9.3:
With that done, it then compiled quite nicely. So I run 'sudo make install', but then when I actually try and load it into Python, I get this error:
>>> import PythonMagick Traceback (most recent call last): File "", line 1, in File "PythonMagick/__init__.py", line 1, in import _PythonMagick ImportError: No module named _PythonMagick
Hmm... So close! Yet so far away. Okay, well maybe I should just try adding the path where the module is installed to my Python path:
>>> import sys
>>> sys.path.append('/opt/local/lib/python2.6/site-packages')
>>> import PythonMagick
Fatal Python error: Interpreter not initialized (version mismatch?)
Abort trap
D'oh! Well, a quick look at the crash log revealed that it was now trying to use the version of the Boost libraries that I'd manually installed from source from '/usr/local/lib' (rather than the MacPorts version in /opt/local/lib) so I deleted the unwanted versions and tried again. Then I got this error:
>>> import PythonMagick Traceback (most recent call last): File "", line 1, in File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/PythonMagick/__init__.py", line 1, in import _PythonMagick ImportError: dlopen(/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/PythonMagick/_PythonMagick.so, 2): Library not loaded: libboost_python.dylib Referenced from: /opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/PythonMagick/_PythonMagick.so Reason: image not found
Well that one's obvious: I needed to add the MacPorts directory to my library path:
$ export LD_LIBRARY_PATH=/opt/local/lib $ export DYLD_LIBRARY_PATH=/opt/local/lib
That gets me a little further:
>>> import PythonMagick Traceback (most recent call last): File "", line 1, in File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/PythonMagick/__init__.py", line 1, in import _PythonMagick ImportError: dlopen(/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/PythonMagick/_PythonMagick.so, 2): Symbol not found: __cg_jpeg_resync_to_restart Referenced from: /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ImageIO.framework/Versions/A/ImageIO Expected in: /opt/local/lib/libjpeg.8.dylib in /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ImageIO.framework/Versions/A/ImageIO
A bit of searching on Google eventually turned up this page that involves an egregious hack relying on case-insensitivity in Mac OS X:
sudo ln -sf /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ImageIO.framework/Versions/A/Resources/libPng.dylib /opt/local/lib/libpng.dylib sudo ln -sf /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ImageIO.framework/Versions/A/Resources/libTIFF.dylib /opt/local/lib/libtiff.dylib sudo ln -sf /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ImageIO.framework/Versions/A/Resources/libJPEG.dylib /opt/local/lib/libjpeg.dylib
Still.... it seems to work, and I can now import PythonMagick into Python! Now I just need to test it.