Archive for the ‘Personal’ Category

Fewer feeds, more favorites on average

Sunday, August 19th, 2007

Despite what I said in my comment, I did end up taking Daniel Jalkut’s message to heart.

To an extent. A tad.

Basically, I cleared out some dead and abandoned feeds. I added a few new ones too. Sorry Daniel, I’m incorrigible! I’m also an enabler: for all you news junkies out there, get your fix by downloading the updated opml of my Favorite Feeds, available in the sidebar of my blog. Go ahead, just browse a bit. Once you develop a taste for syndication — by a taste for I mean an addiction to — you’ll need a powerful feed reader. And then … well, that’s about it.

Embedding frameworks in loadable bundles

Saturday, August 11th, 2007

While I worked for Marko Karrpinen & Co. I only made one commit to BaseTen, but as Sappho would say, that one was a doozie! BaseTen is an open source Cocoa framework for PostgreSQL. It has an API resembling Apple’s Core Data framework, which uses SQLite. You can check out the source and build BaseTen.framework as well as the optional BaseTenAppKit.framework and an Interface Builder palette, BaseTenPalette.palette. (By the way, I abhor Interface Builder. Or at least Interface Builder 2. I’ll reserve judgment on Interface Builder 3 until I learn more about it, and only then will I abhor it.) The frameworks are designed to be embedded within your application’s bundle, in the standard location for embedded frameworks: the directory Contents/Frameworks.

An app needs to know how to locate linked frameworks at runtime, so at compile time the app’s executable gets a record of each linked framework’s install name. An install name is, as you should expect by now, not a name. It’s a path, namely, the location of the dynamic library containing the framework’s code. To be exact, the install name is where the library should be at runtime, for a library wouldn’t even need an install name if it just indicated where the library actually is at compile time. Install names enable you to target Panther, for example, while still compiling with Tiger. You can use the command-line otool -D to see that the install name of

/Developer/SDKs/MacOSX10.3.9.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation

is

/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation

Using absolute paths for install names is fine when your app links against system frameworks, which reside in pre-determined locations, but absolute paths won’t suffice when your app links against embedded frameworks, because the app could be installed almost anywhere in the file hierarchy, e.g., ~/Desktop or /Volumes/MyDistributionDmg. That’s why an embedded framework needs a relative path install name. The BaseTen and BaseTenAppKit projects achieve this by setting the build setting INSTALL_PATH (what else would you do with a build setting but set it?) to @executable_path/../Frameworks. The relative @executable_path is the path to the Contents/MacOS directory in your application’s bundle. When BaseTen is built with that build setting (to answer my last question, you would build with it), the install name of the framework becomes

@executable_path/../Frameworks/BaseTen.framework/Versions/A/BaseTen

as you can verify with otool -D. Thus, when your app links against BaseTen.framework and records the install name, it can find the framework in its own bundle at runtime.

BaseTen’s IB palette needs to use the BaseTen frameworks too. The problem, however, is that if the frameworks are built to be embedded in an application, they aren’t configured correctly to be embedded in the palette. When Interface Builder launches it will fail to load the palette, logging an error:

Interface Builder[29996] *** -[NSBundle load]: Error loading code /Users/jeff/Library/Palettes/BaseTenPalette.palette/Contents/MacOS/BaseTenPalette for bundle /Users/jeff/Library/Palettes/BaseTenPalette.palette, error code 4 (link edit error code 4, error number 0 (Library not loaded: @executable_path/../Frameworks/BaseTen.framework/Versions/A/BaseTen
  Referenced from: /Users/jeff/Library/Palettes/BaseTenPalette.palette/Contents/MacOS/BaseTenPalette
  Reason: image not found))

The reason that the image is not found — the reason behind the reason — is that the executable in this case in not actually BaseTenPalette but rather Interface Builder itself, which is trying to load the palette. The @executable_path leads to

/Developer/Applications/Interface Builder.app/Contents/MacOS

but BaseTen is embedded in

~/Library/Palettes/BaseTenPalette.palette/Contents/Frameworks

so the install name doesn’t locate the framework at runtime.

In Tiger, the relative @loader_path was introduced to supplement @executable_path. The @loader_path is relative to the image loading the dynamic library, wherever that image may be. Thus, if we change the install name of BaseTen to

