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.
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:
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.
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.
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.
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).
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.
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.
Bundles and Frameworks
Mac OS X uses a few concepts not found on many traditional BSD, Linux, Solaris etc. systems.
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:
An "Application" bundle (such as
Foo.app) contains everything (except frameworks/libraries coming from elsewhere) needed to run the
Fooapplication. It is possible to simply drag
Foo.appto any location and it will work as expected (you do not even have to do anything to its Dock icon, if any - courtesy the fact that "aliases" on HFS+ do not break if you move a file without replacing it). The
/Applicationsdirectory contains many such bundles.
A "Framework" (such as
Bar.framework) is a versioned bundle containing resources such as headers, documentation, etc. The
/System/Library/Frameworksdirectory contains numerous frameworks (such as for Kerberos, Python, QuickTime, ScreenSaver, and so on).
A "Loadable" bundle can be a kernel extension (a
.kext, similar to a loadable kernel module on Linux, say), many of which exist in
/System/Library/Extensions, a Plug-in or a Palette.
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
.profile to imply debug or profile code, respectively.
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
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/
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:
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
dyld/Mach-O is similar in many respects to
ld.so/ELF, although they differ both conventionally and fundamentally. Some of these are:
Dynamic shared libraries on Mac OS X have the
.dylibextension. The functionality of several traditional libraries (such as
librpcsvc, etc.) is provided by a single dynamically loadable framework,
libc.dylibetc. are simply symbolic links to
Mac OS X builds libraries and applications with a two-level namespace (as compared to a flat namespace in traditional Unix systems). This topic is described in an Apple Developer Note called Two-Level Namespace Executables. This also means that
LD_PRELOADwill not work with two-level namespace libraries. You can force a flat namespace, but that often messes up things enough to stop the application from running at all. Additionally, you cannot have "weak" symbols (symbols that can be overridden) in libraries.
- Functionality similar to
ldd(on Linux, say) is provided by
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
magic cputype cpusubtype filetype ncmds sizeofcmds flags
MH_MAGIC PPC ALL DYLIB 10 1940 \
NOUNDEFS DYLDLINK PREBOUND SPLIT_SEGS TWOLEVEL
Xcode is Mac OS X "Panther"'s developer tools package. It includes components typical of a comprehensive IDE:
- A source code editor with code completion
- A file browser/organizer
- Support for version control (CVS and Perforce)
- A documentation viewer that can link symbols in the code to documentation
- A class browser
- Various compilers (the GNU suite, including
gcc 3.3and integration with
distccfor distributed builds,
- GDB based graphical and command-line debugging
- An Interface Builder application that provides a GUI for laying out interface objects (various GUI elements), customize them (resize, set and modify attributes), connect different objects together, and so on
- Support for packaging
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
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 (
zsh are the *nix shells included.
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
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.
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.