Configuring a Project for SDK-Based Development

This chapter describes the configuration of installed iOS and OS X SDKs and explains how to set up your Xcode project to use a particular SDK.

SDK Header Files and Stub Libraries

When you install Xcode, the installer creates a /Developer/SDKs directory. This directory contains one or more subdirectories, each of which provides the complete set of header files and stub libraries that shipped for a particular version of iOS or OS X. An OS X SDK is named by major version, such as MacOSX10.6.sdk, but represents the latest minor version available for the major version.

The Xcode installer for iOS places SDKs in the /Developer/Platforms directory, within which is a directory for each platform, such as iPhoneOS.platform. Each platform directory, in turn, contains a Developer/SDKs directory specific to that platform. The iOS SDKs are named by minor versions of iOS, such as iPhoneOS4.2.sdk.

Choosing the latest SDK for your project lets you use the new APIs introduced in the OS update that corresponds to that SDK. When new functionality is added as part of a system update, the system update itself does not typically contain updated header files reflecting the change. The SDKs, however, do contain updated header files.

Each .sdk directory resembles the directory hierarchy of the operating system release it represents: It has usr, System, and Developer directories at its top level. OS X .sdk directories also contain a Library directory. Each of these directories in turn contains subdirectories with the headers and libraries that are present in the corresponding version of the operating system with Xcode installed.

The libraries in an iOS or OS X SDK are stubs for linking only; they do not contain executable code but just the exported symbols. SDK support works only with native build targets.

Base SDK and Deployment Target Settings

To use a particular SDK for an Xcode project, make two selections in your project’s build settings. These choices determine which operating system features your project can use, as follows:

For possible values and more information about build settings in Xcode, see “Building for Multiple Releases of an Operating System” in Xcode Project Management Guide, Xcode Build Setting Reference and “Running Applications” in iOS Development Guide.

When you build your application, your deployment target is reflected in the MinimumOSVersion entry in the application’s Info.plist file. For iOS apps, the MinimumOSVersion entry is used by the App Store to indicate the iOS release requirement.

Figure 2-1 shows a timeline that explains the relationship between deployment target and base SDK.

Figure 2-1  SDK development timeline
Cross-development timeline

The figure describes a project with a deployment target of OS X v10.4 and a base SDK of OS X v10.6. (The version numbers in the figure represent all releases of that version, including system updates.)

In this example, the software can freely use any features from OS X v10.0 through the newest update of version 10.4. It can conditionally take advantage of features from OS X v10.5 and 10.6, after ensuring that each such feature is available.

The effects of these settings at compile time and run time are as follows. If your code uses a symbol:

Always check to see if you are using deprecated APIs; though still available, deprecated APIs are not guaranteed to be available in the future. The compiler warns you about the presence of deprecated APIs in your code, as described in “Finding Instances of Deprecated API Usage.”

When you change the base SDK setting, in addition to changing the headers and stub libraries your code builds against, Xcode adjusts the behavior of other features appropriately. For example, symbol lookup, code completion, and header file opening are based on the headers in the base SDK, rather than those of the currently running OS (if the two differ). Similarly, the Xcode Quick Help affinity mechanism ensures that documentation lookup uses the doc set corresponding to the base SDK.

In addition to setting the base SDK and deployment target for your project as a whole, you can set these values individually for each build target. Target settings override project settings. (However, some Xcode features that attempt to correlate with the base SDK setting, such as symbol definition and documentation lookup, may work differently.)

Weak Linking and Apple Frameworks

The Xcode compiler uses availability macros, attached to the symbols in Apple framework headers, to determine whether symbols are weakly or strongly linked. These macros state in which version of the operating system a feature first appeared. For example, the macro in the following declaration indicates that the enumerateObjectsUsingBlock: method (in the NSArray class) is available starting in OS X v10.6 and iOS 4.0:

- (void)enumerateObjectsUsingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block NS_AVAILABLE(10_6, 4_0);

When a symbol in a framework is defined as weakly linked, the symbol does not have to be present at runtime for a process to continue running. The static linker identifies a weakly linked symbol as such in any code module that references the symbol. The dynamic linker uses this same information at run time to determine whether a process can continue running. If a weakly linked symbol present in a code module is not present in the framework, the code module can continue to run as long as it does not reference the symbol. If a weakly linked symbol is present in its framework, the code can use it normally.

In the case of a deprecated symbol, the availability macro contains further syntax to indicate the version of the operating system in which the symbol was deprecated. In all cases, the reference documentation for a symbol states its availability and, if applicable, its deprecation information. The availability macros are defined in Availability.h and AvailabilityMacros.h in the /usr/include/ directory.

The Xcode compiler interprets each availability macro in light of the base SDK and deployment target settings for a project. The compiler uses these settings to assign appropriate values to the MAC_OS_X_VERSION_MIN_REQUIRED and MAC_OS_X_VERSION_MAX_ALLOWED macros.

For example, suppose in Xcode you set the deployment target (minimum required version) to “OS X v10.5” and the base SDK (maximum allowed version) to “OS X v10.6”. During compilation, the compiler would weakly link interfaces that were introduced in OS X v10.6 while strongly linking interfaces defined in earlier versions of the OS. This would allow your application to run in OS X v10.5 and take advantage of newer features when available.

Before using any symbol introduced in a version of iOS or OS X that is later than your deployment target, check whether the symbol is available. If the symbol is not available, provide an alternate code path. See “Using SDK-Based Development” for more information.

Configuring a Makefile-Based Project

If you have a makefile-based project, you can also take advantage of SDK-based development, by adding the appropriate options to your compile and link commands. Using SDKs in makefile-based projects requires GCC 4.0 or later. To choose an SDK, you use the -isysroot option with the compiler and the -syslibroot option with the linker. Both options require that you specify the full path to the desired SDK directory. To set the deployment target in a makefile, use a makefile variable of the form: ENVP= MACOSX_DEPLOYMENT_TARGET=10.4. To use this variable in your makefile, include it in front of your compile and link commands.

Setting the Prefix File

Xcode supports prefix files, header files that are included implicitly by each of your source files when they're built. Many Xcode project templates generate prefix files automatically, including umbrella frameworks appropriate to the selected type of application. For efficiency, prefix files are precompiled and cached, so Xcode does not need to recompile many lines of identical code each time you build your project. You can add directives to import the particular frameworks on which your application depends.

If you are using SDK-based development, you must ensure that your prefix file that takes into account the selected SDK. That is, don’t set the prefix file to an umbrella header file using an absolute path, such as /System/Library/Frameworks/Cocoa.framework/Versions/A/Headers/Cocoa.h. This absolute path does not work because the specified header is from the current system, rather than the chosen SDK.

To include umbrella framework headers, add the appropriate #import <Framework/Framework.h> directives to your prefix file. With this technique, the compiler always chooses the headers from the appropriate SDK directory. For example, if your project is named TestSDK and it has a prefix file TestSDK_Prefix.pch, add the following line to that file:

#import <Cocoa/Cocoa.h>

If you are using Objective-C, it’s preferable to use the #import directive rather than #include (which you must use in procedural C programs) because #import guarantees that the same header file is never included more than once.