@loader_path/../Frameworks/BaseTen.framework/Versions/A/BaseTen

and the install name of BaseTenAppKit to

@loader_path/../Frameworks/BaseTenAppKit.framework/Versions/A/BaseTenAppKit

then BaseTenPalette should be able to locate the frameworks when Interface Builder launches. Problem solved, right?

If you’ve already skipped ahead to the end of this post, you’ll know that the problem is not solved. (Spoiler alert: Harry drops out of school to follow Trey Anastasio.) We’ve eliminated one error only to find another:

Interface Builder[2599] *** -[NSBundle load]: Error loading code /Users/jeff/Library/Palettes/BaseTenPalette.palette/Contents/MacOS/BaseTenPalette for bundle /Users/jeff/Library/Palettes/BaseTenPalette.palette, error code 4 (link edit error code 4, error number 0 (Library not loaded: @loader_path/../Frameworks/BaseTen.framework/Versions/A/BaseTen
  Referenced from: /Users/jeff/Library/Palettes/BaseTenPalette.palette/Contents/MacOS/../Frameworks/BaseTenAppKit.framework/Versions/A/BaseTenAppKit
  Reason: image not found))

Whereas BaseTenPalette can now find BaseTen at runtime, BaseTenAppKit cannot. They both have a record of BaseTen’s install name as

@loader_path/../Frameworks/BaseTen.framework/Versions/A/BaseTen

but they don’t have the same @loader_path.

At this point, you may throw up your hands and throw in the towel, exclaiming Alas, BaseTen cannot have two install names! — or some such exclamation perhaps not suitable for children. (Oh rat farts!). Yet your exclamation would be in vain, because the install name of the dynamic library doesn’t matter after linking. All that matters is the install name recorded in the linked executable, and that can be forged.

Apple provides the nefarious command-line install_name_tool to forge install names for dylibs and give them fake id’s. This is how frameworks get into bars, since there are very few that are twenty-one years old. You can examine the details of my fix in the BaseTen Trac, but basically what I did to allow BaseTenAppKit to find BaseTen was to run the following command in a build phase script for BaseTenPalette:


install_name_tool -change \
	"@executable_path/../Frameworks/BaseTen.framework/Versions/A/BaseTen" \
	"@loader_path/../../../../Frameworks/BaseTen.framework/Versions/A/BaseTen" \
	"$TARGET_BUILD_DIR/$FRAMEWORKS_FOLDER_PATH/BaseTenAppKit.framework/Versions/A/BaseTenAppKit"
	

I discovered the correct install name through a stroke a genius, or to put it another way, trial and error. The @loader_path for BaseTenAppKit turns out to be

~/Library/Palettes/BaseTenPalette.palette/Contents/Frameworks/BaseTenAppKit.framework/Versions/A

which makes sense in retrospect, but if you could guess ../../../.. on your first try, you’re a superfreak. Anyway, you can check the install names before and after with otool -l, or succinctly with otool -L.

Caveat developtor: for install_name_tool to work, you may need to build your frameworks with the option -header-pad_max_install_names. BaseTen already does this. See the man pages for more information, man.

What I’ve been doing recently

Saturday, July 21st, 2007

I’ve been asked what I do for a living by a number of my loyal fans. For example, two of my parents. (The third doesn’t care.) Deplorably, I receive no residuals from “The Distinguished Gentleman”, so I guess that I’m a working man. I tried working for no pay, but as rewarding as that was, I couldn’t get my landlord to appreciate the value of my contributions to the open source community. Therefore, I had to sell out to The Man.

The man, in this case, was Marko Karppinen. Marko, you Da Man! Paul, you de Man. When I joined Marko Karppinen & Co., the hazing began immediately: my first assignment was to implement full disk encryption. I also had to purify myself in the waters of Lake Päijänne. I must have passed the initiation, though, because Knox 1.5 is here. It kicks ass! (It sure kicked my ass.) If you don’t believe me, you can download and try it yourself free for 30 days. Launch it from the distribution dmg for kicks. Knox makes encrypting your data effortless, disproving the proverb that you can’t put a price on security. In my opinion, Knox is under-priced, and I’m not saying that because I’m financially compensated by MK&C. Actually, I’m not financially compensated by MK&C.

