Distributing WxWidgets Applications-Distributing WxMac Programs
(This page is a work in progress)
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'.
See WxMac-specific_topics#Building_a_MacOSX_application_bundle for more information...
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.
Statically compiling
I (ChoJin) used macport to install wxwidgets, but since there isn't any variant (yet) to force a static version I added my own using the following command line:
sudo port edit wxwidgets
Then add the following lines at the bottom of the file:
variant chojin description { build a static version of the libraries with some other options... } { configure.args-append --enable-std_iostreams configure.args-append --disable-shared configure.args-delete --with-sdl configure.args-delete --with-opengl set installtype release-static }
And save and quit
Feel free to remove the following two lines from the variant if you need/want SDL and OpenGL:
configure.args-delete --with-sdl configure.args-delete --with-opengl
Or to rename the variant from "chojin" to your own :)
By the way, by default, the following options are used by the port: --with-libjpeg --with-libtiff --with-libpng --with-zlib --with-sdl --with-opengl --with-mac --disable-sdltest --enable-unicode --enable-display --enable-monolithic so you don't need to specify them.
You can then install wxwigets using the following command line:
sudo port install wxwidgets +chojin
But if you want to compile wxwidgets manually without using macport you could use (for example):
./configure --with-libjpeg --with-libtiff --with-libpng --with-zlib --with-mac --disable-sdltest --enable-unicode --enable-display --enable-monolithic --enable-std_iostreams --disable-shared --prefix=/Users/arnoutengelen/local
Now wx-config should link with the static version of wxwidgets. The problem is it still compiles with a bunch of dynamic libraries (iconv, libpng, libjpeg and so on)
I therefore used the following code in my Makefile (ideally, wx-config should be patched to do it automatically, but I was too lazy to give it a try):
WXCONFIGLIBS := $(shell wx-config --libs) WXCONFIGLIBS := $(WXCONFIGLIBS:-lpng=/opt/local/lib/libpng.a) WXCONFIGLIBS := $(WXCONFIGLIBS:-lz=/opt/local/lib/libz.a) WXCONFIGLIBS := $(WXCONFIGLIBS:-ljpeg=/opt/local/lib/libjpeg.a) WXCONFIGLIBS := $(WXCONFIGLIBS:-ltiff=/opt/local/lib/libtiff.a) WXCONFIGLIBS := $(WXCONFIGLIBS:-liconv=/opt/local/lib/libiconv.a) LDFLAGS := $(WXCONFIGLIBS)
And use LDFLAGS in your linking line.
you can use "otool -L your_binary" to double check you're not linking anymore with any non-standard dynamic libraries.
Enjoy! it worked for me just fine :)
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..)
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...
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
See also WxMac-specific_topics#Packaging_your_Mac_application_up_for_distribution
See also
http://developer.apple.com/technotes/tn2002/tn2071.html http://developer.apple.com/documentation/DeveloperTools/Conceptual/cross_development