User:Tshead/OSX CPack Bundle Generator: Difference between revisions

From KitwarePublic
Jump to navigationJump to search
 
Line 1: Line 1:
== OverView ==
#REDIRECT [[CMake:CPackPackageGenerators#Bundle_.28OSX_only.29]]
 
Using CMake, I support several cross-platform projects that are deployed on Linux, OSX, and Windows.  Some of these projects use Qt, others use GTK.  On OSX, I prefer distribution via "bundles" over PackageMaker, but I require more flexibility than the OSXX11 generator provides.  For example, GTK projects need to start X11 before the "real" application starts, while Qt projects don't require this functionality.  In both cases, setting DYLD_LIBRARY_PATH at startup eliminates the need to run install_name_tool on libraries included in the bundle.  Some projects require an Info.plist that is more complex than that provided via the current generator.  All projects should integrate well with CMake's existing installation functionality.
 
To do this in the past, I've used "CreateBundle.sh.in" custom shell scripts to do the work of creating bundles, but this is repetitive and error-prone, and it bypasses CMake installation.  What's needed is a more flexible OSX bundle generator for CPack.
 
== Prototype ==
 
You can get a patch for CMake that includes the prototype bundle generator from the CMake bugtracker at http://public.kitware.com/Bug/view.php?id=7170
 
== Behavior ==
 
* The prototype generator creates an OSX bundle with the following layout:
 
<pre>
CPACK_BUNDLE_NAME/
  Contents/
    MacOS/
      CPACK_BUNDLE_NAME (copied from CPACK_BUNDLE_STARTUP_COMMAND)
    Resources/
      (filesystem defined by CMake INSTALL commands)
    Info.plist (copied from CPACK_BUNDLE_PLIST)
</pre>
 
* CPACK_BUNDLE_PLIST is the name of a file that becomes the Info.plist for the bundle.  This could be a hard-coded file included with the program sources, a file generated with CONFIGURE_FILE, etc.  Rationale: Info.plist can become arbitrarily complex, applications need to be able to specify its contents directly.
 
* The bundle's Resources/ directory is populated with the files installed with CMake INSTALL() commands.  Rationale: integrate well with CMake and other package generators (such as NSIS).  Makes it easy to incorporate external dependencies (Qt, GTK) into the bundle.
 
* CPACK_BUNDLE_STARTUP_COMMAND is the name of a file that will be executed when the user opens the bundle.  It could be a binary or a script.  Rationale: for most non-trivial applications, simply running a binary is not enough.  The following sample script demonstrates several common startup operations:
** Starts X11 (required by GTK).
** Updates DYLD_LIBRARY_PATH so that the application can locate libraries that are included in the bundle.  This eliminates the need to run install_name_tool on libraries in the bundle, which is messy and error-prone.  Useful for either Qt or GTK.
** Updates PATH so the "main" application can easily run "child" binaries included in the bundle.
** Sets-up some temporary files and environment variables required by (in this case) GTK.
** Passes information to the application via the command line (in this case, paths to several application resources located in the bundle).
 
<pre>
#!/bin/sh
#
# Author: Aaron Voisine <aaron@voisine.org>
# Inkscape Modifications: Michael Wybrow <mjwybrow@users.sourceforge.net>
# K-3D Modifications: Timothy M. Shead <tshead@k-3d.com>
 
K3D_BUNDLE="`echo "$0" | sed -e 's/\/Contents\/MacOS\/K-3D//'`"
K3D_RESOURCES="$K3D_BUNDLE/Contents/Resources"
K3D_TEMP="/tmp/k3d/$UID"
K3D_ETC="$K3D_TEMP/etc"
K3D_PANGO_RC_FILE="$K3D_ETC/pango/pangorc"
 
echo "running $0"
echo "K3D_BUNDLE: $K3D_BUNDLE"
 
# Start X11 ...
ps -wx -ocommand | grep -e '[X]11.app' > /dev/null
if [ "$?" != "0" -a ! -f ~/.xinitrc ]; then
    echo "rm -f ~/.xinitrc" > ~/.xinitrc
    sed 's/xterm/# xterm/' /usr/X11R6/lib/X11/xinit/xinitrc >> ~/.xinitrc
fi
 
mkdir -p $K3D_TEMP
cat << __END_OF_GETDISPLAY_SCRIPT__ > "$K3D_TEMP/getdisplay.sh"
#!/bin/sh
mkdir -p "$K3D_TEMP"
 
if [ "\$DISPLAY"x == "x" ]; then
    echo :0 > "$K3D_TEMP/display"
else
    echo \$DISPLAY > "$K3D_TEMP/display"
fi
__END_OF_GETDISPLAY_SCRIPT__
chmod +x "$K3D_TEMP/getdisplay.sh"
rm -f $K3D_TEMP/display
open-x11 $K3D_TEMP/getdisplay.sh || \
open -a XDarwin $K3D_TEMP/getdisplay.sh || \
echo ":0" > $K3D_TEMP/display
 
while [ "$?" == "0" -a ! -f $K3D_TEMP/display ];
do
  #echo "Waiting for display $K3D_TEMP/display"
  sleep 1;
done
export "DISPLAY=`cat $K3D_TEMP/display`"
 
ps -wx -ocommand | grep -e '[X]11' > /dev/null || exit 11
 
# Setup temporary runtime files
rm -rf "$K3D_TEMP"
 
# Because the bundle could be located anywhere at runtime, we have to
# create temporary copies of the Pango configuration files that
# reflect our current location
mkdir -p "$K3D_ETC/pango"
sed -e 's|/opt/local/etc|'"$K3D_ETC|g" "$K3D_RESOURCES/etc/pango/pangorc" > "$K3D_ETC/pango/pangorc"
sed -e 's|/opt/local|\"'"$K3D_RESOURCES|g" -e "s/\.so/.so\"/g" "$K3D_RESOURCES/etc/pango/pango.modules" > "$K3D_ETC/pango/pango.modules"
cp -f "$K3D_RESOURCES/etc/pango/pangox.aliases" "$K3D_ETC/pango/pangox.aliases"
 
export "DYLD_LIBRARY_PATH=$K3D_RESOURCES/lib"
export "FONTCONFIG_PATH=$K3D_RESOURCES/etc/fonts"
export "PANGO_RC_FILE=$K3D_PANGO_RC_FILE"
export "PATH=$K3D_RESOURCES/bin:$PATH"
 
#export
exec "$K3D_RESOURCES/bin/k3d" "--log-level=debug" "--plugins=$K3D_RESOURCES/lib/k3d/plugins" "--share=$K3D_RESOURCES/share/k3d" "--ui=$K3D_RESOURCES/lib/k3d/uiplugins/k3d-ngui.module"
</pre>
 
* The bundle is then stored in a compressed disk image.  Rationale: de-facto standard mechanism for distributing bundles.
 
== Required CMake Variables ==
 
The prototype bundle generator uses the following variables:
 
* CPACK_PACKAGE_FILE_NAME - provides the name of the final compressed disk image (the name of the file that is distributed).
* CPACK_PACKAGE_ICON - provides the icon for the mounted disk image (appears after the user mounts the disk image).
* CPACK_BUNDLE_NAME - provides the bundle name (displayed in the finder underneath the bundle icon).
* CPACK_BUNDLE_ICON - provides the bundle icon (displayed in the /Applications folder, on the dock, etc).
* CPACK_BUNDLE_PLIST - path to a file that will become the bundle plist.
* CPACK_BUNDLE_STARTUP_COMMAND - path to a file that will be executed when the user opens the bundle.  Could be a shell-script or a binary.

Latest revision as of 15:41, 16 September 2008