Using Make To Build OSX Apps

by Sebastien Mirolo on Sat, 3 Oct 2009

XCode 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 file had been generated in build/Debug.

[host]$ cd build/Debug && find . -type f

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 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	:=
mainMenuNib	:=	English.lproj/MainMenu.nib QuartzComposerSlideShow 	\
		$(resourcesDir)/$(mainMenuNib) 		\
		Info.plist 				\
	$(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

by Sebastien Mirolo on Sat, 3 Oct 2009