Differences between revisions 4 and 28 (spanning 24 versions)
Revision 4 as of 2008-03-19 04:14:15
Size: 1056
Editor: root
Comment:
Revision 28 as of 2008-03-19 21:11:02
Size: 25155
Editor: root
Comment:
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
Compiling for Mac OS X is generally the same as other platforms, but with some additional work required in post-install processing. Further effort is required if you want to make a build for distribution or that will work on multiple machines and/or architectures.

Dependencies (version I have used successfully in parens):

<ul>
<li>boost (1_34_1)</li>
</ul>

cmake (2.4.8)

fftw (2.1.5)

gsl (1.8)

hdf5 (1.6.6)

jpeg (v6b)

png (1.2.23)

numpy (1.0.4)

Qt/Mac (3.3.8)

szip (2.1)

tiff (3.8.2)

zlib (1.2.1)

If you choose to install these from your package manager, it will be difficult to transfer your EMAN build from machine to machine. For the self-contained package I created, I chose to build them all myself without a package manager for more control over configuration options. However, some of the packages required either patches or some careful massaging to compile properly. I have included detailed instructions and extra files required below:

Detailed instructions for building dependencies on Mac OS X
** NOTE **
** I AM STILL WORKING ON THESE INSTRUCTIONS. :)
**

= DEPENDENCIES =

 * boost (1_34_1)
 * cmake (2.4.8)
 * fftw (2.1.5)
 * gsl (1.8)
 * hdf5 (1.6.6)
 * jpeg (v6b)
 * png (1.2.23)
 * numpy (1.0.4)
 * Qt/Mac (3.3.8)
 * szip (2.1)
 * tiff (3.8.2)
 * zlib (1.2.1)

(verisons I have used in my own builds.)

------

= PREFACE =

Compiling for Mac OS X is generally the same as other platforms, but the dependencies may be a challenge.

You have two routes available. You can install the above dependencies using a package manager such as fink or macports. This is the easier and faster option, but has the downside of making it more difficult to distribute your built package or moving it to a different machine. If you choose this option, please skip to the end. I recommend using Qt/X11 instead of Qt/Mac if you chose this option because Qt/Mac requires a number of additional packaging steps to be functional.

The other option is to build all dependencies manually from source. This is the method I chose for the self-contained EMAN package. However, some of the packages required either patches or some careful massaging to compile properly. It will require a bit more effort than using the package manager.

-------

= PREPARING BUILD ENVIRONMENT =

I opted to place my build environment in a disk image to make it easier to move it from machine to machine. I used Disk Utility to create a sparse disk image with a max size of 40gb (it will shrink to the total size of the files contained.)

I called the disk image "EMAN" and used the following directory structure for organization.

attachment:dirstructure.jpg

"build" is for EMAN build itself. "dep" is the dependency install tree root. "extlib" is for modified dependency libraries. "EMAN" is for the EMAN source. "Resources" are support files to be used in the creation of Mac OS X app bundles. "src" is for downloaded source tarballs and patches. "stage" is where the EMAN package will be prepared for distribution. "vars10.x.sh" is for environment variables specific to building for each Mac OS X version.

Because 10.4 and 10.5 use different versions of Python, I decided to build EMAN and dep libraries separately for each deployment target.

My build environment was 10.5 Leopard on Intel host using Xcode 3.0. I have not personally built for 10.4 on a 10.4 host, but the instructions for 10.5 will probably work. 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.

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. We'll only be covering 10.5 in these instructions, but set MACOSX_DEPLOYMENT_TARGET as well.

