< Day Day Up > |
11.2. Compiling Unix Source CodeMany of the differences between Mac OS X and other versions of Unix become apparent when you try to build Unix-based software on Mac OS X. Most open source Unix software uses GNU autoconf or a similar facility, which generates a configure script that performs a number of tests of the system especially of the installed Xcode Tools and finishes by constructing one or more makefiles. After the configure script has done its job, you run the make command to first compile, and, if all goes well, install the resulting binaries.
In most cases, it's pretty easy to compile a Unix application on Mac OS X. After unpacking the tarball and changing to the top-level source code directory, just issue the following three commands to compile the application: ./configure make make install
The following sections deal with issues involved in successfully performing these steps. Determining how to improvise within that three-step procedure reveals some of the differences between Mac OS X and other Unix systems. 11.2.1. The First Line of DefenseMost tarballs include the following files in the top-level directory:
These files contain useful information that may help you get the application running on Mac OS X. 11.2.2. Host TypeOne of the first difficulties you may encounter when running a configure script is that the script aborts with an error message stating that the host system cannot be determined. Strictly speaking, the host type refers to the system on which software will run, and the build type refers to the system on which the software is being built. It is possible to build software on one system to run on another system, but to do so requires a cross-compiler. We will not concern ourselves with cross-compiler issues. Thus, for our discussion, both the host type and the build (and target) types are the same: powerpc-apple-darwinVERSION, where the VERSION denotes the particular version of Darwin. In fact, a configure script detects Mac OS X by the host/build type named Darwin, since Darwin is the actual operating system underlying Mac OS X. This can be verified by issuing the uname -v command, which tells you that you're running a Darwin kernel, the kernel version, and when it was last built. Many configure scripts are designed to determine the host system, since the resulting makefiles differ depending on the type of system for which the software is built. The configure script is designed to be used with two files related to the host type, usually residing in the same directory as the configure script. These files are config.guess, which is used to help guess the host type; and config.sub, which is used to validate the host type and to put it into a canonical form (such as CPUTYPE-MANUFACTURER-OS, as in powerpc-apple-darwin8.0.0). Although Mac OS X and Darwin have been around for a while now, you may still run across source code distributions that contain older config.* files that don't work with Mac OS X. You can find out if these files support Darwin by running the ./configure script. If the script complains about an unknown host type, you know that you have a set of config.* files that don't support Darwin. In that case, you can replace the config.guess and config.sub files with the Apple-supplied, like-named versions residing in /usr/share/automake-1.6. These replacement files originate from the FSF and include the code necessary to configure a source tree for Mac OS X . To copy these files into the source directory, which contains the configure script, simply issue the following commands from within the sources directory: cp /usr/share/automake-1.6/config.sub . cp /usr/share/automake-1.6/config.guess . 11.2.2.1. MacrosYou can use a number of predefined macros to detect Apple systems and Mac OS X in particular. For example, _ _APPLE_ _ is a macro that is defined on every Apple gcc-based Mac OS X system, and _ _ MACH_ _ is one of several macros specific to Mac OS X. Table 11-1 lists the predefined macros available on Mac OS X
11.2.3. Supported LanguagesWhen using the cc command, which supports more than one language, the language is determined by either the filename suffix or by explicitly specifying the language using the -x option. Table 11-2 lists some of the more commonly used filename suffixes and -x arguments supported by Apple's version of GCC.
Although the HFS+ filesystem is case-insensitive, the cc compile driver recognizes the uppercase C in a source file. For example, cc foo.C invokes cc's C++ compiler because the file extension is an uppercase C, which denotes a C++ source file. (To cc, it's just a command-line argument.) So, even though HFS+ will find the same file whether you type cc foo.c or cc foo.C, what you enter on the command line makes all the difference in the world, particularly to cc. 11.2.4. PreprocessingWhen you invoke cc without options, it initiates a sequence of four basic operations, or stages: preprocessing , compilation, assembly, and linking. In a multifile program, the first three stages are performed on each individual source code file, creating an object code file for each source code file. The final linking stage combines all the object codes that were created by the first three stages, along with user-specified object code that may have been compiled earlier into a single executable image file. 11.2.5. FrameworksIn Mac OS X, a framework is a type of bundle that is named with a framework extension. Before discussing the framework type of bundle, let's first briefly describe the notion of a bundle. A bundle is an important software packaging model in Mac OS X consisting of a directory that stores resources related to a given software package, or resources used by many software packages. Bundles, for example, can contain image files, headers, shared libraries, and executables. In addition to frameworks , there are at least two other types of bundles used in Mac OS X; applications (named with the .app extension), and loadable bundles including plug-ins (which are usually named with the .bundle extension).
The application and plug-in type bundles are built and organized so that the top level directory is named Contents. That is, the directory Contents/ contains the entire bundle, including any file needed by the bundle. Take for example, Safari. If you Control-click on the Safari application in the Finder and select Show Package Contents, the Contents/ directory will be revealed in the Finder. To see what's in the Contents/ directory, quickly hit -3 to switch the Finder to Column View, and then hit the C key on your keyboard (this highlights the Contents folder). You will see the typical contents of an application bundle, including:
Applications can also contain application-specific frameworks , that is, frameworks that are not used by any other application or plug-in. 11.2.5.1. Framework structureFrameworks are critical in Mac OS X. Cocoa, the toolkit for user interface development, consists of the Foundation and Application Kit (or AppKit) frameworks for Objective-C and Java. Frameworks use a versioned bundle structure, which allows multiple versions of the same information; for example, framework code and header files. They are structured in either one of the following ways:
In either case, an Info.plist file describing the framework's configuration must be included in the Resources/ directory. (Chapter 12 discusses how to create frameworks and loadable bundles. This chapter only describes how to use the frameworks.) Before discussing how to use frameworks, let's look at the different kinds of frameworks. A private framework is one that resides in a directory named PrivateFrameworks, and whose implementation details are not exposed. Specifically, private frameworks reside in one of the following locations.
An application-specific framework can be placed within the given application's package. For example, consider the private framework, Graphite.framework, which is located in /System/Library/PrivateFrameworks. This private framework consists of a directory named Graphite.framework/, which, aside from symbolic links and subdirectories, contains the Graphite executable and files named Info.plist and version.plist. No implementation details are revealed. A public framework, on the other hand, is one whose API can be ascertained, for example, by viewing its header files. Public frameworks reside in appropriate directories named Frameworks/. For example, the OpenGL framework resides in /System/Library/Frameworks. This public framework consists of the directory /System/Library/Frameworks/OpenGL.framework, which contains (among other things) a subdirectory named Headers. Implementation details can be ascertained by examining the header files. Precisely where a public framework resides depends on its purpose, and where it is placed. When you build an application, you can program the path of the framework. Later, when the application is run, the dynamic link editor looks for the framework in the path that was programmed into the application. If a framework cannot be found, the following locations are searched in the order shown:
There are three types of frameworks in /System/Library/Frameworks:
To better understand the difference between simple and umbrella frameworks, compare the composition of the simple /System/Library/Frameworks/AppKit.framework with the umbrella framework /System/Library/Frameworks/CoreServices.framework. The umbrella framework contains several other frameworks, namely, CarbonCore, CFNetwork, Metadata, OSSerrvices, SearchKit, and WebServicesCore. The simple framework neither contains subframeworks, nor is it a subframework contained within an umbrella framework. 11.2.5.2. Including a framework in your applicationWhen including application-specific frameworks, you must let the preprocessor know where to search for framework header files. You can do this with the -F option, which is also accepted by the linker. For example: -F directoryname instructs the preprocessor to search the directory directoryname for framework header files. The search begins in directoryname and, if necessary, continues in the standard framework directories in the order listed earlier.
To include a framework object header, use #include in the following format: #include <framework/filename.h> Here, framework is the name of the framework without the extension, and filename.h is the source for the header file. If your code is in Objective-C, the #import preprocessor directive may be used in place of #include. The only difference beyond that is that #import makes sure the same file is not included more than once. The -F option is accepted by the preprocessor and the linker, and is used in either case to specify directories in which to search for framework header files. (This is similar to the -I option, which specifies directories to search for .h files.) By default, the linker searches the standard directories, /Local/Library/Frameworks and /System/Library/Frameworks, for frameworks. The directory search order can be modified with -F options. For example: cc -F dir1 -F dir2 -no-cpp-precomp myprog.c results in dir1 being searched first, followed by dir2, followed by the standard framework directories. While the -F flag is needed only when building application specific frameworks, the -framework is always needed to link against a framework. Specifically, inclusion of this flag results in a search for the specified framework named when linking. Example 11-1 shows "Hello, World" in Objective-C. Notice that it includes the AppKit framework. Example 11-1. Saying hello from Objective-C#include <Appkit/AppKit.h> int main(int argc, const char *argv[]) { NSLog(@"Hello, World\n"); return 0; } Save Example 11-1 as hello.m. To compile it, use -framework to pass in the framework name: cc -framework AppKit -o hello hello.m The -framework flag is accepted only by the linker and is used to name a framework. Compiler flags of particular interest in Mac OS X are related to the peculiarities of building shared code, for example, the compiler flag -dynamiclib, which is used to build Mach-O dylibs. For more details, see Chapter 12. 11.2.6. Compiler FlagsYou can see the gcc manpage for an extensive list of compiler flags. In particular, the gcc manpage describes many PowerPC-specific flags, as well as Darwin-specific flags. Table 11-3 describes a few common Mac OS X GCC compiler flags that are specific to Mac OS X. These flags should be used when porting Unix-based software to Mac OS X. We've also included a few flags that enable various Tree-SSA-based optimizations. These are the flags that begin with -ftree.
|
< Day Day Up > |