08 June 2009

CMake, Python, and MacPorts

Over the last few days, I've been learning the CMake build system. There's a lot that I like about it—it's certainly more scalable than SCons, which I've been using until now. In about a day of fooling around from scratch, I converted one of my main projects (MCGeometry) to CMake.

However, some stuff that should be trivial is tricky (the most frustrating thing is trying to copy files to a build directory -- it installs stuff to the prefix path without a problem, but intermediate copies don't work well at all). I've gone over the fooling around needed to get boost.python to work with MacPorts, but one would expect CMake (since its configuration allows the manual selection of most compilers, libraries, etc.) to handle it without a problem. Sadly, though, when using the FindPythonLibs module and FindSWIG and UseSWIG, it defaults to linking against the Python framework found in /System/Library. I spent probably a few hours googling for a solution, but finally today I found one that works without any hacks at all.

The key is that on Mac OS X systems, rather than looking for headers and libraries, FindPython prefers to search for the Python framework. There are several locations it checks in some preferential order. All that needs to be done is to symlink the Python framework installed by MacPorts to one of the higher-preference locations:

ln -s /opt/local/Library/Frameworks/Python.framework /Library/Frameworks/

Ta-da, now running otool -L on the SWIG modules that CMake generates properly shows that they link against the MacPorts framework, and the right include and library paths are used.

01 June 2009

Boost mpi and python with macports

On my system, I installed MacPorts (formerly DarwinPorts) so that I could get matplotlib and numpy without any extra effort. In the process, it installed its own version of Python in /opt/local instead of the default mac one at /System/Library/Frameworks/Python.framework/Versions/2.5/. The former is now the only Python version I use on my computer. It hadn't posed a problem until I tried to install boostmpi (see previous post on MPI with C++ and Python).

Well, after I told it to use the correct I got the unfortunate error:
"Fatal Python error: Interpreter not initialized (version mismatch?)" A little searching showed that the problem was that the libraries (specifically, the libboost_python dynamic library) was linking against the dynamic library found in /System/Library rather than the one set up in my environment and everywhere else. Using otool -L on the dynamic lib confirmed this, and I used the same tool while trying to find a solution (rather than using the Python failure to check).

On the Mac, installing Boost properly (with any of the libraries that need compiling) requires passing the --toolset=darwin option to bjam. Grepping the Boost source for "/System/Library" revealed that location to be hardwired as the default Python location if the darwin toolset is used. The solution is to specify in the user-config.jam file exactly what version of Python to use and where. My final install script (echo, bjam, and rm are the three commands):
echo "using mpi ; using python : 2.5 : /opt/local/bin : /opt/local/include/python2.5 : /opt/local/lib : ;" > ${HOME}/user-config.jam
bjam --with-mpi --with-python --with-math --with-serialization --toolset=darwin install --prefix=$INSTALLDIR
rm ${HOME}/user-config.jam

Using otool -L on the new libboost_python-xgcc40-mt-1_39.dylib verified that it linked against the correct Python, and boostmpi ran correctly after installing it.