Chapter 11. Compiling Source Code

The Xcode Tools that ship with Tiger provide a development environment for building applications with Cocoa, Carbon, Java, and even AppleScript . Xcode Tools include utilities that should be familiar to any Unix developer who works with command-line compilers . For details about obtaining these tools, see the "Xcode Tools" section in the Preface. Xcode Tools include all sorts of other goodies, including an advanced Integrated Development Environment (IDE), but coverage of those tools is beyond the scope and intent of this book. To learn more about the Xcode Tools, go to /Developer/ADC Reference Library/documentation /DeveloperTools/index.html.

The C compiler that comes with Xcode is based on the Free Software Foundation’s GNU Compiler Collection, or GCC. Apple’s modifications to GCC include an Objective-C compiler, as well as various modifications to deal with the Darwin operating system. The development environment in Mac OS X includes:

AppleScript

This is an English-like language used to script applications and the operating system. AppleScript is installed as part of the Mac OS X operating system and does not require Xcode. Instead, to write AppleScripts, use the Script Editor (/Applications/AppleScript).

AppleScript Studio

This is a high-level development environment based on AppleScript that allows you to build GUI applications by hooking AppleScript into the Cocoa framework. If you plan to build AppleScript Studio applications, you will need to use the Xcode Tools instead of the Script Editor.

Compilers

These compilers are based on GCC and provide support for C, C++, Objective-C, Objective-C++, and assembly. Apple’s enhancements to GCC for Tiger include support for the G5 (also known as the PowerPC 970) and 64-bit arithmetic, as well as the ability to generate optimized code to run on G5, G4, and G3 systems

Compiler Tools

These include the Mac OS X Mach-O GNU-based assemblers, Mach-O static link editor, Mach-O dynamic link editor, and Mach-O object file tools, such as nm, otool, and otool64.

Documentation