{{{
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 vars10.5.sh for quick access:

{{{
#10.5
export MACOSX_DEPLOYMENT_TARGET=10.5
export PREFIX=$BROOT/dep/$MACOSX_DEPLOYMENT_TARGET
export UARCH="-arch i386 -arch ppc -arch x86_64 -arch ppc64"
export SROOT="-isysroot /Developer/SDKs/MacOSX10.5.sdk -mmacosx-version-min=10.5"
export LDF="-Wl,-headerpad_max_install_names"
export CFLAGS="$SROOT $UARCH -O2 -g"
export LDFLAGS="$UARCH $LDF"
export PATH=/bin:/usr/bin:/usr/sbin:/sbin:/usr/local/bin
}}}

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]:

 * boost.patch
 * darwin.jam
 * jpegpatch.zip
 * libtool135update.zip
 * qt3mac.patch.txt
 * qt3mac.patch2.txt

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

--------

= BUILDING DEPENDENCIES =

== CMAKE ==

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

make and make install..


== PNG ==

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

make and make install..


== SZIP ==

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

make and make install..

== GSL ==

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

make and make install..

== BOOST ==

Patch to add fat binary support:
{{{
patch -p1 < $BROOT/src/patches/boost.patch
}}}

Build bjam:

{{{
./configure --with-toolset=darwin --with-libraries=python --prefix=$PREFIX --exec-prefix=$PREFIX/fat
}}}

In tools/build/v2/tools/darwin.jam:
 * change sdkroot to use /Developer/SDKs/MacOSX10.5.sdk
 * Add 64 bit (ppc64, x86_64) to fat arch

{{{
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 --libdir=$PREFIX/fat/lib/ --exec-prefix=$PREFIX/fat/bin/ --with-python sdkroot=$MACOSX_DEPLOYMENT_TARGET arch=fat install
}}}


== JPEG ==

Patches from http://www.kyngchaos.com/macosx/install/libjpeg or download from [MacOSXBuildFiles] page.

{{{
unzip $BROOT/src/patches/libtool135update.zip
unzip $BROOT/src/patches/jpegpatch.zip

cp /usr/share/libtool/config.* ./
patch makefile.cfg makefile.cfg.patch
}}}

Configure..

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

In Makefile, change CC and move it below CFLAGS...

{{{
CC=gcc $(CFLAGS)
}}}

Patch archive_cmds in libtool: needs $CFLAGS

{{{
archive_cmds="\$nonopt \$(test .\$module = .yes && echo -bundle || echo -dynamiclib) $CFLAGS \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$linkopts -install_name \$rpath/\$soname \$verstring"
}}}

make and make install..


== TIFF ==

version-number needs to be changed to current_version in libtool

{{{
sed s/"version-number"/"current_version"/ Makefile.in > Makefile2.in
sed s/"version-number"/"current_version"/ Makefile.am > Makefile2.am
mv Makefile2.in Makefile.in
mv Makefile2.am Makefile.am
}}}

Configure..

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

make and make install..


== HDF5 ==

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

Patch archive_cmds in libtool, needs $CFLAGS
{{{
archive_cmds="\$nonopt \$(test \\\"x\$module\\\" = xyes && echo -bundle || echo -dynamiclib) $CFLAGS \$allow_undefined_flag
}}}

make and make install..


== FFTW2 ==

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

Patch archive_cmds to include $CFLAGS in libtool.. this one 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 and make install..

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

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


== Qt3-Mac ==

Use patches from Fink, or download them from [MacOSXBuildFiles] downloads page.

Carbon dependency makes it 32 bit only.

Apply patches

{{{
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 -bindir $PREFIX/fat/bin/qt3 -libdir $PREFIX/fat/lib/qt3 -plugindir $PREFIX/fat/plugins/qt3 -release -shared -qt-gif -system-zlib -qt-libjpeg -qt-libmng
}}}

In mkspecs/macx-g++/qmake.conf:

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

make and make install..

-----

= PREPARE LIBRARIES =

Make copies of the dylibs. e.g.:

{{{
mkdir $BROOT/extlib/$MACOSX_DEPLOYMENT_TARGET

cd $BROOT/dep/$MACOSX_DEPLOYMENT_TARGET/fat/lib

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

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

Set install_name. necessary for placing the app bundle wherever is convenient.

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

------

= BUILD EMAN =

qmake will fail without this:

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

Do not load vars script. cmake doesn't like it.

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

== 10.5, 32 bit ==

Default options except those below. 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/10.5/include/boost-1_34_1
 BOOST_LIBRARY /Volumes/EMAN/extlib/10.5/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/10.5/EMAN/EMAN
                                                                                                                     
 EXECUTABLE_OUTPUT_PATH /Volumes/EMAN/build/10.5/32/EMAN/bin
 FFTW_INCLUDE_PATH /Volumes/EMAN/dep/10.5/include
 FFTW_LIBRARY /Volumes/EMAN/extlib/10.5/libfftw.dylib
 GSL_CBLAS_LIBRARY /Volumes/EMAN/extlib/10.5/libgslcblas.dylib
 GSL_INCLUDE_PATH /Volumes/EMAN/dep/10.5/include
 GSL_LIBRARY /Volumes/EMAN/extlib/10.5/libgsl.dylib
 HDF_INCLUDE_PATH /Volumes/EMAN/dep/10.5/include
 HDF_LIBRARY /Volumes/EMAN/extlib/10.5/libhdf5.dylib
 JPEG_LIBRARY /Volumes/EMAN/extlib/10.5/libjpeg.dylib
 LIBRARY_OUTPUT_PATH /Volumes/EMAN/build/10.5/32/EMAN/lib
 PNG_INCLUDE_PATH /Volumes/EMAN/dep/10.5/include
 PNG_LIBRARY /Volumes/EMAN/extlib/10.5/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/10.5/qt3/include
 QT_MOC_EXECUTABLE /Volumes/EMAN/dep/10.5/fat/bin/qt3/moc
 QT_QT_LIBRARY /Volumes/EMAN/extlib/10.5/libqt.dylib
 QT_UIC_EXECUTABLE /Volumes/EMAN/dep/10.5/fat/bin/qt3/uic
 RFFTW_LIBRARY /Volumes/EMAN/extlib/10.5/librfftw.dylib
 TIF_INCLUDE_PATH /Volumes/EMAN/dep/10.5/include
 TIF_LIBRARY /Volumes/EMAN/extlib/10.5/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
}}}


== 10.5, 64 bit ==

Same as 10.5/32, but with changes:

{{{
 EMAN_INSTALL_PREFIX /Volumes/EMAN/stage/10.5/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, e.g. $BROOT/stage/10.5/EMAN, which contains EMAN, EMAN.64, etc..

First, Load 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'.

The 'makedist.sh' script does most of packaging work automatically, but I'll step through it below.

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

== Copy extlibs to staging area ==

{{{
cp -vr $BROOT/extlib/$MACOSX_DEPLOYMENT_TARGET/ $BROOT/stage/$MACOSX_DEPLOYMENT_TARGET/extlib/
}}}

== Python dylib links ==

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/$MACOSX_DEPLOYMENT_TARGET/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 a .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>
}}}

I have made Info.plist files for all the gui programs: boxer, checkslice, ctfit, eman, helixboxer, QHelp, qindex, qplot, qsegment, triplot, v2, and v4. I also made icons for the programs and file types that you can use.

=== 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.

{{{
#!/bin/bash
basename=`basename $0`
$EMANDIR/apps/$basename.app/Contents/MacOS/$basename $@
}}}

=== Finder wrapper ===

On Linux and Windows, launching a program from Explorer/Konqueror/etc 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 script to automate the packaging. Be mindful of paths if you are using it with a different build/install environment directory structure.

{{{
emandir=$BROOT/stage/$MACOSX_DEPLOYMENT_TARGET/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
}}}

** NOTE ** ** I AM STILL WORKING ON THESE INSTRUCTIONS. :) **

DEPENDENCIES

  • boost (1_34_1)
  • cmake (2.4.8)
  • fftw (2.1.5)
  • gsl (1.8)
  • hdf5 (1.6.6)
  • jpeg (v6b)
  • png (1.2.23)
  • numpy (1.0.4)
  • Qt/Mac (3.3.8)
  • szip (2.1)
  • tiff (3.8.2)
  • zlib (1.2.1)

(verisons I have used in my own builds.)


PREFACE

Compiling for Mac OS X is generally the same as other platforms, but the dependencies may be a challenge.

You have two routes available. You can install the above dependencies using a package manager such as fink or macports. This is the easier and faster option, but has the downside of making it more difficult to distribute your built package or moving it to a different machine. If you choose this option, please skip to the end. I recommend using Qt/X11 instead of Qt/Mac if you chose this option because Qt/Mac requires a number of additional packaging steps to be functional.

The other option is to build all dependencies manually from source. This is the method I chose for the self-contained EMAN package. However, some of the packages required either patches or some careful massaging to compile properly. It will require a bit more effort than using the package manager.


PREPARING BUILD ENVIRONMENT

I opted to place my build environment in a disk image to make it easier to move it from machine to machine. I used Disk Utility to create a sparse disk image with a max size of 40gb (it will shrink to the total size of the files contained.)

I called the disk image "EMAN" and used the following directory structure for organization.

attachment:dirstructure.jpg

"build" is for EMAN build itself. "dep" is the dependency install tree root. "extlib" is for modified dependency libraries. "EMAN" is for the EMAN source. "Resources" are support files to be used in the creation of Mac OS X app bundles. "src" is for downloaded source tarballs and patches. "stage" is where the EMAN package will be prepared for distribution. "vars10.x.sh" is for environment variables specific to building for each Mac OS X version.

Because 10.4 and 10.5 use different versions of Python, I decided to build EMAN and dep libraries separately for each deployment target.

My build environment was 10.5 Leopard on Intel host using Xcode 3.0. I have not personally built for 10.4 on a 10.4 host, but the instructions for 10.5 will probably work. 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.

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. We'll only be covering 10.5 in these instructions, but set MACOSX_DEPLOYMENT_TARGET as well.

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 vars10.5.sh for quick access:

#10.5
export MACOSX_DEPLOYMENT_TARGET=10.5
export PREFIX=$BROOT/dep/$MACOSX_DEPLOYMENT_TARGET
export UARCH="-arch i386 -arch ppc -arch x86_64 -arch ppc64"
export SROOT="-isysroot /Developer/SDKs/MacOSX10.5.sdk -mmacosx-version-min=10.5"
export LDF="-Wl,-headerpad_max_install_names"
export CFLAGS="$SROOT $UARCH -O2 -g"
export LDFLAGS="$UARCH $LDF"
export PATH=/bin:/usr/bin:/usr/sbin:/sbin:/usr/local/bin

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]:

  • boost.patch
  • darwin.jam
  • jpegpatch.zip
  • libtool135update.zip
  • qt3mac.patch.txt
  • qt3mac.patch2.txt

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