No, Marko isn’t holding my cats hostage for code. I decided to leave the company recently to pursue another opportunity. Plus, the daily commute to Helsinki was kind of long. I left on good terms, hopefully, and I miss those Pyro-maniacs, my fellow MKCKittens (inside joke). They’re a great group of folks! The strangest aspect of my job was that I never met my coworkers, since I quit right before WWDC. D’oh! I like to imagine that the gang at MK&C is exactly like Dethklok. Did anyone see Toki at the Moscone Center? I guess that makes me Pickles, or maybe the rock & roll clown.

It should be noted that according to my careful tests — I checked my gut and Wikipedia — Knox 1.5 was entirely bug free when I finished. By that irrefutable logic, therefore, any problems that you think you may experience with Knox 1.5 are purely imaginary, and you should ask your doctor about Thorazine. I cannot say the same, however, about that whole Master Control Program I wrote, which got a little out of hand.

My other major project at MK&C was Pyro 1.6. If you use Campfire chat, then Pyro will blow your mind. Or anyway, it significantly enhances the experience. Among the new features Pyro 1.6 introduces is instantaneous switching between multiple chat rooms. (I’m partial toward automatic zip-archiving and uploading of folders and packages.) If you don’t use Campfire, you and your company should give it a try. We used Campfire extensively for internal communication and for customer support.

By the way, there are apparently some problems with Pyro under the deceptively-named Safari 3 beta. That’s not our fault, because Apple released it without any advanced notice to developers. The so-called Safari beta is actually an update to the WebKit system framework, affecting any application on your computer that uses WebKit, not just Safari. The Safari beta has caused problems for other apps too, including Vienna and Apple’s own Mail and iChat, so apparently it was a secret within Apple as well, or they didn’t test it enough. Brutal.

Ranting aside, I’d like to thank Marko for letting me hack on his public-facing apps. Not only would I like to thank him, but I shall. Thanks, Marko! I hope that he and everyone else enjoy the results. Now I must move on and take the next step in my goal of total world domination … by cats.

A nice pair of updates

Sunday, June 24th, 2007

I’ve updated my list of Favorite Feeds, which you can download from the sidebar of my blog. The list is in opml format, so you import it into feed readers such as Vienna. And speaking of Vienna, a new beta version of Vienna 2.2 has just been released. If you’re an intrepid or foolhardy type, you can download it from SourceForge. Beware: this is a pre-release version we’ve released. That’s impossible and therefore pretty scary in itself. Moreover, Vienna 2.2 hasn’t been fully tested. It’s certain to have bugs, perhaps an STD or two. We take no responsibility if your computer decides to start playing Global Thermonuclear War; in that unfortunate event, set the controls for the heart of the sun.

Working without a nib, Part 2: Also Also Wik

Monday, June 4th, 2007

I apologize for the fault in the subtitle. Those responsible have been sacked. What I intended to say was that I’ve discovered the Holy Grail of Cocoa hacks: how to create a functional Cocoa application without any nib. In Part 1 of this series, I suggested that you needed a nib for the main menu of the app; some would even argue that having a nib is the essence of a Cocoa app. It turns out that I was wrong, and some (they, the unspecified straw persons) were wrong too. I apologize for any faults in my previous post. Those responsible would be sacked, but those responsible for sacking have just been sacked.

As you may recall if you have a photographic memory or nothing better to do, the main problem with getting rid of nibs is setting the application menu. I had been using a minimal nib as a workaround, but now I have a reliable, though undocumented, solution to the problem. I came upon the solution by using gdb and JJApp (along with a herring) to override initWithCoder: while the main menu is loaded from a nib. The class NSMenu has a private ivar _name, declared in /System/Library/Frameworks/AppKit.framework/Headers/NSMenu.h, that is usually nil, but a few menus — including the application menu — have a string value for the ivar. Although there are no public accessors, we can set the value anyway through the magic of key-value coding. For example, I called setValue:@"NSMainMenu" forKey:@"name" on my main menu and setValue:@"NSAppleMenu" forKey:@"name" on my application menu. This must be done before the return of -[NSApplication finishLaunching], otherwise it will have no effect. I find applicationWillFinishLaunching: to be a good place to set your main menu.

