In Mac OS X, shared resources are packaged using standard frameworks and umbrella frameworks. Both types of framework feature the same basic structure and can contain resources such as a shared library, nib files, image files, strings files, information property lists, documentation, header files, and so on. Umbrella frameworks add minor refinements to the standard framework structure, such as the ability to encompass other frameworks.
Frameworks are packaged in a bundle structure. The framework bundle directory ends with the .framework
extension, and unlike most other bundle types, a framework bundle is presented to the user as a directory and not as a file. This openness makes it easy for developers to browse any header files and documentation included with the framework.
Framework Bundle Structure
Umbrella Framework Bundle Structure
Framework bundles use a bundle structure different from the bundle structure used by applications. The structure for frameworks is based on an earlier bundle format, and allows for multiple versions of the framework code and header files to be stored inside the bundle. This type of bundle is known as a versioned bundle. Supporting multiple versions of a framework allows older applications to continue running even as the framework binary continues to evolve.
The system identifies a framework by the .framework
extension on its directory name and by the Resources
directory at the top level of the framework bundle. Inside the Resources
directory is the Info.plist
file that contains the bundle’s identifying information. The actual Resources
directory does not have to reside physically at the top-level of the bundle. In fact, the system frameworks that come with Mac OS X have a symbolic link to the framework’s Resources
directory in this location. The link points to the most current version of the Resources
directory, buried somewhere inside the bundle.
The contents of the Resources
directory are similar to those for application bundles. (See “Anatomy of a Modern Bundle” in Bundle Programming Guide for more information.) Localized resources are put in language-specific subdirectories that end with the .lproj.
extension. These subdirectories hold strings, images, sounds, and interface definitions localized to the language and region represented by the directory. Nonlocalized resources reside at the top level of the Resources
directory.
When you build a new framework project in Xcode, the build environment creates a versioned bundle structure for you automatically. Listing 1 shows the basic directory structure of the resulting bundle.
Listing 1 A simple framework bundle
MyFramework.framework/ |
MyFramework -> Versions/Current/MyFramework |
Resources -> Versions/Current/Resources |
Versions/ |
A/ |
MyFramework |
Resources/ |
English.lproj/ |
InfoPlist.strings |
Info.plist |
Current -> A |
In this listing, the Versions
directory is the only real directory at the top level of the bundle. Both MyFramework
and Resources
are symbolic links to items in Versions/A
. The reason for the symbolic links is that directory Versions/A
contains the actual contents of the framework. It contains both the executable and the resources used by the framework.
Listing 1 shows that the top-level symbolic links don’t point directly to items inside the Versions/A
directory. Instead, they point to items in the Versions/Current
directory, which itself is a symbolic link to Versions/A
. This additional level of indirection simplifies the process of changing the top-level links of frameworks with many resource types to point to a specific major version of the framework, because only one link, Versions/Current
, needs to be updated.
Each real directory in Versions
contains a specific major version of the framework. Earlier major versions of the framework are needed by clients created when those versions were current at the time. New major versions of a framework are required only when changes in the framework’s dynamic shared library would prevent a program linked to it from running. Programs built using the earlier major version of the library must continue to use it, but programs in development should link against the current version of the library.
Listing 2 shows the MyFramework framework after a adding major revision to it.
Listing 2 A framework with multiple versions
MyFramework.framework/ |
MyFramework -> Versions/Current/MyFramework |
Resources -> Versions/Current/Resources |
Versions/ |
A/ |
MyFramework |
Resources/ |
English.lproj/ |
InfoPlist.strings |
Info.plist |
B/ |
MyFramework |
Resources/ |
English.lproj/ |
InfoPlist.strings |
Info.plist |
Current -> B |
Through the Versions/Current
symbolic link, MyFramework.framework/MyFramework
points to the dynamic shared library of the now current version of the framework, Versions/B/MyFramework
. Because of the use of symbolic links, during a program’s link process, the linker finds the latest version of the framework’s library. This arrangement ensures that new programs are linked against the latest major version of the framework and that programs built with the earlier major version of the framework continue to work unchanged. For more on major and minor framework versions, and on versioning in general, see “Framework Versions.” For more information on using dynamic libraries, see Dynamic Library Programming Topics.
Important: For the linker to find and link the dynamic library, the name of the framework (without the .framework
extension), the symbolic link, and the dynamic library must be the same.
Frameworks typically include more directories than just the Resources
directory. For example, Headers
, Documentation
, and Libraries
. Thus, adding a Headers
directory to the example in Listing 2 would result in a framework like the one shown in Listing 3.
Listing 3 A framework with additional resource types
MyFramework.framework/ |
Headers -> Versions/Current/Headers |
MyFramework -> Versions/Current/MyFramework |
Resources -> Versions/Current/Resources |
Versions/ |
A/ |
Headers/ |
MyHeader.h |
MyFramework |
Resources/ |
English.lproj/ |
Documentation |
InfoPlist.strings |
Info.plist |
B/ |
Headers/ |
MyHeader.h |
MyFramework |
Resources/ |
English.lproj/ |
Documentation |
InfoPlist.strings |
Info.plist |
Current -> B |
To create additional directories in your framework, you must add build phases to the appropriate target in Xcode. The Copy Files build phase lets you create directories and copy selected files into those directories. Table 1 lists some of the typical directories you might add to your framework.
Frameworks require the same sort of configuration as any other type of bundle. In the information property list for your framework, you should include the keys listed in Table 2. Most of these keys are included automatically when you set up the framework properties in Xcode, but you must add some manually.
Because frameworks are never associated with documents directly, you should never specify any document types. You may include display name information if you wish.
For more information on configuration and information property lists, see Runtime Configuration Guidelines.
The structure of an umbrella framework is similar to that of a standard framework, and applications do not distinguish between umbrella frameworks and standard frameworks when linking to them. However, two factors distinguish umbrella frameworks from other frameworks. The first is the manner in which they include header files. The second is the fact that they encapsulate subframeworks.
The purpose of an umbrella framework is to provide all the necessary interfaces for programming in a particular application environment. Umbrella frameworks hide the complex cross-dependencies among the many different pieces of system software. Thus you do not need to know what set of frameworks and libraries you must import to accomplish a particular task. Umbrella frameworks also make faster builds possible through the use of precompiled headers.
An umbrella framework simply includes and links with constituent subframeworks and other public frameworks. An umbrella framework encompasses all the technologies and APIs that define an application environment or a layer of system software. It also provides a layer of abstraction between what outside developers link their programs with and what Apple engineering provides as implementation.
A subframework is structurally a public framework that packages a specific Apple technology, such as Apple events, Quartz, or Open Transport. However, a subframework is public with restrictions. Although the APIs of subframeworks are public, Apple has put mechanisms in place to prevent developers from linking directly with subframeworks (see “Restrictions on Subframework Linking”). A subframework always resides in an umbrella framework installed in /System/Library/Frameworks
, and within this umbrella framework, its header files are exposed.
Some umbrella frameworks include other umbrella frameworks; this is particularly the case with the umbrella frameworks for the Carbon and Cocoa application environments. For example, both Carbon and Cocoa (directly or indirectly) import and link with the Core Services umbrella framework (CoreServices.framework
). This umbrella framework, in turn, imports and links with subframeworks such as Core Foundation.
The exact composition of the subframeworks within an umbrella framework is an internal implementation detail subject to change. By providing a level of indirection, umbrella frameworks insulate developers from these changes. Apple might restructure the subframeworks within an umbrella framework and might add, rename, or remove the header files within subframeworks. If you include the master header file for the subframework, these changes should not affect your programs.
Physically, umbrella frameworks have a similar structure to standard frameworks. One significant difference is the addition of a Frameworks
directory to contain the subframeworks that make up the umbrella framework.
Listing 4 shows a partial listing of the Core Services framework. (The contents of the subframeworks are not included since they are not referenced anyway.) As with standard frameworks, the top-level items are symbolic links to items deeper within the framework directory structure. In this case, the linked libraries and directories are located in folder A
of the framework.
Listing 4 Structure of the Core Services umbrella framework
CoreServices.framework/ |
CoreServices -> Versions/Current/CoreServices |
CoreServices_debug -> Versions/Current/CoreServices_debug |
CoreServices_profile -> Versions/Current/CoreServices_profile |
Frameworks -> Versions/Current/Frameworks |
Headers -> Versions/Current/Headers |
Resources -> Versions/Current/Resources |
Versions/ |
A/ |
CoreServices |
CoreServices_debug |
CoreServices_profile |
Frameworks/ |
CarbonCore.framework |
CFNetwork.framework |
OSServices.framework |
SearchKit.framework |
WebServicesCore.framework |
Headers/ |
Components.k.h |
CoreServices-gcc3.p |
CoreServices-gcc3.pp |
CoreServices.h |
CoreServices.p |
CoreServices.pp |
CoreServices.r |
Resources/ |
Info-macos.plist |
version.plist |
Current -> A |
Unlike standard frameworks, the Headers
directory of an umbrella framework contains a more limited set of header files. It does not contain a collection of the headers in its subframeworks. Instead, it contains only the master header file for the framework. When referring to an umbrella framework in your source files, you should include only the master header file. See “Including Frameworks” for more information.
© 2003, 2006 Apple Computer, Inc. All Rights Reserved. (Last updated: 2006-11-07)