BUILDING DEPENDENCIES

CMAKE

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

make and make install..

PNG

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

make and make install..

SZIP

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

make and make install..

GSL

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

make and make install..

BOOST

Patch to add fat binary support:

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

Build bjam:

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

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

  • change sdkroot to use /Developer/SDKs/MacOSX10.5.sdk
  • Add 64 bit (ppc64, x86_64) to fat arch

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 --libdir=$PREFIX/fat/lib/ --exec-prefix=$PREFIX/fat/bin/ --with-python sdkroot=$MACOSX_DEPLOYMENT_TARGET arch=fat install

JPEG

Patches from http://www.kyngchaos.com/macosx/install/libjpeg or download from [MacOSXBuildFiles] page.

unzip $BROOT/src/patches/libtool135update.zip
unzip $BROOT/src/patches/jpegpatch.zip

cp /usr/share/libtool/config.* ./
patch makefile.cfg makefile.cfg.patch

Configure..

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

In Makefile, change CC and move it below CFLAGS...

CC=gcc $(CFLAGS)

Patch archive_cmds in libtool: needs $CFLAGS

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

make and make install..

TIFF

version-number needs to be changed to current_version in libtool

sed s/"version-number"/"current_version"/ Makefile.in > Makefile2.in
sed s/"version-number"/"current_version"/ Makefile.am > Makefile2.am
mv Makefile2.in Makefile.in
mv Makefile2.am Makefile.am

