Revision 2 as of 2007-05-01 10:34:30

Clear message

Universal Libraries and Extensions for OS X 10.4+

Introduction and Background

Recent versions of Xcode for Mac OS X 10.4 Tiger introduced the ability to create multi-architecture (PowerPC and x86) executables and libraries, known as Universal binaries. Most UNIX librariesÂ’ build configurations have not adapted their build 'recipes' to utilize this capability, so they produce only the approriate binary for the platform on which they were compiled, resulting in slower or no execution on the other platform. This is certainly true of PIL, the Python Imaging Library, as of version 1.1.5. While each build 'recipe' differs depending upon the tools used by its maker and the libraries it is dependent upon, here are some instructions for builidng a Universal PIL and associated libraries, and a few tips on getting 'off-the-shelf' UNIX libraries to compile as Universal libraries.

Note: Prebuilt universal packages for Python 2.4 are available at http://pythonmac.org/packages/py24-fat/index.html"

PIL (Python Imaging Library) Example

To build a Universal PIL, we must first build Universal versions of its depedent libraries:

Notes and Assumptions

  1. The source code versions here are valid at the time of writing but will inevitably become out of date. If we are lucky, newer versions will detect OS X and build Universal versions for us. If not, you'll have to adjust the instructions accordingly.
  2. I assume you are famliar with operating the UNIX shell on OS X and with the typical UNIX install 'recipe':
    • /configure; make; sudo make install
  3. I allow the libraries to be installed on my system in the default locations rather than just a temporary build directory because this recipe is about making a working installation and not about building the components to create a package.
  4. We really don't need to make Universal binaries jsut to install on a single paltform, but I am providing this to show the diffrerent techniques I have stumbled upon to coax UNIX libraries to compile 'universally'

Universal freetype2

  1. first get the source and put it a working directory you choose: http://easynews.dl.sourceforge.net/sourceforge/freetype/freetype-2.1.10.tar.gz

  2. open a Terminal window and change your working directory to the local of the archive file: pushd <your directory path here>

  3. unarchive it: tar zxf freetype-2.1.10.tar.gz

  4. change to the working directory for the source: cd freetype-2.1.10

  5. configure the source for your platform: ./configure

  6. find the file freetype uses to determine hwo to compile the source on UNIX platforms and open it in your favorite text editor: ./builds/unix/unix-cc.mk

  7. change the line: CFLAGS := -c to CFLAGS :=-arch ppc -arch i386 -c

  8. build the library: make

  9. Install it in the default location (/usr/local); sudo make install

  10. return to the original directory: popd

Universal jpeg-6b

  1. first get the source and put it a working directory you choose: http://www.ijg.org/files/jpegsrc.v6b.tar.gz

  2. open a Terminal window and change your working directory to the local of the archive file: pushd <your directory path here>

  3. unarchive it: tar zxf jpegsrc.v6b.tar.gz

  4. change to the working directory for the source: cd jpeg-6b

  5. configure the source for your platform: ./configure

  6. find the make file created by the configure command: ./Makefile and opeon in the text editor

  7. change the line: CFLAGS= -O2 -I$(srcdir) to CFLAGS= -arch ppc -arch i386 -O2 -I$(srcdir)

  8. build the library: make

  9. Install it in the default location (/usr/local): sudo make install

  10. copy the manifest files to a standard'include' directory: sudo cp jconfig.h jmorecfg.h jpeglib.h /usr/local/include

  11. copy the static library to the standard library directory for add-ons: sudo cp libjpeg.a /usr/local/lib/

  12. use 'ranlib' to ensure a proper table of contents is generated for the library: sudo ranlib /usr/local/lib/libjpeg.a

  13. return to the original directory: popd

Universal PIL

  1. first get the source and put it a working directory you choose: http://effbot.org/downloads/Imaging-1.1.5.tar.gz -o Imaging-1.1.5.tar.gz

  2. open a Terminal window and change your working directory to the local of the archive file: pushd <you directory path here>

  3. unarchive it: tar zxf Imaging-1.1.5.tar.gz

  4. change to the working directory for the source: Imaging-1.1.5

  5. find the file used by Python to guide a build of an extension module: setup.py and open it in th text editor.

  6. change the line: JPEG_ROOT = None to JPEG_ROOT = libinclude("/usr/local") (the place we put the jpeg library and header files)

  7. build the Python extension: sudo python setup.py build_ext -i (the sudo is necessary if you don't have the requried permissions for the /usr/local directories)

  8. run the self tests to ensure it all worked: python selftest.py and you should see the output: 55 tests passed.

  9. if it passes all 55 tests, install the PIL module: sudo python setup.py install

  10. We are done. return to the starting point pushd and we should have a working installation of PIL.

A few More

"It just goes to show you--there's always something"

Each library has its own tricks but there are some standard way of changing the build environment and paramters without making permanent changes to the files. Why didn't I use them above? Because, just as the famous saying for that other language (hint: PERL) says: there's more than one way to do it" and this is about techniques and tricks, not efficiency for now.

[Reader note: Copying the files /usr/share/libtool/config.sub and config.guess into your build directory will cause the ./configure script to work properly for jpeg-6a and freetype2]

Unable to edit the page? See the FrontPage for instructions.