PATH Documentation > Release Notes

Mac OS X Developer Release Notes:
Two-Level Namespace Executables

Should I Read This?
This release note describes the Two-Level Namespace Executables feature of the Mac OS X 10.1 linkers and runtime environment. You need to read this note if your application is based on the Mach-O executable format (which is true if you use Project Builder or the Mac OS X command-line build tools) and one of the following criteria is true.
  • You plan to build your application on Mac OS X 10.1 but want to release it for use with older Mac OS X system releases.
  • Your application loads code (such as plugins and bundles) at runtime.

The Problem (and the Solution)

The shared library implementation shipped with Mac OS X 10.0 is a robust, featureful implementation, with one small problem.

When an executable file is loaded into a program, the dynamic linker (the part of the system responsible for loading code on demand) attempts to find all of the unresolved symbols (functions in other executable files). In order to do this, it needs to know which libraries contain those symbols. So when the program is built, you must specify the libraries that contain those functions to the static linker (the part of the build system responsible for linking object files together). The static linker places the names of those libraries into your program's executable file.

The problem is that the static linker in Mac OS X 10.0 records only the names of the libraries, but not which functions are to be found in each of libraries. Therefore, it's not possible to load two libraries containing a definition of the same symbol name, because it's not possible to determine which library you really wanted the symbol from.

For example, two libraries might both implement a "log" function. One of the libraries might be a math library, and the other might be a library for logging messages to the system console. If your program calls the math library "log," there is no way to guarantee that you are not calling the system console "log".

This isn't usually a problem on Mac OS X 10.0, because the build system will give you a multiple-defined-symbols error message when you attempt to build your application using libraries that contain a symbol with the same name. But consider the following situations.

To solve this problem, the Mac OS X 10.1 runtime environment supports a new feature that records the names of symbols expected to be found in a library along with the library name. An executable file built with this feature enabled is called a two-level namespace executable. An executable file without this feature is called a flat namespace executable.

When your program links to a symbol defined in a subframework of an umbrella framework, the linker records the name of the umbrella framework as the parent library for the symbol. At runtime, the linker searches the umbrella framework, including all of the subframeworks it contains, to find the symbol.

For example, if your program references the function MoveWindow, which is implemented in the HIToolbox subframework of the "Carbon" umbrella framework, "Carbon" will be recorded as the library name. Consequentially, if a later release of the Carbon umbrella framework moves the MoveWindow function to a new or different subframework (for example, a WindowManager framework), your program will continue to function.

Using Two-Level Namespace Executables On Mac OS X 10.0

The static linker enables the two-level namepace option (-twolevel_namespace) by default in Mac OS X 10.1. Two-level namespace executables are compatible with Mac OS X 10.0, where the linker will treat them as flat namespace executables (although your program may unexpectedly quit with a "multiple defined symbols" error if the resulting flat namespace contains multiple symbols with the same name).

However, applications that you build as two-level namespace executables will cause versions of the update_prebinding tool up to and including the version installed with Mac OS X 10.0.4 to crash. update_prebinding is used by the Mac OS X installer to redo the prebinding optimization (see the Prebinding release note for more information). If the prebinding tool crashes, the installer will complete the installation, but the resulting system won't be fully prebound. To work around this problem, you have two options:

Running Your Application as a Flat Namespace Executable

If you want to test your two-level namespace as a flat namespace image on Mac OS X 10.1, set the DYLD_FORCE_FLAT_NAMESPACE environment variable to launch your program as a flat namespace executable.

Note that when you do this, your program may terminate with a "multiple defined symbols" error if the resulting flat namespace contains multiple symbols with the same name.

Troubleshooting Two-Level Namespace Builds

Some existing projects will not link without modification, for the following reasons:

Building Your Application With PlugIns and Bundles

If your project includes bundles that must be resolved against symbols in the program that loads them, do not use the linker option -undefined suppress when building your bundles. Instead, use -undefined error and make sure you specify the path to the program you are linking against with the option -bundle_loader pathnameToYourProgramOrFramework. For Project Builder projects, add these arguments to the the OTHER_LDFLAGS build setting of the bundle's target (in the expert settings table of the Build Settings tab).

Using the -bundle_loader option instead of -undefined suppress will cause an ordering problem if the bundles are located inside your application's bundle. For the application to copy the bundles to itself with a Copy Files build phase, the bundles must be built first. However, to properly link against the app and get their symbols resolved the bundles must build after the application.