Configure..

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

make and make install..

HDF5

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

Patch archive_cmds in libtool, needs $CFLAGS

archive_cmds="\$nonopt \$(test \\\"x\$module\\\" = xyes && echo -bundle || echo -dynamiclib) $CFLAGS \$allow_undefined_flag

make and make install..

FFTW2

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

Patch archive_cmds to include $CFLAGS in libtool.. this one 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 and make install..

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

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

Qt3-Mac

Use patches from Fink, or download them from [MacOSXBuildFiles] downloads page.

Carbon dependency makes it 32 bit only.

Apply patches

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 -bindir $PREFIX/fat/bin/qt3 -libdir $PREFIX/fat/lib/qt3 -plugindir $PREFIX/fat/plugins/qt3 -release -shared -qt-gif  -system-zlib -qt-libjpeg -qt-libmng 

In mkspecs/macx-g++/qmake.conf:

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

make and make install..


PREPARE LIBRARIES

Make copies of the dylibs. e.g.:

mkdir $BROOT/extlib/$MACOSX_DEPLOYMENT_TARGET

cd $BROOT/dep/$MACOSX_DEPLOYMENT_TARGET/fat/lib

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

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

Set install_name. necessary for placing the app bundle wherever is convenient.

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


BUILD EMAN

qmake will fail without this:

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

