30 June 2009

Loading Frameworks at Runtime

I recently looked at an application that was trying to solve the "install at first launch" problem. The application in question needed to install several third-party frameworks and a daemon at first launch. Then, it needed to launch the daemon and use frameworks itself. The application needed to be relocatable, we couldn't rely on the application being in a certain location, and it couldn't have a separate installer. Cosmetically, we didn't like the look of the double-launch application where an application bounces in the doc, disappears, and then comes back to life.

Is this beginning to sound contrived? It was, indeed, a real situation, due partly to the issues that arise from working with third-party software and a marketing department with strict user experience oversight. At first glance the requirements seemed contradictory but we were able to get things to work using weak linking and runtime loading. Fortunately the frameworks were written in Objective-C with its awesome runtime message dispatching.

Weak Linking

The first problem was getting our application to even launch when the frameworks were not installed. Since the application linked to the frameworks in their installed location, a location dictated by the third-party daemon, it was obvious that they would not exist until after our application installed them. They would be missing on the first launch for every user.

To let our application load even if it couldn't find the libraries we used weak linking. Weak linking tells the application loader to continue if it can't link to libraries that are specified in a binary's load commands. You can see which libraries will be loaded in your application by using the otool -L <executable> command. By default, all of these libraries must be in their specified location or the application will fail launching.

When you specify that you want a library to be weakly linked, the loader will continue loading the application even if it cannot find the required libraries. This is extremely useful for using features in a new operating system while continuing to support an older OS. For example, an application could weakly link to a Leopard only framework, but continue to support Tiger. The application would be responsible for checking at runtime for the existence of symbols in any weakly linked framework before using it.

Xcode 3.0 makes weak linking very easy. Simply go to the "Linked Libraries" list in the "General Tab" of the "Target Info" dialog. On the right-hand-side, click on the pop-up button that says "Required" and change it to "Weak". Piece of cake.

Here is a great article on weak linking from Apple.

However, weak linking only lets our application load if frameworks are missing. It doesn't let us use functionality from frameworks that appear after we install them. To do that, we have to use the dynamic loader, dlopen().

Dynamic Loading

Once our application has launched, it has the chance to install the frameworks and the daemon in the correct locations; authenticating with the user, if necessary. However, if we try to access any of the functionality in the frameworks, the application will crash. Since the frameworks were not around when the application loaded, the loader didn't resolve the symbols in that framework.

To load a framework at runtime, simply issue the dlopen() with a path to the framework you need to load. Apple describes the solution in the Dynamic Library Usage Guidelines.

For example, to load an imaginary framework "Imaginary.framework" from "/Library/Frameworks", you would use:

framework_handle = dlopen("/Library/Frameworks/Imaginary.framework/Imaginary", RTLD_LAZY);

Now, the symbols within the loaded framework are available for use within your application. But wait! not quite.

Loading Symbols

If your application is using the Objective-C runtime for messaging and loading classes, your are finished. You can now create classes and call methods on these classes without modifying the rest of your application. However, if you need to load C functions or static objects (such as string constants), the individual symbols must be loaded too. Continuing our example above, if we had an NSString* constant "IFWhiteRabbit" defined in our framework, we could get access to this constant using the dlsym() function.

NSString** whiteRabbit_handle = (NSString**)dlsym(framework_handle, "IFWhiteRabbit");

With non-Objective-C symbols, each one needs to be loaded separately, including functions. This can cause significant complexity with the code, or alternative paths whether the frameworks were available at runtime, or if they were loaded later. If the frameworks were loaded at runtime, the IFWhiteRabbit constant could be used directly in the code. If the framework was loaded at runtime, a handle would have to be loaded and then dereferenced to get access to the data.

Apple encourages the use of a top-level class that would provide strings or other constants via accessor methods. In this way, no code differences would be required for frameworks that were loaded at runtime or at launch. Also, if at all possible, using the high-level CFBundle or NSBundle can simplify loading code at runtime.


