
One of the most powerful yet under-appreciated frameworks in Mac OS X is
Core Foundation, also known as CF. CF provides the fundamental C data
types (for example, String, Dictionary, Array, Data and Number) as well as the essential
services (such as plug-ins, URL handling and networking) that underlie both
Cocoa and Carbon. In particular, CF provides convenient facilities for
importing and exporting these types as part of a rich, flexible data
structure known as a property list, which is used extensively for system
configuration, application parameters, and user defaults.
A very useful thing about CF is that most of it is available
from Apple as an open source project known as CF-Lite, available on
Apple's Open Source website. Because CF is open source, developers can compile
and run it on Macintosh as well as other platforms—and this opens up a number of interesting
possibilities. These cross-platform opportunities, and how to exploit
them using open source, are the focus of this article.
As an example, consider a Cocoa application that provides an
administrative front-end to an open source database, such as MySQL.
Using Cocoa bindings, a rich graphical front-end can be created using
virtually no code, which would save the user's choices as a property
list, in either an XML or binary format. That file can be sent to
the server using DAV or a shared filesystem, where a trusted server
application would read it and perform the necessary administrative
tasks.
If both client and server systems are running Mac OS X, you could write
the entire application in Cocoa. But, what if your servers are
running Linux? Do you have to give up and write the entire thing as a web
application? Or, must you learn how to define and parse your own XML schema to
share information between the client and server?
In a word: No. Instead, you can take advantage of the open source
nature of CF-Lite to create a cross-platform tool that will read
standard Mac OS X property lists virtually anywhere.
In this article, we start by describing the kind of environment you need to build CF-Lite on Mac OS
X, Darwin, Linux and even Windows (via Cygwin). Next, we walk
you through the basics of CF-Lite, including a simple application for
reading and displaying property lists. After that, we'll delve into
the detailed mechanics of actually building, installing, and testing
CF-Lite on various platforms; and we even provide the project on the
ADC Member Site (you can join for
free). Finally, we'll suggest ideas for future
exploration, including modifying CF-Lite or making use of other Darwin
projects.
What You Need to Get Started
1. You need access to at least one of the following: Mac OS X, a Darwin
volume, a Linux volume, or a Windows system with Cygwin installed (see
the section below, "What is Cygwin?"). On Mac OS X, install the Xcode development tools from the
installation CD.
2. You need to download the CoreFoundation project from Apple's Darwin Projects
source site. Look for the project name that begins with "CF": this
is the latest version of CF-Lite, and should be your primary reference
point.
If you'd like to download the entire project at once, you can use
rsync from the community-run OpenDarwin mirror:
$ rsync -vL "darwinsource.opendarwin.org::darwinsource/10.3.8/*.tar.gz" ./
Though not as definitive as the Apple site, OpenDarwin may be more
convenient, and include changes from other members of the community; see
For More Information below for details.
3. In addition, on platforms other than Mac OS X you need the
following header files from
/System/Library/Frameworks/CoreServices.framework. Without
them, you will get compiler errors regarding Mac OS X version
availability and undefined data types. Copy the files to
/usr/include/, so they will be included in GCC's standard
search path:
AssertMacros.h
AvailabilityMacros.h
TargetConditionals.h
4. You can download and use this sample Xcode project,
plistProject, from the ADC
Member site.
All of the functions discussed in this article are included in
main.c. A sample schema.xml file is also
included in the project folder.
What is Cygwin?
Cygwin is a collection of UNIX tools, coupled with a Linux emulation
layer, that run in a shell environment on Windows 95 and later. The
tools are ports of FSF (Free Software Foundation) programs and other
sources. The environment permits the use of many applications and
utilities that are standard in Linux distributions. Programs (should)
behave within Cygwin the same way they would under a Linux shell.
Note that it is theoretically possible to build CF-Lite using native
Windows services and tools; however, currently the Cygwin build is
simpler and more robust, so we will use that for the purposes of this
article.
In general, the same commands apply to Linux and Cygwin. If you
have access to a Windows system, but not a full Linux installation, you
can build and test CF-Lite using Cygwin. Check out the Cygwin website for more information. When
installing Cygwin, you first download and run the setup
program, then select the packages you want to install. For this article,
install the developer packages for GCC, including the C compiler and the
make utility. There are many additional packages available
for you to experiment with.
CF-Lite Overview
CF-Lite, the Darwin version of Core Foundation, is a subset of CF that
does not include some functionality available on Mac OS X. However, it
does contain the data structures used for managing common application
objects—such as strings and numbers of various formats—which are
of particular interest for cross-platform projects.
Data types
Core Foundation's object model supports encapsulation and polymorphic
functions, and is based on opaque types. The individual fields of an
object based on an opaque type are hidden from clients, but the type's
functions offer access to most values of these fields.
"Class" is not used to refer to opaque types because, despite the conceptual similarity of class and
opaque type, many might find the term confusing. However, the Core Foundation documentation frequently
refers to specific, data-bearing instances of these types as "objects".
Core Foundation has many opaque types, and the names of these types
reflect their intended uses. For example, CFString is an opaque type
that "represents" and operates on Unicode character arrays. ("CF" is, of
course, a prefix for Core Foundation.) CFArray is an opaque type for
indexed-based collection functionality. The functions, constants, and
other secondary data types in support of an opaque type are generally
defined in a header file having the name of the type; CFArray.h, for
example, contains the symbol definitions for the CFArray type.
A link to Core Foundation documentation is provided at the end of this article. In particular, read the overview.
A Property List Example
Our primary example involves the use of Core Foundation property
lists, or "plists," as a common data exchange mechanism between Mac OS
X, Darwin, and Linux. All plists have an XML syntax, which imposes structure
on the data stored in the plist. Also, plists use a key-value association,
where you specify an identifier, or key, for the data element to
retrieve, and the plist returns the associated value(s). Plists are more
flexible than simple 1-to-1 mappings: A key may map to an array of
values, or multiple data elements. Plist keys and values may be any of
several Core Foundation data types, including String, Dictionary, Array,
Data, and Number. The example includes each of these in the sample
plist.
Core Foundation property lists are of type
CFPropertyList, and are usable across many types of Xcode
projects. For this example, we started from the CoreFoundation Tool
template, as shown in Figure 1.
Figure 1: Creating a CoreFoundation Tool project in Xcode
Listing 1 shows a slightly revised version of
DictionaryExample.c. This file is available on
Mac OS X as part of the Core Foundation example code, in the
folder /Developer/Examples/CoreFoundation/Dictionary. This
example is included as part of the Developer Tools install from the
Mac OS X Developer Tools CD.
The #include statement at the top of Listing 1 adds to the GCC search path the header file CoreFoundation.h, which is part of the CoreFoundation framework. This particular header is an umbrella header, in that it then #includes other headers. Apple has modified GCC to accomodate frameworks in the search path. Later in the article, we will address this issue on Linux.
The function propertyListExample in Listing 1 creates and populates a dictionary (of data type CFMutableDictionaryRef). It then creates a CFDataRef object by calling CFPropertyListCreateXMLData. There are several calls to CFShow to print out messages or formatted objects to the console (see Figure 2).
Listing 1: Creating and saving a property list
#include <CoreFoundation/CoreFoundation.h>
void propertyListExample( void );
void writePropertyListToFile( CFDataRef data );
const char * kFilename = "/schema.xml";
int main( int argc, const char * argv[] ) {
// Create and save the plist.
propertyListExample();
return 0;
}
void propertyListExample( void ) {
CFMutableDictionaryRef dict;
CFNumberRef num;
CFArrayRef array;
CFDataRef data;
#define NumKids 2
CFStringRef kidsNames[] = { CFSTR( "John" ), CFSTR( "Kyra" ) };
#define NumPets 0
int yearOfBirth = 1965;
#define NumBytesInPic 10
const unsigned char pic[ NumBytesInPic ] =
{ 0x3c, 0x42, 0x81, 0xa5, 0x81, 0xa5, 0x99, 0x81, 0x42, 0x3c };
CFDataRef xmlPropertyListData;
CFStringRef xmlAsString;
// Create and populate a pretty standard mutable dictionary: CFString keys, CF type values.
// To be written out as a "propertyList", the tree of CF types can contain only:
// CFDictionary, CFArray, CFString, CFData, CFNumber, and CFDate.
// In addition, the keys of the dictionaries should be CFStrings.
dict = CFDictionaryCreateMutable( NULL, 0, &kCFCopyStringDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks );
CFDictionarySetValue( dict, CFSTR( "Name" ), CFSTR( "John Doe" ) );
CFDictionarySetValue( dict, CFSTR( "City of Birth" ), CFSTR( "Springfield" ) );
num = CFNumberCreate( NULL, kCFNumberIntType, &yearOfBirth );
CFDictionarySetValue( dict, CFSTR( "Year Of Birth" ), num );
CFRelease( num );
array = CFArrayCreate( NULL, ( const void ** )kidsNames, 2, &kCFTypeArrayCallBacks );
CFDictionarySetValue( dict, CFSTR( "Kids Names" ), array );
CFRelease( array );
array = CFArrayCreate( NULL, NULL, 0, &kCFTypeArrayCallBacks );
CFDictionarySetValue( dict, CFSTR( "Pets Names" ), array );
CFRelease( array );
data = CFDataCreate( NULL, pic, NumBytesInPic );
CFDictionarySetValue( dict, CFSTR( "Picture" ), data );
CFRelease( data );
// We now have a dictionary which contains everything we want to know about
// John Doe; let's show it first:
CFShow( CFSTR( "John Doe info dictionary: " ) );
CFShow( dict );
// Now create a "property list", which is a flattened, XML version of the
// dictionary:
xmlPropertyListData = CFPropertyListCreateXMLData( NULL, dict );
// The return value is a CFData containing the XML file; show the data
CFShow( CFSTR( "Shown as XML property list (bytes): " ) );
CFShow( xmlPropertyListData );
// Given CFDatas are shown as ASCII versions of their hex contents, we can also
// attempt to show the contents of the XML, assuming it was encoded in UTF8
// (This is the case for XML property lists generated by CoreFoundation currently)
xmlAsString = CFStringCreateFromExternalRepresentation( NULL, xmlPropertyListData,
kCFStringEncodingUTF8 );
CFShow( CFSTR( "The XML property list contents: " ) );
CFShow( xmlAsString );
writePropertyListToFile( xmlPropertyListData );
CFRelease( dict );
CFRelease( xmlAsString );
CFRelease( xmlPropertyListData );
}
void writePropertyListToFile( CFDataRef data ) {
CFStringRef errorString;
CFPropertyListRef propertyList = CFPropertyListCreateFromXMLData( NULL, data,
kCFPropertyListMutableContainersAndLeaves, &errorString );
if ( errorString == NULL ) {
CFStringRef urlString = CFStringCreateWithCString( NULL, kFilename, CFStringGetSystemEncoding() );
CFURLRef fileURL = CFURLCreateWithFileSystemPath( NULL, urlString, kCFURLPOSIXPathStyle, FALSE );
CFWriteStreamRef stream = CFWriteStreamCreateWithFile( NULL, fileURL );
Boolean isOpen = CFWriteStreamOpen( stream );
CFShow( CFSTR( "Property list (as written to file):" ) );
CFShow( propertyList );
CFIndex bytesWritten = CFPropertyListWriteToStream( propertyList, stream,
kCFPropertyListXMLFormat_v1_0, NULL );
CFWriteStreamClose( stream );
}
else {
CFShow( errorString );
CFRelease( errorString );
}
CFRelease( propertyList );
}

