Overview

Building Darwin projects is almost certainly different than any other open source projects you've built before.

Most projects originating from Apple are built with Xcode. On the other hand, most open source projects from other systems are built with GNU make or BSD make. Projects from BSD or GNU/Linux are often built in a similar style to one another, and you may be used to the tight-knit build environment provided by these systems. For example, FreeBSD's make world is widely revered by open source enthusiasts.

Because Darwin draws from many different open source systems, Apple wraps each of these projects with its own high-level makefile to give them a consistent interface that can be used to build all projects with very little variation. Most of the behavior of these wrapper makefiles is defined by the CoreOSMakefiles project in Darwin. The xcodebuild tool also conforms to this interface.

Build Command

This document will refer to command line invocation used to build a Darwin project as the build command. The tool that is invoked by the build command is the build tool. Currently, all Darwin projects are built with one of two build tools: xcodebuild and make.

Note: In Mac OS X 10.2 and later, make is GNU Make, and can also be invoked as gnumake. The BSD make command is known as bsdmake.

If the project contains an Xcode project (.xcodeproj, .xcode, .pbproj), then the xcodebuild tool should be used. Otherwise, the make tool should be used.

In general, the arguments passed to the build tool will not differ no matter which build tool is used. The first argument should be "install". Unlike other projects which might require a "make all" before a "make install", Darwin projects skip ahead to the install phase right away. Because each project will attempt to set the correct user and group ownership on the files it produces, it's always necessary to build Darwin projects as the root user. After the "install" argument, many additional argument are passed. Each of these arguments is described in the Roots and Environment Variables sections below.

Here is the build command that was used for xnu (the Darwin kernel) when compiling Darwin 8.0.1, the release corresponding to Mac OS X 10.4 (Tiger):

root# make install  \
	"SRCROOT=/SourceCache/xnu/xnu-792" \
	"OBJROOT=/private/var/tmp/xnu/xnu-792.obj~1" \
	"SYMROOT=/private/var/tmp/xnu/xnu-792.sym~1" \
	"DSTROOT=/private/var/tmp/xnu/xnu-792.root~1" \
	"RC_ProjectName=xnu" \
	"RC_ProjectSourceVersion=792" \
	"RC_ProjectNameAndSourceVersion=xnu-792" \
	"RC_ProjectBuildVersion=1" \
	"INSTALLED_PRODUCT_ASIDES=YES" \
	"MACOSX_DEPLOYMENT_TARGET=10.4" \
	"NEXT_ROOT=" \
	"RC_ARCHS=ppc i386" \
	"RC_CFLAGS=-pipe -no-cpp-precomp -arch ppc -arch i386" \
	"RC_JASPER=YES" \
	"RC_NONARCH_CFLAGS=-pipe -no-cpp-precomp" \
	"RC_OS=macos" \
	"RC_RELEASE=Tiger" \
	"RC_XBS=YES" \
	"RC_i386=YES" \
	"RC_ppc=YES" \
	"SEPARATE_STRIP=YES" \
	"UNAME_RELEASE=8.0" \
	"UNAME_SYSNAME=Darwin"

Roots

In this document, Roots refer to several different filesystem directories that are used when building Darwin projects. The Build Root is the directory that is the filesystem root for the current build environment. This will either be the actual root directory (/) or another directory which contains a full build environment and has been set to the root directory using chroot.