Another caveat is that the old deleting-the-nib trick doesn’t work at all if you change NSPrincipalClass in Info.plist. When I set it to my NSApplication subclass, the app refuses to launch, complaining, No NSMainNibFile specified in info dictionary, exiting. Strangely, it works fine if I leave NSPrincipalClass alone and call [[JJApplication class] poseAsClass:[NSApplication class]] in main.m. A special treat is that Cocoa automatically adds the Special Characters item to the Edit menu at runtime. Thanks, Cocoa! You can see all of this yourself by downloading my sample Xcode project, Nibless. If you use my code in your app, I may sue you, or I may kiss you. In either case, it’s a risk you’ll have to take. (It!)

Despite the fact that my solution is for the most part unsupported by official API (consult the book of armaments!), there’s good reason to think that it’s stable and should survive Leopard at least. Apple is unlikely to remove an ivar from such an important class as NSMenu. More important, the value of the ivar seems to be the way that archived menus indicate their function to Cocoa and to Interface Builder, as reflected by the “Special Menus” setting in the Inspector. Try opening keyedobjects.nib with BBEdit, and you’ll see that the file is just a plist containing definitions of the objects in the nib.

In Part 5 of this series — sorry, Part 3 — I’ll investigate the cause of the log message Could not connect the action buttonPressed: to target of class NSApplication when launching without a nib. I’ll also attempt to populate the Open Recent menu. The Clear Menu item seems to work, but for some reason I can’t get items to appear in the menu. So, um, anything that you could do to help would be very helpful.

I’d like to end this post on a personal note. Many of my legions of fans have sent emails asking for more information about me: birth date, hobbies, pet peeves, dress size, etc. I prefer not to start a cult of personality, but I’ve decided that you, the heroes, deserve something. Thus, I’m going to share one particularly juicy tidbit. My favorite color is … blue. No, yellooooooooow!

Selectors and performance anxiety

Sunday, March 25th, 2007

As I sit on my front porch looking at the 73° temperature (K, since I live on Neptune) in the weather widget on my new MacBook Pro, I can’t help but think that life is good. Yet there’s a nagging voice in the back of my head, reminding me of unresolved issues. Wait, that’s the cat wanting to come outside. In addition, I hear the echoes of Jim Kerr. Let’s forget about them, though, and talk about -[NSObject performSelector:withObject:afterDelay:]. This has absolutely nothing to do with my previous post, honest. You can trust me, because we Neptunians (Neptunites? Neptuners?) cannot lie. We’ve been known to exaggerate, but only once every billion years or so.

The question on all of our minds, at least those of us not suffering from March Madness (to be followed no doubt by April Antisociality and May Melancholy), is what happens when you call performSelector:withObject:afterDelay: with a delay of (NSTimeInterval)0.0 during application launch. It turns out that you can call this successfully pretty much anytime, even during -[NSApplication init], in which case the currentRunLoop will be created immediately rather than during -[NSApplication setServicesMenu:]. It’s also safe to call this as late as during the delegate method applicationDidFinishLaunching:. Regardless of when you call performSelector:, the selector will be performed during -[NSApplication nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantFuture] inMode:kCFRunLoopDefaultMode dequeue:YES] — not the first one, which returns an NSApplicationActivatedEventType, but the one after that. The second one returns an event of type NSFlagsChanged, but I’m not sure whether that matters.

If you call performSelector: multiple times during launch, the selectors will be performed consecutively, during the very same nextEventMatchingMask:, in the order in which they were set up to be performed. Everything seems to happen before any user events — keyboard, mouse, interface licking — are processed. Thus, my conclusion is that -[NSObject performSelector:withObject:afterDelay:0.0] is a safe and effective way of scheduling methods to be performed after application launch but before the user starts wrecking stuff and wreaking havoc. Of course, I also believed that beer was a safe and effective antiseptic, so take my conclusion with a grain of salt … just not in your wound.

Remember, Jim, ice cream is a dish best served cold.

Favorite Feeds updated

Sunday, February 11th, 2007

I’ve updated my list of Favorite Feeds, which is available from the Downloads category in the sidebar of my blog’s front page. It’s in .opml format for easy import into Vienna and other feed readers. The list includes a rather large collection of Cocoa developer blogs, if you’re interested in that kind of thing, and I assume that you are, because you can’t be here just for the jokes.

