Cocoa development in Emacs - Part 2
Cocoa programming In Emacs
EditingJust edit your source files as usual in Emacs. If your Objective-C files end with ‘
.m’, you’ll automagically be put into Objective-C mode. I find the default Objective-C formatting to be annoying. (I like four-space indentation.) In your
(c-set-style "bsd")– you can then use
[tab]to indent the code just like in C mode. It’ll auto-format Objective-C methods with multi-line arguments thusly:
[image drawAtPoint: NSZeroPoint fromRect: NSMakeRect(0, 0, WIDTH, HEIGHT) operation: compositingOperation fraction: 1.0];... left-aligning and indenting all of the method names. Like C-mode you’ll need to do the dirty work of pressing
[ret] [tab]after each line as you’re entering the code. If you want the arguments to line up too, you can force-include tabs by doing
C-q [tab]. That’ll insert a tab character (which Emacs then interprets as a spacing operation) rather than having the tab interpreted as a command to indent the line. One handy shortcut:
C-iis the same as the
[tab]key, but it’s a whole lot easier to do
C-q C-ithan to do
Depending on your Emacs mojo, you can set up various bits of magic
to automatically create headers,
NSView subclasses and
other conveniences that Project Builder has. I find those annoying
(I’m easily annoyed, if you couldn’t tell already) and always
ended up deleting what Project Builder made for me anyway.
The compiling command I use relies on Project Builder having a list of involved files in the Files pane of the project window. To support this, I create the files as usual in Emacs. When it comes time to sticking them into the project, I open a Finder window to my source directory and drag the files into the appropriate place in the Project Builder window (which I keep minimized to hide the jazz I don’t use – see the window up there in my workspace screen shot). This has the nice side effect of letting me organize the files in Project Builder for public consumption (making nice little hierarchies) while freeing me of actually having to *use* nice little hierarchies that require extra time to open and close when looking through them.
Now to the good stuff. To build in Emacs, run the program
in a shell buffer in which you’ve changed to the directory where your
Project Builder file lives. (translation:
cd ~/Development/cocoa/Greeble). This command will
a lot of spew. If you have syntax errors, the build will stop after
the first file and say something like this:
BWQuartzViewDemo.m:88: illegal function call, found `;’ cpp-precomp: warning: errors during smart preprocessing, retrying in basic mode BWQuartzViewDemo.m: In function `DrawStarburst': BWQuartzViewDemo.m:8: warning: unused variable `i&'; BWQuartzViewDemo.m: In function `-[BWQuartzViewDemo drawRect:withContext:]': BWQuartzViewDemo.m:88: parse error before `;' ...failed CompileC /Users/markd/Development/Borkware/GrafDemo/build/GrafDemo.build/GrafDemo.bui ld/Objects/ppc/BWQuartzViewDemo.o ... ** BUILD FAILED **
What had happened was that I forgot to close a parenthesis on line 88,
and it looks like I got a bit sloppy on line 8 by leaving an unused
variable. (Bad Bork!) What I’d do upon seeing this is go to the
BWQuartzViewDemo.m (see random hints for moving between
buffers easier), jump to line 88 and assess the problem (which
is usually just something dumb). You can go to line 88 by using
M-x goto-line [ret] 88 [ret]. That’s too
much typing, so I have a key binding to use –
C-x n – as
I thank the BooBooHead for this idea. Stick this in your
(global-set-key "\M-n" 'goto-line)
Granted, this is a little more work than clicking a bright red error line in one of the sliding Project Builder tabs. I look at it as an incentive to not make mistakes in the first place.
What doesn’t show up very clearly are warnings in source files. Since
they’re not errors they don’t halt the
pbxbuild command, and so
they may get lost in its noise. I could probably write a spiffy Perl
or Python script to filter
pbxbuild and show those warnings,
I’m too lazy to do that. If I happen to cause something like:
BWQuartzViewDemo.m: In function `-[BWQuartzViewDemo initWithFrame:]': BWQuartzViewDemo.m:52: warning: `BWQuartzView' does not respond to `initwithFrame:' BWQuartzViewDemo.m:52: warning: passing arg 1 of `objc_msgSendSuper' from incompatible pointer type
... (note that I dorked the capitalization of init*w*ithFrame), I could
miss that in the
pbxbuild output. After a while you get used
to the style of output from
pbxbuild and you’ll notice the
lines printed for a warning will catch your eye as they scroll past. You
do a reverse search on “warning”, e.g.
By default (at least with the December DevTools), the project depends
on itself, so it will always generate a warning each time you build.
That’s handy to know that you’ve found the beginning of your build and
don’t have warnings. If you do see some warnings, you can see what
they are and fix them. Don’t forget that
M-> takes you
back to the end of your shell buffer so you can get back to the
command line, so checking for warnings (if you even suspect them) is
C-r warn M-> (7 keystrokes) which can be
executed very quickly.
Okay, remember the
!x shell idiom I blathered about earlier?
After you run
pbxbuild the first time, you can run it quickly
again by doing
Now here’s one of those awkward commands that I could wrap in a shell
script, but I choose not to since I’m lazy. (I actually tried a
Python script and a little Cocoa app to do this, and they failed in
weird and wonderful ways, probably due to
stdout not getting set up properly before executing the Cocoa
program. After an hour I stopped).
If you’re in the directory with your project file (like with a
project created by Project Builder), the executable for your
program lives at:
When I first start working with a program in a new shell session,
I have to invoke that full path name on the command line to run
I can hear you booing and hissing. “Where’s your love of few keystrokes? Where’s the speed, man? I don’t want to type that !&@><*e#! in every time."
First off, entering that command string isn’t too hard. You can do it with:
bu [tab] Proj [tab] app [tab] [tab] M [tab] [tab] [ret]
... 16 keystrokes for a 48-ish character string. Not as bad as it looks.
For every subsequent invocation of this program, you can do the two-stroker
(remember that fetches the last command that starts with ‘b’).
So once I get the buffer warmed up with a single:
... and a single: % build/ProjectName.app/Contents/MacOS/ProjectName
... my compile / run cycle is now:
... and do a quick eyeball
... over and over and over (and over) again. I almost never quit my Emacs (or my Terminal.app for that matter) so my shell buffer stays warmed up for days and days (sometimes even weeks if I’m working on the same project), which makes the (not-really-that) onerous initial program launch not as bad has having to do it every single time.
gdb. I’ve used it for over ten years on various Unix projects in my career. Jasik’s The Debugger is about the only other debugger I like nearly as much. (Well, and December’s
ladebugon Digital Unix, back in the day when I was doing multithreaded apps.)
gdb is easy. It’s:
% gdb build/ProjectName.app/Contents/MacOS/ProjectName
Okay, so that’s kind of nasty to have to type in. Remember the
!$ thingie (pick off the last word from a command)? Here’s a
place where it’s
very useful. Assume your Emacs shell buffer is warmed up having done
at least one
pbxbuild and one
... which runs the command
% !b ... which does the command
Oops, you crashed your program by Doing Something. Better run it in
% gdb !$
... which will then do the command
(Okay, okay – you could use
!! also, since
build/ProjectName.app/... is the entire command as well as
being the last word. I like using the mental model of
!$ for file names, and for feeding
you give it a file name, hence I use
!$. I also try not to
think too hard about this kind of stuff. It’s under my fingers, it’s
fast, and it works.)
Here are some quick gdb commands to get you started
help– Shows help.
run– Runs the program.
where– Shows a stack trace (handy if you crash).
The stack trace is newest functions on top, oldest on the bottom. If you have a deep stack, you may need to scroll up. I recommend running gdb inside of an Emacs shell buffer so you can scroll around it like any Emacs buffer.
down– Move up and down the stack frames (moving from function to function on the call stack). You can give these commands a numerical argument to move
break -[ClassName methodName: args:]- Set a breakpoint on a particular method in Objective-C. So, you could do something like
break -[BWCurveCanvas drawRect:]
info breakpoints– See your breakpoints as a numbered list.
del #– Delete a breakpoint.
disable breakpoint #– Disable a particular break point. You can later re-enable it by using
enable breakpoint #.
print someVariableName– Display the contents of a variable.
po someObjectReference– Call the object’s toString method and display it. Note this may be dangerous if the object is trashed.
thread apply all where– See a stack trace for all threads.
list– See where in the code you are.
next– Execute the next statement, not going into functions.
step– Execute the next statement, stepping into functions.
kill– Terminate the program.
quit– Exit the debugger and terminate the program.
detach– Let the program run free and disassociate the debugger.
attach– Attach the debugger to an already running program.
You can also run
gdb inside of Emacs like an IDE
=> in the code to show what line you’re on, setting
breakpoints with a keystroke
in the source code buffer). To do this, use:
M-x gdb [ret]
... give it the path to the program file
in your source code buffer nad do a
C-x [space], which
a break point. Then in the
gdb buffer (called
*gud-ProjectName*, which you can rename to
something more reasonable) enter the
run command. Then
do whatever it takes to trigger your breakpoint.
gdb buffer, do your ‘
next’ commands and see the effect on your source
Personally, I don’t use debuggers very much: usually just when I have
a crasher that I want to see a stack trace for. The command-line
gdb in a shell is pretty much all I use now. If
you do like using debuggers to step through stuff (handy if you’re
dealing with a lot of unfamiliar code, or if you’re billing by the
hour), the IDE mode may serve you well.
One of the cooler things you can do with the command-line
that you can’t do with the current crop of OS/X GUI debuggers is to
ssh into a computer, attach to a running program, and poke
around. Let’s say you have a user that’s consistently having problems
with your GUI app that you just can’t reproduce. Perhaps the office
has a stray Bogon generator.
ssh into their machine (after they give you a login
sufficient privileges), attach
gdb to their running program
and set breakpoints as they mess around with stuff until the code
breaks. They can then minimize the unresponsive windows of your app
while you’re dinking around. They can get on with their work in other
programs until you’re ready for them to do something else.
Random hintsHere are some random hints, shortcuts and techniques I use to optimize my workflow. What works for me might not work for you. The best thing is to just wade in, make mistakes, find out what works (and do it) and what annoys you (and avoid it).
tcshcomes by default with OS X. Unfortunately, sometimes Emacs spazzes out and says:
Warning: no access to tty (Inappropriate ioctl for device). Thus no job control in this shell
... which stinks since you can’t
control-C a program to
interrupt it, and worst of all, programs that prompt for passwords (like
cvs which running remotely) will just not
work – what a pain. One workaround is to use
bash instead of
tcsh. You can get
bash from apple’s
downloads, and make it your shell with:
sudo niutil -createprop . /users/bork shell /usr/local/bin/bash
... or whatever path you specify for
If you have similarly named file names due to consistent nomenclature
(for example, all fine Borkware classes start with
to retype or tab-complete the file names all the time when switching between
them is a royal pain in the ass. If I’m going to be working with a set of
a while, I rename the buffer (which doesn’t affect the name of the
file) to something easier to type.
So say I’m working with the files
BWQuartzDemo.m. Switching between these files is awkward.
What I do is rename the buffers thusly:
BWQuartzView.m : quartz
BWQuartzView.h : hquartz
BWQuartzDemo.h : demo
BWQuartzDemo.h : hdemo
Moving to the .m files requires 4 keystrokes,
C-x b q [tab] [ret] or
C-x b d [tab] [ret], and three of those
keystrokes are overhead you’ll
have to pay no matter what. Moving to the respective .h file requires 5
C-x b hq [tab] [ret], etc.
C-x 2 splits Emacs horizontally. You can have a
different buffer open in each pane (say, a header file above and the C
source code below, or a source file above and the compiling shell that shows
the errors below).
You can also split Emacs vertically with
C-x 3. If you
have a nice big screen, you can make your Emacs window huge and have
your source and header files side-by-side.
You can subdivide these panes as well.
C-x 3 C-x 2 will split Emacs
vertically, then split the left-hand buffer in half (giving you three
panes to play with).
C-x o will move you ‘forward’
through the panes. A buddy of mine from BitWrangler gave me some Emacs magic to
move ‘backwards’ through the panes as well, using
(define-key global-map "\C-xp" 'previous-window) (defun previous-window (&optional back-count) "Select the ARG'th previous window" (interactive "P") (if back-count (setq back-count (prefix-numeric-value back-count)) (setq back-count 1)) (other-window (- back-count)))
Emacs’ incremental search is awesome.
C-s starts the
search, then you type, and the first thing that matches what you’ve
typed up to that point scrolls into view. I concatenate the Foundation Kit
and Application Kit header files into one big “Moby” file. This is
very handy for exploring the API, as well as getting the
argument names and types for a message.
To create the file, execute these two lines of code in a shell:
% cat /System/Library/Frameworks/AppKit.framework/Headers/*.h >
% cat /System/Library/Frameworks/Foundation.framework/Headers/*.h >> ~/moby.h
To find a particular class in there, do an incremental search on the
tab character, like
C-s C-q C-i NSObject