What is Mac OS X?

© Amit Singh. All Rights Reserved.Written in December 2003

Programming on Mac OS X

Mac OS X is a fertile field for all kinds of programming endeavors, especially if you have a *nix frame of reference. Life is still much better for a developer on Windows than on Mac OS X - no matter what one might think of the usability, etc. of Windows. Apple has been trying to improve things for developers lately, which is a good sign.

This page discusses some programming facilities, frameworks and tools available on Mac OS X.

Application Environments

Since Mac OS X is derived from various sources, it has a multitude of Application Environments. We discussed these in Above the Kernel. To recapitulate:

BSD

Mac OS X uses FreeBSD as a reference code base for its BSD derivations (Panther derives from FreeBSD 5.0). It includes a BSD-based POSIX API (BSD style system call vector, uap based argument passing, etc.). An example of intercepting system calls on Mac OS X is covered in the article Re-routing System Calls. OS X also supports System V IPC, asynchronous I/O, poll() (emulated over select()), etc. Arbitrary C programming is not any different than on any generic Unix platform. Here is an example of re-routing function calls by overwriting and injecting machine instructions.

Carbon

This is a set of procedural C-based APIs for Mac OS X that are based on the old Mac OS 9 API (actually dating back as far back as Mac OS 8.1). Carbon was originally designed to provide an easy development migration path from Mac OS 9 to Mac OS X. The Carbon APIs are all-encompassing (they include legacy interfaces), covering most things that you are likely to do programmatically on Mac OS X. Carbon specific code is not portable to other platforms.

Classic

Mac OS X includes a Classic (Mac OS 9) emulator that executes in a protected memory environment so as to let users run programs written for Mac OS 9. Apple does not encourage you to actually develop for this environment.

Cocoa

This is an object-oriented Objective-C based API that's the preferred way of doing things in Mac OS X (if what you want to do can be done through Cocoa), particularly because of how well it's supported by Apple's Rapid Development tools. However, there are many parts of Mac OS X, and applications from 3rd party vendors, that have not converted to Cocoa completely, or at all. A Cocoa application can call the Carbon API when necessary. Cocoa is largely based on the OpenStep frameworks, and consists of primarily two parts: the Foundation (fundamental classes) and the Application Kit (classes for GUI elements).

Although Cocoa is not really portable across platforms, you might be able to get your Cocoa programs to work on a number of platforms if you take GNUstep into account. Here's what the GNUstep FAQ has to say about portability between Cocoa and GNUstep (quoted verbatim):

It's easier from GNUstep to Cocoa than Cocoa to GNUstep. Cocoa is constantly changing, much faster than GNUstep could hope to keep up. They have added extensions and new classes that aren't available in GNUstep yet. Plus there are some other issues. If you start with Cocoa:

My definition of "portability" (in the current context) is not about feasibility, but the practicality of doing so. Given enough resources, one could port anything to anything - often by emulating/implementing the "source" API on the "target". The WINE project is a wonderful effort. Microsoft once used help from Mainsoft to get Internet Explorer and Outlook Express to run on Solaris. Still, Win32 code is not portable from a practical viewpoint.

Java

Mac OS X includes a complete J2SE implementation. The Swing implementation generates native OS X GUI elements for a uniform look and feel. JAR files are treated as shared libraries. Note that Cocoa includes Java packages that let you create a Cocoa application using Java as the programming language.

X11

Mac OS X includes (optionally) an X Window System implementation based on XFree86 4.3+. The X server has been optimized for OS X via integration with Quartz and supports OpenGL, rootless and full screen modes, an Aqua-compatible window manager (quartz-wm) and a menu in the Dock. The presence of a good quality X server and the X11 SDK is a big win because it makes possible to port (in most cases with no or minor changes) a large number of existing X11 applications to Mac OS X, including use of toolkits such as GTK, KDE, various others.

As mentioned in Architecture of Mac OS X, Mac OS X has a number of very different APIs due to the many environments constituting it. The example of BSD and Carbon Process Manager processes was given before. Similarly, what thread API you use on Mac OS X is determined by what environment you are programming in. Mach provides low-level kernel threads. The pthread library, /usr/lib/libpthread.dylib (actually a symlink to libSystem.dylib) provides POSIX threads. Carbon includes a threads package for cooperatively scheduled threads (Thread Manager) and another for preemptively scheduled threads (Multiprocessing Services). Cocoa uses the NSThread class, while Java uses java.lang.Thread. All these are built using pthreads.

Bundles and Frameworks

Mac OS X uses a few concepts not found on many traditional BSD, Linux, Solaris etc. systems.

Bundle

A Bundle is a directory that stores executable code and the software resources (icons, splash images, sounds, localized character strings, interface builder "nib" files, .rsrc resource files, etc.) related to that code. Although a bundle is a directory containing potentially numerous subdirectories and files, it is treated as a single entity for various purposes.

