Ruby and Python Programming Topics for Mac

Retired Document

Important:
The current version of Ruby (2.0) is not supported as a Cocoa scripting language in OS X v10.9. The remainder of the content in this document has not been reviewed for accuracy. Apple recommends Objective-C for the development of Cocoa apps.

Generating Framework Metadata

The programmatic interfaces of virtually all frameworks on OS X, even Objective-C frameworks, have ANSI C elements such as functions, string constants, and enum constants. The scripting Objective-C bridges, RubyCocoa and PyObjC, can introspect most object-oriented symbols of Objective-C frameworks at runtime, but they cannot introspect ANSI C symbols. Fortunately, there is a utility, gen_bridge_metadata, that parses the non-introspectable symbols of framework and libraries and constructs a representation of them that the PyObjC and RubyCocoa bridges can read and internalize at runtime. These generated symbols are defined as XML elements in framework metadata files (also known as BridgeSupport files).

An obvious advantage of framework metadata is that gives the scripting bridges access to the programmatic interfaces of non-Objective-C frameworks, such as Core Foundation, Core Graphics, and Directory Services. Many of the ANSI C frameworks shipped by Apple in OS X v10.5 and later systems include metadata files, and thus their interfaces are accessible from RubyCocoa and PyObjC scripts.

The following sections describe the framework metadata generated to supported the RubyCocoa and PyObjC bridges and explains how to generate metadata files and create the exception files that support that metadata.

The Location and Structure of Framework Metadata Files

Framework metadata is XML markup stored in a file named after the framework and with an extension of bridgesupport. Thus, the metadata file for the Application Kit framework (AppKit.framework) is named AppKit.bridgesupport. Each metadata file describes exactly one framework or dynamically shared library. The RubyCocoa and PyObjC bridges look for metadata files in several places:

Inside the Resources folder of the framework bundle (non-localized) inside a folder named BridgeSupport. This is the preferred approach if you own the framework.

In /System/Library/BridgeSupport (this location is reserved for Apple)

In /Library/BridgeSupport

In ~/Library/BridgeSupport (that is, in the user’s home directory)

The bridges search the locations in the above order and load the first metadata file they find for a given framework. Note that the bridges might also look in the RubyCocoa and PyObjC frameworks for metadata files.

A metadata file consists of several sections of different elements each defining an ANSI C symbol and, in some cases, an Objective-C symbol. The sections include metadata descriptions of string constants, enum constants, functions, structures, opaque objects, classes (with their methods), and informal protocols.

Note: For a detailed description of the content and structure of framework metadata files, see the BridgeSupport(5) man page. For an explanation of the Objective-C type-encoding constants used as values in attributes, see The Objective-C Programming Language.

At the top of the metadata XML hierarchy is the root element, signatures. It has a version attribute.

<signatures version='1.0'>

Following this is a section dealing with string constants. Listing 1 shows a section of metadata markup that describes string constants by name and encoding type.

Listing 2shows a section of metadata markup that describes enum constants by name and integer value.

Listing 2 Part of the enum section, AppKit.bridgesupport

<enum name='NSServiceMalformedServiceDictionaryError' value='66564'/>

<enum name='NSServiceMiscellaneousError' value='66800'/>

<enum name='NSServiceRequestTimedOutError' value='66562'/>

<enum name='NSShadowlessSquareBezelStyle' value='6'/>

<enum name='NSShiftKeyMask' value='131072'/>

<enum name='NSShowControlGlyphs' value='1'/>

<enum name='NSShowInvisibleGlyphs' value='2'/>

<enum name='NSSingleDateMode' value='0'/>

<enum name='NSSingleUnderlineStyle' value='1'/>

<enum name='NSSizeDownFontAction' value='4'/>

<enum name='NSSizeUpFontAction' value='3'/>

<enum name='NSSmallCapsFontMask' value='128'/>

<enum name='NSSmallControlSize' value='1'/>

The metadata for functions is more complicated, as it has to describe argument and return types. Listing 3 shows the metadata definition of several functions.

Listing 3 Part of the function section, AppKit.bridgesupport

<function name='NSDrawBitmap'>

