8.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 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, 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 invoke StuffIt Expander 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.

Also, because the Mac OS X HFS+ filesystem is case-insensitive, watch out for tarballs that have filenames differing in case only (as in makefile and Makefile ). While it's unlikely to find filenames like this in a modern software package, it's not unusual in older tarballs.


The following sections deal with issues involved in successfully performing these steps. Determining how to improvise within this three-step procedure reveals some of the differences between Mac OS X and other Unix systems.

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

8.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-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-darwin7.0.0 ).

Although Mac OS X and Darwin have been around for a while now, you may still run across source code distributions containing 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 set of config.* files does not support Darwin, ./configure will complain about an unknown host type.

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

You can use a number of predefined macros to detect Apple systems and Mac OS X in particular. Table 8-1 lists the predefined macros available on Mac OS X.

Table 8-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 -faltivec flag.


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.


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

Table 8-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 notpreprocessed

 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 .

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

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 and general precompilation, see Chapter 9). cpp-precomp is faster than cpp , but 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 

Earlier versions of the Xcode Tools (known as the Developer Tools) used the - traditional-cpp switch, but this switch had undesirable side effects and is deprecated.


8.2.5 Frameworks

In Mac OS X, frameworks are bundles that are 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 that consists 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 figs/command.gif -3 to switch the Finder to Column View, and then hit the C key on your keyboard. You will see the typical contents of an application bundle. In particular, you will see:

  • 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/ , which 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.

8.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 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 9 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. The same is true for the gdb framework, also located in /System/Library/PrivateFrameworks.

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 following order:


~/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 their 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 librares in these frameworks (for example, the Application Kit, or AppKit) are provided by Apple for use 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 , OSSerrvices , SearchKit, and WebServicesCore . The simple framework does not contain subframeworks, nor is it a subframework contained within an umbrella framework.

8.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 8-1 shows "Hello, World" in Objective-C. Notice that it #includes the AppKit framework.

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

If you are linking against a framework, such as GLUT and/or OpenGL from C code, you will probably need to include -lobjc , since the frameworks will depend on the Objective-C runtime. For example, you can compile SGI's prim.c (OpenGL primitives example) with cc prim.c -framework GLUT -framework OpenGL -lobjc (be sure to include the GLUT framework with #include <GLUT/glut.h> rather than <GL/glut.h> ).


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

8.2.6 Compiler Flags

An extensive list of compiler flags can be found at http://developer.apple.com/technotes/tn2002/tn2071.htmlor by viewing the gcc man page. In particular, the gcc manpage describes many PowerPC-specific flags, as well as Darwin-specific flags. Table 8-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.

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

- arch ppc970

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

- mcpu=970 , - mcpu=G5

Enables the use of G5-specific instructions.

- mtune=970 , - mtune=G5

Optimizes code for the G5.

- force_cpusubtype_ALL

Forces 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

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

- mpowerpc-gpopt

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

- fasm-blocks

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

- fconstant-cfstrings

Automatically creates CoreFoundation-type constantString . (see gcc manpage for details.)

- fpascal-strings

Allows the use of Pascal-style strings.

- fweak-coalesced

Linker ignores weakly coalesced definitions in favor of one ordinary definition.

- findirect-virtual-calls

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

- fapple-kext

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

- fcoalesce-templates .

Coalesces instantiated templates.

- fobjc-exceptions

Supports 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

Issues a warning about #pragma , use only once if necessary.

- Wextra-tokens

Issues a warning if prepreprocessor directives end with extra tokens.

- Wnewline-eof

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

- Wno-altivec-long-deprecated

Doesn'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

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

- fast

Optimizes 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 9).

- 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

Binds 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 in formation.)




Mac OS X Panther for Unix Geeks
Mac OS X Panther for Unix Geeks
ISBN: 0596006071
EAN: 2147483647
Year: 2003
Pages: 212

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net