Mac OS X can have different kinds of bundles:

One of the Finder flags is kHasBundle, which, if set, makes the bundle appear as a file package (a single opaque entity), with exceptions and specific behavior for different bundle types.

The various bundle extensions referred to above are only conventions - a bundle can have any extension. For example, instead of a .app, you can have a .debug or .profile to imply debug or profile code, respectively.

Framework

A Framework, as stated above, is a type of a bundle that contains shared resources such as dynamic shared libraries, header files, icons and images, documentation, etc. Moreover, frameworks are versioned. Major versions are incompatible while minor versions are compatible. One framework can have multiple major versions.

Consider an example:

# ls -lF /System/Library/Frameworks/OpenGL.framework total 32 lrwxr-xr-x ... Headers@ -> Versions/Current/Headers lrwxr-xr-x ... Libraries@ -> Versions/Current/Libraries lrwxr-xr-x ... OpenGL@ -> Versions/Current/OpenGL lrwxr-xr-x ... Resources@ -> Versions/Current/Resources drwxr-xr-x ... Versions/

Except Versions/, everything else is a symbolic link (to entities from the current major version). The file OpenGL is the dynamic shared library:

# file -L OpenGL OpenGL: Mach-O dynamically linked shared library ppc

The default path for searching frameworks (as used by the dynamic link editor) is:

$(HOME)/Library/Frameworks /Library/Frameworks /Network/Library/Frameworks /System/Library/Frameworks

As we have seen, Mac OS X has complex entities (like a .app directory tree) exposed as a single, click-able entity through the Finder. The same effect as double-clicking on an entity's icon can be achieved on the command line through the open utility. It opens a file, folder, or a URL, in an appropriate manner. For example, opening a .app folder would launch that application, opening a URL would launch an instance of the default web browser with that URL, opening an MP3 file would open it in the default MP3 player, etc.

Runtime Environments

Mac OS X has two primary runtime environments: one based on the dynamic link editor, dyld, and the other based on Code Fragment Manager (CFM). OS X does not support ELF, and there's no dlopen, although the dlcompat library provides a limited compatibility layer (using native OS X functions) so that common Unix source can be compiled easily.

CFM determines addresses for referenced symbols in executables at build time (a static approach). The executable format used is called PEF (Preferred Executable Format). dyld resolves undefined symbols at execution time. The executable format is Mach-O (Mach object-file-format).

Mac OS X is natively a dyld/Mach-O platform - all system frameworks are built using dyld. In fact, the CFM/PEF environment is itself built on top of dyld/Mach-O. However, there exist provisions to call dyld code from CFM code. Moreover, if you wish to debug or trace a CFM application using GDB, you would need to use a Mach-O program called LaunchCFMApp:

/System/Library/Frameworks/Carbon.framework/Versions/\ A/Support/LaunchCFMApp

dyld/Mach-O is similar in many respects to ld.so/ELF, although they differ both conventionally and fundamentally. Some of these are:

Mac OS X uses Mach-O and not ELF simply because NEXTSTEP used Mach-O. Apple had a large enough TODO list that moving to ELF for the sake of mainstream conformity was not justified. Like NEXTSTEP, Mac OS X supports "fat" binaries where an executable image contains binaries for more than one platform (such as PowerPC and x86). Apple's port of GNU CC allow for fat binaries to be produced (provided assemblers and libraries are available for each specified architecture).

Prebinding

Mac OS X uses a concept called "prebinding" to optimize Mach-O applications to launch faster. Prebinding is the reason you see the "Optimizing ..." message when you update the system, or install certain software.

The dynamic link editor resolves undefined symbols in an executable (and dynamic libraries) at run time. This activity involves mapping the dynamic code to free address ranges and computing the resultant symbol addresses. If a dynamic library is compiled with prebinding support, it can be predefined at a given address range. This way, dyld can use predefined addresses to reference symbols in such a library. Of course, for this to work, libraries cannot have preferred addresses that overlap. Apple specifies address ranges for 3rd party (including your own) libraries to use to support prebinding.

update_prebinding is run to (attempt to) synchronize prebinding information when new files are added to a system. This can be a time consuming process even if you add or change a single file, say, because all libraries and executables that might dynamically load the new file must be found (package information is used to help in this, and the process is further optimized by building a dependency graph), and eventually redo_prebinding is run to prebind files appropriately.

/usr/bin/otool can be used to determine if a binary is prebound:

# otool -hv /usr/lib/libc.dylib /usr/lib/libc.dylib: Mach header magic cputype cpusubtype filetype ncmds sizeofcmds flags MH_MAGIC PPC ALL DYLIB 10 1940 \ NOUNDEFS DYLDLINK PREBOUND SPLIT_SEGS TWOLEVEL

Xcode

Xcode is Mac OS X "Panther"'s developer tools package. It includes components typical of a comprehensive IDE:

