Many 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 Unix-based open source 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 Development 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.
TIP: Most tarballs will include a configure script, so you do not need to generate it yourself. However, if you retrieve autoconf-managed source code from a CVS archive, you will have to run autoconf.sh manually to generate the configure file.
In most cases, performing the following three steps is all that is needed to successfully compile a Unix-based application on Mac OS X after you have unpacked the tarball and changed to the top-level source code directory:
./configure make make install
WARNING: Mac OS X web browsers are configured to invoke StuffIt on compressed archives. So, if you click on a link to a tarball, you may find that it gets downloaded to your desktop and extracted there. If you'd prefer to manage the download and extraction process yourself, Control-click or right-click on the link so you can specify a download location.
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.
Most tarballs will include the following files in the top-level directory: README, INSTALL, and a file named PORT or PORTING. These files contain useful information that may help you get the application running on Mac OS X.
One of the first difficulties you may encounter in running a configure script is when 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 will differ depending on the type of system for which the software is being 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-darwin6.0).
Since Mac OS X and Darwin are relatively new, you may 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 .
You 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 4-1 lists the predefined macros available on Mac OS X.
Macro |
When defined |
---|---|
When the compiler is compiling Objective-C .m files or Objective-C++ .M files. (To override the file extension, use -ObjC or -ObjC++). |
|
When the compiler is compiling .s files. |
|
When compiling for systems that use natural alignment, such as powerpc. |
|
If, and only if, the -bsd flag is specified as an argument to the compiler. |
|
When compiling for systems that support Mach system calls. |
|
When compiling for any Apple system. Currently defined only on Mac OS X systems running Apple's variant of the GNU C compiler. Do not rely on this macro to tell you that you are on Darwin or Mac OS X, since third-party compilers may not define this macro. |
|
When compiling for any Apple system. Integer value that corresponds to the (Apple) version of the compiler. |
|
When AltiVec support was enabled with the -faltivec flag. |
WARNING: Do not rely on the presence of the _ _APPLE_ _ macro to determine which compiler features or libraries are supported. Instead, we suggest that you use a package like GNU autoconf to tell you which features the target operating system supports. This approach makes it more likely that your applications can compile out-of-the-box (or with little effort) on operating systems to which you don't have access.
When 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 4-2 lists some of the more commonly used filename suffixes and -x arguments supported by Apple's version of GCC.
File suffix |
Language |
-x argument |
---|---|---|
.c |
C source code to be preprocessed and compiled |
c |
.C, .cc, .cxx, .cpp |
C++ source code to be preprocessed and compiled |
c++ |
.h |
C header that should neither be compiled nor linked |
c-header |
.i |
C source code that should be compiled but not preprocessed |
cpp-output |
.ii |
Objective-C++ or C++ source code that should be compiled but not preprocessed |
c++-cpp-output |
.m |
Objective-C source code |
objective-c |
.M, .mm |
Mixed Objective-C++ and Objective-C source code |
objective-c++ |
.s |
Assembler source that should be assembled but not preprocessed |
assembler |
.S |
Assembler source to be preprocessed and assembled |
assembler-with-cpp |
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.
When 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.
Apple's compiler provides two preprocessors. The default preprocessor for both C and Objective-C is the precompilation preprocessor written by Apple, named cpp-precomp. The standard GNU C preprocessor, named cpp, is also available and is the default for Objective-C++ code. cpp-precomp supports precompiled header files. (For more information about cpp-precomp, see Chapter 5.) cpp-precomp is faster than cpp. However, some code may not compile with cpp-precomp. In that case, you should invoke cpp by instructing cc not to use cpp-precomp. For example, to compile the C program myprog.c using the standard GNU preprocessor, cpp, use the -no-cpp-precomp switch as follows:
cc -no-cpp-precomp myprog.c
WARNING: Earlier versions of the Mac OS X Developer Tools used the -traditional-cpp switch, but this switch had undesirable side effects and is deprecated.
Chapter 5 describes precompilation in more detail.
Object-oriented frameworks are critical in Mac OS X. Indeed Cocoa, the object-oriented toolkit for user interface development, consists of the Foundation and Application Kit (or AppKit) frameworks for Objective-C and Java. It is often necessary to 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. Thus:
-F directoryname
instructs the preprocessor to search the directory directoryname for framework header files. The search begins in directoryname and, if necessary, continues in order in the following standard framework directories:
/Library/Frameworks (if the -no-cpp-precomp flag is specified)
/System/Library/Frameworks
To include a framework object header in Objective-C, use #import. The format of the #import preprocessor directive in your Objective-C code is:
#import <frameworkname/headerfilename.h>
Here, frameworkname is the name of the framework without the extension, and headerfilename.h is the source for the header file.
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
will result in dir1 being searched first, followed by dir2, followed by the standard framework directories. The other flag pertaining to frameworks is -framework. Inclusion of this flag results in a search for the specified framework named when linking. Example 4-1 shows "Hello, World" in Objective-C. Notice that it #imports the AppKit framework.
#import <Appkit/AppKit.h> int main(int argc, const char *argv[]) { NSLog(@"Hello, World\n"); return 0; }
Save Example 4-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. The flag -nostdinc is used to prohibit the search for header files in any directory other than those specified via other options, such as -I. Since strict ANSI-C does not allow many of the preprocessor constructs used in most software created nowadays, the preprocessors are designed to allow several nonstandard ANSI-C constructs by default. Although it is usually undesirable to do so, you must include the compile driver flags -trigraphs, -undef, and -pedantic to enforce strict ANSI-C standards .
There are also several undocumented features of the compiler. These include the following cc command-line flags.
Other compiler flags of particular interest in Mac OS X are related to the peculiarities of building shared code. For more details, see Chapter 5.
Copyright © 2003 O'Reilly & Associates. All rights reserved.