Category: Carbon

Weak Linking

December 5th, 2007 — 6:05pm

It’s been a while since I posted. Since then, Leopard has been released and it’s been keeping me busy. Now that I’ve finally upgraded my dev machine to Leopard, I’ve started implementing Leopard-specific functionality. I still want to maintain Tiger-compatibility but there are cases where I need to reference new symbols in Leopard. These articles 1 2 tell you what you need to know, though I thought I’d provide a boiled down guide to what you need to do.

For the purposes of this article, we’ll assume we want a binary that will run on Tiger or later but have access to Leopard-only functionality. In this case, the deployment target is Tiger and the Target SDK (which API version you are using) is Leopard.

  • In Xcode, Project->Edit Project Settings->General. For Cross-Develop Using Target SDK, select the latest OS version whose features you want to use. In this case, Mac OS X 10.5
  • targetsdk.png

  • Click on the Build tab. Make sure the Configuration pop-up is set to All Configurations. Set Mac OS X Deployment Target to the minimum OS version you want to support (Mac OS X 10.4).
  • deploymenttarget.png

In most cases, this is all you need to do. Why’s that? It’s because Apple defines Availability macros that they use to set what symbols are available for different OS releases, based on the settings you just made above. If your target SDK is a later version than your deployment target, the symbols unique to the later target are weak-linked. This means that if the symbol does not exist, it will be set to NULL. As indicated in the articles linked above, you can compare these symbols to NULL before using them. Note that this mostly pertains to things like C functions. For Objective-C, you can check for the existence of classes using NSClassFromString(). For methods, just use -respondsToSelector:. What this all allows is for your program to dynamically use Leopard-specific functionality if it’s available. You can test for specific functionality without relying on doing a broader OS version check.

Of course, there are cases where things don’t work out of the box. For instance, it seems the headers for some lower level APIs aren’t set up with the Availability macros. In such a case, you can do your own prototype, this time asserting the weak linking:

extern void somefunction() __attribute__((weak_import));

If you don’t do this, somefunction() will end up being non-null even on older OS versions which will screw up your check for the function’s existence.

And then there are issues that aren’t based on API so much as behavior. For instance, if there was a bug in Tiger that was fixed in Leopard. It’s not the type of thing your program can detect so in such cases you’ll have to resort to version checking.

Nothing particularly new here but thought it might be helpful for people doing the OS version straddle for the first time.

1 comment » | Carbon, Cocoa, OS X, Programming, Xcode

Mystery Bug: Heisenberg’s Uncertainty Principle

March 7th, 2007 — 6:59pm

I’ve spent the past couple hours going crazy over a bug. It’s the type of bug where it breaks except for when you look at it, in which case, it works all the time. Don’t believe me? Compile the following program:

#import <Foundation/Foundation.h>

int main(int argc, const char *argv[])
    NSAutoreleasePool     *pool;
    NSString              *path;
    NSDictionary          *dict;
    pool = [[NSAutoreleasePool alloc] init];
    path = [NSString stringWithUTF8String:argv[1]];
    dict = [[NSFileManager defaultManager] fileAttributesAtPath:path

    // The busy flag will be NULL if you comment out the next line.
    //NSLog(@"DICT: %@", dict);

    NSLog(@"Creation: %@", [dict objectForKey:NSFileCreationDate]);
    NSLog(@"Busy: %@", [dict objectForKey:NSFileBusy]);

By the way, I know I’m not releasing the pool.

Now, take a file and set its busy flag. You can do this as follows:

/Developer/Tools/SetFile -a Z some file

Then run my little program with some file as an argument. Notice how the busy flag is null?

Well, let’s see what’s in the dictionary passed back to us to find out what’s going wrong here. Edit the program above to uncomment the NSLog statement. Run it again. Notice how the busy flag is now set?

It appears that the dictionary is half-initialized until you happen to call certain methods (-allKeys works as well as -description). I haven’t tested every key but it does seem to be peculiar to NSFileBusy.

For the time being, I’m going to switch to Carbon to do this but I’d love to hear theories (or even facts) on what’s going on here. Let the wild speculation begin.

Oh, and since I brought up Heisenberg, I can’t let an opportunity to include an artful rendering of a dead cat pass by so here:

dead cat

6 comments » | Carbon, Cocoa, Debugging, OS X, Programming

System Icon Viewer

September 10th, 2006 — 11:06am

When I saw this post, I mentioned to Daniel Jalkut that I had done the same thing that he did (which was to create an NSImage category to access Carbon’s Icon Manager’s icons). After his obligatory insistence that I start a blog, I sent him a little program I had thrown together to preview the icons.

Since he referenced it in his post, I’ve made it available. It’s not pretty as it was just slapped together but it’s functional. It does show that if you are using Cocoa, the category is pretty much unnecessary as NSWorkspace seems to return the same icons, with a few exceptions. Of course, if the icon you want is one of those exceptions, you can look and decide for yourself.

System Icon Viewer source

7 comments » | Carbon, Cocoa, Downloads, Icons, Programming

Back to top