Archive for October, 2009

Building Boost on Snow Leopard

Wednesday, October 14th, 2009

Behind the scenes we’re working on great stuff that requires the phantastic Boost libraries. Unfortunately building those libraries isn’t always that easy. Starting with Snow Leopard and its Xcode 3.2 we were no longer able to build universal binaries of Boost the way we used to. After reading a lot of articles and forums for a solution (none of them worked for us) we came up with our own solution.

The goal: we want to have 4-way universal binaries of static Boost libraries. That is PowerPC 32-Bit, PowerPC 64-Bit, Intel 32-Bit, and Intel 64-Bit.

The problem: As soon as we tried to use address-model=32_64 in the bjam command we just got weird errors.

The solution: It’s pretty easy; just avoid compiling for multiple architectures at once. We solved the problem by compiling for each architecture separately and finally putting things together into universal binaries using the lipo tool.

I wrote a perl script to accomplish that. Please be aware that I’m not a very experienced scripter. My primary programming languages are Obj-C, C++, and Java, but I avoid scripting whenever possible. So the following script may be by far not the best solution and I “hacked” it together for our own purposes only. The script is currently working for Boost 1.40 and the resulting binaries are installed into /build_external.

The way we build the Boost libraries they should be usable on any PPC- or Intel-Mac running Mac OS X 10.4 (Tiger) or later in 32-Bit and 64-Bit applications.

Feel free to use the script and adapt it for your specific needs. Use at your own risk.

#!/usr/bin/perl
# usage:
# - make sure $PREFIX and $VER are correct
# - Extract the boost source archive and cd into the extracted folder (e.g. "boost_1_40_0").
# - execute this script

use strict;
use File::Basename;

my $PREFIX = "/build_external";
my $VER = "1_40";
my $GCC = "xgcc40-mt";

# compile boost for PPC 32-Bit:

system("bjam --prefix=$PREFIX --libdir=$PREFIX/libPPC32 --layout=versioned toolset=darwin-4.0 macosx-version=10.5 macosx-version-min=10.4 architecture=power address-model=32 link=static install");

#compile boost for PPC 64-Bit:

system("bjam --prefix=$PREFIX --libdir=$PREFIX/libPPC64 --layout=versioned toolset=darwin-4.0 macosx-version=10.5 macosx-version-min=10.4 architecture=power address-model=64 link=static install");

#compile boost for Intel 32-Bit:

system("bjam --prefix=$PREFIX --libdir=$PREFIX/libIntel32 --layout=versioned toolset=darwin-4.0 macosx-version=10.5 macosx-version-min=10.4 architecture=x86 address-model=32 link=static install");

#compile boost for Intel 64-Bit:

system("bjam --prefix=$PREFIX --libdir=$PREFIX/libIntel64 --layout=versioned toolset=darwin-4.0 macosx-version=10.5 macosx-version-min=10.4 architecture=x86 address-model=64 link=static install");

#collect all boost libraries in libPPC32, libPPC64, libIntel32, and libIntel64:

my %libs;
my @globLibs;
my $lib;

@globLibs = glob("$PREFIX/libPPC32/libboost_*-$GCC-$VER.a");
foreach $lib (@globLibs) {
%libs = map { $_ => 1 } keys %libs, basename($lib);
}
@globLibs = glob("$PREFIX/libPPC64/libboost_*-$GCC-$VER.a");
foreach $lib (@globLibs) {
%libs = map { $_ => 1 } keys %libs, basename($lib);
}
@globLibs = glob("$PREFIX/libIntel32/libboost_*-$GCC-$VER.a");
foreach $lib (@globLibs) {
%libs = map { $_ => 1 } keys %libs, basename($lib);
}
@globLibs = glob("$PREFIX/libIntel64/libboost_*-$GCC-$VER.a");
foreach $lib (@globLibs) {
%libs = map { $_ => 1 } keys %libs, basename($lib);
}

#iterate over all boost libraries and execute the appropriate lipo command to create universal libraries in lib:

my $cmd;
my $archs;
my $archLib;
foreach $lib (keys %libs) {
$archs = "";
$cmd = "lipo -create";
$archLib = "$PREFIX/libPPC32/$lib";
if (-e $archLib) {
$cmd = $cmd." ".$archLib;
$archs = $archs." ppc";
}
$archLib = "$PREFIX/libPPC64/$lib";
if (-e $archLib) {
$cmd = $cmd." ".$archLib;
$archs = $archs." ppc64";
}
$archLib = "$PREFIX/libIntel32/$lib";
if (-e $archLib) {
$cmd = $cmd." ".$archLib;
$archs = $archs." i386";
}
$archLib = "$PREFIX/libIntel64/$lib";
if (-e $archLib) {
$cmd = $cmd." ".$archLib;
$archs = $archs." x86_64";
}

$cmd = $cmd." -output $PREFIX/lib/$lib";

print("----------------------------------------------\nCreating universal$archs library $lib ...\n");
`$cmd`;
# system("lipo -info $PREFIX/lib/$lib");
}