Figure 2: The plist Displayed in the Xcode Run Log Window
Notice, in the functions in Listing 1, that most of the CF objects are allocated by other functions within the Core Foundation API. In these cases, the caller is responsible for releasing the objects when finished, using CFRelease. Forgetting to do this will result in memory leaks.
The function writePropertyListToFile in Listing 1 accepts the raw plist data, creates a CFPropertyList object, and writes that out to an XML file. The plist contents get written out in XML format regardless of how you name the file; we used the .xml extension here as a hint to text editors on how to display the contents. The output file contents are shown in Listing 2. The file can then be copied for use on other machines and/or platforms, which is the subject of the next section.
Listing 2: The Property List as an XML file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>City of Birth</key>
<string>Springfield</string>
<key>Kids Names</key>
<array>
<string>John</string>
<string>Kyra</string>
</array>
<key>Name</key>
<string>John Doe</string>
<key>Pets Names</key>
<array/>
<key>Picture</key>
<data>
PEKBpYGlmYFCPA==
</data>
<key>Year Of Birth</key>
<integer>1965</integer>
</dict>
</plist>
If you open the plist file using /Developer/Applications/Utilities/Property List Editor on Mac OS X, you will see the contents formatted slightly differently, as shown in Figure 3.

Figure 3: The plist in the Property List Editor
Reading the Property List on Darwin
Because Darwin includes CF-Lite, all of the API functions used in
these examples should just work. So, the next step is to copy the plist
file to a Darwin system. The example application discussed in this
section opens and reads the plist. Because Darwin shares the same
version of GCC as Mac OS X, this plist reader is structured
similarly to the plist writer discussed above. As shown in Listing 3,
the reader includes similar declarations at the top, and the
CF calls work the same way. Note that the plist file is
assumed to be in the root directory.
Listing 3: Reading the property list from the XML file
#include <CoreFoundation/CoreFoundation.h>
void readPropertyListFromFile( void );
const char * kFilename = "/schema.xml";
int main ( int argc, const char * argv[] ) {
// Read the plist.
readPropertyListFromFile();
return 0;
}
void readPropertyListFromFile( void ) {
CFDataRef data = NULL;
FILE *file = fopen( kFilename, "r" );
if ( file != NULL ) {
int result = fseek( file, 0, SEEK_END );
result = ftell( file );
rewind( file );
char * buffer = ( char * )calloc( 1, result );
if ( buffer != NULL ) {
if ( fread( buffer, result, 1, file ) > 0 ) {
data = CFDataCreate( NULL, buffer, result );
}
free( buffer );
}
fclose( file );
}
if ( data != NULL ) {
CFPropertyListRef propertyList = CFPropertyListCreateFromXMLData( NULL, data,
kCFPropertyListImmutable, NULL );
CFShow( CFSTR( "Property list (as read from file):" ) );
CFShow( propertyList );
}
CFRelease( data );
}
On Darwin, you can compile the above source code using GCC, like this:
gcc -framework CoreFoundation -o reader main.c
The -o flag precedes the name of the object file that GCC should create, which we can then execute:
$ ./reader
Property list (as read from file):
<CFDictionary 0x5009a0 [0xa01900e0]>{type = mutable, count = 6, capacity = 17, pairs = (
1 : <CFString 0x500ad0 [0xa01900e0]>{contents = "Name"} =
<CFString 0x500ae0 [0xa01900e0]>{contents = "John Doe"}
4 : <CFString 0x500b00 [0xa01900e0]>{contents = "Pets Names"} =
<CFArray 0x500b20 [0xa01900e0]>{type = immutable, count = 0, values = ()}
5 : <CFString 0x500960 [0xa01900e0]>{contents = "City of Birth"} =
<CFString 0x500980 [0xa01900e0]>{contents = "Springfield"}
13 : <CFString 0x500bc0 [0xa01900e0]>{contents = "Year Of Birth"} =
<CFNumber 0x500be0 [0xa01900e0]>{value = +1965, type = kCFNumberSInt64Type}
16 : <CFString 0x500a90 [0xa01900e0]>{contents = "Kids Names"} =
<CFArray 0x500680 [0xa01900e0]>{type = mutable-small, count = 2, values = (
0 : <CFString 0x500770 [0xa01900e0]>{contents = "John"}
1 : <CFString 0x500640 [0xa01900e0]>{contents = "Kyra"} )}
19 : <CFString 0x500b30 [0xa01900e0]>{contents = "Picture"} =
<CFData 0x500b90 [0xa01900e0]>{length = 10, capacity = 10, bytes = 0x3c4281a581a59981423c}
)}
$
CFShow writes to the console, similarly to printf in the C standard library. This makes it a portable, though limited, debugging tool.
Reading the Property List on non-Darwin systems
Linux and Cygwin do not include CF-Lite, so before we can use the plist in an application, we first need to create and deploy the CoreFoundation library. To do this, you need to download the CF-299 project, as discussed above in the section "What you need to get started".
A Patch for Linux
If you are developing on Linux, Cygwin, or another non-Darwin platform, download and install the CF-299.linux.diff patch onto CF-299. Several files in CF-299 require updating or they won't compile. Patching is the easiest way to bring them up-to-date.
To install the patch, rename or copy the directory CF-299 to CF-299.orig, and then execute the patch command, like this:
$ cp -R CF-299 CF-299.orig
$ patch -p0 < CF-299.linux.diff
patching file CF-299.orig/AppServices.subproj/CFUserNotification.c
Hunk #1 succeeded at 80 (offset 2 lines).
...
$
CF-299.orig now contains the updated files, and should build on Linux and Cygwin.
Building and Deploying CF-Lite
This section discusses the Darwin and Linux platforms in detail. Although Darwin already includes GCC and other tools, the build process can be modified by passing parameters to make. This section provides instructions on how to do that. Plus, you can use these instructions if you later decide to modify CF-Lite, and need to rebuild and redeploy it on Darwin (or Linux).
Note that you can build CF-Lite on Mac OS X, and copy the library to
a Darwin volume for use. But do not copy a CF-Lite version of the
library named CoreFoundation into
/System/Library/Frameworks/CoreFoundation.framework on a
Mac OS X volume. The reason is that the Darwin version (CF-Lite) omits important
functionality available in the Mac OS X version. So, you cannot substitute a CF-Lite
build for the Core Foundation library on a volume that boots Mac OS X.
The operating system will crash on restart, or even hang after you have
copied the updated file into the framework directory. In the latter case
you will need to reboot from an installer CD or select a different
startup volume (hold the Option key down while booting).
Again, you can build CF-Lite on Mac OS X for use on Darwin, but do not
replace the Mac OS X CoreFoundation libraries (this
includes CoreFoundation, CoreFoundation_debug,
and CoreFoundation_profile) with CF-Lite versions.
Building and Deploying on Darwin
On Darwin, most packages should build without modification, as long
as you retrieve the package version corresponding to your kernel
version. Core Foundation has not changed much since the release of
Mac OS X 10.3 Panther. This article uses CF-299 (Core
Foundation build 299) and Darwin 7.2.1, although later versions of
either may work fine together. However, introducing other packages may
add dependencies, so you should always first try to download the package
versions appropriate for your kernel version. On the website, package
versions are grouped by kernel version. If you want to build Darwin
7.2.1 packages, you will find the appropriate package archives linked
off the Darwin 7.2.1 page.
The Makefile removes most of the drudgery from the build process. It determines the operating system for which the package is being built, sets paths for generated or copied files, invokes the compiler, and so on. The most comprehensive target in the CF-Lite Makefile is named 'install'. You invoke the install target like this:
$ make install
If you are unfamiliar with Makefiles and/or the GNU build tools, you
should first read the ADC article The
GNU Compiler Collection on Mac OS X. That article lists several references that
provide even more detail about the GCC tools.
All Darwin projects use the following environment variables while building, with the corresponding default values:
| Variable Name |
Description |
Default Value |
| SRCROOT |
Path to the sources being built. |
. (current directory) |
| OBJROOT |
Path where intermediate build objects (.o's) should be stored. |
/tmp/CoreFoundation.obj |
| SYMROOT |
Path where build results with debugging symbols are stored. |
/tmp/CoreFoundation.sym |
| DSTROOT |
Path where final build projects are stored. |
/tmp/CoreFoundation.dst |
You can override any of the environment variables on the command-line. For example, to change the destination of the final product(s), you can specify a new value for DSTROOT like this:
$ make DSTROOT=/usr/lib install
...
Done!
$
The Darwin Build Scripts are a collection of tools that assist compilation of the many projects contained in Darwin. Here are some of the highlights:
- The included
Makefile will compile the tools and install them.
- The
darwinxref tool is used to retrieve the list of projects,
and versions, that compose a Darwin release. Additionally, darwinxref
can store and retrieve information about which tools, libraries, and
headers are necessary for building specific Darwin projects.
- The
darwinbuild script can be used to build Darwin projects.
If you are cross-compiling—building on one platform for
deployment on another (for example, Darwin on Linux)—you will need to explicitly specify the target platform
when invoking make. However, a problem with cross-compiling
CF-Lite is the difference in include paths and filenames. If you want to
build for Linux, you should perform the build on a Linux system, or a
volume that has booted Linux.
If you modify any header files, you should precede any 'make build' or 'make install' with a 'make clean.' This deletes the existing build products, and indirectly forces a recompile of the .c files.
$ make clean
Deleting build products...
$
Building and Deploying on Linux
CF-Lite contains #ifdefs in each source and header file,
and also in the Makefile, that distinguish between code blocks unique to
Darwin (usually denoted by the symbol __MACH__) versus
other operating systems. Linux #ifdefs are included in
places, although you may find that various files do not have their Linux
code up-to-date. This condition will manifest itself as compiler
warnings and errors. You are certainly welcome to attempt to fix the
problems: after all, that is the essence of the open source philosophy.
You may submit your changes back to the OpenDarwin community for
inclusion in later releases. If you get stuck, consider asking for help
on the darwin-development mailing lists. Another developer may have
already fixed the same problem, and/or the update is not yet public. Or
you may have found a previously unnoticed problem that someone with a
different skill set will be more adept at fixing.
If you look through the CF-Lite .h and .c files, you will notice that most of them include headers using one of two paths:
#include "CFInternal.h"
#include <CoreFoundation/CFBase.h>
The first searches the current directory for the file, the second looks in one or more known locations. This includes /usr/include, and directories included on the gcc command line. On the second line, because the reference is to a file located in a folder named CoreFoundation, the compiler will complain unless we provide such a folder. You could copy every header to this CoreFoundation subdirectory, but that gets tedious and error-prone, as any changes to one set of headers need to be reflected in the other set.
A better approach is to create a directory of symbolic links back to the headers in each subproject:
$ mkdir CoreFoundation
$ cd CoreFoundation
$ find ../*.subproj -name \*.h -exec ln -s {} ';'
This works on Linux and Cygwin. It is not necessary on Darwin because
GCC has been modified to accept the parameter -framework,
and will search the framework directories for headers.
You then build as described previously in the Darwin section. In the following example, the completed library is placed at /tmp/CoreFoundation.dst/usr/local/lib/libCoreFoundation.a (the default value for DSTROOT).
$ make clean
Deleting build products...
$ make install
...
Done!
$
When working from a shell, you may lose text as it scrolls past, if you cannot set the window buffer size large enough. For a project the size of CF-Lite, the number of error or warning messages may be substantial. Since those print to stderr, you should redirect stderr to a file. Here is how you can redirect both stdout and stderr to the same log file:
$ make > my.log 2>&1
Building and deploying on Cygwin
You should first create the directory of symbolic links as described above. Once that is done, use the sequence of build commands shown in Figure 4.

Figure 4: Building the library in Cygwin
Note the output from the debug target. This is an addition to the Makefile, and is included here only for illustration (it has no impact on the actual build). Running make and invoking the debug target shows that the platform name is "CYGWIN_NT-5.1". This value is read from the Cygwin environment. (On a true Linux system the debug target prints "Linux".) However, you should force make install to use a PLATFORM value of "Linux", since there is no "CYGWIN" platform defined in the Makefile.
The code for the debug target is this:
debug:
$(SILENT) $(ECHO) $(PLATFORM)
This prints the value of the PLATFORM variable, which is defined in the Makefile but assigned a value at runtime. You can add statements to display additional variable values. The debug target is not included in the original CF-299 source, but you can insert the above code into the Makefile target section; the end of the file is a good location.
Testing CF-Lite
With the library in place, we can write a simple test application that loads the plist from the XML file and prints the result to the console. Let's address this question for Darwin and Linux.
Testing on Linux
The plist reader application works the same under Linux as under Darwin (see the section titled "Reading the property list on Darwin"), but we first need to build it. Compiling main.c requires a different command-line than on Darwin:
gcc -o reader -I/tmp/CoreFoundation.dst/usr/local/include/CoreFoundation main.c
-L/tmp/CoreFoundation.dst/usr/local/include/CoreFoundation
-lCoreFoundation -lpthread -lm
Both the compiler and linker need to know of any additional directories to search: the compiler for included header files, the linker for libraries. The flags are different (-I for cc, -L for ld), but the paths both reflect the distribution directory from the CF-Lite build product.
We also need to specify the libraries to link against. The -l flags indicate the library names. On the gcc command-line, order matters, so CoreFoundation (the physical file can be named either libCoreFoundation.a or libCoreFoundation.so) must be listed first, because it depends on the pthreads library (/lib/libpthread.so) and the math library (/lib/libm.so).
Once built, the application runs the same as on Darwin:
$ ./reader
Property list (as read from file):
<cfdictionary 0xa050958 [0x459160]>{type = mutable, count = 6, capacity = 17, pairs = (
1 : <cfstring 0xa051330 [0x459160]>{contents = "Name"} =
<cfstring 0xa051348 [0x459160]>{contents = "John Doe"}
4 : <cfstring 0xa051360 [0x459160]>{contents = "Pets Names"} =
<cfarray 0xa051378 [0x459160]>{type = immutable, count = 0, values = ()}
5 : <cfstring 0xa050918 [0x459160]>{contents = "City of Birth"} =
<cfstring 0xa050938 [0x459160]>{contents = "Springfield"}
13 : <cfstring 0xa051418 [0x459160]>{contents = "Year Of Birth"} =
<cfnumber 0xa051438 [0x459160]>{value = +1965, type = kCFNumberSInt64Type}
16 : <cfstring 0xa050988 [0x459160]>{contents = "Kids Names"} =
<cfarray 0xa0509a0 [0x459160]>{type = mutable-small, count = 2, values = (
0 : <cfstring 0xa0509b8 [0x459160]>{contents = "John"}
1 : <cfstring 0xa051318 [0x459160]>{contents = "Kyra"}
)}
19 : <cfstring 0xa051388 [0x459160]>{contents = "Picture"} =
<cfdata 0xa0513e8 [0x459160]>{length = 10, capacity = 10, bytes = 0x3c4281a581a59981423c}
)}
$
Testing on Cygwin
Cygwin uses a similar sequence as Linux. In Figure 5, we create the symbolic links to the CoreFoundation headers under /CoreFoundation, since that is on the include search path for gcc. Here, we nest a directory of links within another. This is because of the relative paths in the #include statements within the header files, which the header files use to include each other. We use relative directory locations in this example, although you can also use absolute values that start with the Cygwin root (/).

Figure 5: Setting up the header file symbolic links in Cygwin
Figure 6 shows the GCC invocation, and the execution of the reader application. Note here that the -I/ flag instructs the compiler to search under the root directory for the include files, or symbolic links to the header files. So, instead of looking in /tmp/CoreFoundation.dst/usr/local/include/CoreFoundation (as in the Linux example above), here we instruct GCC to look in /CoreFoundation, which is the directory we populated in Figure 5. Where to put the header files or symbolic links is an arbitrary decision. Just remember to include that directory in the search path when invoking GCC.

Figure 6: Building and running the test application in Cygwin
Ideas for Future Exploration
CF-Lite can always benefit from developer input. Since the Darwin implementation receives the most attention, you might consider working on the Linux, Cygwin, FreeBSD, or Win32 ports. Browse the source code or use the compiler warnings to help you determine what needs to be implemented or improved. For example, when compiling CF-Lite on Linux you will receive numerous warnings stating: CF spin locks not defined for this platform -- CF is not thread-safe. In CFInternal.h, spin locks are undefined for every non-Mach platform. CFRunLoop support also needs attention on non-Mach platforms. If you have the time and skills, consider working on these or other areas.
Providing Feedback to Apple
Bugs relating to CoreFoundation functionality on Mac OS X
should be reported through Apple Bug
Reporter.
Platform specific bugs (for platforms other than Mac OS X) should be reported to OpenDarwin Bugzilla. Specify the CoreFoundation component of the OpenDarwin product.
Changes can be submitted to OpenDarwin using bugzilla, and to Apple using the Modification Notice form. As always bugs, changes, and ideas for enhancements can be discussed on the darwin-developers mailing list.
For More Information
Using the techniques discussed in this article, you can modify, build, and deploy your own versions of Darwin projects. You may also submit modifications for inclusion in future releases. The best starting point is Apple Developer Connection's Darwin project page, which contains links to source code and documents, including FAQs. The links below will help you find more specific information.
Source Code
- Apple's Darwin source site should serve as your primary reference for Darwin projects. Look for the project named "CF-nnn"; this is the latest version of CF-Lite.
- OpenDarwin CVS is
the place to obtain a work in progress version of the same projects.
Here you can download the Darwin 7.0/Mac OS X 10.3 version of
the CF-299
project, which served as the example for this article.
Tools
Documentation
Posted: 2005-4-11
|