Speaking of Cocoa developer blogs, I do have a backlog of content that I plan to publish. Really. I’ve confronted a number of coding issues over the past few months that nearly (you be the judge) drove me insane, so I feel an obligation to write about them in order to preserve, or at least not worsen, your mental health. Stay tuned! Don’t take me off your speed dial.

Now back to our regularly scheduled static…

WordPress Bug Fix!

Saturday, January 20th, 2007

This is the first post in what I hope is a series, which I’ll call “WordPress Bug Fix Near Saturday”. And while I’m naming things, I’ll call this first post “Episode IV: A New Hope” (to be followed, no doubt, by “Episode V: All Hope Dashed”). I’m very happy to report that the ETag parsing bug has been fixed in WordPress 2.0.7. Thus, if you’re running WordPress 2.0.7 on your site, you no longer have to comment out the following line in the file wp-includes/classes.php:

@header("ETag: $wp_etag");

My logs confirm that WordPress is now correctly parsing its own ETags and sending out HTTP 200 and 304 responses as appropriate. The Penultimate Warrior is victorious and undefeated! Note, however, that none of the bugs that I reported before the Warrior started Running Wild® (cp. Going Wild®) have been fixed yet.

Speaking of my web site logs, they contain a list of phrases that were used to find my site from internet search engines. I’d like to share a few of them that have caught my eye:

  1. instructions+for+using+the+thighmaster

    Squeeze, release, repeat. You’re welcome.

  2. how+do+u+declare+a+pointer+to+an+array+of+pointers+to+int%3f%3f+in+c+language

    int * (* ptr)[];

  3. talk+to+cat+software

    That doesn’t exist, Dr. Doolittle. Try meowing.

  4. cat+lederhosen

    I’ve given your IP to the SPCA.

  5. betamax+the+sausage+and+the+mouse

    These aren’t the droids we’re looking for.

  6. what+does+ns+stand+for+i+cocoa

    NeXTSTEP. Next!

  7. circle+k+employee+uniforms

    I’m so very sorry, dude.

  8. if+jeff+s+usual+is+a+hint+for+a+password+what+is+the+password

    Stop trying to hack into my account, you scoundrel!

Leopard Tech Talk: Postlude

Thursday, December 14th, 2006

If you think that America is a free country, try driving through Illinois. Their state motto is Give us all of your spare change. As I mentioned before, one of the Mac OS X Leopard Tech Talks was held in Chicago yesterday. (Except that it wasn’t yesterday when I mentioned it before.) I was there, and I had a good time. As you would expect, security was tight: I was asked for my name before receiving a name tag. Apple was kind enough to provide food and drink for the free event, which was much appreciated, though the NDA prevents me from disclosing the items on the menu. I will, however, reveal the latest secret Leopard feature. I can confirm that seeded builds now include a Spotlight-searchable C++ GUI Programming Guide. Thanks, PC guy!

I believe that I can also reveal, since I discovered this information myself by testing, that Vienna is Leopard-ready. Or at least, nothing appeared broken when I played with it for 5 minutes. Yay!

I met a number of people at the event, including fellow blogger Geoffrey Schmit of Sugar Maple Software. The biggest celebrity was Sal Soghoian, AppleScript product manager for Apple. Indeed, he was so famous that he wasn’t required to wear the standard Apple employee uniform, or the 15 pieces of flair. To their credit, the ’software evangelists’ who gave the tech talks were open and honest. They answered my questions, and they also convinced me to shave my head and dance with an iPod at airports. I would like to thank them, as well as Apple for bringing the show on the road to a location near me.

All I can really say about the content of the talks is that Leopard has a lot of cool stuff for developers. I’m tempted now to get an ADC Select Membership, so that I can receive seeds. (In case you’re wondering, Leopard seeds are not distributed to the attendees of Leopard Tech Talks.) Perhaps that was their insidious purpose. Anyway, I would recommend attending if there’s a Leopard Tech Talk in your area. Amen!

Leopard Tech Talk: See you in Chicago

Friday, December 1st, 2006

I’ve received a confirmation email from ADC that I can attend the Leopard Tech Talk in Chicago on December 13. Thanks, Apple! I’ll try to ensure that Vienna is Leopard-ready.

If you’d like to meet me there, let me know. I should be conspicuous as the only poor soul without a laptop.