<arg type='{_NSRect={_NSPoint=ff}{_NSSize=ff}}'/>

<arg type='i'/>

<arg type='i'/>

<arg type='i'/>

<arg type='i'/>

<arg type='i'/>

<arg type='i'/>

<arg type='B'/>

<arg type='B'/>

<arg type='@'/>

<arg type='^*'/>

</function>

<function name='NSDrawButton'>

<arg type='{_NSRect={_NSPoint=ff}{_NSSize=ff}}'/>

<arg type='{_NSRect={_NSPoint=ff}{_NSSize=ff}}'/>

</function>

<function name='NSDrawColorTiledRects'>

<arg type='{_NSRect={_NSPoint=ff}{_NSSize=ff}}'/>

<arg type='{_NSRect={_NSPoint=ff}{_NSSize=ff}}'/>

<arg c_array_length_in_arg='4' type='^i' type_modifier='n'/>

<arg c_array_length_in_arg='4' type='^@' type_modifier='n'/>

<arg type='i'/>

<retval type='{_NSRect={_NSPoint=ff}{_NSSize=ff}}'/>

The gen_bridge_metadata tool also processes some aspects of Objective-C that the bridges cannot introspect at runtime, such as type modifiers, C-array arguments, and values returned by reference. It also reconciles some aspects that are different in the scripting languages and Objective-C, such as Boolean values. These details mostly derive from exceptions files (see Creating the Exceptions File). Listing 4 shows a section of metadata specifying methods of the NSTypesetter class.

Using the gen_bridge_metadata Tool

The gen_bridge_metadata tool parses framework header files and runs the gcc compiler on a framework binary to extract the public symbols. With this data, it composes an XML metadata file for the specified framework. The simplest form of the command requires only the name of the framework (minus the framework extension) and the name of the output file:

$> gen_bridge_metadata -f MyFramework -o MyFramework.bridgesupport

For this shorthand reference to a framework to work, the framework must be installed in one of the standard file-system locations: /System/Library/Frameworks, /Library/Frameworks, /Network/Library/Frameworks, or ~/Library/Frameworks. If the framework is located elsewhere, you can specify an absolute path to the framework instead.

Most frameworks require a manually prepared exceptions file to complete the framework metadata. You specify this file on the command line with the -e option:

Framework metadata files cannot describe inline functions in a form that the bridges can use. If your framework has inline functions, you therefore also need to generate a dynamically shared library, which the bridges can use. The file extension for the created file should be dylib. The following is an example command:

$> gen_bridge_metadata -f MyFramework -F dylib -o MyFramework.dylib

The -F option is for specifying a format, one of “final”, “exceptions-format”, or “dylib”. The default format is “final”.

For more information on gen_bridge_metadata consult the gen_bridge_metadata(1) man page. You can also run the tool with an argument of -h (or --help) to get a list of options.

Creating the Exceptions File

You might have to supplement the metadata for your framework with an exceptions file. An exceptions file records aspects of a framework’s programmatic interface that the bridges cannot introspect at runtime or that conflict with something in a scripting language. These items include type modifiers, C-array arguments, informal protocols, values returned by reference, and Boolean values.

First, you need to create an exception template, which will provide the structure of the XML file. Run the following at the command line to create the exceptions template:

Next open the template file in a text editor and insert your framework-specific information in the appropriate places.

Note: Instructions on completing an exceptions file will be provided in a future version of this document. For now, you can consult the BridgeSupport(5) manual page.

When your exception file is complete, you can generate the final bridge support file for your framework, as described in Using the gen_bridge_metadata Tool. Make sure that you supply the -e parameter and the path to the exceptions file. The gen_bridge_metadata tool will fail if your exception file contains any errors.

Creating Your Own Bridge

Beginning in OS X version 10.5, you can easily create your own bridge between Objective-C and any language. You can use the generated bridge support files and the libffi library to have your bridge call C functions and create C closures in a dynamic, architecture-agnostic way. Libffi provides a bridge from interpreted code to compiled code that can tell the interpreter at runtime the number and types of function arguments and return values.

You can learn more about libffi by reading the manual pages for ffi, ffi_prep_cif, ffi_prep_closure, and ffi_call.