One solution for an application that loads plug-ins or other bundles is to provide your plug-in API implementation in a framework that bundles can link against. Your application will also link to that framework. For example, Interface Builder exposes an API for people who wish to write new palettes of objects. There is an InterfaceBuilder.framework that implements the functionality of the API. The Interface Builder application itself calls routines in this framework, and so do plug-in-palettes. This organization provides several benefits:

Alternately, you can use a second application target called "Foo Wrapper" to fix the dependency problem:

  1. Set the application name of the new target to the same name as the real application target ("Foo", in this example).
  2. Set the original application target to not install itself.
  3. Set the wrapper target to install itself.
  4. Add a Copy Files phase to the wrapper target and remove all the other build phases.
  5. Set up the Copy Files phase the same way as it was in the original app target.
  6. Make the wrapper target depend on the app target and on all the bundle targets.
  7. Make things that used to depend on the app target depend on the wrapper target instead.
  8. If the app target was the first target in your target list, make the wrapper target first.
  9. Finally, because the installation is now being performed by the Foo Wrapper target, but the actual application is being built by the Foo target, when the install happens, Project Builder will not remove debugging symbols from the application executable file. To fix this problem, add a shell script build phase to the Foo Wrapper target that is set to run only for install builds and that contains the following script:

    strip -S ${SYMROOT}/${PRODUCT_NAME}.${WRAPPER_EXTENSION}/Contents/MacOS/$ {PRODUCT_NAME}

New Dynamic Linking Functions for Use With Two-Level Namespace Executables

The runtime symbol lookup routines released in Mac OS X 10.0 (located in the header <mach-o/dyld.h> and listed below) perform lookups in the flat, global symbol namespace, and thus, when you use them to find symbols in your plugins, may not return the intended symbols in for two-level namespace applications.

The "hint" provided to NSLookupAndBindSymbolWithHint is a performance "hint" for the flat namespace lookup, and is thus not used as the first level name for a two-level namespace lookup. To perform a lookup within a two-level namespace executable, use the function NSLookupSymbolInImage, as documented below.

Applications built as two-level namespace executables should instead use the following new routines.

NSAddImage

const struct mach_header *
NSAddImage(
    char *image_name,
    unsigned long options);
#define NSADDIMAGE_OPTION_NONE                  0x0
#define NSADDIMAGE_OPTION_RETURN_ON_ERROR       0x1
#define NSADDIMAGE_OPTION_WITH_SEARCHING        0x2
#define NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED 0x4

NSAddImage loads the shared library specified by image_name into the current process, returning a pointer to the mach_header data structure of the loaded image. Any libraries that the specified library depends on are also loaded.

If the shared library specified by image_name is already loaded, the mach_header already loaded is returned.

The image_name parameter is a pointer to a C string containing the pathname to the shared library on disk. For best performance, specify the full pathname of the shared library—do not specify a symlink.

The options parameter is a bit mask. Valid options are:

The linkEdit error handler is documented in the NSModule(3) man page.

NSLookupSymbolInImage

extern NSSymbol
NSLookupSymbolInImage(
    const struct mach_header *image,
    const char *symbolName
    unsigned long options);
#define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND            0x0
#define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW        0x1
#define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_FULLY      0x2
#define NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR 0x4

NSLookupSymbolInImage returns the specified symbol (as an NSSymbol) from the specified image.

Error handling for NSLookupSymbolInImage is similar to error handling for NSAddImage.

The image parameter is a pointer to a mach_header data structure. You can get this pointer from a shared library by calling NSAddImage.

The symbolName parameter is a C string specifying the name of the symbol to retrieve.

The options parameter is a bit mask. The following options are valid:

NSIsSymbolNameDefinedInImage

extern enum DYLD_BOOL
NSIsSymbolNameDefinedInImage(
    const struct mach_header *image,
    const char *symbolName);

NSIsSymbolNameDefinedInImage returns true if the specified image (or, if the image is a framework, any of its subframeworks) contains the specified symbol, false otherwise.

The image parameter is a pointer to a mach_header data structure. You can get this pointer from a shared library by calling NSAddImage.

The symbolName parameter is a C string specifying the name of the symbol to retrieve.

The image parameter for NSLookupSymbolInImage and NSIsSymbolNameDefinedInImage is a pointer to the mach_header data structure of a Mach-O shared library. You can obtain a pointer to a mach_header data structure from:

Copyright © 2001 Apple Computer, Inc.