There is extensive documentation for Xcode, available in both HTML and PDF formats. The Xcode documentation can be found in /Developer/ADC Reference Library. These documents are also available online from the Apple Developer Connection (ADC) web site (http://developer.apple.com).

Tip

You can access the documentation for GCC after you’ve installed Xcode by opening /Developer/ADC Reference Library/documentation/DeveloperTools/gcc-4.0/gcc/index.html.

Debugger

The Apple debugger is based on GNU gdb.

Miscellaneous Tools

These include traditional development tools, such as make (both GNU, which is the default, and BSD) and GNU libtool, graphical and command-line performance tools, Xcode for WebObjects, parsing tools (such as lex, flex, yacc, and bison), standard Unix source code management tools (such as CVS and RCS), and an extensive set of Java development tools. There’s also a frontend to GCC, distcc, which uses Bonjour to distribute builds of C, C++, Objective-C, or Objective-C++ code across computers on a network.

Xcode

Formerly known as Xcode is an IDE for Mac OS X that supports Cocoa and Carbon programming with C, C++, Objective-C, and Java. (Xcode was known as Project Builder in pre-Panther releases of Mac OS X.)

Interface Builder

This is a graphical user interface (GUI) editor for Cocoa and Carbon applications .

Header Doc 8

This is a set of command-line tools for including structured comments in source code and header files, which are later used to create HTML and XML output. A set of manpage generation tools is also included. Header Doc’s two main Perl scripts are headerdoc2html and gatherheaderdoc. Kyle Hammond’s Cocoa frontend to Header Doc is available at http://www.isd.net/dsl03002/CocoasProgramming.html. See /Developer/ADC Reference Library/documentation/DevelopTools/Conceptual/HeaderDoc/index.html for details.

We won’t address the complete Mac OS X development suite in this chapter. Instead, we’ll focus on the command-line development tools and how they differ from the implementations on other Unix platforms.

Java programmers will find that the Mac OS X command-line Java tools (see "Java Development Tools" in Appendix B) behave as they do under Unix and Linux. Another resource for Java developers is Mac OS X for Java Geeks (O’Reilly).

Perl programmers coming from previous Macintosh systems will find that Mac OS X does not use MacPerl (http://www.macperl.com), but instead uses the standard Unix build of the core Perl distribution (http://www.perl.org). For additional information on using Perl under Mac OS X, see Chapter 19.

Compiler Differences

GCC is supported on a wide range of platforms, and it is the default compiler on Mac OS X. There are, however, some important differences between the version of GCC that ships with Mac OS X and those found on other Unix systems.

One difference that experienced GCC users may notice, particularly if they have extensive experience with mathematical and scientific programming, is that the Xcode Tools do not include FORTRAN . However, both Fink (http://fink.sourceforge.net) and DarwinPorts (http://darwinports.opendarwin.org) include g77, the GNU FORTRAN ’77 compiler. (For information on using Fink and DarwinPorts, see Chapters 13 and 14, respectively.) Also, the Darwin archive includes the source code for g77, which you can use to compile FORTRAN code. Additionally, two open source FORTRAN 95 projects are available for Mac OS X, the GNU FORTRAN 95, or gfortran, which is a compiler frontend to GCC 4.0 (http://gcc.gnu.org/fortran) and the g95 project (http://g95.sourceforge.net). g95 can be installed on Mac OS X with the binaries provided on its home site or with Fink. At the time of this writing, gfortran for GCC 4 is listed among Fink’s unsupported packages.

Tip

Mac OS X’s C compiler contains a number of Mac-specific features that have not been folded into the main GCC distribution. (It is up to the Free Software Foundation (FSF) to accept and merge Apple’s patches.) For information on how Apple’s compiler differs from the GNU version, see the README.Apple file in the Darwin CVS archive’s gcc4 subdirectory.

As of this writing, Apple’s cc compiler is based on GCC 4.0. However, GCC 3.3 is also available as /usr/bin/gcc-3.3. By default, invoking cc or gcc invokes GCC 4.0; both /usr/bin/cc and /usr/bin/gcc are symbolic links to /usr/bin/gcc-4.0. You can change the default GCC to GCC 3.3 by running the command gcc_select 3.3. Similarly, you can change it back to GCC 4.0 with gcc_select 4.0. The gcc_select command (used with one of the options 3.3 or 4.0) changes the symbolic links /usr/bin/cc and /usr/bin/gcc to point to the desired version of gcc. Since files in /usr/bin are changed by this command, you must execute it with sudo.

You can see the current settings by running gcc_select with no arguments:

    $ gcc_select
    Current default compiler:
    gcc version 4.0.0 20041026 (Apple Computer, Inc. build 4039)

Tip

The Mac OS X Compiler Release Notes (/Developer/ADC Reference Library/Documentation/releasenotes) should be consulted for details on the most currently known problems, issues, and features.

Perhaps the most important improvement in GCC 4.0 is the incorporation of Tree Single Static Assignment (SSA) optimization rather than Register Transfer Language, used in older versions of GCC. SSA was available in some earlier versions, but was experimental and had to be switched on by special compiler flags, for example, -fssa. Although we haven’t tested them thoroughly, according to the Apple’s Xcode2 web site (http://www.apple.com/macosx/features/xcode), the incorporation of Tree SSA has improved the following optimizations:

  • Scalar replacement of aggregates

  • Constant propagation

  • Value range propagation

  • Partial redundancy elimination

  • Load and store motion

  • Strength reduction

  • Dead store elimination

  • Dead and unreachable code elimination

  • Auto-vectorization to take advantage of the Velocity Engine

  • Loop interchange

  • Tail recursion by accumulation

See http://gcc.gnu.org/projects/tree-ssa for more details on SSA.

Additional improvements in GCC 4.0 include a more efficient C++ parser and a dynamic C++ standard library, libstdc++; in pre-Tiger releases of Mac OS X you could only statically link it. There’s also support for 128-bit long double floating-point types and 64-bit computing.

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.

Tip

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

Warning

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.

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.

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-darwin VERSION, 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 .

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

Tip

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.

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.

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.

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.

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.

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.

Tip

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
");
  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.

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.

Architectural Issues

There are a few architectural issues to be aware of when developing or porting software on Mac OS X. In particular, vectorization, pointer size, endianness, and inline assembly code tend to be the most common issues developers run into.

AltiVec

The Velocity Engine, Apple’s name for Motorola 128-bit AltiVec vector processor that allows up to 16 operations in a single clock cycle, is supported on both G4 and G5 processors by the Mac OS X GCC implementation. The Velocity Engine, which executes operations currently with existing integer and floating-point units, can result in significant performance gains, especially for highly parallel operations. The compiler flag -maltivec can be specified to compile code engineered to use the AltiVec instruction set. Inclusion of this command-line option to cc defines the preprocessor symbol _ _VEC_ _. (See Table 11-3 for more AltiVec-related compiler flags.)

64-bit Computing

On a 32-bit system, such as Mac OS X running on the G3 or G4, C pointers are 32 bits (4 bytes). On a 64-bit system, such as Mac OS X running on the G5, they are 64 bits (8 bytes). As long as your code does not rely on any assumptions about pointer size, it should be 64-bit clean. For example, on a 32-bit system, the following program prints “4”, and on a 64-bit system, it prints “8”:

    #include <stdio.h>
    int main( )
    {
      printf("%d
", sizeof(void *));
      return 0;
    }

Some 64-bit operating systems, such as Solaris 8 on Ultra hardware (sun4u) and Mac OS X Tiger on G5 hardware, have a 64-bit kernel space, but support both 32- and 64-bit mode applications, depending on how they are compiled. On a G5 system, the pointer size is 64-bits. Other data types are mapped onto the 64-bit data type. For example, single precision floats, which are 32-bit, are converted to double precision floats when they are loaded into registers. In the registers, single precision instructions operate on these single precision floats stored as doubles performing the required operations on the data. The results, however, are rounded to single precision 32-bit. Apple has provided several technical documents containing information and advice on optimizing code to take advantage of the 64-bit G5 architecture:

Tip

Additional information can be found at http://developer.apple.com/hardware/ve/g5.html. These documents describe in detail the issues involved in tuning code for the G5. We note here only a few issues.

The architecture of the G5 allows for much greater performance relative to the G4. This performance potential is partly due to the fact that the G5 allows 200 instructions in core, compared to only 30 for the G4. Moreover, the G5 has 16 pipeline stages, 2 load/store units, and 2 floating points units, compared to 7 pipeline stages, 1 load/store unit, and 1 floating points unit on the G4. The L1 cacheline size is also 128 bytes on the G5, compared to 32 bytes on the G4. Additionally the processor and memory bandwidth is much greater on the G5, relative to the G4. The technical notes mentioned earlier in this section have additional information on hardware differences.

One important implication of the greater number of pipeline stages on the G5 relative to the G4 is that instruction latencies are greater on the G5. You can often gain significant improvements in performance by using performance tools to identify loops that account for a large percentage of computation time. Once identified, you can either manually unroll these loops, or use the -funroll-loops compiler flag. The compiler flag -mtune-970 can also be useful in this situation, as it schedules code more efficiently for the G5. The -fast compiler flag sets these options (among others) automatically.

To better take advantage of the longer cacheline size in L1 cache on the G5, algorithms should be designed for greater data locality, and use contiguous memory accesses when possible. For example, arrays in C store entries row-wise. To ensure contiguous memory accesses, design your code so that it accesses array elements row-by-row. The G5 has four hardware prefetchers, which (if accesses to memory are contiguous) are triggered automatically to help reduce cache misses. Performance tools, such as the CHUD suite (see Chapter 12), can help you optimize code by profiling computation and memory usage—some of them even make suggestions on how to improve performance.

While the G5 running Mac OS X Panther provided a fine computing platform, Mac OS X Tiger, which allows applications to access a 64-bit address space, opens up a new realm of computational capabilities. Since Tiger supports 64-bit arithmetic instructions on PowerPC architectures, even if your code is compiled in 32-bit mode, your code will not necessarily run more efficiently when compiled in 64-bit mode. It should be noted that, even on a G3 system, 32-bit applications have a 128-bit long-double data type, and a 64-bit long-long data type.

To compile 64-bit code using GCC, be sure to use the GCC 4.0, and specify the ppc64 architecture with -arch ppc64. The -arch ppc compiler flag together with -arch ppc64 produces a “fat” binary, that is, one that can be run on either 32-bit or 64-bit systems. When a fat binary is run on a 64-bit system, it runs as a 64-bit executable. On the other hand, when the same fat binary is run on a 32-bit system, it runs as a 32-bit executable. Specifying the -arch ppc compiler flag alone produces a 32-bit executable. Since 32-bit is the default, it is unnecessary to specify this flag alone, Additionally, the -Wconversion compiler flag may be useful when converting 32-bit code to 64-bit code. The _ _LP64_ _ and _ _ppc_ _ macros can be used to conditionally compile 64-bit code. At the time of this writing, only C and C++ can be compiled in 64-bit mode. Following is a list of things to bare in mind when engaging in 64-bit computing on Tiger.

  • Tiger follows the LP64 64-bit data model, also used by SUN and SGI: ints are 32-bit, while longs, long-longs, and pointers are 64-bit.

  • In 64-bit code, ints cannot hold pointers.

  • Use of a cast between a 64-bit type and a 32-bit type can destroy data.

  • In Tiger, only non-GUI applications can be compiled as 64-bit. You can, however, use a 32-bit GUI to launch and control the a 64-bit application.

  • Compiling an application as 64-bit produces a 64-bit version of the Mach-O binary format, used in Mac OS X. You can determine if a program was compiled as 64-bit, 32-bit, or flat using the file command.

  • 64-bit applications may use only 64-bit frameworks, while 32-bit applications may use only 32-bit frameworks.

  • Tiger ships with only two 64-bit frameworks: System and Xcelerate.

Endian-ness

CPU architectures are designed to treat the bytes of words in memory as being arranged in big- or little-endian order . Big-endian ordering has the most significant byte in the lowest address, while little-endian has the most significant byte at the highest byte address.

The PowerPC is bi-endian, meaning that the CPU is instructed at boot time to order memory as either big- or little-endian. In practice, bi-endian CPUs run exclusively as big- or little-endian. In general, Intel architectures are little-endian, while most, but not all, Unix/RISC machines are big-endian. Table 11-4 summarizes the endian-ness of various CPU architectures and operating systems. As shown in Table 11-4, Mac OS X is big-endian.

Table 11-4. Endian-ness of some operating systems

CPU type

Operating system

Endian-ness

Dec Alpha

Digital Unix

little-endian

Dec Alpha

VMS

little-endian

Hewlett Packard PA-RISC

HP-UX

big-endian

IBM RS/6000

AIX

big-endian

Intel x86

Windows

little-endian

Intel x86

Linux

little-endian

Intel x86

Solaris x86

little-endian

Motorola PowerPC

Mac OS X

big-endian

Motorola PowerPC

Linux

big-endian

SGI R4000 and up

IRIX

big-endian

Sun SPARC

Solaris

big-endian

Inline Assembly

As far as inline assembly code is concerned—if you have any—it will have to be rewritten. Heaven help you if you have to port a whole Just-In-Time (JIT) compiler! For information on the assembler and PowerPC machine language , see the Mac OS X Assembler Guide (/Developer/ADC Reference Library/documentation/DeveloperTools/Reference/Assembler/index.html).

X11-based Applications and Libraries

Fink and DarwinPorts (covered in Chapters 13 and 14, respectively) can be used to install many X11-based applications, such as the GNU Image Manipulation Program (GIMP), xfig/transfig, ImageMagick , nedit, and more. Since Fink understands dependencies, installing some of these applications causes Fink to first install several other packages. For example, since the text editor nedit depends on Motif libraries, Fink will first install lesstif. (This also gives you the Motif window manager, mwm.) Similarly, when you install the GIMP via Fink, you will also install the packages for GNOME, GTK+, and glib.

You can also use Fink to install libraries directly. For example:

    $ fink install qt

installs the X11-based Qt libraries; DarwinPorts can be used in a similar manner.

Building X11-based Applications and Libraries

If you cannot find binaries for X11-based applications or prefer to build the applications yourself, many tools are available to do so. When you install the Xcode Tools, make sure you install the optional X11SDK , which contains development tools and header files for building X11-based applications. If you didn’t install X11SDK when you first installed Xcode, you can still install it from the Xcode folder on the Mac OS X Install DVD.

The process of building software usually begins with generating one or more makefile s customized to your system. For X11 applications, there are two popular methods for generating makefiles:

  • One method is to use a configure script, as described earlier in this chapter.

  • The other popular method for generating makefiles involves using the xmkmf script, which is a frontend to the imake utility. xmkmf invokes imake, which creates the makefile for you. To do this, imake looks for a template file called Imakefile.

With imake-driven source releases, you’ll find Imakefile in the top-level source directory after you download and unpack a source tarball. After reading the README or INSTALL files, examine the Imakefile to see if you need to change anything. Then the next step is usually to issue the command:

    $ xmkmf -a

When invoked with the -a option, xmkmf reads imake-related files in /usr/X11R6/lib/X11/config and performs the following tasks recursively, beginning in the top-level directory and then in the subdirectories, if there are any:

    $ make Makefiles
    $ make includes
    $ make depend

The next steps are usually make, make test (or make check), and make instal l.

To illustrate this method of building software, consider the script in Example 11-2, which downloads and builds an X11-based game.

Example 11-2. Downloading and building an X11-based game
# Download the source tarball
curl -O ftp://ftp.x.org/contrib/games/xtic1.12.tar.gz

# Unpack the tarball
gnutar xvfz xtic1.12.tar.gz

# Change to the top-level build directory
cd xtic1.12/

# Generate the Makefile
xmkmf -a

# Build everything (some X11 apps use 'make World')
make

# Have fun!
./src/xtic

AquaTerm

The X Window System is useful to Unix developers and users, since many Unix-based software packages depend on the X11 libraries. An interesting project that sometimes eliminates the need for X windows is the BSD-licensed AquaTerm application, developed by Per Persson (http://aquaterm.sourceforge.net). AquaTerm is a Cocoa application that can display vector graphics in an X11-like fashion. It does not replace X11, but it is useful for applications that generate plots and graphs.

The output graphics formats that AquaTerm supports are PDF and EPS. Applications communicate with AquaTerm through an adapter that acts as an intermediary between your old application’s API and AquaTerm’s API.

At the time of this writing, AquaTerm has adapters for gnuplot and PGPLOT, as well as example adapters in C, FORTRAN, and Objective-C. For example, assuming that you have installed both X11SDK and AquaTerm, you can build gnuplot (http://www.gnuplot.info) so graphics can be displayed either in X windows or in AquaTerm windows.

See AquaTerm’s web site for extensive documentation, including the latest program developments, examples, mailing lists and other helpful resources.

Xgrid

Xgrid is an application used to create a loosely coupled cluster of Macs that can be used to run an application in parallel. That is, in a manner such that the computational work of an application is partitioned into subtasks and the subtasks are distributed and executed simultaneously across machines in the cluster. The phrase distributed computing is often used to describe the situation. Applications that can benefit from distributed computing are those whose computations can be partitioned into relatively large independent tasks, each running on a different processor and requiring little communication with each other. An application in which the same computation is performed on independent chunks of data falls into this category. Such applications are often called embarrassingly parallel. The classic examples of embarrassingly parallel applications include Monte Carlo simulation, Mandelbrot set computation, and low level image processing. Creating a distributed cluster can be complicated, and Xgrid is designed to make this task easy.

Conceptually, Xgrid has three components: a client, a controller, and an agent. From the user perspective, the client submits a job to the controller, the controller partitions the job into independent tasks and sends these tasks to available agents in the cluster, then the agents execute the tasks. When an agent complete its task, the results are sent back to the controller, which collects the results and returns the job to the client after the job has completed.

For a job to run on a cluster, the job must not only be parallelizable, it must also be run without user interaction. For command-line applications, no account on the agent is required, since the job is run as user nobody. GUI-based applications, on the other hand, require a user account that must be logged on.

Although the full version of Xgrid, including GUI tools, is available for Tiger Server, a stripped down version of Xgrid is bundled with the desktop version of Tiger. This stripped down version includes a System Preference for enabling the Xgrid agent (System Preferences → Sharing → Services → Xgrid), as well as the xgridctl command-line tool for starting the Xgrid controller, and xgrid, for submitting jobs to the controller as an Xgrid client.

To start the Xgrid controller daemon, xgridcontrollerd, enter the following command:

    $ sudo xgridctl controller start

xgridcontrollerd starts whenever Tiger client boots up, after you enter the following command:

    $ sudo xgridctl controller on

The controller daemon listens for submitted jobs from clients and advertises its presence on a LAN via Bonjour.

Tip

It’s important to allow TCP traffic through port 4111 in case you’re running Tiger’s built-in firewall. (See the section on The Mac OS X Firewall in Chapter 16 for details.)

To enable the Xgrid agent, you must configure and enable the Xgrid service in the Sharing preference panel, as shown in Figure 11-1.

Configuring Xgrid Agent in Tiger
Figure 11-1. Configuring Xgrid Agent in Tiger

Agent configuration involves choosing a controller and either setting the agent to always be available or only when the computer is idle. Since Xgrid supports Bonjour, the hostnames of any controllers on the LAN show up in the drop-down menu of “Use a specific controller.” You can also choose the authentication method as one of password, single sign-on (using Kerberos and Directory Services), or none. Xgrid in Tiger supports two-way password authentication between the controller and agents, although currently setting a controller password with xgridctl is not supported. In the full version of Xgrid that ships with Tiger Server, you can use Server Admin to set the Xgrid controller password. If the controller is running on Tiger Server with password authentication, you can supply the controller’s password when submitting a job using the xgrid command, either with the -p password flag or by setting the environment variable:

    $ export XGRID_CONTROLLER_PASSWORD="good_password"

Tip

An Xgrid agent for Unix and Linux is available at http://www.novajo.ca/xgridagent.

You can submit an Xgrid job from a client with the xgrid command:

    $ xgrid -h hostname -out outdir -p password -job submit command args

Here, hostname is the IP number or hostname of the machine running the Xgrid controller, outdir is the directory in which the results are placed, password is the controller’s password, and command args is a Unix shell command with its arguments.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.218.89.173