Porting - 1. Basics

1.1 Where Darwin came from

Darwin is a Unix-like operating system that evolved from NeXTStep / OpenStep. Lore has it that it was initially forked off 4.4BSD Lite. The BSD heritage still shows, in fact Darwin was recently modernized with code from FreeBSD and NetBSD.

Darwin's kernel is based on a combination of Mach 3.0, BSD, and proprietary functionality like the object-oriented driver layer IOKit. Although Mach originally is a micro-kernel design, the BSD kernel that sits on top of it is monolithic and the two are now so intertwined that they must be regarded as a single monolithic kernel.

The user-space tools and libraries shipped with Darwin are mostly of the BSD persuation, as opposed to the GNU tools you get with Linux. Apple is not as strict as other BSDs though, and goes for useful compromises. For example, Apple ships both BSD make and GNU make, with GNU make installed as the default.

1.2 The Compiler and Tools

Short story: The compiler is a gcc derivate, but installed as cc; you may have to patch Makefiles. Most packages won't build shared libraries. If you get errors related to macros, use the -no-cpp-precomp option.

Long story: The compiler tool chain in the Mac OS X Developer Tools is a strange beast. The compiler is based on the gcc 2.95.2 suite, with modifications to support the Objective C language and some Darwin quirks. The preprocessor (cpp) is available in two versions. One is the standard precompiler (from gcc 2.95.2), the other one is a special precompiler written by Apple, with support for precompiled headers. The latter one is used by default, because it is faster. However, some code doesn't compile with Apple's precompiler, so you must use the -no-cpp-precomp option to get the standard precompiler. (Note: I previously recommended the -traditional-cpp option. The semantics of this option have changed slightly with GCC 3, breaking most packages that use it. -no-cpp-precomp has the desired effect on both the current Developer Tools and future compilers based on GCC 3.)

The assembler says it's based on gas 1.38. The linker is not based on GNU tools. This is a problem when building shared libraries, as GNU libtool and configure scripts generated by it don't know how to handle Apple's linker.

1.3 Host type

Short story: If configure fails with 'Can't determine host type', copy config.guess and config.sub from /usr/share/libtool (/usr/libexec for OS versions prior to 10.2) into the current directory.

Long story: The GNU world uses a canonical format to specify system types. It has three parts: cpu type, manufacturer and operating system. Sometimes a fourth part is added - then the third part denotes the kernel, while the fourth denotes the operating system. All parts are lower case and concatenated using dashes. Some examples: i586-pc-linux-gnu, hppa1.1-hp-hpux10.20, sparc-sun-solaris2.6. The host type for Mac OS X 10.0 is powerpc-apple-darwin1.3. Versions of Mac OS X 10.2 bring various powerpc-apple-darwin6.x.0 and 10.3 gives powerpc-apple-darwin7.x.0, where "x" depends on the exact OS version.

Many packages that use autoconf want to know the host type of the system they are compiled on. (Side note: to support cross-compiling and porting, there are actually three types - the host type, the build type and the target type. Usually, they're all the same.) You can either pass the host type to the configure script as a parameter or you can let it guess.

The configure script uses two companion scripts to determine host types. config.guess tries to guess the host type, config.sub is used to validate and canonicalize the host type. These scripts are maintained as separate entities, but they are included in every package that uses them. Until very recently, these scripts didn't know about Darwin or Mac OS X. If you have a package that doesn't recognize Darwin, you must replace the config.guess and config.sub included in the package. Luckily, Apple put working versions in /usr/share/libtool (/usr/libexec for pre-10.2 OS), so you can just copy them from there.

If you are constructing a Fink package, you can use the UpdateConfigGuess and/or UpdateConfigGuessInDirs fields in your .info package description file to do this update automatically.

1.4 Libraries

Short story: You can safely remove -lm from Makefiles, but you don't need to.

Long story: Mac OS X doesn't have separate libc, libm, libcurses, libpthread etc. libraries. Instead, they're all part of the system library, libSystem. (In earlier versions, this actually was the System framework.) However, Apple placed appropriate symlinks in /usr/lib, so linking with -lm will work. The only exception is -lutil. On other systems, libutil contains functions related to pseudo-terminals and login accounting. These functions are in libSystem, but there is no symlink to provide a libutil.dylib.

1.5 Other sources of information

Another source of information for porting is the Wiki at MetaPkg Wiki.

You can also read Apple Technical Note TN2071: "Porting Command Line Unix Tools to Mac OS X".

Next: 2. Shared Code