PREFACE

This page contains instructions on compiling EMAN for OS X in a format suitable for distribution for the 4 main OS X supported architectures: 32 and 64 bit PowerPC and Intel x86. This requires significantly more work than setting up a simple environment to use on just one machine. Instructions for a non-distributable build are here: EMAN_COMPILE_MacOS_X


DEPENDENCIES TO INSTALL

(verisons I have used in my own builds. I have placed copies of all srcs in MacOSXBuildFiles)

Building manually is recommended over using a package manager such as fink or macports, which cause significant difficulties by compiling and linking against their own python distributions. It is preferred to use the system built-in python.


PREPARING BUILD ENVIRONMENT

I setup my build environment (segregated from /usr/local to keep things tidy) as below, as a disk image mounted under /Volumes/EMAN. Minor changes will be required to paths in the instructions if you chose a different setup.

./build/                                # main builds
        ./EMAN                          # EMAN builds

./EMAN                                  # EMAN source

./dep                                   # Install prefix; used instead of /usr/local

./stage                                 # Staging area to install EMAN and setup distribution bundle

./src                                   # Dependency sources
./patches                               # Dependency patches

./extlib                                # Fixed dylibs (@loader_path..) that we'll link against and use in bundle
                                                
./Resources                             # Files for making Qt/Mac .app bundles
        ./PkgInfo
        ./icns
        ./plists
        ./scripts       

My build environment was 10.5 Leopard on Intel host using Xcode 3.0.

I recommend 10.5 for EMAN use; Python 2.5 is newer, the 10.5 Python interpreter includes readline support, and building some of the dependencies for 10.4 is a bit tricky. Building for 10.4 target on a 10.5 host is possible and requires Xcode 2.5 to be installed in parallel to Xcode 3.0 (this is how I prepared the 10.4 version for distribution; make sure you use the /Xcode2.5/usr/bin tools in your path, /Xcode2.5/SDKs/.., etc.) I have not attempted to build for 10.4 on a 10.4 host.

Because 10.4 and 10.5 use different versions of Python, the EMAN Python bindings will only work on the version it was built against: Python 2.3 for 10.4, Python 2.5 for 10.5.

So, for simplicity's sake, I will only discuss building for 10.5 target on a 10.5 host in these instructions.

Mac OS X supports multiple architectures in a single "universal" or "fat" binary/library. This is achieved by passing -arch flags to gcc (this is a special Apple-gcc flag) which will take care of all the details. Alternatively you can compile for different architectures separately and merge them together afterwards. For 10.5 I built both 32 and 64 bit versions for both Intel and PowerPC (i386, x86_64, ppc, ppc64.) On 10.4 I built only 32 bit versions for Intel and PowerPC.

I use these two variables in most of the scripts I provide. Set BROOT to the root of the build environment; in my case it was the disk image I made mounted on /Volumes/EMAN. We'll only be covering 10.5 in these instructions, but set MACOSX_DEPLOYMENT_TARGET as well since some of the Apple tools look for it.

export BROOT=/Volumes/EMAN/
export MACOSX_DEPLOYMENT_TARGET=10.5

The following environment variables were sufficient to get clean universal builds of dependencies in most cases. I put these in a file for quick access.

export PREFIX=$BROOT/dep/$MACOSX_DEPLOYMENT_TARGET
export UARCH="-arch i386 -arch ppc -arch x86_64 -arch ppc64"
export CFLAGS="-isysroot /Developer/SDKs/MacOSX10.5.sdk -mmacosx-version-min=10.5 $UARCH -O2 -g"
export LDFLAGS="$UARCH -Wl,-headerpad_max_install_names"

If you want to install all the dependencies in /usr/local, set PREFIX to accordingly. I chose to keep everything on the disk image I made, separated by deployment target.


PATCHES REQUIRED

Several dependencies required patches to compile properly. Most of them are taken from fink/macports, or other internet sources. I have them available for download at MacOSXBuildFiles:

I placed the patches in $BROOT/src/patches.


BUILDING DEPENDENCIES

CMAKE

