Mac OS X Tiger for Unix Geeks

 < Day Day Up > 

11.2. Compiling Unix Source Code

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 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.

Most tarballs 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, 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

Mac OS X web browsers are configured to unpack 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.

11.2.1. The First Line of Defense

Most tarballs include the following files in the top-level directory:

README

This is an introduction to the application and source code. You'll often find copyright information in this document, notes about bug fixes or improvements made to different versions, and pointers to web sites, FAQs, and mailing lists.

INSTALL

This document contains step-by-step installation instructions.

PORT or PORTING

If present, one of these documents will include tips for porting the application to another Unix platform.

These files contain useful information that may help you get the application running on Mac OS X.

11.2.2. Host Type

One 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. Macros

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 11-1 lists the predefined macros available on Mac OS X

Table 11-1. Mac OS X C macros

Macro

When defined

_ _OBJC_ _

When the compiler is compiling Objective-C .m files or Objective-C++ .M files. (To override the file extension, use -ObjC or -ObjC++.)

_ _ASSEMBLER_ _

When the compiler is compiling .s files.

_ _NATURAL_ ALIGNMENT_ _

When compiling for systems that use natural alignment, such as powerpc.

_ _STRICT_BSD_ _

If, and only if, the -bsd flag is specified as an argument to the compiler.

_ _MACH_ _

When compiling for systems that support Mach system calls.

_ _APPLE_ _

When compiling for any Apple system. Defined on Mac OS X systems running Apple's variant of the GNU C compiler and third-party compilers.

_ _APPLE_CC_ _

When compiling for any Apple system. Integer value that corresponds to the (Apple) version of the compiler

_ _VEC_ _

When AltiVec support was enabled with the -maltivec flag.

_ _APPLE_VEC_ _

When AltiVec support was enabled with the -mpim-altivec flag.

_ _LP64_ _

Defined on 64-bit systems such as the G5. This macro can be used to conditionally compile 64-bit code

Do not rely on the presence of the _ _APPLE_ _ macro to determine which compiler features or libraries are supported. Instead, we suggest using 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.

11.2.3. Supported Languages

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 11-2 lists some of the more commonly used filename suffixes and -x arguments supported by Apple's version of GCC.

Table 11-2. File suffixes recognized by cc

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.

11.2.4. Preprocessing

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.

11.2.5. Frameworks

In 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).

  • An application bundle contains everything an application needs to run: executables, images, etc. You can actually see these in the Finder if you Control-click on an application's icon, and select Show Package Contents.

  • A framework bundle, on the other hand, is one that contains a dynamic shared library along with its resources, including header files, images, and documentation.

  • A loadable bundle contains executables and associated resources, which are loaded into running applications; these include plug-ins, and kernel extensions.

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:

  • The required XML property list file named Info.plist, which contains information about the bundle's configuration

  • A folder named MacOS/, which contains the executable

  • A folder named Resources/ that contains, among other resources, image files

  • Files named version.plist and PkgInfo

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 structure

Frameworks 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:

  • Symbolic links are used to point to the latest version. This allows for multiple versions of the framework to be present.

  • In the Framework bundle structure, the top level directory is named Resources. The actual Resources/ directory need not be located at the top level of the bundle; it may be located deeper inside of the bundle. In this case, a symbolic link pointing to the Resources/ directory is located at the top level.

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.

  • ~/Library/PrivateFrameworks

  • /Library/PrivateFrameworks

  • /System/Library/PrivateFrameworks

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:

~/Library/Frameworks

This is the location for frameworks used by a single user.

/Library/Frameworks

Third-party applications that are intended for use by all users on a system should have its frameworks installed in this directory.

/Network/Library/Frameworks

Third-party applications that are intended for use by all users across a local area network (LAN) should have its frameworks installed in this directory.

/System/Library/Frameworks

The shared libraries in these frameworks provided by Apple, for example, in the Application Kit (or AppKit), are to be used by all applications on the system.

There are three types of frameworks in /System/Library/Frameworks:

Simple public framework

Apple defines a simple framework as one which is neither a subframework nor an umbrella framework, and has placed in this category only those frameworks that have been used in older versions of Mac OS X. One such example is AppKit, which is located in /System/Library/Frameworks/AppKit.framework and can be examined in the Finder.

Subframework

A subframework is public, but has a restriction in that you cannot link directly against it. Its API is exposed, however, through its header files, and subframeworks reside in umbrella frameworks . To use a subframework, you must link against the umbrella framework in which it resides.

Umbrella framework

This type of framework includes other umbrella frameworks and subframeworks. The exact composition of an umbrella's subframeworks is an implementation detail which is subject to change over time. The developer need not be concerned with such changes, since it is only necessary to link against the umbrella framework and include only the umbrella framework's header file. One advantage to this approach is that not only can definitions be moved from one header file of a framework to another, but in the case of umbrella frameworks, the definition of a function can even be moved to another framework if that framework is included in the umbrella framework.

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 application

When 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.

The -F option is necessary only when building application-specific frameworks.

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 Flags

You 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.

Table 11-3. Selected Mac OS X GCC compiler flags

Flag

Effect

-no-cpp-precomp

Turns off the Mac OS X preprocessor in favor of the GNU preprocessor.

-ObjC, -ObjC++

Specifies objective-c and objective-c++, respectively. Also passes the -ObjC flag to ld.

-faltivec

Enables AltiVec language extension. Provided for compibility for earlier versions of GCC.

-maltivec

Enables AltiVec language extension.

