Goal: Build CairoGraphics private Frameworks directory, using only X-Code. Produce fat binaries capable of running on 10.4, 10.5, 10.6, on PPC, and on Intel. The result is for the native OSX backends, not the any of the X-Windows ones. A "private" Framework is not a generally reusable one, but one that is packaged specifically with a .app bundle.
Original Author: Travis Griggs (travisgriggs@gmail.com)
Original Version: 1.8.8
Other Tested Versions: 1.9.4, 1.10.2
Tools Needed:
- Terminal (or command line tool of choosing)
- X Code installed
Initial Setup
Designate a directory to work in. Clean it out and then we'll do all work in there with fresh copies.
export BuildDir=${HOME}/BuildCairo
rm -rf ${BuildDir}
mkdir ${BuildDir}
cd ${BuildDir}
Download and untar tarballs
Use curl to download FOUR tarballs: pkg-config, libpng, pixman, cairo. Adjust specific version paths as desired
curl http://pkgconfig.freedesktop.org/releases/pkg-config-0.23.tar.gz -o pkgconfig.tgz
curl ftp://ftp.simplesystems.org/pub/libpng/png/src/libpng-1.2.40.tar.gz -o libpng.tgz
curl http://www.cairographics.org/releases/pixman-0.16.2.tar.gz -o pixman.tgz
curl http://www.cairographics.org/releases/cairo-1.8.8.tar.gz -o cairo.tgz
tar -xzf pkgconfig.tgz
tar -xzf libpng.tgz
tar -xzf pixman.tgz
tar -xzf cairo.tgz
mv pkg-config-* pkgconfig
mv libpng-* libpng
mv pixman-* pixman
mv cairo-* cairo
Why the last 4 mv commands? The default directory names are things like pixman-0.1.16 (version numbers included in the name). Some of the packages have compile paths dependent on the simpler names. So we do all 4 of them to keep them simple and consistent.
Build Pkg-config
Now we compile the pkg-config utility, and set up some environment variables to manage it. Make sure that if you open a new shell, you set the two PKG_CONFIG related variables again.
Why pkg-config? Pkg-config is a package configuration management tool. OSX comes with one, but it's very old and the Cairo build system wants a newer one. You may have a new one via something like macports, but we don't want some of the other macports derived pkg-config dependencies. Building our own keeps the build nice and isolated.
cd ${BuildDir}/pkgconfig
./configure --prefix=${BuildDir}
make
make install
export PKG_CONFIG=${BuildDir}/bin/pkg-config
export PKG_CONFIG_PATH=${BuildDir}/lib/pkgconfig
The --prefix argument affects the make install command, such that it places any binaries built in our own directory, requiring no root permissions of us. Makes it easy to clean everything up later too.
Setup environment variables for fat binary compilation
WARNING If you have to go backwards in these steps, it is important that you unset these variables before trying to compile pkg-config again. Or use a different shell. We set these variables AFTER pkg-config is built for a reason.
We set the following 3 environment variables to influence the compile/link operations buried in subsequent commands, so that we build fat binaries, that can be run as far back as 10.4. If you open a new shell, you'll need to set these variables again.
export MACOSX_DEPLOYMENT_TARGET=10.4
export CC="gcc-4.0"
export LDFLAGS="-arch ppc -arch i386 -isysroot /Developer/SDKs/MacOSX10.4u.sdk"
export CFLAGS="-Os -arch ppc -arch i386 -isysroot /Developer/SDKs/MacOSX10.4u.sdk"
Why are we setting CC? For 10.6 machines. You can skip it for 10.5/10.4. But for 10.6, the default gcc version is 4.2.0 which doesn't mix well with the 10.4 SDK.
What if you want 64 bit builds too? Then you have a choice to make. If you want 64 bit, you have to set 10.5 as your low limit. And you end up with the following variant of the above. You should do only one of the 2 sets, the above 3 commands, or the 3 below.
export MACOSX_DEPLOYMENT_TARGET=10.5
export LDFLAGS="-arch ppc -arch i386 -arch ppc64 -arch x86_64 -isysroot /Developer/SDKs/MacOSX10.5.sdk"
export CFLAGS="-Os -arch ppc -arch i386 -arch ppc64 -arch x86_64 -isysroot /Developer/SDKs/MacOSX10.5.sdk"
Build libpng
Build the libpng library, and install it in our local build directory.
cd ${BuildDir}/libpng
./configure --prefix=${BuildDir} --disable-dependency-tracking
make
make install
What's the --disable-dependency-tracking? We need that since we enabled all of the different -arch flags in our CFLAGS/LDFLAGS variables.
Why are we doing this? CoreGraphics supports png functions, but the APIs are not the same as the wide spread libpng APIs, which Cairo is written for. We could try and use the one from macports, or some other source, but you'll need to track down and deal with those dependencies in that case.
Build pixman
Build the pixman library, and install it locally. Pixman is used by the Cairo library for (among other things) all of its fallback operations and Image surface type operations.
cd ${BuildDir}/pixman
./configure --prefix=${BuildDir} --disable-dependency-tracking
make
make install
Build cairo
This builds the final library. It's not ready for widespread distribution yet, keep going after this step.
cd ${BuildDir}/cairo
./configure --prefix=${BuildDir} --disable-xlib --disable-ft --disable-dependency-tracking
make
make install
Why the --disable-xlib thing? The configure script will print a list of features that are enabled and disabled when it is done. It mostly guesses them right. It is actually possible to build a Cairo library with both X windows and Quartz backends enabled, but actually using the library then has some nuances. So for the goal of this particular build, to produce a Cairo framework to use with native Apple apps, we disable the X windows backend.
Package dylibs as a relocatable Frameworks staging directory
Private Frameworks for a relocatable .app bundle in OSX, are by convention stored in a Framworks directory which is placed next to the MacOS. So we'll build that directory here. First, we'll make that directory and copy the relevant dylibs there.
mkdir ${BuildDir}/Frameworks
cd ${BuildDir}/Frameworks
cp ${BuildDir}/lib/libpng12.0.dylib .
cp ${BuildDir}/lib/libpixman-1.0.dylib .
cp ${BuildDir}/lib/libcairo.2.dylib .
Your freshly copied dylib's still have one problem. They have absolute filenames embedded in them, which look like our ${BuildDir} path. We use the install_name_tool to adjust the 'id' and 'dependency' fields found in the headers of the dylib files. The @ character is not a bug.
install_name_tool -id @executable_path/../Frameworks/libpng12.0.dylib libpng12.0.dylib
install_name_tool -id @executable_path/../Frameworks/libpixman-1.0.dylib libpixman-1.0.dylib
install_name_tool -id @executable_path/../Frameworks/libcairo.2.dylib libcairo.2.dylib
install_name_tool -change ${BuildDir}/lib/libpixman-1.0.dylib @executable_path/../Frameworks/libpixman-1.0.dylib libcairo.2.dylib
install_name_tool -change ${BuildDir}/lib/libpng12.0.dylib @executable_path/../Frameworks/libpng12.0.dylib libcairo.2.dylib
Congratulations!
You've got a Frameworks directory you can move around now with relocatable path entries in it. Place it in your .app bundle in the Contents directory, next to the MacOS directory. In your executable, you can load and bind Cairo by passing "@executable_path/../Frameworks/libcairo.2.dylib" to dlopen().