./configure --prefix=$PREFIX --disable-dependency-tracking --disable-static --enable-shared LDFLAGS="$LDFLAGS" CFLAGS="$CFLAGS" CXXFLAGS="$CFLAGS"
make
make install

PNG

./configure --prefix=$PREFIX --disable-dependency-tracking --disable-static --enable-shared CFLAGS="$CFLAGS" CXXFLAGS="$CFLAGS"  LDFLAGS="$LDFLAGS"
make
make install

SZIP

./configure --prefix=$PREFIX --disable-dependency-tracking --disable-static --enable-shared CFLAGS="$CFLAGS" CXXFLAGS="$CFLAGS" LDFLAGS="$LDFLAGS"
make
make install

GSL

./configure --prefix=$PREFIX --disable-dependency-tracking --disable-static --enable-shared CFLAGS="$CFLAGS" CXXFLAGS="$CFLAGS"  LDFLAGS="$LDFLAGS"
make
make install

BOOST

Patch from Adobe to add fat binary support:

patch -p1 < $BROOT/src/patches/boost.patch

Build bjam:

./configure --with-toolset=darwin --with-libraries=python --prefix=$PREFIX

In tools/build/v2/tools/darwin.jam:

feature sdkroot : 10.5 10.3.9 10.2.8 : propagated link-incompatible ;
flags darwin.compile OPTIONS <sdkroot>10.5 : -isysroot /Developer/SDKs/MacOSX10.5.sdk -mmacosx-version-min=10.5 ;
flags darwin.link OPTIONS <sdkroot>10.5 : -isysroot /Developer/SDKs/MacOSX10.5.sdk -mmacosx-version-min=10.5 ;

feature arch : native ppc i386 fat : composite propagated ;
flags darwin.compile OPTIONS <arch>fat : -arch i386 -arch ppc -arch x86_64 -arch ppc64 ;
flags darwin.link OPTIONS <arch>fat : -arch i386 -arch ppc -arch x86_64 -arch ppc64 ;

Compile and install..

./tools/jam/src/bin.macosxx86/bjam -d+2 --user-config=user-config.jam --prefix=$PREFIX --with-python sdkroot=$MACOSX_DEPLOYMENT_TARGET arch=fat install

JPEG

