Using Make To Build OSX Apps
by Sebastien Mirolo on Sat, 3 Oct 2009XCode is a great Development Environment; it is great for edit/compile/run cycles. For nightly packaging, testing and Quality Assurance so far I have not found anything better than fully automated systems built around regular makefiles and shell/python scripts. To find out how to write a make-oriented system to build OSX applications, best is to download an example project and start playing with it.
I downloaded the SlideShow Sample Code, built it with the provided XCode project and start looking around what files got produced.
A familiar QuartzComposerSlideShow.app file had been generated in build/Debug.
[host]$ cd build/Debug && find . -type f QuartzComposerSlideShow.app/Contents/PkgInfo QuartzComposerSlideShow.app/Contents/Info.plist QuartzComposerSlideShow.app/Contents/MacOS/QuartzComposerSlideShow QuartzComposerSlideShow.app/Contents/Resources/English.lproj/MainMenu.nib/objects.nib QuartzComposerSlideShow.app/Contents/Resources/Transition.qtz
A make-oriented system will thus have to produce those files as well. Transition.qtz is already present in the source directory so it is straight forward to copy at the right place. Other files, we need to figure out how to produce. Since gcc is used to build the executable, there is surely a log somewhere with information about the XCode build.
[host]$ grep -rl gcc build/
The file build-state.dat looks promising. We can find lines to build main.o from main.m and build QuartzComposerSlideShow from main.o. The line to produce MainMenu.nib/ can also be executed on a shell prompt and produce the expected file. PkgInfo and Info.plist are both created with builtin-infoPlistUtility which does not seem to be a command line tool. Browsing through the web, it gets quickly confirmed that builtin-infoPlistUtility is internal to XCode and both text files, PkgInfo and Info.plist, are a creator code and an information list that can definitely be easy hand-crafted. Armed with that knowledge, I renamed main.m into QuartzComposerSlideShow.m to take advantage of make pre-defined rules and wrote the following makefile fragment to build the same QuartzComposerSlideShow.app XCode does.
installDirs := install -d installFiles := install -m 644 installExecs := install -m 755 ibtool := /Developer/usr/bin/ibtool TARGET_ARCH := -arch i386 CFLAGS := -x objective-c -arch i386 -fmessage-length=0 \ -pipe -Wno-trigraphs -fpascal-strings -fasm-blocks -O0 \ -mfix-and-continue -mmacosx-version-min=10.6 -gdwarf-2 CPPFLAGS := -isysroot /Developer/SDKs/MacOSX10.6.sdk LDFLAGS := -framework Cocoa -framework Quartz -prebind resourcesDir := QuartzComposerSlideShow.app/Contents/Resources mainMenuNib := English.lproj/MainMenu.nib QuartzComposerSlideShow.app: QuartzComposerSlideShow \ $(resourcesDir)/$(mainMenuNib) \ Info.plist \ Transition.qtz $(installDirs) $@/Contents/MacOS $(installExecs) $< $@/Contents/MacOS echo "echo -ne '????????'" | bash > $@/Contents/PkgInfo $(installFiles) $(filter %.plist,$^) $@/Contents $(installFiles) $(filter %.qtz,$^) $@/Contents/Resources touch $@ $(resourcesDir)/$(mainMenuNib): $(wildcard $(mainMenuNib)/*.nib) $(installDirs) $(dir $@) $(ibtool) --strip $@ --output-format human-readable-text $(dir $<) QuartzComposerSlideShow: QuartzComposerSlideShow.m