Borkware Miniblog

August 25, 2007

In praise of little command-line apps

Filed under: irc, programming — Mark Dalrymple @ 1:54 pm

Folks who have hung around with me know I’m an emacs weenie. It’s not that its necessarily the best tool in the known universe, but it’s what I’ve been using for 17+ years as a paid professional on a number of different platforms, and I’ve developed a number of workflow habits that give me the illusion of being productive.

Central to my daily workflow is having several shell buffers open in my emacs session. This means I can boing from a source file to a shell with a half dozen keystrokes.
One side effect of this is that I can create, use, then forget about little command-line programs extremely quickly. They become great little testbeds. No need to create an Xcode project, or create an Executable in an existing Xcode project. I understand that BBedit and Textmate let you run shells within the editor without any extra baggage, which is all kinds of awesome.

One day on the #macdev IRC channel, someone was complaining (gee, that never happen!) that they tried to NSLog a dictionary, and It Didn’t Work. Someone else, who is ordinarily always correct, suggested that NSLog might send -description to the first argument. I didn’t think so, but wasn’t sure enough to argue. So I hopped over to Terminal, made a little program, and tried it out. Turns out you get a compiler warning if you pass a non-NSString to NSLog, and then the program gets an exception when NSLog tries to send -length to the passed-in object.

Knowledge gained in under a minute.

And now I’ve burned an hour writing about it. Oh well. But I’m waiting on a flight, so it’s time better spent than reading yet another Lord Peter Wimsey novel.

Here’s the program:

#import <Foundation/Foundation.h>
 
/*
gcc -g -Wall -framework Foundation -o logger logger.m
*/
 
int main (void) {
    [[NSAutoreleasePool alloc] init];
    NSDictionary *arg = [NSDictionary dictionary];
 
    NSLog(arg);
 
    return (0);
 
} // main

And it took about a minute from initial question to the acquisition of knowledge, including fixing a syntax error. More sophisticated test programs may take longer, but usually not that much longer.

I do this kind of stuff when playing with a new Cocoa class, too. It’s much easier to cook up a little ad-hoc test case to verify my understanding of some aspect of NSWhatever than to try to scaffold something in a big application.

OK, so what are the important highlights of the code? The first interesting bit is the compile line I’ve got in the comment. Having a compile line in each source file makes it easy to find the file, copy out the compile line, paste it into a terminal and go. No need to modify a project or a central makefile (although those studlier than I with makefiles could make an implicit rule for *.m files, but I’ve already have enough scar tissue on my soul courtesy of make) This also makes it handy for folks who are looking at the code after you put it into a pastebin. No need for them to figure out how to run it. Just save the text, copy the command and then paste it into Terminal.

For folks not familiar with the gcc command, here are the moving parts:

  • gcc : run the C compiler. If you’re doing C++, use g++
  • -g : turn on debugging. You might need to run your program in the debugger.
  • -Wall : turn on a bunch of warnings. If your code has any warnings, don’t ask anyone for help until you fix those warnings. To do otherwise would be rude. Although it’s ok to ask for help if you’re having trouble figuring out what a warning means.
  • -framework Foundation : use the Foundation framework. This lets #import <Foundation/Foundation.h> work, and also satisfy the linker when you use Foundation functions and classes. If you’re using AppKit too, then use #import <Cocoa/Cocoa.h> in the code and -framework Cocoa on the command line.
  • -o logger : create an executable program called logger. If you omit this, the incredibly obvious name of a.out is picked by the compiler.
  • logger.m : the source file to compile.

After that comes the main() function. You don’t need to declare argc and argv if you’re not interested in the command line arguments. After that I usually make an autorelease pool, and then the stuff I want to test. main requries a return, so you gotta add one, or else the compiler will whine at you.

You may have noticed I didn’t use a template file with all this boilerplate stuff already filled out. It’s just a personal weirdism I guess. It takes me longer to find the file, edit the parts that change (whether to use Foundation, Cocoa, or neither; the file name; any additional complier flags like -D), and navigate around than it does to just blort out everything linearly. But I’m a very fast typer and don’t like to wait for personal pipeline stalls when having to make decisions.

Many of the examples in AMOSXP are like this — small stand-alone programs that explore one thing. I’m not sure which came first, doing all of the examples, or using small apps to test something I need to figure out. But no matter where it cam from, I’m a big fan of the technique.

Advertisements

3 Comments »

  1. You could also make an alias for the custom gcc command for building foundation based command line applications. –Kent

    Comment by Kent Sandvik — August 25, 2007 @ 8:09 pm

  2. I do this all the time as well. It’s great for quick research.

    I have a whole directory full of these programs. Since I almost always create these tests in this one directory, I do have a template file in that directory that I always copy.

    If you don’t want to deal with finding the template, just make an alias or script that will copy it from some known location to the current dir. Also, I just default to Cocoa as I can stick in Foundation and Carbon code in as needed. For most tests, it’s rare when I need to keep the dependencies tight.

    Comment by Paul Kim — August 25, 2007 @ 8:22 pm

  3. Another idea, write a script that scans the file for the compile command and executes it. Call it something like “compiletest”.

    At least for those of us that aren’t always parked in emacs, it saves having to copy and paste it out of the file.

    Comment by Paul Kim — August 31, 2007 @ 1:45 pm


RSS feed for comments on this post.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.