2.8. Bundles and Frameworks
Before discussing other
layers
of Mac OS X, let us look at the
bundle
and
framework
abstractions, since much of the
user
-level functionality in Mac OS X is implemented as frameworks, and a framework is a specific type of a bundle.
2.8.1. Bundles
A bundle is a collection of
related
resources packaged as a directory hierarchy. Examples of resources that reside in bundles include executables, shared libraries, plug-ins, header files, images, audio files, documentation, andrecursivelyother bundles. The bundle abstraction is very useful in packaging, deploying, maintaining, and using software. Consider the example of an application bundle, which is one of the most commonly used bundle types on Mac OS X. Figure 212 shows the hierarchical structure of the iTunes application bundle.
An application bundle is a directory with a
name
that conventionally has a
.app
suffix. Mac OS X applications are often more than just a single stand-alone executable. For example, an application may use a variety of media filesicons, splash images, and soundsin its user interface. An application may implement much of its functionality modularly, across one or more dynamic shared libraries. An application may also support a plug-in architecture through which anybody may extend the application's functionality by writing loadable plug-ins. Bundles are well suited for such applications because they keep the various constituents of the application together in a structured manner. As shown in Figure 212, the iTunes application bundle contains the main iTunes executable, a loadable plug-in bundle, icons, media files, a helper application, localized documentation, and so on. Everything resides within the
iTunes.app
directory, rather than being strewn over many system directories. Given such bundles, application installation and removal can be as trivial as copying or deleting, respectively, a single
.app
directory. Applications can also be moved after installation since they are usually self-contained.
The Finder treats several types of bundles as
opaque
, atomic entitiesas if they were files and not directories. For example, double-clicking on an application bundle launches the application. The user may browse the bundle's contents by using the Finder's Show Package Contents contextual-menu item. A bundle's opaqueness may be asserted in several ways, for example, through a property list file, through a
PkgInfo
file, and through the
kHasBundle
file system attribute.
Several types of Mach-O binaries exist within bundles on Mac OS X. Bundles can be programmatically accessed using the
CFBundle
and
NSBundle
APIs. Table 21 lists several examples of bundle types on Mac OS X.
Table 21. Examples of Bundle Types on Mac OS X
|
Bundle Type
|
Default Extension
|
Explanation
|
|
Automator action
|
.action
|
Automator actions are extensions to the default set of actions supported by the Automator workflow-based application, which allows users to graphically construct a sequence of actions by picking one or more actions from a palette of available actions. These bundles can be implemented in Objective-C or AppleScript.
|
|
Application
|
.app
|
Mac OS X application bundles typically contain dynamically linked executable programs along with any resources needed by the programs.
|
|
Bundle
|
.bundle
|
A
.bundle
package is a loadable bundle containing dynamically linked code that can be loaded by a program at runtime. The program must explicitly load such a bundle using dynamic linking functions. Several Mac OS X applications use
.bundle
plug-ins to extend their feature sets. For example, the Address Book application can load Action Plug-In bundles from specific directories, allowing programmers to populate the Address Book rollover
menus
with custom items. iTunes uses bundles to implement visual plug-ins, whereas iMovie uses them to implement effects, titles, and transitions.
|
|
Component
|
.component
|
Core Audio plug-ins, which are useful for manipulating generating, processing, or receiving audio streams, are implemented as
.component
bundles.
|
|
Dashboard widget
|
.wdgt
|
Dashboard is a lightweight runtime environment introduced in Mac OS X 10.4 for running small
accessory
programs called
widgets
in a logically separate layer atop the desktop. Dashboard widgets are packaged as
.wdgt
bundles.
|
|
Debug (application)
|
.debug
|
Applications with debugging symbols can be packaged as
.debug
bundles, which the Finder treats similarly to
.app
bundles.
|
|
Framework
|
.framework
|
A framework is a dynamic shared library packaged with resources such as header files, API documentation, localized strings, helper programs, icons, splash images, sound files, and interface definition files. An umbrella framework is a bundle that contains one or more subframeworks in its
Frameworks
subdirectory. The Carbon and Core Services frameworks are examples of umbrella frameworks.
|
|
Kernel extension
|
.kext
|
Kernel extensions are dynamically loadable kernel modules. They are similar to
.bundle
bundles in that they contain code that is programmatically introduced into a running programthe program being the kernel in this case. However, kernel extensions are statically linked.
|
|
Keynote file
|
.key
|
Applications can use bundles as complex "file formats" to hold arbitrary data in documents. Apple's Keynote software uses bundles to store presentations. A
.key
bundle contains an XML-based representation of the presentation's structure, along with resources such as images, thumbnails, audio, and video.
|
|
Metadata importer
|
.mdimporter
|
Metadata importers are used by the integrated Spotlight search technology in Mac OS X. Such an importer gathers information from one or more specific file formats. Developers of applications with custom file formats can provide their own metadata importers that Spotlight can use as plug-ins while indexing a file system.
|
|
Package
|
.pkg
,
.mpkg
|
A
.pkg
bundle is an installation package created using the
PackageMaker.app
application. A package's contents include files and directories
belonging
to the installable software it represents, along with information that may be needed to install the software. A metapackagea
.mpkg
bundlecontains a file that includes a list of packages or metapackages and any other information that might be needed to install them. Unlike a package, a metapackage does not itself contain any installable software. Double-clicking a package or a metapackage launches the Mac OS X installer application.
|
|
Palette
|
.palette
|
A palette is a loadable bundle that contains code and
user-interface
objects used by Apple's integrated development environment (IDE).
|
|
Plug-in
|
.plugin
|
A
.plugin
is a loadable bundle similar in concept to a
.bundle
but has more architectural and implementation requirements. Contextual-menu plug-ins, which are used to extend the list of commands on Finder contextual menus, are implemented as
.plugin
bundles. Other examples of such bundles include certain QuickTime plug-ins and extensions called
Image Units
to the Core Image and Core Video technologies.
|
|
Preference pane
|
.prefPane
|
Preference panes are bundles used to manage system-wide software and hardware preferences. The System Preferences application displays the union of various
.prefPane
bundles located in
/System/Library/PreferencePanes/
,
/Library/PreferencePanes/
, and
~/Library/PreferencePanes/
.
|
|
Profile (application)
|
.profile
|
Applications with profiling data can be packaged as
.profile
bundles, which the Finder treats similarly to
.app
bundles.
|
|
Service
|
.service
|
A service is a bundle that provides generic functionality for use by other applications. Examples of services include text-to-speech conversion, (
SpeechService.service
), spell checking (
AppleSpell.service
), and Spotlight searching (
Spotlight.service
). Services can be made available on a system-wide basis through
.service
bundles. A service is usually contextual in its operationit operates on a currently selected entity, such as a piece of text. For example, the AppleSpell service will run a spelling check on the selected text.
|
|
Screensaver
|
.saver
,
.slideSaver
|
Mac OS X provides APIs for creating screensavers based on program-generated content or slide shows. Such screensaver programs are packaged as
.saver
and
.slideSaver
bundles, respectively. Note that a
.slideSaver
bundle does not contain any executable codeit contains only a set of images in its
Resources
directory and an information property list file.
|
|
System Profiler reporter
|
.spreporter
|
The System Profiler application displays information about the system's hardware and software. It uses
.spreporter
bundles residing in
/System/Library/SystemProfiler/
to collect information. Each reporter bundle provides information about a particular area. For example, there are system reporter bundles for attached displays, FireWire devices, Serial ATA devices, USB devices, and installed software and fonts.
|
|
Web plug-in
|
.webplugin
|
The Safari web browser supports an Objective-C-based plug-in model for displaying new types of content in the browser through plug-ins. QuickTime support in Safari is implemented as a
.webplugin
bundle.
|
|
Xcode plug-in
|
.ibplugin
,
.pbplugin
,
.xcplugin
,
.xctxtmacro
,
.xdplugin
|
The functionality of Apple's Xcode development environment can be extended through several types of plug-ins.
|
As shown in Table 21, bundles are used to implement several types of plug-ins. From a generic standpoint, a plug-in is an external piece of code that runs in a
host
environment. Typically the host is an application, but it can be an operating system or perhaps even another plug-in. The host must be designed to be extensible through plug-insit must export an API for the plug-in to conform to. Thus, by using the host's plug-in API, a plug-in can add functionality to the host without requiring recompilation of, or even access to, the host's source.
Note that the bundle extensions listed in Table 21 are only conventionsit is possible to have a bundle with an arbitrary extension, as long as certain requirements are satisfied or the application using the bundle
knows
how to handle the extension.
2.8.2. Property List Files
You will frequently come across
property list
(
plist
) files on Mac OS X. They are on-disk representations of organized data. When such data is in memory, it is structured using basic data types native to the Core Foundation framework.
The Core Foundation data types used in property lists are
CFArray
,
CFBoolean
,
CFData
,
CFDate
,
CFDictionary
,
CFNumber
, and
CFString
. An important feature of these data types is that they are readily portable across multiple Mac OS X subsystemsfor example, CF data types have analogs in the I/O Kit.
An on-disk property list is a serialized version of an in-memory property list. A plist file may store information in either binary format or
human-readable
XML format.
The two most common uses of plist files on Mac OS X are by bundles and by applications.
A bundle uses a special type of plist filean
information property list
to specify its critical attributes, which are read by other programs while handling the bundle. The default name for an information property list file is
Info
.plist
. Consider an application bundle's
Info.plist
file, whose contents may include attributes such as the following:
-
The document types handled by the application
-
The name of the bundle's main executable file
-
The name of the file containing icons for the bundle
-
The application's unique identification string
-
The application's version
Applications use property list files to store user preferences or other custom configuration data. For example, the Safari web browser stores a user's bookmarks in a plist file called
Bookmarks.plist
. Numerous configuration plist files can be found in a user's
~/Library/Preferences/
directory. Typically, applications store per-user configurations or preferences in this directory using a reverse DNS naming convention. For example, the Safari web browser's preferences are stored in
com.apple.Safari.plist
.
Property list files can be created and manipulated using several tools on Mac OS X. The
plutil
command-line program can be used to convert a plist file from one format to another. It also checks plist files for syntax errors. XML-format plist files can be edited using any text editor, although it might be more
convenient
(and less
error-prone
) to use the Property List Editor graphical application, which is part of Apple Developer Tools. The Cocoa and Core Foundation frameworks provide APIs for programmatically accessing plist files. As alluded to earlier, several standard object types in these frameworks are stored, organized, and accessed as property lists.
2.8.3. Frameworks
In its simplest form, a Mac OS X framework is a bundle containing one or more shared libraries. Besides stand-alone shared librariessuch as the ones in
/usr/lib/
Mac OS X contains a large number of frameworks. Whereas a shared library contains shared code, a framework usually contains one or more shared libraries along with other types of related resources.
From an implementation standpoint, a framework is a directory hierarchy encapsulating shared resources such as the following:
A framework directory has a
well-defined
structure consisting of files and folders, some of which are mandatory; the others are optional. Figure 213 shows the files and folders contained in the hypothetical Foo framework.
Figure 213. Bundle structure of a Mac OS X framework
Foo.framework/
# Top-level directory
Headers -> Versions/Current/Headers
# Symbolic link
Foo -> Versions/Current/Foo
# Symbolic link
Libraries -> Versions/Current/Libraries
# Symbolic link
Resources -> Versions/Current/Resources
# Symbolic link
Versions/
# Contains framework major versions
A/
# Major version A
Foo
# Framework's main dynamic library
Headers/
# Public headers
Bar.h
Foo.h
Libraries/
# Secondary dynamic libraries
libfoox.dylib
libfooy.dylib
Resources/
English.lproj/
# Language-specific resources
Documentation/
# API documentation
InfoPlist.strings
# Localized strings
Info.plist
# Information property list file
B/
# Major version B
Foo
Headers/
Bar.h
Foo.h
Libraries/
libfoox.dylib
libfooy.dylib
Resources/
English.lproj/
Documentation/
InfoPlist.strings
Info.plist
Current -> B
# Symbolic link to most recent version
|
The
Info.plist
file within the
Resources
subdirectory of a framework contains its identifying information. Frameworks support versioning: If an application depends on a particular version of a framework, either the exact version or a compatible version of that framework must exist for the application to run. Major version differences are incompatible, whereas minor version differences are compatible. A single framework bundle may contain multiple major versions. The framework shown in Figure 213 contains two versions, A and B. Moreover, all files and directories in the framework's top-level directory, except
Versions
, are symbolic links to entities belonging to the major version
Current
.
Foo
, the file with the same name as that of the framework directory's prefix, is the main dynamic shared library.
Figure 214 shows the standard Mac OS X frameworks categorized by the typical purposes they are used for.
An umbrella framework can contain other subframeworks and even other subumbrella frameworks. Umbrella frameworks are used to hide interdependencies between discrete system libraries by effectively presenting a metalibrary that is the union of all libraries within it. An umbrella framework's bundle structure is similar to that of a standard framework, but it also contains a subdirectory called
Frameworks
, which contains subframeworks. Typically, the programmer may not link directly to subframeworks.
In fact, the programmer need not know whether a framework is an umbrella framework or notlinking to an umbrella framework automatically provides access to its constituents. At runtime, if the dynamic linker comes across a symbol that has been recorded as "contained in an umbrella framework," the linker will search the umbrella framework's subframeworks, sublibraries, and subumbrellas. Similarly, an umbrella framework's header files automatically include any header files in the subframeworks. Figure 215 shows the standard umbrella frameworks on Mac OS X.
Frameworks can also be
private
in that they are unavailable for linking by user programs. Some frameworks are private because they are embedded within other bundles such as application bundles. Mac OS X contains a number of frameworks that are private to Apple. These reside in
/System/Library/PrivateFrameworks/
. Examples of private frameworks include
DiskImages.framework
,
Install. framework
,
MachineSettings.framework
,
SoftwareUpdate.framework
, and
VideoConference.framework
. Their privacy is manifested in the following ways from the standpoint of a third-party programmer.
-
Apple does not publish the APIs of these frameworks. Even their header files are not available.
-
By default, a third-party programmer cannot link with these frameworks. However, it is possible to link with a private framework by explicitly passing the full pathname of its containing directory to the linker. Doing so is unsupported by Apple.
When a dynamically linked program is compiled, the installation paths of the libraries it links with are recorded in the program. These paths are typically absolute for system frameworks that are part of Mac OS X. Some applications, particularly third-party applications, may contain their own frameworks within their application bundles. Paths to such frameworks or libraries, when recorded in an application, can be recorded relative to the application bundle.
When the dynamic link editor needs to search for frameworks, the fallback paths it uses are
~/Library/Frameworks/
,
/Library/Frameworks/
,
/Network/
Library/Frameworks/
, and
/System/Library/Frameworks/
, in that order. Similarly, fallback paths for dynamic libraries are
~/lib/
,
/usr/local/lib/
, and
/usr/lib/
. Note that
path
searching is not performed in a user's home directory for setuid programs that are not executed by the real user.
2.8.4. Prebinding
Mac OS X uses a concept called
prebinding
to optimize Mach-O applications to launch faster by reducing the work of the runtime linker.
As we saw earlier, the dynamic link editor,
dyld
, is responsible for loading Mach-O code modules, resolving library dependencies, and preparing the code for execution. Resolving undefined symbols in executables and dynamic libraries at runtime involves mapping the dynamic code to free address ranges and computing the resultant symbol addresses. If a dynamic library is compiled with prebinding support, it can be
predefined
at a given preferred address range.
This way,
dyld
can use predefined addresses to reference symbols in such a library. For this to work, libraries cannot have overlapping preferred addresses. To support prebinding, Apple marks several address ranges as either reserved or preferred for its own software and specifies
allowable
ranges for use by third-party libraries.
dyld
was optimized in Mac OS X 10.3.4 such that prebinding of applications is no longer necessary. Moreover, prebinding of applications is entirely deprecated on Mac OS X 10.4.
Let us consider an examplethat of the System framework (
System.framework
). The shared library within this framework is actually a symbolic link to the libSystem dynamic library in
/usr/lib/
. In other words,
System.framework
is a wrapper around libSystem. Let us use
otool
to display the load commands in libSystem to determine its preferred load address (Figure 216).
Figure 216. Listing the load commands in a Mach-O file
$
otool -l /usr/lib/libSystem.dylib
/usr/lib/libSystem.dylib:
Load command 0
cmd LC_SEGMENT
cmdsize 872
segname __TEXT
vmaddr 0x90000000
vmsize 0x001a7000
fileoff 0
filesize 1732608
maxprot 0x00000007
initprot 0x00000005
nsects 12
flags 0x0
...
|
{% if main.adsdop %}{% include 'adsenceinline.tpl' %}{% endif %}
The
vmaddr
value shown in Figure 216 is the preferred load address of libSystem. We can use the C program in Figure 217 to print the
names
and load addresses of all Mach-O object files loaded into the program's address space and to check whether libSystem is loaded at its preferred address or not.
Figure 217. Printing libraries loaded in a program
// printlibs.c
#include <stdio.h>
#include <mach-o/dyld.h>
int
main(void)
{
const char *s;
uint32_t i, image_max;
image_max = _dyld_image_count();
for (i = 0; i < image_max; i++)
if ((s = _dyld_get_image_name(i)))
printf("%10p %s\n", _dyld_get_image_header(i), s);
else
printf("image at index %u (no name?)\n", i);
return 0;
}
$
gcc -Wall -o printlibs printlibs.c
$
./printlibs
0x1000 /private/tmp/./printlibs
0x91d33000 /usr/lib/libmx.A.dylib
0x90000000 /usr/lib/libSystem.B.dylib
0x901fe000 /usr/lib/system/libmathCommon.A.dylib
|
The
update_prebinding
program is run to attempt to synchronize prebinding information when new files are added to a system. This can be a
time-consuming
process even if you add or change only a single file. For example, all libraries and executables that might dynamically load the new file must be found. Package information is used to expedite this process. A dependency graph is also built. Eventually
redo_prebinding
is run to prebind files appropriately.
After a software update or installation, while the installer program displays the "Optimizing..." status message, it is running the
update_prebinding
and
redo_prebinding
(if necessary) programs.
As shown in Figure 218,
otool
can be used to determine whether a binary is prebound.
Figure 218. Determining whether a Mach-O file is prebound
$
otool -hv /usr/lib/libc.dylib
/usr/lib/libc.dylib:
Mach header
magic cputype cpusubtype filetype ncmds sizeofcmds flags
MH_MAGIC PPC ALL DYLIB 10 2008 NOUNDEFS DYLDLINK
PREBOUND SPLIT_SEGS
TWOLEVEL
|
|