-mpim-altivec

Enables AltiVec language extension as defined in the Motorola AltiVec Technology Programming Interface Manual (PIM). This option is similar in effect to -maltivec, but there are some differences. For example, -mpim-altivec disables inlining of functions containing AltiVec instructions as well as inline vectorization of memset and memcopy.

-mabi-altivec

Adds AltiVec ABI extensions to the current ABI.

-mnoabi-altivec

Disables AltiVec ABI extensions for the current ABI.

-mnopim-altivec

Disables the effect of -mpim-altivec.

-mno-altivec-long-deprecated

Disables the warning of the deprecated long keyword in AltiVec data types.

-mnoaltivec

Disables AltiVec language extension.

-arch ppc970 -arch pp64

Compile for the PowerPC 970 (aka G5) processor, and assemble only 64-bit instructions.

-mcpu=970 -mcpu=G5

Enables the use of G5-specific instructions.

-force_cpusubtype_ALL

This will force a runtime check to determine which CPU is present and will allow code to run on the G3, G4, or G5, regardless of which CPU was used to compile the code. Exercise caution if you use this and G5-specific features at the same time.

-mpowerpc64

When used in combination with -mcpu=970, -mtune=970, and -force_cpusubtype_ALL, the G5's support for native 64-bit long-long is enabled.

-mpowerpc-gpopt

Use the hardware based floating-point square function on the G5. (Use with -mcpu=970, -mtune=970, and -mpowerpc64.

-ftree-pre

Partial redundancy elimination on trees.

-ftree-fre

Full redundancy elimination on trees.

-ftree-ccp

Sparse conditional constant propagation on trees.

-ftree-ch

Loop header copying on trees. Enabled by default with -O, but not with -Os.

-ftree-dce -ftree-dominator-opts

Dead code elimination on trees.

-ftree-elim-checks

Elimination of checks based on scalar.

-ftree-loop-optimize

Loop optimization on trees.

-ftree-loop-linear

Linear loop transformations on trees to improve cache performance and allow additional loop optimizations.

-ftree-lim

Loop invariant motion on trees.

-ftree-sra

Scalar replacements of aggregates.

-ftree-copyrename

Copy renaming on trees.

-ftree-ter

Temporary expression replacement during SSA to normal phase.

-ftree-lrs

Live range splitting during SSA to normal phase.

-ftree-vectorize

Loop vectorization on trees. This enables -fstrict-aliasing, by default.

-fstrict-aliasing

Apply the strictest aliasing rules.

-fasm-blocks

Allow blocks and functions of assembly code in C or C+ source code.

-fconstant-cfstrings

Automatic creation CoreFoundation-type constant. (See the gcc manpage for details.)

-fpascal-strings

Allow the use of Pascal-style strings.

-fweak-coalesced

Weakly coalesced definitions are ignored by the linker in favor of one ordinary definition.

-findirect-virtual-calls

Use the vtable to call virtual functions, rather than making direct calls.

-fapple-kext

Make kernel extensions loadable by Darwin kernels. Use in combination with -fno-exceptions and -static.

-fcoalesce-templates

Coalesce instantiated templates.

-fobjc-exceptions

Support structured exception handling in Objective-C. (See the gcc manpage for more details.)

-fzero-link

Instructs dyld to load the object file at runtime.

-Wpragma-once

Issue a warning about #pragma use only once if necessary.

-Wextra-tokens

Issue a warning if preprocessor directives end with extra tokens.

-Wnewline-eof

Issue a warning if a file ends without a newline character.

-Wno-altivec-long-deprecated

Don't issue a warning about the keyword "long' used in an AltiVec data type declaration.

-Wmost

Same effect as -Wall -Wno-parentheses.

-Wno-long-double

Don't issue a warning if the long-double type is used.

-fast

Optimize for PPC7450 and G5. The -fast flag optimizes for G5, by default. This flag can be used to optimize for PPC7450 by adding the flag -mcpu=7450. To build shared libraries with -fast, include the -fPIC flag.

-static

Inhibits linking with shared libraries provided that all of your libraries have also been compiled with -static.

-shared

Not supported on Mac OS X.

-dynamiclibs

Used to build Mach-O dylibs (see Chapter 12).

-mdynamic-no-pic

Compiled code will itself not be relocatable, but will have external references that are relocatable.

-mlong-branch

Calls that use a 32-bit destination address are compiled.

-all_load

All members of static archive libraries will be loaded. (See the ld manpage for more information.)

-arch_errors_fatal

Files that have the wrong architecture will result in fatal errors.

-bind_at_load

Bind all undefined references when the file is loaded.

-bundle

Results in Mach-o bundle format. (See the ld manpage for more information.)

-bundle_loader executable

The executable that will load the output file being linked. (See the ld manpage for more information.)

-fnon-lvalue-assign

Allow cast and conditionals to be used as lvalues. Although this is on by default in Apple's GCC 4.0, a deprecation warning will be issued whenever an lvalue cast or lvalue conditional is encountered as such lvalues will not be allowed in future versions of Apple's GCC.

-fno-non-lvalue-assign

Disallow lvalue cast and lvalue conditionals.

-msoft-float

Enable software floating-point emulation rather than using the floating-point register set. This emulation is not performed on Mac OS X since the required libraries are not included. On Mac OS X this flag prevents floating-point registers from copying data from one memory location to another.

-Os

Optimize for size. On Apple PowerPC, this disables string instructions. To enable string instructions, use -mstring.

     < Day Day Up > 

    Категории