In the beginning there was the resource fork. Macintosh applications, extensions, libraries etc. could store all kinds of data such as window layouts, pictures, sounds, strings inside their resource fork, avoiding a confusing mass of files. Data such as the creator and the type of files was stored in the filesystem There was a convenient API for accessing and manipulating this data. All was well in the kingdom of Apple.

And then there was chaos

But not all filesystems have the concept of having separate forks. When macintosh files travelled via filesystems like FAT32 they would lose their resource fork and more often than not become useless. When people upload and download files, they travel as a simple stream of bytes. Protocols such as HTTP don't care about resource forks and don't know about the Macintosh file and creator types. Even data fork only Macintosh files would arrive devoid of file type, leaving the user to guess what kind of file it was. And so it came to be that all travelling macintosh files had to disguise themselves using encodings such as Macbinary or binhex, that they may reach their destination safely.

From Mac OS X's BSD roots came UFS, a filesystem with no concept of forks. Apple came up with what is basically a kludge to allow files with resource forks to survive and work properly on such disks. It was clear that there needed to be some safer way of putting applications together.

Apple's answer to this problem is the bundle. If you look at it from a terminal window is just a folder. A bundle is capable of containing several types of objects. These can be applications, frameworks (basically a shared library) or loadable code. A kernel extension for example is a special type of loadable code, as are Contextual Menu Item plugins. All though follow the same basic construction.

Anatomy of a bundle

At the very least the bundle's folder will contain another folder, called Contents. It may optionally contain folders called Plug-ins, SharedFrameworks and SharedSupport.

In the Contents folder there are a number of special folders :

  • Folders containing platform specific executables or data. These folders must have names according to the platform they are destined for, right now there is a choice of MacOS or MacOSClassic. If you try to run or load a bundle, the system will look in the appropriate platform folder for the executable. It should be noted that the classic Mac OS does not support bundles (it has a similar concept known as a package). For this a reason when applicable an alias to the classic executable is placed in the bundle's folder.
  • Resources: This contains items such as pictures, sounds, window layouts or strings files. It can contain subfolders with names like English.lproj or French.lproj. When you ask for a given item, for example a window layout (usually stored as a nib), it will check the subfolders in an order determined by the user's language preferences. Thus a single application or library can contain many different languages, or even variants of a language, for example American versus British English.
  • Frameworks: Contains, as you might have guessed, frameworks that the application uses. There is a slight difference between this folder and the SharedFrameworks folder mentioned earlier. If a framework is in the Frameworks folder, then that version of the framework will always be used, even if the system has a more recent version. If it is in SharedFrameworks however, a more recent version can be used.
An important file, named Info.plist must reside inside the Contents folder. It's an xml file that defines some of the key properties of the bundle at hand, for example the name of the file containing executable code, version information to be shown in the Get Info window or types of files that the application can open. Specific types of bundles may have additional properties defined. A CFPlugin, which is a special kind of loadable code bundle has information about the types of Factories the plugin implements. A bundle usually also contains a file called PkgInfo that contains creator and type codes for the bundle. This information is also in Info.plist, however it is accessed sufficiently frequently that it made sense to have a copy of the information available separately.

Advantages of using bundles

The main advantage of a bundle is that is an entirely self-contained item. There are no separate files for a user to forget, install, or rename by accident. You can move a bundled application by dragging and dropping a single item. A bundle is also able to reside on filesystems without separate resource forks. You could also have bundles containing executables for several different processor architectures.

You might be wondering how the OS knows if a given folder is a bundle or not. I haven't been able to find any hard info on this, but through a bit of experimentation I've noticed that a bundle must have an extension and an Info.plist file. Additionally applications and frameworks must use the extensions .app and .framework. Personally I find this encoding of file metadata in file names a big step back, but Apple doesn't seem to care about that anymore.