
The Three20 Modularized Build System
====================================

First, some history.

Three20 was originally built by Joe Hewitt as part of the Facebook for iPhone app. Since
then, the library has gone on to be used by countless developers in their efforts to
create amazing apps for the App Store. The Three20 community itself has blossomed to
include more than 800 developers in the Google Group and more than 2000 watchers on GitHub.

The library originally debuted with a number of powerful features, including the style system,
rethought table controllers and data sources, and a navigator with persistence. As time
progressed, more features were added to the library, and Three20 continued to prove to be a
versatile tool in many iPhone developers' arsenals on the App Store battlefield. Debug
utilities, JSON and XML support, and a growing set of sample applications and tutorials
were introduced over time.

But as Three20 grew, it began to experience growing pains. Many developers derided the
lack of documentation and comprehensive unit tests. More pointed out that some of the new
features being included in the Three20 library weren't critical for their needs, or
that they were already including some components, such as JSON parsers, in their own
projects. And some argued that if outside libraries were going to be included in Three20,
then the developer should still have a choice as to which library they actually want to use.

All of these requests were incredibly hard to satisfy given the way the Three20 library was
originally designed: **as a single library**.

### The Conceptual Split

In late 2009, when Jeff took over Three20, he spent a fair amount of time absorbing the
framework. He determined that there were four primary aspects to Three20: Core, Network,
Style, and UI. Each was dependent upon the previous aspect in the list, and collectively they
formed the Three20 library. Over the next five months a great deal of time was invested in
drawing lines in the sand in order to create a conceptual divide between the four aspects.

### Building the New Three20

With the lines in the sand drawn, it became much easier to begin tearing apart
interdependencies between the four components of Three20. Two new libraries for Core and Network
were then built separately from the rest of the source. For the first time since Three20
was introduced, it was possible to use aspects of Three20 **without pulling in the entire library**.

But a limitation with this system was quickly brought to light. If we were to
continue building separate libraries for each subsection of Three20, then the libraries
would somehow need to share common configuration properties.

### Enter UXKit

David Morford built the UXKit project in late 2009 as a fork of Three20 with significant project
layout and organizational changes, and then released the code under the Apache 2.0 license.
Thanks to this generous contribution to the open source community, there was a working
example of a way to build a set of modular libraries that all shared common configurations
using .xcconfig files.

Three20's new modular system is based on this design.

Modular Three20
---------------

Three20 is now split into a set of libraries that, brought together, compose the original
Three20 library. The libraries are listed below for your information (kept up-to-date in the
DependencyCharts.mdown article):

    ------------------------------------------
    |                    UI                  |
    ------------------------------------------
    | UINavigator  |            |   Style    |
    |--------------|            |------------|
    |   UICommon   |            |  Network   |
    ------------------------------------------
    |                   Core                 |
    ------------------------------------------

And then there are the extensions.

    -------------   ------------
    |  extJSON  |   |  extXML  |
    -------------   ------------
    ----------------------------
    |          Network         |
    ----------------------------
    |           Core           |
    ----------------------------

If the diagrams aren't particularly clear to you, they're drawn as though the libs
were structured like a building; the lowest levels are the foundation and
the upper levels depend on the lower levels for support. Each "box" in the diagram
is a library.


What's Changed
--------------

A lot has changed in order to make Three20 a modular library. Many changes will
undoubtedly spur debate, but from a high perspective this new modular project structure
is going to be the way Three20 progresses into the future.


### Source Code Layout

**Who does this impact?** Anyone who has modified or wishes to modify the internals
of Three20.

#### The Old

    samples/               <- All sample code
    src/Three20/           <- All header files for Three20
    src/                   <- All implementation files for Three20
    src/Three20.bundle     <- The Three20 bundle
    src/Three20.xcodeproj  <- The project for the Three20 library

#### The New

    Articles/              <- Articles, such as this one, discussing Three20
    Build/                 <- All build output, including Products
    Build/Products/        <- The products of all libs and samples
    samples/               <- All sample code
    src/                   <- All project directories (see below)
    src/common/            <- Common files used by most libs
    src/scripts/           <- Common scripts used by most libs
    
    src/Three20.bundle     <- The Three20 bundle
    src/Three20.xcodeproj  <- The Legacy project for the Three20 library

A project directory looks as follows:

    Three20UI/Configurations/     <- Project-specific configurations
    Three20UI/Headers/            <- The lib's headers
    Three20UI/Sources/            <- The lib's implementation files
    Three20UI/Three20UI.xcodeproj <- The lib project
    Three20UI/UnitTests/          <- The lib's unit tests and related resources

#### Rationale behind the new project structure.

The biggest change of note is the movement of all source files to their specific
library's sub-directories. The reasoning for this is that, by separating the code
at some high level, it will be much easier to pull out a component of Three20 and
use it by itself.

