Sol's Graphics for Beginners

Appendix A - Releasing on OS X

(last revised 5. July 2005)

Note: Apple has published a new "installer policy" paper after this appendix was written).

Note2: SDL distribution for osx has changed since this tutorial was written, so at least some of the material in this chapter is out of date.

If you're new to Mac OS X programming (like I am at the moment), you're bound to hit a couple of problems when wrapping up your software product for release.

Since I'm new to this stuff while I'm writing this, some of the advice I'm giving is bound to be misleading.

Let's say that you have your SDL application ready, and you want to give it to someone else. In windows or linux, this would mean (at bare minimum) that you just compile with release options on, zip things up and give it to someone. On a mac? Not (quite) so fast.

To be honest, if you weren't using SDL, it might be almost that fast, but since you (most likely, since you're reading this) are, keep reading.

The Mac OS X software is typically distributed in bundles. A bundle consists of a directory structure under which application stores the executable, resources, private frameworks and private dynamic libraries.

As an example, open Finder, and go to Applications. Control-click on Sherlock (or any other application, really) and select 'show package contents'. This causes Finder to go to the directory. If you try the same in a console, you'll find that the application is actually just a normal directory with a certain directory tree structure under it.

Note the MacOS and Resources directories. These contain the application's executable and its resources.

We want to make one of those out of our SDL app. We actually already have, if we've been using xcode - it's in the 'build' directory under the project directory.

If you copy that .app to someone elses' system, and they don't have SDL installed (or any other dynamic libraries or strange frameworks that you might be using), the application won't launch.

You have a couple of options. First is to ask anyone who wants to try your application to install SDL. The second, much nicer option in my opinion, is to turn SDL into a private framework, hidden under the .app tree structure.

On other systems (like linux or windows) this would basically mean copying the dynamic libs to the same directory as the executable. On OS X we'll need to perform a couple of extra steps.

First, do one experiment. Start a terminal, go to the MacOS directory of your SDL application (inside the bundle), and run "otool -L ".

This will list the libraries the binary is using. As you can see, OS X refers to the libraries with an explicit path. There's an install_name_tool that can be used to patch executables if you're desperate, but it's better to set up the install paths properly at build time.

Now, that wasn't exactly an option when I installed SDL, since I didn't compile it yourself. (This situation may have changed in the later builds of SDL, so you may not have this problem). Again, there's two things you could do; either make a shell script that is run at build time that patches the executable and also the SDL's dynamic library to point at the 'private directory', or you could download SDL's source package (the .tar.gz one) and compile it yourself.

I opted to compile it myself. There's a README.MacOS (or some such) in the package which explains how SDL can be compiled under OS X. Once you have the xcode project open, go to the target settings and find the INSTALL_PATH. Change its setting to "@executable_path/../Frameworks" (without the quotes). The @executable_path is a magic string that OS X replaces with the path to your executable - and that's the MacOS directory under your bundle. Thus, the above goes up one directory and then dives into Frameworks.

Next, we want to copy the framework under our bundle. Go back to your own project and create a new copy build phase (project->new build phase->new copy build phase), and set it to copy files under 'Frameworks'.. This build phase will appear in the file tree as "Targets/yourapp/Copy Files". Drag the SDL framework to the "Copy Files" folder. Now when you build the application, the framework is copied to its correct place (under the 'Frameworks' inside your .app bundle).

Next, add all the data files your application needs into the project the same way as you've added any source files. Move these under the 'Resources' folder in the file tree. The files will then be copied to the 'Resources' directory in your bundle.

Your application won't find the files, though, so you'll need to edit the SDLmain.m (under 'Classes') to change to the Resources-directory. It's in Objective-C, but don't worry, the changes are pretty simple. Open the SDLmain.m and find setupWorkingDirectory. Replace the "../../../" with "../Resources".

Since we want to change to this directory regardless of whether we've been launched from the Finder or otherwise, find where the setupWorkingDirectory is called and replace gFinderLaunch with 1.

If everything went correcly, your app bundle should, after these changes, work fine on any OS X machine. If you're using some other dynamic libraries (such as SDL_Mixer), you'll have to repeat the same kinds of steps for each library.

Next, let's add an icon. Design a 48x48 icon as a transparent GIF or PNG with an alpha layer (this isn't neccessarily the best way to go about it, but I've found it works). Run Icon Composer (under /Developer/Applications) and insert the image as all of the icon versions. Accept scaled versions and extract alpha masks. (You could create separate icons for all sizes, naturally, to get the smaller versions to look better).

Save the icon under your project, and go to your project's target settings, and go to info.plist Entries->Simple View->Application Icon. Type the name of the icon file, including its .icns extension, to the field. Close the settings and add the icon file to your project, and move it under the Resources.

Now you should have the icon on your .app bundle. You may have noticed the infoPlist.strings file under Resources. Open it. You may wish to adjust the strings listed in the file.

You may wish to ajust the compile settings to drop the debug symbols, but apart from that, your application is starting to be ready for release.

Finally, let's package the app into a compressed disk image. This is possible using the 'disk utility' application, but let's go through how to do it in the console.

Create a new directory and copy the app bundle there from under the build directory. Copy any documentation or other end-user accessible files to the same directory. Start up a console, and run:

hdiutil create -srcfolder AAA -format UDZO -imagekey zlib-level=9 BBB.dmg

where AAA is the path to the directory where you compiled the distributables, and BBB is the name of your package. UDZO stands for the compression method; OS X Tiger adds UDBZ compression, which is slower but typically compresses (slightly) better. If you're distributing only for Tiger or later, you may wish to try it out.

After this, you should have a BBB.dmg (or however you named it) which can be mounted by double-clicking it in Finder, and the user can copy your bundle to their system by dragging.

And that's it!

Any comments etc. can be emailed to me.