libjpeg is very old (1998) and needs much work to compile properly on a modern system. Patches from MacPorts (http://trac.macports.org/browser/trunk/dports/graphics/jpeg/files ) or download from MacOSXBuildFiles page.

for i in $BROOT/src/patches/jpeg-6b/patch-*;do patch < $i;done

./configure --prefix=$PREFIX --disable-dependency-tracking --disable-static --enable-shared CFLAGS="$CFLAGS" CXXFLAGS="$CFLAGS"  LDFLAGS="$LDFLAGS"
make
make install

TIFF

./configure --prefix=$PREFIX --disable-dependency-tracking --disable-static --enable-shared CFLAGS="$CFLAGS" CXXFLAGS="$CFLAGS"  LDFLAGS="$LDFLAGS"
make
make install

The extra steps previously described in this document only seem to be required for 10.4.

HDF5

./configure --prefix=$PREFIX --disable-dependency-tracking --disable-static --enable-shared CFLAGS="$CFLAGS" CXXFLAGS="$CFLAGS"  LDFLAGS="$LDFLAGS"

Universal support requires patch to archive_cmds in libtool, needs $CFLAGS:

archive_cmds="\$nonopt \$(test \\\"x\$module\\\" = xyes && echo -bundle || echo -dynamiclib) $CFLAGS \$allow_undefined_flag -o \$lib \$libobjs \$deplibs\$linker_flags -install_name \$rpath/\$soname \$verstring"

make
make install

FFTW2

./configure --prefix=$PREFIX --enable-float --disable-fortran --disable-dependency-tracking --disable-static --enable-shared  CFLAGS="$CFLAGS" CXXFLAGS="$CFLAGS"  LDFLAGS="$LDFLAGS"

Universal support requires patch to archive_cmds in libtool, needs $CFLAGS, fftw2 needs it twice:

archive_cmds="\$CC $CFLAGS -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs && \$CC \$(test .\$module = .yes && echo -bundle || echo -dynamiclib) $CFLAGS  \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs\$linker_flags \$(test .\$module != .yes && echo -install_name \$rpath/\$soname \$verstring)"

make
make install

EMAN expects srfftw.h, sfftw.h. After install, go to the include directory (in my case $BROOT/dep/include) and make these links:

ln -s fftw.h sfftw.h
ln -s rfftw.h srfftw.h

Qt3-Mac

Use the patches (qt3mac.patch.txt, qt3mac.patch2.txt) from Fink, or download them from MacOSXBuildFiles downloads page. This is necessary for Qt/Mac 3.3.8 to work on 10.5.

Qt has a Carbon (deprecated Apple GUI library) dependency that is 32 bit only. Unfortunately, this will limit all EMAN GUI programs to 32 bits. Programs without a GUI work fine as 64 bit (disable GUI in cmake.)

Apply patches and fix a flag in Makefile:

sed s/free-3.3.5/free-3.3.8/g $BROOT/src/patches/qt3mac.patch.txt > ./qt3mac.patch1.txt 
cmd="s|@PREFIX@|`pwd`|g"
sed -e $cmd < ./qt3mac.patch1.txt | patch -p1

patch -p1 < $BROOT/src/patches/qt3mac.patch2.txt

perl -pi.bak -e 's|cp \-P|cp \-Rp|' qmake/Makefile.unix

These must be in path for qmake to work correctly.

export DYLD_LIBRARY_PATH=`pwd`/lib
export PATH=$PATH:`pwd`/bin

./configure -prefix $PREFIX/qt3 -release -shared -qt-gif  -system-zlib -qt-libjpeg -qt-libmng 

Make the following to changes to QMAKE_CFLAGS and QMAKE_LFLAGS in mkspecs/macx-g++/qmake.conf:

QMAKE_CFLAGS = -pipe -arch ppc -arch i386 -isysroot /Developer/SDKs/MacOSX10.5.sdk
        ...
QMAKE_LFLAGS = -headerpad_max_install_names -arch ppc -arch i386 -Wl,-syslibroot,/Developer/SDKs/MacOSX10.5.sdk

make
make install


PREPARE LIBRARIES

Copy the built dylibs to extlib (yours may be slightly different):

mkdir $BROOT/extlib

cd $BROOT/dep/lib

cp libboost_python-1_34_1.dylib libfftw.dylib libgsl.dylib libgslcblas.dylib  libhdf5.dylib libjpeg.dylib librfftw.dylib libsz.dylib libtiff.dylib qt3/libqt.dylib $BROOT/extlib/

cd $BROOT/extlib
mv libboost_python-1_34_1.dylib libboost_python.dylib

Set install_name. This is necessary for libraries to be located without polluting DYLD_LIBRARY_PATH.

for i in *dylib;do install_name_tool -id @loader_path/../../extlib/$i $i;done


BUILD EMAN

Clear the environment variables (CFLAGS, LFLAGS, ..) we made for the dependencies and run cmake. CMAKE_INSTALL_NAME_DIR sets dylib @loader_path references properly. You may need to change the paths below.

$BROOT/dep/bin/ccmake -DCMAKE_INSTALL_NAME_DIR:STRING=@loader_path/../lib  $BROOT/EMAN/

10.5, 32 bit

Use default options except those below. You may need to enter advanced mode ('t' key) to set some. Replace any /Volumes/EMAN.. paths with the correct path to your build/install environment. Link against the libraries you created with the modified install_names.

 BOOST_INCLUDE_PATH               /Volumes/EMAN/dep/include/boost-1_34_1                                                                                     
 BOOST_LIBRARY                    /Volumes/EMAN/extlib/libboost_python.dylib                                                                                 
                                                                                                               
 CMAKE_BACKWARDS_COMPATIBILITY    2.4                                                                                                                             
                                                                                                            
 CMAKE_CXX_FLAGS                  -mmacosx-version-min=10.5                                                                                                       
 CMAKE_C_FLAGS                    -mmacosx-version-min=10.5                                                                                                       

                                                                                                        
 CMAKE_INSTALL_NAME_DIR           @loader_path/../lib                                                                                                             
 CMAKE_OSX_ARCHITECTURES          i386;ppc                                                                                                                        
 CMAKE_OSX_SYSROOT                /Developer/SDKs/MacOSX10.5.sdk                                                                                                  
 CMAKE_VERBOSE_MAKEFILE           ON                                                                                                                                                                                                                                  
 EMAN_INSTALL_PREFIX              /Volumes/EMAN/stage/EMAN/EMAN                                                                                              
                                                                                                                     
 FFTW_INCLUDE_PATH                /Volumes/EMAN/dep/include                                                                                                  
 FFTW_LIBRARY                     /Volumes/EMAN/extlib/libfftw.dylib                                                                                         
 GSL_CBLAS_LIBRARY                /Volumes/EMAN/extlib/libgslcblas.dylib          
 GSL_INCLUDE_PATH                 /Volumes/EMAN/dep/include                                                                                                  
 GSL_LIBRARY                      /Volumes/EMAN/extlib/libgsl.dylib                                                                                          
 HDF_INCLUDE_PATH                 /Volumes/EMAN/dep/include                                                                                                  
 HDF_LIBRARY                      /Volumes/EMAN/extlib/libhdf5.dylib                                                                                         
 JPEG_LIBRARY                     /Volumes/EMAN/extlib/libjpeg.dylib                                                                                         
 PNG_INCLUDE_PATH                 /Volumes/EMAN/dep/include                                                                                                  
 PNG_LIBRARY                      /Volumes/EMAN/extlib/libpng.dylib                                                                                          
 PYTHON_INCLUDE_PATH              /Developer/SDKs/MacOSX10.5.sdk/System/Library/Frameworks/Python.framework/Versions/2.5/Headers                                  
 PYTHON_LIBRARY                   /Developer/SDKs/MacOSX10.5.sdk/usr/lib/libpython.dylib                                                                          
 QT_INCLUDE_DIR                   /Volumes/EMAN/dep/qt3/include                                                                                              
 QT_MOC_EXECUTABLE                /Volumes/EMAN/dep/qt3/bin/moc                                                                                          
 QT_QT_LIBRARY                    /Volumes/EMAN/extlib/libqt.dylib                                                                                           
 QT_UIC_EXECUTABLE                /Volumes/EMAN/dep/qt3/bin/uic                                                                                          
 RFFTW_LIBRARY                    /Volumes/EMAN/extlib/librfftw.dylib                                                                                        
 TIF_INCLUDE_PATH                 /Volumes/EMAN/dep/include                                                                                                  
 TIF_LIBRARY                      /Volumes/EMAN/extlib/libtiff.dylib                                                                                         
 X11_X11_INCLUDE_PATH                                                                                                                                             
 X11_X11_LIB                                                                                                                                                      
 X11_Xext_LIB                                                                                                                                                     
 X11_Xlib_INCLUDE_PATH                                                                                                                                            
 X11_Xutil_INCLUDE_PATH                                                                                                                                           
 Z_LIBRARY                        /Developer/SDKs/MacOSX10.5.sdk/usr/lib/libz.dylib  

qmake may require something like this to find libqt:

export DYLD_LIBRARY_PATH=$BROOT/dep/src/qt-mac-free-3.3.8/lib/

10.5, 64 bit

Same as 10.5/32, but with changes:

 EMAN_INSTALL_PREFIX              /Volumes/EMAN/stage/EMAN/EMAN.64                                                                                                             
 CMAKE_OSX_ARCHITECTURES          x86_64;ppc64                                                                                                                                                        
 ENABLE_GUI                       OFF                                                                                                                                                              


EMAN POST-INSTALL

Hopefully EMAN compiled and installed without any problems. I installed my EMAN to a staging directory to prepare it for distribution, /Volumes/EMAN/stage/EMAN, which contains EMAN, EMAN.64, etc..

First, Load build environment vars to get $BROOT and $MACOSX_DEPLOYMENT_TARGET.

Second, optionally, set staging dir icon using Finder... copy appropriate .icns file and paste into folder icon in 'get info'.

You can get all the files I will use on the MacOSXBuildFiles downloads page.

Copy extlibs to staging area

cp -vr $BROOT/extlib/ $BROOT/stage/extlib/

The python dylib loader seems to only look for .so files instead of .dylib files. This creates these links. If you built EMAN for 64 bits as well, repeat for that as well.

cd $BROOT/stage/EMAN/EMAN/lib/; \
for i in *.dylib;       do \
        test=`echo $i | sed s/dylib/so/`; \
        ln -sv $i $test; \
done;

Creating App Bundles

Qt/Mac GUI programs on Mac OS X will not connect properly to the window manager unless they have an .app bundle structure and correct Info.plist file. See the Apple Bundle documentation for more details.

This is the basic structure of an app bundle:

boxer.app/
        /Contents
                /Info.plist                             # xml package definition
                /PkgInfo                                # identifies as application, framework, etc.
                /MacOS                                  # bin directory
                        /boxer                          # main executable
                /Resources                              # application resources dir
                        /boxer.icns                     # app icon
                        /icon-box.icns          # file type icon

Our actual bundles will be slightly more complex and contain a few symlinks and wrappers to save on disk space and effort.

Info.plist files

First, we need to create Info.plist files for each EMAN GUI program. I'll use the boxer program as an example.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>

This key tells the Finder which document types boxer can handle, as well as maps an icon to the file.

        <key>CFBundleDocumentTypes</key>
        <array>
                <dict>
                        <key>CFBundleTypeExtensions</key>
                        <array>
                                <string>box</string>
                        </array>
                        <key>CFBundleTypeIconFile</key>
                        <string>icon-box.icns</string>                  
                        <key>CFBundleTypeName</key>
                        <string>Box database</string>
                        <key>CFBundleTypeRole</key>
                        <string>Editor</string>
                        <key>LSIsAppleDefaultForType</key>
                        <true/>
                </dict>         
        </array>

CFBundleName is the localized display name for the application. If this is not set, it will be the name of the executable. Since we'll be using wrappers, we'll set this, otherwise the program will come up as "boxer.wrapper" or similar.

        <key>CFBundleName</key>
        <string>Boxer</string>

The name of the executable that will run when opened via Finder

        <key>CFBundleExecutable</key>
        <string>boxer.wrapper</string>

A few more keys that define the info string, the icon file to be used, etc.

        <key>CFBundleGetInfoString</key>
        <string>EMAN</string>
        <key>CFBundleIconFile</key>
        <string>boxer</string>
        <key>CFBundlePackageType</key>
        <string>APPL</string>
        <key>CFBundleSignature</key>
        <string>????</string>
</dict>
</plist>

The remainder of the gui programs (checkslice, ctfit, eman, helixboxer, QHelp, qindex, qplot, qsegment, triplot, v2, v4) follow a similar pattern, with changes to CFIconFile, CFExecutable, CFBundleName, and file type associations. You can copy the plist files I already prepared (which include file associations) and icons.

Command-line wrapper

To launch the GUI programs properly from the command line, you can either make your $PATH very complex, or just use a simple wrapper script. You'll use this as 'applaunch.sh' in the next few steps.

basename=`basename $0`
$EMANDIR/apps/$basename.app/Contents/MacOS/$basename $@

Finder wrapper

On Linux and Windows, launching a program from from the GUI file browser typically just adds any files to be opened as command line args. On Mac OS X, however, it's instead passed as an Objective-C object to the application. You can patch your ported program to support this, or you can use a wrapper script that emulates argv support. I chose to use PythonObjC because it is installed by default on OS X. I modified a script provided by Apple to function as the wrapper. You can download it from the resources page and use it as 'argvemulator.py' in the following steps.

Creating bundle structure and copying files into it

I use the following steps to prepare the bundles. Be mindful of paths if you are using it with a different build/install environment directory structure. $skeldir should point to where you've placed the Resource files (in my case, /Volumes/EMAN/Resources, which has icns, plists, and other subdirectories.)

emandir=$BROOT/stage/EMAN/EMAN;
skeldir=$BROOT/Resources
cd $emandir

Clean out any existing app directory, and create a list of all binaries that link against Qt/Mac.

rm -rf $emandir/apps
mkdir $emandir/apps
c=""
cd $emandir/bin
for i in *;do a=`otool -L $i | grep libqt`;if [ -n "$a" ];then c="$c $i";fi;done
cd $emandir

Create the directory structure for the app bundle. Copy the PkgInfo file (they all use the same one.) Copy the icon file. Copy the correct plist file. Copy the argvemulator as a wrapper so it operates properly when launched from the Finder. Move the binary from the EMAN dir to a directory in the bundle. Link to another wrapper to make it launch properly (e.g. 'boxer') from the command line. Create symlinks 'lib' and 'extlib' so the dylibs can be found.

for i in $c;do  \
        cd $emandir; \
        ad=$emandir/apps/$i.app; \
        mkdir -v $ad; \
        mkdir -v $ad/Contents; \
        mkdir -v $ad/Contents/MacOS; \
        mkdir -v $ad/Contents/Resources; \
        mkdir -v $ad/Contents/Resources/EMAN; \
        mkdir -v $ad/Contents/Resources/EMAN/bin; \
        cp -v $skeldir/PkgInfo $ad/Contents/PkgInfo; \
        cp -v $skeldir/icns/$i.icns $ad/Contents/Resources/$i.icns; \
        cp -v $skeldir/plists/$i.plist $ad/Contents/Info.plist; \
        cp -v $skeldir/scripts/argvemulator.py $ad/Contents/MacOS/$i.wrapper; \
        mv -v $emandir/bin/$i $ad/Contents/Resources/EMAN/bin/$i; \
        cd $emandir/bin; \
        cp -v $skeldir/scripts/applaunch.sh ./$i; \
        cd $ad/Contents/MacOS; \
        ln -sv ../Resources/EMAN/bin/$i ./$i; \
        cd $ad/Contents/Resources/EMAN; \
        ln -sv ../../../../../lib ./lib; \
        cd $ad/Contents/Resources; \
        ln -sv ../../../../../extlib/ ./extlib; \
done

EMAN environment variables script

Create an EMAN init script (init.EMAN.sh), which will be 'source'd from .bashrc to setup PATH, PYTHONPATH, etc. And a similar csh script for .cshrc.

export EMANBASE=/Applications/EMAN/

export EMANDIR=$EMANBASE/EMAN
export PATH=$PATH:$EMANDIR/bin
export PYTHONPATH=$PYTHONPATH:$EMANDIR/lib

setenv EMANBASE /Applications/EMAN

setenv EMANDIR ${EMANBASE}/EMAN
set path=($path ${EMANDIR}/bin)

if ( $?PYTHONPATH ) then
else
setenv PYTHONPATH
endif

setenv PYTHONPATH ${PYTHONPATH}:${EMANBASE}/EMAN/lib:${EMANBASE}/extlib/site-packages
endif

Add it to the bundle:

cp -vr $BROOT/Resources/scripts/init.EMAN.sh $BROOT/stage/EMAN/
cp -vr $BROOT/Resources/scripts/init.EMAN.csh $BROOT/stage/EMAN

Package into disk image

cd $BROOT/stage/
rm -v EMAN_*.dmg
hdiutil  create -srcfolder EMAN EMAN_Leopard.dmg


Installation

Copy $BROOT/stage/EMAN to /Applications using the Finder (this will read all the Info.plist files and install file type associations.)

Alternatively, attach the disk image, and copy EMAN from there to /Applications.

Add the following to your ~/.bashrc file:

test -r /Applications/EMAN/init.EMAN.sh && . /Applications/EMAN/init.EMAN.sh

or ~/.cshrc:

test -r /Applications/EMAN/init.EMAN.csh && . /Applications/EMAN/init.EMAN.csh


Contact Information

If you have any difficulties, you may email me: Ian Rees, ian.rees at bcm edu.

Enjoy. :)

EMAN_COMPILE_MacOS_X_for_Distribution (last edited 2009-07-22 21:32:58 by root)