Another notable change is the unification of the build output into a single
directory. This was done because of the way that headers are now handled;
all headers are copied into the `Build/Products/three20/` directory. Go check it out right now
if you've already built any of the new libs. This makes it possible to define the
noted directory as the "header search path" for all libraries instead of adding
each project's `Headers` directory to the header search path.

A nice side effect of having a unified build directory is that it makes it possible
to delete all build output by deleting a single directory. When hacking on
Three20 it can often be necessary to start from a clean slate in order to ensure
that the library isn't being built with phantom files.


### Imports

**Who does this impact?** Anyone who has imported headers other than
`Three20/Three20.h` in their projects.

When Three20 was built as a single library, all header files were in the src/Three20
directory. This made importing files as simple as

    #import "Three20/TTNavigator.h"

Now that all headers are placed in their respective library's `Headers/` directory, the
above import is no longer how you will import Three20 headers.

Instead, you need to be aware of which library the header is in. In the above example,
we were importing `TTNavigator.h`, which resides in the `Three20UINavigator` library,
so we'd now use

    #import "Three20UINavigator/TTNavigator.h"

This follows for every library in the new Three20.

You will also need to update your header search path to use `Build/Products/three20` instead
of `src/Three20` (see ***Migrating to the New Three20***).


Backwards-Compatibility
-----------------------

The new Three20 provides backwards-compatibility with projects that still use the
single library design. This has been accomplished by maintaining the paths of the
old project and bundle, and making the old Three20 project (referred to as the
"legacy" project/lib) link to the new Three20 libs. A script has been added to the legacy
lib that copies all headers into their old location in the event that a project
directly references any headers.

A fair effort has been placed in making it likely that when you pull the latest
Three20, you'll still be able to build your project. However, no endeavor of this
magnitude is likely to go off without a hiccup, so if you have any questions please
feel free to email Jeff (jverkoey@gmail.com) or the Google news group
(three20@googlegroups.com).


Migrating to the New Three20
----------------------------

If you use the old Three20 library, migrating to the new one is a fairly simple process.  
**Estimated time: 5 minutes.**

1. Delete the old `Three20.xcodeproj` reference from your project.
2. Drag `Three20.xcodeproj` from `three20/src/Three20/` into your project.
3. Open the Three20 Xcode Project that you just added to your app and expand the "Dependencies"
   group. Select all of the projects listed there and drag them to your app as well. You should
   now have the following list of Three20 projects added to your app:
     * Three20Core
     * Three20Network
     * Three20Style
     * Three20UICommon
     * Three20UINavigator
     * Three20UI
     * Three20
3. Select all of the `xcodeproj` items in Xcode that you just created and look at
   the "Detail" tab.
4. Ensure that the checkbox beside each `lib` file is checked. If not, check it.  
   Alternatively, you can expand each Three20 project and drag the `.a` file to your
   target's "Link Binary With Libraries" action.
5. In Xcode's app menu, click `Project => Edit Active Target`.
6. Click the "General" tab.
7. Click the plus button below "Direct Dependencies" and add `Three20`.
8. Click the "Build" tab.
9. Add `../three20/Build/Products/three20` to "Header Search Paths" and remove
   `../three20/src/`  
   **Note:** Change the relative path (`../`) accordingly.
10. Hit build. You will now be building your app with the new modular libs.


Troubleshooting
---------------

This is a modest attempt at covering the bases with respect to troubleshooting, but is
by no means guaranteed to be comprehensive.

### Where'd the XML parser go?

If you were using `TTXMLParser` or `TTURLXMLResponse`, you will now have to
include the `extThree20XML` library into your project and include
`extThree20XML/extThree20XML.h`. This will only work once you've
migrated your project (see ***Migrating to the New Three20***).

### Where'd the JSON parser go?

If you were using `TTURLJSONResponse`, you will now have to include the
`extThree20JSON` library into your project and include
`extThree20JSON/extThree20JSON.h`. This will only work once you've
migrated your project (see ***Migrating to the New Three20***).

You have a choice of JSON parsers to use when adding the library to your
project. There will be two targets, one for SBJSON and another for YAJL. Select one
or the other to link to as a library, but **not both**.

### I'm getting a "No such file or directory" error for a Three20 import.

All headers are now grouped by the library in which they reside. This means that if
you're importing a header from the UINavigator library, that you'll need to use
`Three20UINavigator/` instead of `Three20/`. If you're not sure which library a particular
header resides in, just do a `find src -name SomeHeader.h` to find which library it's
in.

### I'm getting a linker error when I build my app.

Double-check and triple-check that you're actually linking all of the necessary
libraries in your target. Look at the "Link Binary with Libraries" section and ensure
that everything is as you expect it to be.

Things to note: the new Three20 lib is actually a composite lib composed of `Core`,
`Network`, `Style`, `UICommon`, `UINavigator`, and `UI`. If you are linking to the
Three20 lib, you don't need to link to any of the listed libs again. Notice that none
of the extensions are included in the composite lib.

This article written by:  
-- Jeff Verkoeyen (@featherless) *Created on May 2, 2010.*