With a combination of weak linking and dynamic loading, we were able to provide a single application for the user that installed necessary third-party software at runtime and could be located at any location on the disk. It also avoided the double-bouncing doc icon. Everyone was happy. Even marketing.

23 March 2009

Automating the Setup of Xcode Executables


Xcode does not store Executable settings in the project file. The settings end up in the user.pbxuser. These files do not typically get checked in to version control system, making sharing the setup of these executable impossible. This causes problems if you have environment settings, or command line arguments that need to be called in your executable in a consistent way, across all developer machines.

The situation that motivates this post is the need to set the DYLD_FALLBACK_LIBRARY_PATH in a unit test executable to help it find a third-party dynamic library. Simple command line tools do not get the same benefits of application bundles, which have their dependent frameworks and libraries packaged neatly away. Command-line tools are simply executable code without packaged resources or private frameworks. Because there is no package, when the executable can only link to libraries in known locations such as /usr/lib/ or /System/Library/Frameworks.

At times this can cause problems. When unit testing code, you might create a simple executable that links in required frameworks and runs tests on them and produces code coverage. The problem is that your application will be able to link to a variety of dynamic libraries and frameworks and embed them its bundle. The unit test executables, on the other hand, do not have a bundle. How then, can your executable find these dynamic libraries and frameworks at runtime?

Note: A solution to this particular problem is to copy all of the frameworks and libraries into the $BUILT_PRODUCTS_DIR, this can be done simply with a build phase in your test target, but doesn't serve to demonstrate the automation of other environment variables or command line arguments.

AppleScript to the Rescue

Fortunately for us, Xcode is an extremely scriptable application. Here is a script that modifies the currently building target and sets up some environment variables on the linked executable.

-- Function: setEnvironmentVariable

-- Sets an environment variable in the executable, which is linked to the current target. If the

-- environment variable exists, the value is overwritten. If the environment variable doesn't exist

-- the variable is created and set.


-- Args:

--    variableName - name of the environment variable to set

--    variableValue - value of the environment variable being set

on setEnvironmentVariable(variableName, variableValue)

tell application "Xcode"

tell active project document

set executableName to name of executable of active target as string

tell executable executableName

-- Check to see if the fallback path already exists

set hasVariable to false as boolean

repeat with environmentVariable in environment variables

if name of environmentVariable is equal to variableName then

-- Overwrite any value

set value of environmentVariable to variableValue

set active of environmentVariable to yes

set hasVariable to true as boolean

exit repeat

end if

end repeat

-- Since the fallback path doesn't exist yet, create it

if not hasVariable then

make new environment variable with properties ¬

{name:variableName, value:variableValue, active:yes}

end if

end tell -- executable

end tell -- active project document

end tell -- Xcode

end setEnvironmentVariable

tell application "Xcode"

tell active project document

-- First, find the path to the project directory

set projectPath to path as string

-- Create a library path to the third-party and in-house libraries

set dyldLibraryPath to projectPath & "../relative/path/to/third-party/lib" & ":" & ¬

projectPath & "../relative/path/to/in-house/lib"

-- Create a framework path to the third-party and in-house frameworks

set dyldFrameworkPath to projectPath & "../relative/path/to/third-party/frameworks" & ":" & ¬

projectPath & "../relative/path/to/in-house/frameworks"

-- Next, add path to the DYLD fallback paths

my setEnvironmentVariable("DYLD_FALLBACK_FRAMEWORK_PATH", dyldFrameworkPath)

my setEnvironmentVariable("DYLD_FALLBACK_LIBRARY_PATH", dyldLibraryPath)

end tell -- active project document

end tell -- Xcode

Adding the Script to your Target

To add the above script to a target, first, save the script as an applescript. Then add a "Run Script" build phase with the one line

osascript path/to/script.applescript

Obviously replacing the path and file name to that of your own script.

28 January 2009

Awesome Truncation for (nearly) Free!