Do not load vars script. cmake doesn't like it.

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

10.5, 32 bit

Default options except those below. 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/10.5/include/boost-1_34_1                                                                                     
 BOOST_LIBRARY                    /Volumes/EMAN/extlib/10.5/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/10.5/EMAN/EMAN                                                                                              
                                                                                                                     
 EXECUTABLE_OUTPUT_PATH           /Volumes/EMAN/build/10.5/32/EMAN/bin                                                                                            
 FFTW_INCLUDE_PATH                /Volumes/EMAN/dep/10.5/include                                                                                                  
 FFTW_LIBRARY                     /Volumes/EMAN/extlib/10.5/libfftw.dylib                                                                                         
 GSL_CBLAS_LIBRARY                /Volumes/EMAN/extlib/10.5/libgslcblas.dylib          
 GSL_INCLUDE_PATH                 /Volumes/EMAN/dep/10.5/include                                                                                                  
 GSL_LIBRARY                      /Volumes/EMAN/extlib/10.5/libgsl.dylib                                                                                          
 HDF_INCLUDE_PATH                 /Volumes/EMAN/dep/10.5/include                                                                                                  
 HDF_LIBRARY                      /Volumes/EMAN/extlib/10.5/libhdf5.dylib                                                                                         
 JPEG_LIBRARY                     /Volumes/EMAN/extlib/10.5/libjpeg.dylib                                                                                         
 LIBRARY_OUTPUT_PATH              /Volumes/EMAN/build/10.5/32/EMAN/lib                                                                                            
 PNG_INCLUDE_PATH                 /Volumes/EMAN/dep/10.5/include                                                                                                  
 PNG_LIBRARY                      /Volumes/EMAN/extlib/10.5/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/10.5/qt3/include                                                                                              
 QT_MOC_EXECUTABLE                /Volumes/EMAN/dep/10.5/fat/bin/qt3/moc                                                                                          
 QT_QT_LIBRARY                    /Volumes/EMAN/extlib/10.5/libqt.dylib                                                                                           
 QT_UIC_EXECUTABLE                /Volumes/EMAN/dep/10.5/fat/bin/qt3/uic                                                                                          
 RFFTW_LIBRARY                    /Volumes/EMAN/extlib/10.5/librfftw.dylib                                                                                        
 TIF_INCLUDE_PATH                 /Volumes/EMAN/dep/10.5/include                                                                                                  
 TIF_LIBRARY                      /Volumes/EMAN/extlib/10.5/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  

10.5, 64 bit

Same as 10.5/32, but with changes:

 EMAN_INSTALL_PREFIX              /Volumes/EMAN/stage/10.5/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, e.g. $BROOT/stage/10.5/EMAN, which contains EMAN, EMAN.64, etc..

First, Load 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'.

The 'makedist.sh' script does most of packaging work automatically, but I'll step through it below.

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

Copy extlibs to staging area

cp -vr $BROOT/extlib/$MACOSX_DEPLOYMENT_TARGET/ $BROOT/stage/$MACOSX_DEPLOYMENT_TARGET/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/$MACOSX_DEPLOYMENT_TARGET/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 a .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>

I have made Info.plist files for all the gui programs: boxer, checkslice, ctfit, eman, helixboxer, QHelp, qindex, qplot, qsegment, triplot, v2, and v4. I also made icons for the programs and file types that you can use.

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 Explorer/Konqueror/etc 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 script to automate the packaging. Be mindful of paths if you are using it with a different build/install environment directory structure.

emandir=$BROOT/stage/$MACOSX_DEPLOYMENT_TARGET/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_COMPILE_MacOS_X_for_Distribution (last edited 2009-07-22 21:32:58 by root)