The first four arguments following "install" in the example build command above specify the filesystem path of the four Roots: SRCROOT, OBJROOT, SYMROOT, and DSTROOT. These Roots represent absolute paths to four different directories that will be used while building the project. SRCROOT gives the location of the sources to be built, OBJROOT gives the location for intermediate files created during the build (.o's), SYMROOT gives the location for debug symboled output files, and DSTROOT gives the location for the finished product. With the exception of SRCROOT, all of these directories should be empty before the build begins, and should be owned by root:wheel.

After the build is complete, the OBJROOT is no longer needed and may be deleted. In order to install the newly built project, the contents of the DSTROOT may be copied to the root filesystem (/). Many, but not all, Darwin projects are compatible with a full Mac OS X system, so exercise caution and be prepared to undo your changes.

Important note: because Apple never uses paths with spaces during the build, some Darwin projects may not build correctly if spaces are used in one of these paths. This may lead to files being written to arbitrary locations on the disk, and could lead to loss of data. Never use spaces in the Roots' paths.

When Apple builds Mac OS X, paths of the following form are used for the Roots:

	SRCROOT=/SourceCache/project/project-version
	OBJROOT=/private/var/tmp/project/project-version.obj~1
	SYMROOT=/private/var/tmp/project/project-version.sym~1
	DSTROOT=/private/var/tmp/project/project-version.root~1

Environment Variables

Xcode and the CoreOSMakefiles determine much of their behavior based on the current environment variables. Each of the variables passed in the Build Command should also be set in the environment. When Apple builds Mac OS X, many additional environment variables are set. Here are the variables which are set while building projects found in Mac OS X 10.4 (Tiger):

RC_ProjectName=project
The name of the project being built. For example, when building the Darwin kernel, this should be "xnu". This variable has special significance for projects that have build aliases.
RC_ProjectSourceVersion=version
The source code version of the project being built. For example, when building the Darwin kernel for Mac OS X 10.4 (Tiger), this should be "792".
RC_ProjectNameAndSourceVersion=project-version
The combination of $RC_ProjectName and $RC_ProjectSourceVersion separated by a hyphen.
RC_ProjectBuildVersion=number
A number that may be used to distinguish multiple attempts to build the same project.
SRCROOT=/SourceCache/project/project-version
Absolute path to the sources being built.
OBJROOT=/private/var/tmp/project/project-version.obj~build_version
Absolute path to directory for intermediate files.
SYMROOT=/private/var/tmp/project/project-version.sym~build_version
Absolute path to directory for debug symboled files.
DSTROOT=/private/var/tmp/project/project-version.root~build_version
Absolute path to directory for finished product.
INSTALLED_PRODUCT_ASIDES=YES
By default Xcode will place build products directly into $DSTROOT. Setting INSTALLED_PRODUCT_ASIDES to YES instructs Xcode to place build products in $SYMROOT first, then copy them to $DSTROOT. This allows the debug symboled binary to be retained in $SYMROOT, while the binary $DSTROOT can be stripped of debug symbols using strip. (INSTALLED_PRODUCT_ASIDES implies SEPARATE_STRIP to a certain degree.)
SEPARATE_STRIP=YES
Instructs Xcode to explicitly use the strip command instead of the -s argument to the linker (ld). This is necessary because the linker is unable to strip some projects of their debug symbols successfully.
MACOSX_DEPLOYMENT_TARGET=10.4
This Mac OS X version number is used by the Cross Development feature of Xcode, and indicates which version of the Mac OS you intend to run your finished product on. The AvailabilityMacros.h header file conditionally defines the Mac OS API based on what is available in that version of the Mac OS. See Tech Note 2064 for more details.
RC_RELEASE=Tiger
This variable should match the MACOSX_DEPLOYMENT_TARGET:
	10.0 = Cheetah
	10.1 = Puma
	10.2 = Jaguar
	10.3 = Panther
	10.4 = Tiger
UNAME_RELEASE=8.0
This Darwin version number overrides the output of the uname -r command to match RC_RELEASE:
	Cheetah = 1.0 (old release number scheme)
	Puma    = 5.0 (new release number scheme)
	Jaguar  = 6.0
	Panther = 7.0
	Tiger   = 8.0
NEXT_ROOT=
The NEXT_ROOT variable allows for the finished products to be rooted somewhere other than /. Its presence here is for legacy support only. In Mac OS X, all projects are installed into /, so this is always an empty string.
RC_ARCHS=ppc i386
The list of architectures to build. All Darwin projects are built as Universal Binaries.
RC_i386=YES
This should be set to YES if i386 is listed in $RC_ARCHS, or empty otherwise.
RC_ppc=YES
This should be set to YES if ppc is listed in $RC_ARCHS, or empty otherwise.
RC_CFLAGS=-pipe -no-cpp-precomp -arch ppc -arch i386
Arguments to be passed to the C compiler. This is a combination of the $RC_NONARCH_CFLAGS variable, and a -arch flag for each architecture specified in RC_ARCHS.
RC_NONARCH_CFLAGS=-pipe -no-cpp-precomp
Arguments to be passed to the C compiler, excluding any -arch arguments.
UNAME_SYSNAME=Darwin
Overrides the output of the uname command. This should always be set to Darwin.
RC_OS=macos
Indicates that the project is being built for the Mac OS. This should always be set to macos.
RC_XBS=YES
Indicates that the Mac OS X build system is in use. Apple-specific changes to open source projects may be conditionalized on this variable. This should always be set to YES.
RC_JASPER=YES
Indicates that the Mac OS X build system is in use. Apple-specific changes to open source projects may be conditionalized on this variable. This should always be set to YES.
RC_TRACE_ARCHIVES=YES
Indicates that the linker (ld) should print a message for each static archive that is linked into the final product:
[Logging for Build & Integration] Used static archive: filename
RC_TRACE_DYLIBS=YES
Indicates that the linker (ld) should print a message for each dynamic library that is linked from the final product:
[Logging for Build & Integration] Used dynamic library: filename

Dependencies

Many Darwin projects require headers, libraries, and binaries from other Darwin projects. These cross-dependencies are far too numerous to list here, suffice to say, it's something to be aware of. Furthermore, not all of these dependencies are available on a Mac OS X system by default. Apple omits many "private" headers files, static libraries, and build tools from the Mac OS X system. These tools are availablein the Darwin sources, but those projects must be built and installed prior to any project that uses them. For example, compiling xnu requires the kextsymboltool binary from the kext_tools project, and the libkld.a static archive from cctools_ofiles, among others.

Build Aliases

Some Darwin projects use the exact same set of sources as another project, but produce different results based on the arguments passed to the build command. These projects are known as build aliases. Build aliases are used in cases where a single set of source is beneficial for compatibility. One example is a client and a server which share a common proprietary protocol that much be revised on both ends simultaneously. Another use is to help avoid a circular dependency between two projects. Most dependencies are at a project-level granularity, and a build alias provides finer-grained project build results.

When building a project that is a build alias, it is important that the RC_ProjectName environment variable is set to the name of the build alias, not the original sources. Additionally, many build aliases need an alternate argument than the standard "install" argument described in the build command. Since "install" is commonly known as the target of the makefile, this alternate argument is known as the alternate target.

When the build tool is a make, the alternate target entirely replaces the "install" argument. For example:

root# make ofiles_install \
	"SRCROOT=/SourceCache/cctools/cctools-576" \
	"OBJROOT=/private/var/tmp/cctools_ofiles/cctools_ofiles-576.obj~1" \
	"SYMROOT=/private/var/tmp/cctools_ofiles/cctools_ofiles-576.sym~1" \
	"DSTROOT=/private/var/tmp/cctools_ofiles/cctools_ofiles-576.root~1" \
	"RC_ProjectName=cctools_ofiles" \
	"RC_ProjectSourceVersion=576" \
	"RC_ProjectNameAndSourceVersion=cctools_ofiles-576" \
	"RC_ProjectBuildVersion=1" \
	...

When the build command is xcodebuild, the alternate target is passed after "install" as "-target alternate". For example:

root# xcodebuild install -target libmx \
	"SRCROOT=/SourceCache/Libm/Libm-92" \
	"OBJROOT=/private/var/tmp/Libmx/Libmx-92.obj~1" \
	"SYMROOT=/private/var/tmp/Libmx/Libmx-92.sym~1" \
	"DSTROOT=/private/var/tmp/Libmx/Libmx-92.root~1" \
	"RC_ProjectName=Libmx" \
	"RC_ProjectSourceVersion=92" \
	"RC_ProjectNameAndSourceVersion=Libmx-92" \
	"RC_ProjectBuildVersion=1" \
	...

Mac OS X 10.4 (Darwin 8.0) contains the following build aliases:

original projectbuild aliasalternate target
DSNSLPluginsDSNSLAppleTalkPluginAppleTalk
DSPasswordServerPluginDSPasswordServerFrameworkPasswordServerFramework
DirectoryServiceDirectoryServiceDaemonDirectoryServiceDaemon
DirectoryServiceDirectoryServiceMIGDirectoryServiceMIG
LibcLibc_debugnone
LibcLibc_headersnone
LibcLibc_mannone
LibcLibc_profilenone
LibcLibc_staticnone
LibmLibmxlibmx
cctoolscctools_ofilesofiles_install
configdconfigd_executablesconfigd_executables
configdconfigd_pluginsconfigd_plugins
cupscups_ppcinstallppc
launchdlaunchd_libslaunchd_libs
dyldlibdyldlibdyld
passwordserver_saslpasswordserver_saslkerberosKerberosTarget
perlperl_extrasinstallextras

installhdrs

Almost all Darwin projects support an alternate target called "installhdrs". Building with this target instead of "install" causes only the header files produced by the project to be installed into $DSTROOT. When Apple builds Mac OS X, and "installhdrs" build is performed on every project that supports it. The resulting header files are all installed into the build root before the full build begins.

Since dependencies are calculated at a project-level granularity, but two projects often need access to each others' header files, the installhdrs phase helps avoid most circular dependency issues.

installsrc

All Darwin projects support an alternate target called "installsrc". When this target is used, the project should make an idempotent copy of itself into $SRCROOT. Files that are in the current project directory but not part of the project itself (i.e. CVS, or .gdb_history) need not be copied during installsrc. This target is used internally by Apple and is usually unnecessary for building Darwin sources.