Sometimes you need to shorten a string to make it fit within certain bounds. using the NSString - (void)drawAtPoint:(NSPoint)aPoint withAttributes:(NSDictionary *)attributes method will draw the string, but won't perform any truncation. The - (void)drawInRect:(NSRect)aRect withAttributes:(NSDictionary *)attributesmethod will truncate, but just clips at the end. Sometimes what we really want is the behavior that window titles show, an ellipsis at the end. Here's an example:

This behavior can be selected using the Inspector in Interface Builder for NSTextFields. But what do we do if we are drawing text in a custom view? It turns out that it is very simple to get automatic truncation, in at the head, in the middle, or at the tail of the string. Here's how:

  1. Add a paragraph style to the attributes dictionary. In this example, we do this in theinit method.
      // Set the paragraph style attribute to truncate the tail.
      NSMutableParagraphStyle* style = [[[NSParagraphStyle defaultParagraphStyle] mutableCopy] autorelease];
      // Here we specify the truncation location with a constant.
      [style setLineBreakMode:NSLineBreakByTruncatingTail];
      // Make an attribute dictionary for the attributed string
      NSDictionary _textAttributes = [[NSDictionary dictionaryWithObjectsAndKeys:
            [NSFont systemFontOfSize:[NSFont labelFontSize]], NSFontAttributeName,
            style, NSParagraphStyleAttributeName,
            nil] retain];
  2. Calculate the rectangle in which you want to draw the string.
  3. Then draw the string using the NSString drawInRect:withAttributes:. Here's an example from our custom view's drawRect: method.
      [_text drawInRect:textRect withAttributes:_textAttributes];

There are actually three kinds of truncation that you can specify in this method, NSLineBreakByTruncatingHead NSLineBreakByTruncatingMiddle, and as observed, NSLineBreakByTruncatingTail. It is that easy.

17 November 2008

SketchUp 7 is Out!

For my day job, I work on SketchUp, a 3D modeling tool written for designers, not CAD jockeys (no offense to CAD jockeys, ahem). SketchUp is by far my favorite Google product. @Last software, the original creators of SketchUp, was acquired by Google about a year before I got here. Fortunately, we have been able to keep the same passionate development team together (except for a few additions, like your truly). I really love working with these guys.

Today, it has finally gone public that we are releasing SketchUp 7. You can even see a video with me in it on that page, though I can't really recommend my acting. I work on the 2D presentation tool called LayOut. I helped develop the new curve tool, the editable paths, the move rotate and scale manipulators, and the in-place group edit. It has been a great year and I'm really proud of what we've come up with.

So that's it for this week. It has been a crazy few months. I think we're all looking forward to Christmas break!

26 August 2008

Localization and Internationalization

With a co-worker, I recently had the chance to investigate how the Mac OS localization system works. We were curious to see how difficult it would be to convert several interdependent projects (frameworks and applications) to use the suggested ISO language designators (e.g. en.lproj, es.lproj) from the deprecated language designators (e.g. English.lproj, Spanish.lproj). Recorded below are some of the lessons we learned.

The Set Up

According to the Internationalization Programming Topics (applicable page), the old language designators (English.lproj, Spanish.lproj, German.lproj, etc) are deprecated, and could be discontinued in the future. The documentation strongly suggests using the ISO language designators (en.lproj, es.lproj, de.lproj, etc). Judging from Apple's own applications, the OS will be supporting the legacy designators for some time to come. Still, we want to be up to date so it was a little surprising to see that Xcode seems to favor these legacy language designators rather than the ISO labels. The default application template includes an English.lproj directory and sets the Development Region to be English in the Info.plist.

Still, Xcode makes adding new localizations pretty easy. Select the resource that you would like to localize in the file Group Tree and then Get Info. At the bottom of the General tab, there is an "Add Localization" button. When you click on it a sheet appears with a combo box that you can enter the name of the localization. Again, Xcode give examples in the combo box of the deprecated language designators, but it is easy enough to type in the two letter ISO language designator. Once you do this, a new lproj directory is created and a copy of the resource is placed in it.

