Distributing WxWidgets Applications-Distributing WxMac Programs
From WxWiki
(This page is a work in progress)
Contents |
[edit] Creating a Bundle
On Mac, it's nice to distribute your applications as one self-contained 'Bundle'. A 'bundle' is basically a directory with a given structure, typically named 'foo.app', which shows up as a drag-and-droppable, startable 'program'.
TODO: describe this better.
Gotcha: when you change Info.plist, sometimes the information in it is still cached somewhere. A reboot might help, I'm not sure how to do this gracefully.
[edit] Statically compiling
This didn't really work for me.
I compiled wxMac like this:
./configure --disable-shared --enable-monolithic --disable-dynlib --disable-dynamicloader --prefix=/Users/arnoutengelen/local
Now you can simply compile using wx-config, but it will link dynamically to some libraries like libiconv (though this might not be a problem since supposedly this dylib is distributed with any reasonably recent (10.3+) versions of MacOS X). Adding '-static' to the command fails with the following error message:
/var/tmp//ccPTunDf.s:9427:FATAL:incompatible feature used: directive .non_lazy_symbol_pointer (must specify "-dynamic" to be used)
I don't know how to fix that (yet).
[edit] Including shared libraries in the bundle
Luckily the site at http://doc.trolltech.com/qq/qq09-mac-deployment.html explains how to include the shared libraries in the bundle itself:
- Create a Contents/Frameworks directory in the bundle
- Use 'otool -L' (the Mac alternative for 'ldd') to see which shared libs are required
- Copy the shared libraries into it
- For the library:
install_name_tool -id @executable_path/../Frameworks/whatever.dylib demo.app/Contents/Frameworks/whatever.dylib
And for the executable:
install_name_tool -change /path/to/whatever.dylib @executable_path/../Frameworks/whatever.dylib demo.app/Contents/MacOS/demo
- check if that worked with otool
(untested right now..)
[edit] Including shared libraries in the bundle (Verified)
The problem of the method above is that the dynamic libraries themselves depend on the library. With patching the executable only it's not done.
All library-internal cross references have to be removed (replaced) too. The library is linked internally to the major.minor.micro named versions of the dynamic libraries (e.g. libwx_mac_qa-2.6.0.dylib).
To accomplish this task I've written a bash script which is listed here (I haven't found a sourcecode highlighting function for this wiki -- is there any?):
WXLIBPOSTFIX=*wx*2.6.0.dylib
APP=WorldApp
WXLIBDIR=../../../wxwidgets/build-dynamic/lib
BINDIR=./build/Release/$APP.app/Contents/MacOS
LIBDEFDIR=/usr/local/lib
echo "Copying dynamic libraries to " $BINDIR " ..."
cp $WXLIBDIR/*.dylib $BINDIR
echo "Changing directory to " $BINDIR " ..."
export TMP=$PWD
cd $BINDIR
# patch all wx dynlibs and Saracon executable
for file in `ls $WXLIBPOSTFIX`
do
# patch all library internal cross references
echo "Patching " $file "..."
for fileother in `ls $WXLIBPOSTFIX `
do
# library
echo " Patching " $fileother " with " $file "..."
install_name_tool -change $LIBDEFDIR/$file @executable_path/$file $fileother
done
# patch current library itself
install_name_tool -id @executable_path/$file $file
# patch executable
install_name_tool -change $LIBDEFDIR/$file @executable_path/$file $APP
done
cd $TMP
This script can be added for instance to the build phases of XCode or called from within of a makefile. Make sure that's a bash shell. Others might cause errors. Furthermore the executable has to be linked with the
-headerpad_max_install_names
option enabled to ensure install_name_tool will work correctly (otherwise complications may arise due to the fact that there is no room for the new pathnames in the executable)
The following variables are required:
- WXLIBPOSTFIX: The wx dylib pattern which matches the desired version and wx-internal cross references.
- APP: The executable name.
- WXLIBDIR: Directory of the wxWidgets dylibs (can also be a system directory when installed)
- BINDIR: Directory of the executable AND dylibs (it's a limitation of this script but it can be adapted easily)
- LIBDEFDIR: Default dylib directory when linking (ususally it's '/usr/local/lib'). It can be found out when inspecting the crash report...
[edit] Creating a .DMG
http://www.stepwise.com/Articles/Technical/2001-03-29.01.html describes how to package your application as a DMG. This seems to be slightly outdated though. The steps I'm using are:
- hdiutil create -megabytes 10 -layout NONE Pathalizer.dmg
- hdid -nomount Pathalizer.dmg
- newfs_hfs -v pathalizer /dev/disk1
- hdiutil eject /dev/disk1
- hdid Pathalizer.dmg
- cp -r Pathalize.app /Volumes/pathalizer/
- eject using finder
[edit] See also
http://developer.apple.com/technotes/tn2002/tn2071.html http://developer.apple.com/documentation/DeveloperTools/Conceptual/cross_development
