Mac OS X ships with over 100 open source projects that provide a wealth of functionality. While Apple provides working versions of these for both PowerPC and Intel architectures, sometimes you want to build your own to tune performance or enable custom features. Most of these open source projects use a makefile to drive the build process, which is fine if you intend to build the project the same way each time.
A more flexible approach is to create an Xcode project based on the makefile. Migrating a makefile-based project over to a native Xcode project provides several advantages:
With the transition of Mac OS X to the Intel architecture, distributing a single binary that encompasses multiple architectures is often preferable to keeping track of separate, architecture-specific binaries. This can be accomplished by building the project as a Universal Binary, a file that contains code for both the PowerPC and Intel architectures.
In this article we use Xcode to build a Universal Binary framework from the OpenSSL source. You may first wish to read the previous article, Building an Open Source Universal Binary, in which we built static libraries and test applications. That article provides a foundation that will help you understand the project we are building in this article.
You can download the Xcode project .DMG file (540KB), created for this article.
The first step is to download and unpack the OpenSSL source code archive. This article uses version 0.9.8a. After downloading, double-click on the
Figure 1: OpenSSL Project Folder Hierarchy
Most open source projects use a makefile to control the build process. The makefile sets flags that instruct the compiler and linker which source files to include, what build options to use, and the type of the final binary. A discussion of makefiles is included in several ADC articles and documents that are referenced at the end of this article.
What this means is that if you want to port a makefile-based project to Xcode, you should spend some time getting familiar with the makefile. In this example, the makefile helps pare down the list of source code files. OpenSSL includes some files that only pertain to specific platforms, such as the file
The overall build sequence is shown below. Note that we build the framework just once; Xcode handles the packaging into one Universal Binary.
This general plan may be used with other open source projects.
Creating the Framework
Now that we have taken a cursory glance at the OpenSSL archive structure and the desired set of build steps, we can start the Xcode project process. If you prefer to download the finished Xcode project, use the link provided in the "For More Information" section at the end of this article.
Our first step is to create a new project. In Xcode, select File > New Project.... Then, in the Assistant dialog, choose project type "Cocoa Framework", as shown in Figure 2.
Figure 2: Create A New Xcode Project
Name the project "OpenSSLFramework", and create it inside the OpenSSL folder, as shown in Figure 3. Note that the default Xcode behavior is to create a subfolder named after the target, but in this case we removed the subfolder from the path.
Figure 3: Create The Project Directly In The OpenSSL Folder
Figure 4 is a snapshot of the final project, in case you would like to see where this is going. Note that we deleted the default groups "Classes" and "Other Sources". We moved the file
Figure 4: Snapshot Of The Final Project
The following target properties require modification in order to properly build the framework.
Adding the Source Code Files
This step involves adding the source files that make up the
The simplest way to handle this is to first add all the source files from
Figure 5: Add Existing Files
Figure 6: Add Source Files To Target
For example, Listing 1 shows a portion of
Listing 1: Sub-Project Makefile
# # crypto/aes/Makefile # # snip LIB=$(TOP)/libcrypto.a LIBSRC=aes_core.c aes_misc.c aes_ecb.c aes_cbc.c aes_cfb.c aes_ofb.c aes_ctr.c LIBOBJ=aes_misc.o aes_ecb.o aes_cfb.o aes_ofb.o aes_ctr.o $(AES_ASM_OBJ) # snip
In the project, navigate to
Figure 7: Remove Unnecessary Source Files
What you should be left with for this particular folder is shown in Figure 8.
Figure 8: Remaining Files Match the Makefile
Finally, add to the top-level of "Groups & Files" the file
Building the Framework
Now that the project is ready, try building the framework using Build > Build. If all goes well it should build without error, as shown in Figure 9. Note the summary of steps in the bottom pane. This is GCC's way of telling you exactly what commands ran during the process.
Figure 9: Build Result
Listing 2: The file Command
mertz:/Frameworks/OpenSSLFramework.framework/Versions/A asd$ file OpenSSLFramework OpenSSLFramework: Mach-O fat file with 2 architectures OpenSSLFramework (for architecture i386): Mach-O dynamically linked shared library i386 OpenSSLFramework (for architecture ppc): Mach-O dynamically linked shared library ppc mertz:/Frameworks/OpenSSLFramework.framework/Versions/A asd$
If the framework does not build on your first attempt, the most likely cause
is including files that have dependencies on other files that are not included.
Look at any included header files, and make sure there is a path to those files.
You may need to update the
Some of the makefiles contain targets that include
Creating the Test Application
OpenSSL includes a number of test files, usually just a main function that exercises a specific portion of the library. In this section we will create an Xcode target for testing OpenSSL's cast functionality. This target builds a Carbon application that both links against the framework and copies the framework into the application's bundle. This means you do not need to worry about
Integrating a Cocoa framework into a Carbon application provides access to many more features than we use in this example. Read more about it in the Carbon-Cocoa Integration Guide.
Create a new target of type Carbon Application, as shown in Figures 10 and 11.
Figure 10: Create The Target
Figure 11: Name The Target
We then need to modify these phases of the target:
These modifications are discussed in the following sections.
Nesting the Framework Target
Our first task is to nest the OpenSSLFramework build target in the Cast Test target. This creates a dependency on the framework target. When you build Cast Test, the framework target will be built first. If it needs rebuilding, that will be done automatically. This eliminates the need to manually check whether the framework is up-to-date when you build the application that uses the framework.
As shown in Figure 12, drop the
Figure 12: Drag-and-Drop The Framework Target
The result is shown in Figure 13.
Figure 13: The Nested Framework Target
In this phase, we add the file
Figure 14: Add Files
Figure 15: Add casttest.c
Using the Assistant, specify that
Figure 16: Select Target
Figure 17: Add Complete
We need to make a simple change at the top of
Listing 3: Change header location in casttest.c
// Change this: "../e_os.h" // to: #include <e_os.h>
Link Binary With Libraries
The "Link Binary With Libraries" phase is where we specify any frameworks or libraries to link against. Drag the
Figure 18: Drag The Framework To The Link Phase
We need to add a "Copy Files" phase to explicitly copy the framework into the application's bundle. As shown in Figure 19, select Project > New Build Phase > New Copy Files Build Phase.
Figure 19: Add A Copy Files Phase
Next, select "Frameworks" in the "Destination" popup menu.
Figure 20: Select The Destination For The Copy Files Phase
Finally, drag the
Figure 21: Drag The Framework Onto The Phase
Build And Test
Figure 22: Cast Test Results
The test applications provide an easy path to getting familiar with the libraries and how to use them, in preparation for incorporating OpenSSL into your own application.
For More Information
Using the techniques discussed in this article, you can migrate other open source projects to the Universal Binary architecture. The sources below will help you find more specific information.