We played around a bit with a simple application that simply had an image well and a text field on a window. We created several localizations and put custom text and custom images into the text field and image well, respectively, for each locale. Then, we built the application and started moving things around to see what the localization system would do.

Test One, Removing .lproj Directories

Without describing all of the permutations we went through, here's the final experiment we performed. In the Contents/Resources directory, we had the following lproj directories: English.lproj, en.lproj, Spanish.lproj, es.lproj, German.lproj, and de.lproj. In the System Preferences, in the International Pane, we set our first three Languages to be German, then Spanish, then English.

First we opened the application and it showed we were using the resources in the de.lproj directory. We renamed the de.lproj directory and then relaunched the application. The German.lproj directory was used. After commenting out German.lproj, the es.lproj was used, then the Spanish.lproj, then en.lproj, and finally English.lproj. There were two lessons learned here. First, the ISO names are preferred and the language search order in the System Preferences is honored.

Test Two, Removing Resources

Next, we wanted to see what would happen if we deleted resources from within the lproj directories. Our thought from the above experiment was that it would follow the same search path until it found the resource in a localized directory. As we discovered above, when we removed an entire lproj directory, it would fall back to the next most appropriate language. However, if we only removed a resource within an lproj directory, it wouldn't fall back to the next appropriate language, but it would fall back to the English.lproj. Why was it favoring English.lproj, when we had en.lproj and it seemed to favor en.lproj in our first test? The answer is that once the appropriate lproj is found, all of the others are ignored, with the one exception being the lproj designated as the Development Region in the Info.plist.

As described in The Bundle Programming Guide (relevant section) the search for resources goes something like this:

  1. Look for a non-localized verison of the resource.
  2. If that doesn't work, look in the lproj folder that the system tells you to use.
  3. If that doesn't work, look in the lproj that has been designated as the Development Region in the Info.plist.

Sure enough, along with the default English.lproj that Xcode creates for you, it also sets up English as the Development Region (see the CFBundleDevelopmentRegion key in the Info.plist). Once we change the value of that key to en the application started using en.lproj as the fallback for missing localized resources. So the lesson learned with this test is If it can't find the resources, it will fall back to the Development region lproj.


So, with these experiments under our belts, we feel much more comfortable about converting to the ISO names. We just need to remember:

  • The ISO names are preferred. Names like English.lproj are deprecated.
  • ISO names are searched before deprecated names when the system selects the appropriate lproj.
  • If the system can't find the appropriate lproj, it will search for other languages in the order specified in the International Preference Pane.
  • If a resource isn't found in the selected lproj, it falls back to the lproj designated as the development region with the CFBundleDevelopmentRegion in the Info.plist.

This is a sophisticated system of localization that is predictable and flexible, when you know what is going on. Hopefully, after reading this, you do!

15 August 2008

Using Google Testing Framework in your Xcode Projects

Google has recently released open source project called the Google Testing Framework (blog post, project site), or gtest for short. This post will explain how you'll be able to use this unit testing framework in your own Mac OS X projects. This tutorial, which is also posted here, begins by quickly explaining what to do for experienced users, then go into depth about each step with additional explanation below. Finally, there is an example project that uses gtest that you can download to get started.

Quick Start

Here is the quick guide for using gtest in your Xcode project.

  • Download the source from the website using this command: svn checkout http://googletest.googlecode.com/svn/trunk/ googletest-read-only
  • Open up the gtest.xcodeproj in the googletest-read-only/xcode/ directory and build the gtest.framework.
  • Create a new "Shell Tool" target in your Xcode project called something like "UnitTests"
  • Add the gtest.framework to your project and add it to the "Link Binary with Libraries" build phase of "UnitTests"
  • Add your unit test source code to the "Compile Sources" build phase of "UnitTests"
  • Edit the "UnitTests" exectable and add an environment variable "DYLD_FRAMEWORK_PATH" with the value of the relative path to the framework containing the gtest.framework.
  • Build and Go

