2.8. Bundles and FrameworksBefore 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. BundlesA 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. Figure 212. Hierarchical structure of the iTunes application bundleAn 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.
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 FilesYou 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.[32] 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 listto 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:
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. FrameworksIn 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.[33] 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
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. Figure 214. Standard frameworks on Mac OS XAn 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.[34] 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.
Figure 215. Standard umbrella frameworks on Mac OS XFrameworks 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.
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. PrebindingMac 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.[35] 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
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
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
|