A new Xcode project can be instantiated from a large number of templates. As can be seen, it supports development of various kinds of programs in C, C++, Objective-C, Objective-C++, Java and Assembly. For example, it is almost trivial to create things such as Screen Savers, Preference Panes (the kind you see under System Preferences), etc.

Xcode has some neat and useful features: Predictive compilation runs the compiler in the background as you edit the source. Once you are ready to build, the hope is that most of the building would have been done already. "Zero Link" links at runtime instead of compile time, whereby only code needed to run the application is linked in and loaded. A related feature is "Fix and Continue", courtesy which you can make a change to your code and have the code compiled and inserted into a running program. Distributed builds are also supported via integration with distcc.

Programming Languages

Compilers and Libraries

Apple provides a customized/optimized GNU CC, with backends for C, C++, Objective-C and Objective-C++. For Java, two compilers are included: javac and IBM's jikes. Compilers for many other languages are available either precompiled (such as the XL Fortran Advanced Compiler from IBM), or can be compiled from source, which is not any harder in general than compiling the same source on, say, Linux or FreeBSD. The same goes for development libraries - it should be easy to compile many open source platform-independent / multi-platform libraries from source on OS X. Many important libraries and APIs are either included with Mac OS X, or are readily available (Gtk/Gtk++, Java, OpenGL, Qt, QuickTime, Tcl/Tk, X11R6). The system comes with several special purpose (and/or optimized) libraries as well, such as for Numerical Computing and Image processing (BLAS, vBigNum, vDSP, vImage, LAPACK, vMathLib, etc.)

Interpreters

A number of scripting languages are included in Mac OS X, such as AppleScript (including the AppleScript Studio IDE), Perl (Mac OS X "Panther" has perl 5.8.1), PHP, Python (Panther has python 2.3, with bindings to CoreGraphics), Tcl, and Ruby. Mac OS X also supports the Open Scripting Architecture (OSA), using which it is possible to get JavaScript (a port of Mozilla JavaScript) in the form of an OSA component. You can get support for more languages (Lisp, Scheme, ...) via Fink, and it should be straightforward to compile most of them from source, if desired. bash, tcsh, and zsh are the *nix shells included.

Scriptability

AppleScript is the preferred scripting system on Mac OS X, providing direct control of many parts of the system as well as applications. In other words, AppleScript lets you write scripts to automate operations, exchange data with and send commands to applications, etc.

While I personally find AppleScript syntax to be exasperating (I never really enjoyed COBOL for that matter), it is useful. Consider a contrived example for a taste of AppleScript:

tell application "Finder" set system_version to (get the version) as number do shell script "say 'This is Mac OSX'" & system_version return system_version end tell

Running the above (either in ScriptEditor or through the osascript command line utility) should cause the say utility (see below) to speak the version of Mac OS X (well, assuming you are running Mac OS X) to you. By the way, you do not need to run a shell command and use the say utility: AppleScript has a say command of its own.

Now, whether you are impressed by (or happy with) Mac OS X's scriptability depends on which system you are contrasting with. As mentioned at the beginning of this section, if you are coming from a traditional Unix/Unix'ish world (FreeBSD, Linux, Solaris, *nix, ...), you should find it impressive, a lot perhaps (barring the miniscule possibility that you are an anti-Mac/pro-XYZ zealot). However, you might not think much of this if you have been using Microsoft's COM/DCOM/.NET.

Along the lines of making a *nix developer/user happy though, Apple has been exposing various aspects of Mac OS X functionality to be driven via a traditional command line. Consider some examples:

drutil is a command line tool that interacts with the DiscRecording framework. The command:

# drutil getconfig supported

will probably tell you more than you want to know about your CD/DVD burner.

hdiutil is a powerful utility for manipulating disk images.

say is a command line utility to convert input text to speech using the Speech Synthesis manager.

sips is a command line interface to the Scriptable Image Processing Server. The graphical abilities of Mac OS X are exposed through this image processing service. The SIPS architecture contains tools for performing basic image alterations and support various image formats. The goal is to provide quick, convenient, desktop automation of common image processing operations.

Tools

The Developer Framework contains a wealth of tools for various programming, debugging, profiling and other developmental tasks. The CHUD (Computer Hardware Understanding Development) Tools are particularly useful for various kinds of benchmarking and optimization. Mac OS X Developer Tools Overview contains detailed information on almost all tools included in Xcode. Mac OS X Hacking Tools is a compendium of some useful programs on Mac OS X (mostly outside of Xcode).

Lastly, the OS X Terminal.app, is one of the better terminal applications around, which does matter to me while programming, since I do not use an IDE for everything. The terminal advertises itself as xterm-color, has Unicode support (though broken), drag-and-drop support (dragging an icon to the terminal would drop its pathname or URL string), transparency support (has a minor problem in Panther - there's ghosting of text under certain conditions), etc.

<<< Mac OS X Filesystems main A Sampling of Mac OS X Features >>>