Now, I'll go into depth to each of these steps, describing in more detail how to complete it and mentioning some variations.

Get the Source

Currently, the gtest.framework discussed here isn't available in a tagged release of gtest, it is only available in the trunk. As explained at the gtest svn site, you can get the code from anonymous SVN with this command:

svn checkout http://googletest.googlecode.com/svn/trunk/ googletest-read-only

Alternatively, if you are working with Subversion in your own code base, you can add gtest as an external dependency to your own Subversion repository. By following this approach, everyone that checks out your svn repository will also receive a copy of gtest (a specific version, if you wish) without having to check it out explicitly. This makes the set up of your project simpler and reduces the copied code in the repository.

To use svn:externals, figure out where you would like to have the external source reside. I choose to put the external source inside the trunk, because I want it to be part of the branch when I make a release. However, keeping it outside the trunk in a version-tagged directory called something like third-party/gtest/1.0.1, is another option. Then, use svn propedit svn:externals _directory_ to set the property on a directory that will contain the code. The directory that receives the svn:externals property must already be in the repository.

The command svn propedit will bring up your Subversion editor, making editing the long, (potentially multi-line) property simpler. This same method can be used to out a tagged branch, by using the appropriate URL (e.g. http://googletest.googlecode.com/svn/tags/release-1.0.1). Additionally, the svn:externals property allows the specification of a particular revision with the -r_##_ option (e.g. externals/src/googletest -r60 http://googletest.googlecode.com/svn/trunk).

Here is an example of using the svn:externals properties on the trunk (read via svn propget) of a project. This value checks out a copy of gtest into the trunk/externals/src/googletest/ directory.

[Computer:svn] user$ svn propget svn:externals trunk
externals/src/googletest http://googletest.googlecode.com/svn/trunk

Add the Framework to Your Project

The next step is to add the gtest framework to your own project. I'll describe the two most common ways below.

  • Option 1 — The simplest way to add gtest to your own project, is to open gtest.xcodeproj (found in the xcode/ directory of the gtest trunk) and build the framework manually. Then, add the built framework into your project using the "Add->Existing Framework..." from the context menu or "Project->Add..." from the main menu. The gtest.framework is relocatable and contains the headers and object code that you'll need to make tests. This method requires rebuilding every time you upgrade gtest in your project. How often that is, depends on you.
  • Option 2 — If you are going to be living off the trunk of gtest, incorporating its latest features into your unit tests (or are a gtest developer yourself). You'll want to rebuild the framework every time the source updates. to do this, you'll need to add the gtest.xcodeproj file to you project. Then, from the build products that are revealed by the projects disclosure triangle, you can find the gtest.framework which can be added to your targets (discussed below).

Make a Test Target

To start writing tests, make a new "Shell Tool" target. This target template is available under BSD, Cocoa, or Carbon. Add your unit test source code to the "Compile Sources" build phase of the target.

Next, you'll want to add gtest.framework in two different ways, depending upon which option you chose above.

  • Option 1 — During compilation, Xcode will need to know that you are linking against the gtest.framework. Add the gtest.framework to the "Link Binary with Libraries" build phase of your test target. This will include the gtest headers in your header search path, and will tell the linker where to find the library.
  • Option 2 — If your working out of the trunk, you'll also want to add gtest.framework to your "Link Binary with Libraries" build phase of your test target. In addition, you'll want. to add the gtest.framework as a dependency to your own target. This way, Xcode will make sure that gtest.framework is up to date, every time your build your target. In addition, if you don't share build directories with gtest, you'll have to copy the gtest.framework into your own build products directory using a "Run Script" build phase.

Set Up the Executable Run Environment

Since the unit test executable is a shell tool, it doesn't have a bundle with a Contents/Frameworks directory, in which to place gtest.framework. Instead, the dynamic linker must be told at runtime to search for the framework in another location. This can be accomplished by setting the "DYLD_FRAMEWORK_PATH" environment variable in the "Edit Active Executable ..." Arguments tab, under "Variables to be set in the environment:". The path for this value is the path (relative or absolute) of the directory containing the gtest.framework.

If you haven't set up the DYLD_FRAMEWORK_PATH, correctly, you might get a message like this:

[Session started at 2008-08-15 06:23:57 -0600.]
    dyld: Library not loaded: @loader_path/../Frameworks/gtest.framework/Versions/A/gtest
      Referenced from: /Users/username/Documents/Sandbox/sidelight/svn/trunk/samplecode/gTestExample/build/Debug/WidgetFrameworkTest
      Reason: image not found

To correct this problem, got to the direcotry containing the executable named in "Referenced from:" value in the error message above. Then, with the terminal in this location, find the relative path to the directory containing the gtest.framework. That is the value you'll need to set as the DYLD_FRAMEWORK_PATH.

Build and Go

Now, when you click "Build and Go", the test will be executed. Dumping out something like this:

[Session started at 2008-08-06 06:36:13 -0600.]
[==========] Running 2 tests from 1 test case.
[----------] Global test environment set-up.
[----------] 2 tests from WidgetInitializerTest
[ RUN      ] WidgetInitializerTest.TestConstructor
[       OK ] WidgetInitializerTest.TestConstructor
[ RUN      ] WidgetInitializerTest.TestConversion
[       OK ] WidgetInitializerTest.TestConversion
[----------] Global test environment tear-down
[==========] 2 tests from 1 test case ran.
[  PASSED  ] 2 tests.

The Debugger has exited with status 0.  


I've included an example project in the sidelight project called gtestSample. It is a self contained example (including the svn:externals property) that you can check out using:

svn checkout http://sidelight.googlecode.com/svn/trunk/samplecode/gtestSample  gtestSample

Next, build the gtest.framework included in the externals directory of the gtestSample. The WidgetFramework.xcodeproj builds a simple C++ framework and uses gtest to test its only class. Note: The WidgetFramework.xcodeproj expects the gtest.framework to be built in its own project directory.


Unit testing is a valuable way to ensure your data model stays valid even during rapid development or refactoring. The Google Testing Framework is a great unit testing framework for C and C++ which integrates well with an Xcode development environment.

05 August 2008

The Google Testing Framework

The autotools scripts that come with googletest work just fine on Mac OS X, but they build only for a single architecture. If you want to use it with a universal binary (say 32- and 64-bit x86) you have to build it twice, and then use lipo to stick it together. To avoid that hassle, I put together an Xcode project to generate a universal-binary version of the framework (it is pretty easy, in Xcode). I learned (and relearned) a few things along the way:

  • You can preprocess the Info.plist (of course), and you can specify a file to be its prefix header (build setting: "Info.plist Preprocessor Prefix File" or "INFOPLIST_PREFIX_HEADER"). This is a relatively easy way to do string substitution into your Info.plist and I used it in gtest.framework to set up some version strings. One tricky thing is that the Info.plist seems to be generated before any other build phase. Hence, you can't have a "Run Script" phase extract the version strings and generate the prefix header and then use it later on in a different build phase. If you do want to autogenerate the Info.plist prefix header, the "Run Script" has to be part of a separate target and make that target a dependency of the target that generates the Info.plist.
  • The $DERIVED_FILE_DIR is great for storing intermediate files. When you clean the project, the files you put in here are thrown out. Also, it appears that files you place in this directory are included in the "HEADER_SEARCH_PATHS". This is the destination I chose for the Info.plist prefix header.
  • Make liberal use of the "Input Files" and "Output Files" of the Run Script Build Phase. They actually work as advertised. The script will not be run unless files in these locations have been touched.
  • If you want to build a test executable that uses external frameworks (such as gtest.framework) without pulling everything together into a bundle, you can specify the DYLD_FRAMEWORK_PATH in the executable's environment variables and set it to the location of the framework. This should not be used for production executables code, only test code.

The trunk of the googletest project now includes the Xcode project to build the universal-binary framework.