Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2008-919
$eventId
ID of event: wwdc2008
$eventContentId
ID of session without event part: 919
$eventShortId
Shortened ID of event: wwdc08
$year
Year of session: 2008
$extension
Extension of original filename: m4v
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2008] [Session 919] Understandi...

WWDC08 • Session 919

Understanding the Xcode Project Management and Build System

Tools • 1:05:15

Beneath the surface of Xcode lies a powerful, highly configurable build system. Understand how to configure Xcode build settings at the project, target, and file level. Learn best practices for structuring complex projects to achieve blazing fast build times on your multi-core Mac. See how to select the right compiler for your project. Get the most out of the tools you use every day.

Speaker: Chris Espinosa

Unlisted on Apple Developer site

Downloads from Apple

SD Video (725.6 MB)

Transcript

This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.

Welcome to Understanding the Xcode Project Management and Build System Session 919. If this is not the flight you planned to take, we recommend you deplane now. I'm Chris Espinosa. I'm the manager of the Xcode Core Technologies Group. Chris Espinosa We have a fairly short agenda for you today, long on content, short on bullet items.

I'm going to start with a brief review of the Xcode build process and the Xcode project architecture. Those of you who are old hands at Xcode or have been using Xcode 3.1 for a while may wish to just, you know, twitter your disrespect for a little while and sit it out until the interesting part comes. Those of you who are new to Xcode, this is a really important part of the presentation because it'll get us all.

Chris Espinosa We'll get you all on some common terminological grounds. People coming from different traditions and different environments may mean completely different things when I say target or project or build setting or environment variable. I'm going to try to get us on some common ground so when we get into the deep water, you'll understand what I'm talking about.

Second is we'll do some what's new in Xcode 3.1. Those of you who have the Xcode 3.1 seed, there are a lot of these that are covered in the release notes, but there's nothing like seeing it done live on stage in front of you. To show you what the power of the new features really is.

And then we'll go into some advanced techniques. The main technique I'm going to be demonstrating and describing in some detail is how to use cross project references, how to cause one project to invoke a build in another project and to use its build products in order to create a larger one. How to chain multiple projects together. We'll give a couple of demos and then we'll start to take questions and have a lot of time for questions. Okay.

Let's start with the brief review. When I say project, I mean the Xcode project, the .Xcode file that you double-click to open an Xcode project. Inside the project are two things, targets and content. And the targets are an organizing principle for the rest of the content. When you build, you don't build a project.

You build a target. That's an important distinction. People say, I want this project to build this other project. And I say, wait. If you're saying that, you don't have it straight in your head. A target is what is built. A project is simply a container that holds targets.

The target is a collection of inputs, source files, resource files, and instructions on how to build those inputs to produce a build product. I'm going to use that term a lot, build product. That's what it's all about. Every target builds a build product. And it builds it from source files. It builds it using rules. It builds it using build settings.

The content is organized in a target in a set of build phases, and each build phase handles a particular type of input. There's a compile sources build phase that builds all your source files. There's a copy bundle resources build phase that copies all of the resources in your target into the bundle in the build product.

You can create your own build phases to run an arbitrary script in the shell or to perform an explicit copy of other things to other places actions. The build phases are done in a stepwise order depending on both the order you place them in and their dependency requirements.

Chris Espinosa Things may be done in different order depending upon what depends on what other things. Chris Espinosa Each target has its own Chris Espinosa set of build phases, and the contents of one, the build product of one target can be included in a build phase of another target. That's the key to using multiple projects in Xcode.

Like I said, targets have sources, inputs, they have rules, and then they have settings, build settings that tell the compiler, the linker, the resource compiler, how to do what it's going to do. And those build settings are really what you spend most of the time adjusting when you're configuring your Xcode project and your Xcode targets. Each target has its own set of build settings, and that applies to building that target.

At the top level, the project also has a set of build settings that applies generally across all of the targets. And it's a hierarchy, just like object-oriented programming. The project build settings are superior, but the target build settings can override the project build settings. So if you've got something that you want to apply across everything you're going to build, like I want this to build 32-bit or 64-bit, I want this to build debug or not debug, I want this to build my English language version versus some other version, you put that at your project level and all targets inherit it.

If you have something that you want to differ from target to target, this target is building a static library so it has this set of settings, this target is building an application, it has different settings, this target is building a shared library, it has different settings. The specialization goes at the target level.

Project build settings are superior, but the target build settings are inferior, and the target build settings are inferior. Project level general, target level specialization. The number one user error with Xcode is, "I set this build setting and it didn't take effect." And that's because, well, you set it at the project level and you already had an override set at the target level.

So if you set a build setting and it's not taking effect, go to your target level and make sure that it's set at the target level. If not, either set it explicitly at the target level or take that build setting and delete it from the target to let the project level setting shine through. Number one rule.

Now, this is a common mistake as well. People use these terms loosely, project, target, executable, and build product. There's often a one-to-one-to-one-to-one correspondence between these. In fact, when you create a project from the templates, the stationery we provide, you get a project, and in that project is one target. And that one target creates one build product, and that one build product corresponds to an executable that can launch and run and debug that build product. And they all have the same name, so people think they're all the same thing.

But they're not. They're four separate things. The project, the target, the build product that the target builds, and the executable that launches and debugs that are four separate things, and you adjust them differently according to what you want to do. And I think to start with, we'll bring up Michael Rodden, and we'll show you the basics of going through building a simple Xcode project to show you what the build is like and what the parts are. So Michael's going to go to the Open Recents menu.

This is the code that builds the text edit application that's standard on every Macintosh Mac OS X machine. So first we're going to disclose the project folder and take a look at what's inside the project folder. Michael, if you could move it a little bit, the window a little bit to the right because it's being clipped on the screen. There we go. So you see inside the project, the top level project object are all of the files within the project.

And if you collapse that -- actually, if you scroll down, down at the bottom, there is a folder called products. You open that up. And that is a proxy, a representative of what our final build product is going to be. Textedit.app. That's what we intend to build. Now I want to show you how we're going to build that. The way we build it is that in this project there is a target. One target called Textedit.

Textedit is represented with, you know, a kind of A with a green check mark. The green check mark means it's the active target. It's what's going to be built when I click the build button. If you disclose that target and open it up, you see it's build phases.

It compiles sources. It copies bundle resources. It links the binaries with the libraries. And it even runs a little script at the end. Each one of those is a step with certain inputs. You can see the inputs by disclosing, for example, the compile sources. It says it compiles 12 sources. Those are the 12 source files it compiles.

Okay? So this is the structure of a project in the build system. Now to adjust the build settings in an Xcode project, you double click the target. And this is the table of build settings for that. It's a rather long table. If you scroll it down, you'll see that there are several hundred options that you can set for all kinds of things going on in that target. And that's why it's useful to have a little filter bubble at the top where you type something and it'll narrow it down to just the ones that you care about.

One of the things that we're going to talk about later is, for example, the deployment target. It's which version of the operating system. So rather than search through it, why don't you just type DEPL. Oh, that narrows it down a little bit. Deployment target. There we go. Compiler default. It's in bold because it's defined at this level. And by compiler default, that means it's going to be whatever it is for this operating system. We're running on 10.5 here, so it means we're going to build for 10.5.

[Transcript missing]

When we build the target, it creates the build product, and then it'll create, and then if we want to launch or debug it, we control that with this executable. You double-click that, and you get a panel with some tabs for arguments and debugging. And you can see in arguments, for example, if you want to add arguments to be passed at the command line, if you have argc and argv in your main, that's where you pass those.

If you're looking at environment variables and you want to set them, you set them there. So these are how you control how the application is launched after it's built. But you can see that the project, the target, the build product, and the executable that runs it are four separate things.

Okay, now we're going to start building it. So you open up the build results window. Okay. from that menu which is way up there in the ceiling. And this is the build results window, and it's empty because, well, we haven't built anything. So first thing we're going to do is just click build.

And you can see that each of our build steps... Oh, you didn't have that checked, okay. Want to clean it? Oh, there we go. You can see each of the build steps... Each build phase has a collection of steps, and each step is listed there. And some of them have warnings. That's fine. It's not our code.

Each one of those lines has behind it a whole lot of what went on to apply for that input to that target, the settings in that target's build settings inspector to that operation. And we're going to show you how to do it. Open up a text edit window. There we go. We happen to have one handy. And just drag and drop one of those compiling lines into it.

So that's the text where if you were in a make file or if you were executing this from the command line, this is the command that you'd issue to the GCC compiler to compile that line. It's a whole lot of stuff going on, and it's mainly providing the header and library search paths, the framework link paths, the build settings, the warnings, the optimizations, all of the architectures, all the controls you want.

If you've got something wrong with your build, if you don't know what's going on, go look at this because all of the information literally is in this line. You may not be able to understand it, but if you've got a build that's working and a build that's not working, compare those two. The difference will be there, I guarantee you. And if you're filing something on Xcode users at list.apple.com or filing a bug reporter report, this is what we need to tell you what's going on.

Now, this is line by line. It could be very tedious to copy everything out. So we have a build transcript hidden under a little button, the third one in, and it shows you the complete build transcript of the entire build. This can be several hundred K to a megabyte of text.

For every step, for every build phase, in every target that you build, the complete and detailed instructions of how it built are here. And if you do the command line Xcode build, this is what you see spewing out at the console. Except in Xcode 3.1, we give you a nice summary of what the errors were at the end. That's a nice touch. If you look at one of the compile lines, you can see, for example, the find it in there.

Oh, we're using compiler default so it wasn't set, right? Yeah. So when we showed you the build setting for the deployment target, the value there is passed in, if we had set it to something, it would be passed in a dash M Mac value.

[Transcript missing]

Okay, so we'll come back to the build process after we talk a little bit about what's new in Xcode 3.1 because I want to demonstrate those to you.

There are six new things in Xcode 3.1 I want to talk about. They are all about, they're mainly around the addition of SDKs to support iPhone development. Okay? And everything that we're going to talk about and show applies both to Mac OS X development and to iPhone development. The important difference between Xcode 3.1 and previous versions of Xcode is that the tool chain, the compilers, the linkers, all of the things that are actually used to build code, are moving into the SDKs from the native system.

The iPhone uses a different chip, and so all of the tools to target the iPhone's chip are actually in the iPhone's SDK, not in Xcode itself. We're making Xcode a much more generalized, portable, pluggable IDE so that if we come out with a new architecture, with a new platform, with a new chip, and we have a whole new set of compilers, that's just another SDK you drop into Xcode. And we'll show you how we do that.

[Transcript missing]

Those of you who've been with us for a while know that the biggest change with Xcode 2.5 and Xcode 3.0 was to make the developer directory self-contained. Before Xcode 2.5, when you installed the Xcode tools in your system, they went into the root level of the system, and they were there, and they were immutable, and they replaced everything that went there before, and you couldn't use a previous or a later version of Xcode.

Starting with Xcode 2.5 on Tiger and Xcode 3.0 on Leopard, we made the developer folders completely self-contained and independent of each other. So you could have Xcode 2.5 and 3.0, for example, side-by-side on the Leopard machine, and we've even extended that to 3.1. So you can have on one machine 2.5, 3.0, and 3.1 all together next to each other, and their tool chains and their SDKs and their IDEs and everything else is self-contained. Everything is distinct and self-contained, so you launch one Xcode, you get its tools, you launch a different Xcode, you use its tools.

But we've gone a step further with Xcode 3.1. With 3.0, the tools, the compilers, and everything are right there in the top level of the Xcode developer folder. But in Xcode 3.1 and moving on in the future, like I said, we're moving the tools into the SDKs. So there are several SDKs in each developer folder for 10.4 and 10.5 and 10.6, and those nominally contain the headers and the libraries that you use to build for that version of the operating system.

But now, They also contain specific tools for the platform that you're targeting. So, for example, the iPhone SDK doesn't just have a library folder with its frameworks in it. It also has user bin and GCC in its own GCC compiler that targets the chip that's in the iPhone.

Chris Espinosa So, this is really important because this means as we go further, you're going to be able to add more tools and customize tool chains just by building them into an SDK and dropping it into Xcode rather than waiting for us to do a turn of the Xcode architecture. That's going to be very important for scalability in the future.

SDKs and deployment targets are a really favorite topic and one that's easily confused in Xcode. There are a lot of SDKs now and a lot of different target platforms that you can develop for. And what you want to do when you set up a target in your Xcode project is you want to decide two things. First, what's the earliest version of the OS I want to run on? We recommend that you periodically leave 10.1, 10.2, and 10.3 users behind. If you're building for Snow Leopard, consider supporting Leopard and perhaps even Tiger users. That is called your deployment target.

You set that in a pop-up in your build setting inspector. You say, "If my deployment target is 10.4, my code will work on all 10.4 machines and later." But you have a second decision to make because you don't want to bind yourself to only the features available in 10.4. Especially if you're running on 10.5 and 10.6, you may want to say, "Well, yeah, I will support "I want to take advantage of these new APIs that are available in Leopard." Then you build against the Leopard SDK.

If you pick an SDK, the deployment target by default is that SDK's version. If you build against the 10.4 SDK by default, you're deploying for 10.4. If you build against the 10.5 SDK by default, you're deploying to 10.5. And of course, an application built for a specific version of the operating system is going to continue to run on later versions of the operating system, so far as the operating system supports the chipset and the language and everything that that was written for. But it won't take advantage of the new features.

In order to take advantage of the new features of an SDK, you have to build against the SDK for that platform. And then what happens? Well, if I build against the 10.5 SDK to take advantage of 10.5 features, what do I do about the 10.4 users? Well, what happens is that all of the APIs that are not available in 10.4 When your program loads, they're replaced with null function pointers.

And your job at runtime is to determine whether or not the function you want to call is available and skip around it if it's a null function pointer or not available and use it if it is. That's the way to write an application that launches on 10.4 and shows 10.4 functionality, but also launches on 10.5 and takes advantage of new 10.5 features.

Okay? This is going to be true of the iPhone platforms as well. The deployment target setting, which used to be called Mac OS X Deployment Target, but has been cleverly renamed Deployment Target, now controls either Mac OS X or iPhone deployment. We just swizzle it to the right value to pass to whichever compiler we happen to be invoking. So if you build with a deployment target for iPhone 2.0 against either the iPhone 2.0 or Simulator 2.0 SDK, you will run on 2.0 and whatever later versions.

Since we don't really have backwards compatibility to the 1.0 because we don't have a development model for 1.0, we don't have iPhone deployment versions earlier than that. So we don't have a deployment model for 1.0 or Simulator 2.0 right now. But the same mechanism will take effect. As we add more iPhone SDKs, you'll use that in the same way you're using the Mac OS X Deployment Target and SDKs.

Now, if you've got multiple SDKs, or if you've got an application that you're building against the 10.4u or 10.5 SDK, and you want to see what it's like on 10.6 Snow Leopard, or if you've got a core piece of functionality that you're building for Mac OS and you want to say, see, you know, it's just links against, you know, foundation and core foundation and maybe a couple of other frameworks.

Can this build for the iPhone? Chris Espinosa Used to be that you'd have to go into your target settings and change the base SDK and save that and run it and rebuild it. And if you have multiple targets, you'd have to do that for every target. And then you don't want to commit that to your repository because you don't want all of your coworkers to get that.

Right now we have an active SDK pop-up in the toolbar. You can add it to your toolbar or it's part of the overview toolbar that you can add to your default toolbar. And what this does is this sets a temporal override. This is important. It's a temporal override to the SDK. It does not change your project.

Your project settings will still be unchanged. If you close your project, if you commit it to the repository, that won't be changed. It's only a user interface feature that lies to the build system and says, you think you're building with 10.4u, but the user said build with 10.5 just to see. But the effect is that everything will build with 10.5. There's also a value in that pop-up for project settings, which is I'm going to build this project. I want to build it with what it says it wants to be built with. that's a useful thing to do.

The Active SDK is really useful in a try before you buy if you want to see what your project is going to behave like in Snow Leopard or see what your Mac project is like in the iPhone world. It's also the crucial control you use to switch back and forth between building for the iPhone SDK, the iPhone device, and the iPhone simulator. Those are different SDKs.

They have different tool chains. They have different platforms. They have different code bases. They actually build for different architectures. So it's important to switch back and forth with that pop-up in the SDK rather than have to drill down all the way in the inspector to see what's going on.

Last topic is weak frameworks. I told you a little bit about what happens if your deployment target is set earlier than your SDK. For any given framework that's on both platforms, any new APIs in the new framework will be replaced with null pointers when you're launching on the older system.

That's how you can write one piece of code that launches on both and it takes advantage of new functionality of present and skips around null pointers or crashes on the old system. What about whole new frameworks? What if you want to write something that takes advantage of OpenCL on Snow Leopard but OpenCL is not available on Leopard? What you do is you bring that framework into your application but you mark it weak.

That means when Xcode goes to link it, it says, "I'm going to link against this and I'm going to desire it at runtime but not expect it at runtime." Normally, you build against frameworks, you compile against your headers, you link against them and when your application goes to load, it has to find those frameworks in order to fix up all of the references. If a framework is missing, your application will just not launch at all.

But if you mark that framework weak when you build it, And you compile against a weak framework. When you launch, if it's missing, your application will launch, but all of the function pointers to it will be null. It's even better than that, because the compiler doesn't expect a framework not to be present, so it's going to assume that those function pointers could never be null, even though there are, so your checks against null function pointers are going to be optimized out of your code.

So what you have to do when you're using weak frameworks is you have to do a secondary check. You have to use a DYLD call, or you have to look at a version number to figure out what system you're running on, whether that framework is present, and jump around large bodies of code, or even conditionally, you know, to even go to a different module or plugin according to what OS you're running on. It gives you the flexibility, but there is a little more work you have to do in your code in order to do it. to build against a weak framework.

The way you control weak frameworks is pretty easy. When you add the framework, there's a way to check to say whether it's weak or not. You can go into the link binaries with libraries build phase, select that, you see the detail view, and there's a column in the detail view called role. And in that role, you can change any framework linkages to be required or weak, according to whether you want it required or weak. Chris Espinosa Finally, we've made some changes in the way we deal with architectures.

The main issue with architectures is that when you ship products to users, you want them to run on as broad a number of architectures as possible. At least PowerPC and Intel, and if you've got a 64-bit application, you want PowerPC, Intel, and 64-bit PowerPC and 64-bit Intel as well for the Leopard platform.

[Transcript missing]

Once again, let's bring up Michael Rodden and show you how that all works.

For this demo, we're going to use a project that we call Ytap Support. We took the Ytap Hello, everyone. I'm Chris Espinosa, and I'm the founder of the Mac OS X Frameworks. We're going to build it into a static library, and we've configured this project so it can build either for the iPhone SDK, either the device or the simulator, or for Mac OS X. So this is going to be a cross-platform static library that can be built and included in multiple applications. So first, let's go look at the Ytap support target. It's a target just like we saw before.

We go to its build settings. Now look at its architectures. Pop the architectures value. It says standard 32-bit universal. Okay. It doesn't say exactly what it is. I can go in and find out if I want. But that's going to be a value that's going to persist over time. If we change what the definition of standard architectures are, if we, for example, start building on Spark machines, we'll just add Spark to the list of standard architectures and you'll inherit that for free. Very valuable thing.

Chris Espinosa Now go look at the base SDK. Right now, this project is configured for Mac OS X 10.5 SDK. If you change that to the iPhone simulator, Well, notice that standard architectures has now changed to iPhone simulator standard architecture, which is i386. A Mac OS X application, by default, is two-way FAT, universal.

But a simulator application, by default, is only x86, i386, because that's the only platform the simulator runs on. Okay? Now, if we look at the debug configuration, that's what we're looking at now. Notice the build active architecture only checkbox is checked. If you switch to the release configuration... You'll see that it's unchecked.

That means that if our architecture is multiple values, if we're building universal, in our release configuration, it will always build multiple architectures, but in our debug configuration, it's only going to build one for quick turnaround. Chris Espinosa Okay? Now we want to see some of the linker specifications, so just let's type in linker.

And notice other linker flags. See the lines below it? It's got a disclosure arrow. We've got different frameworks being configured for different sides of this static library. Chris Espinosa If we're building for any Mac OS X, well, we want to link against Cocoa. But if we're building for any iPhone device or simulator, we want to link against UIKit. And so we just have per SDK variants on the linker flags in order to bring in the different frameworks for the different configurations.

Chris Espinosa Correspondingly, in the source code, there's a pound if iPhone that imports UIKit. Chris Espinosa Or pound imports Cocoa, depending upon which it's being built for. Chris Espinosa Okay? So if we build this, if we open up the build results window and build it, and we're building for the 10.5 SDK, yeah.

So we'll build this and if you can open up the transcript or just actually just hover, this is a new feature, just hover and wait. And it shows us a tool tip saying what that step was built for and it says active architecture i386, active SDK 10.5 SDK. So we know that we just built all those files for the SDK. But if you go to the pop-up up there, the overview pop-up, Change that to simulator iPhone OS 2.0 and then rebuild. Everything gets rebuilt. You hover over it.

and you see that it's building for the Active SDK iPhone OS Simulator SDK. Now, here's the important part. If you open up the transcript, Here you can probably use your fancy control zoom in. Oh, there we go. So show the, yeah, this is the fun part. Notice the path to GCC here. It's getting GCC 4.0, not from user bin, which is where a make file would get it, and not from slash developer slash user bin, which is where Xcode 3.0 would get it, but it's getting it from the iPhone simulator SDK.

The simulator SDK carries its own copy of GCC with it that goes all the way back to the early slides that I showed where the simulators, where the SDKs are self-contained development environments, and when you switch in the UI, you're actually switching your entire tool chain out from under you just like that. Okay? Thank you, Michael. Thank you.

So that's what's new in Xcode 3.1. It's mainly a lot of features to ease development against multiple SDKs and to build projects that can build against multiple SDKs. And when you build a project against multiple SDKs, or even when you build a moderately complex project just for the Mac OS, you're probably not going to have that mental model of one project, one target, one build product, one executable to launch it. You're going to have multiple projects. The projects may have multiple targets.

The targets will have many build phases and steps. Each of them may create multiple build products, and then they'll want to use each other's build products. They'll want to bring them in, copy them into their folders, link against them, do all sorts of complex things. Most of this historically has been left as an exercise to the reader. We're going to walk you through it now and show you the general techniques you need to use to make this work in Xcode.

First of all, we're going to talk about subprojects. There are no subprojects. If you are thinking of sub-projects, you are thinking in a way that will get you into trouble down the road. Because Xcode projects have a complex and networked relationships. They are not strict subordinates. Chris Espinosa Any tree is a subset of a graph, of course. So you can set up any tree of projects you want. And if you want projects to act like sub-projects of other projects, you can do that.

Chris Espinosa But Xcode allows you to create multiple branching dependencies among projects so that you can share code in really powerful ways. Chris Espinosa So if you are thinking that you are going to make this project a sub-project, you are going to have to make it a sub-project.

Chris Espinosa If you are thinking that you are going to make this project a sub-project of another project, try to erase that thought from your mind and say, "I am going to refer to this project from another project." Chris Espinosa And that will open up a lot more possibilities for what you can do in the future.

[Transcript missing]

First, the way to establish a cross-project reference. It's pretty simple. You have project A, you have project B, you drag project B into project A. That's pretty simple. That does nothing. It just lets Project A know that Project B exists. One of the things it does do is it shows you the build products of Project B inside the Groups and Files tree of Project A so that you can use them in other places, but it's up to you to say where.

So the second step is how to use the build projects. The most common thing If project A builds a small part, or if project B builds a small part and project A brings that in as a static library or a shared library or something, you need to move that into a build phase.

So normally what you do is you just take that build product icon in the groups and files tree that just appeared when you dragged in the project, and you drag it down into your product's build phase and add it. That's the basic technique for making an application link with a framework that you've built.

But you're not done yet. If the framework is in a well-known common place, your application will work. But if you want to embed that framework within your application, you need to make sure that whenever you build the application, the framework is up to date. Whenever you build the framework, it reminds the application that it needs to relink with it.

That means you need to create a dependency. Chris Espinosa You go to the target. The target has a list of dependencies. It has a list of other targets that need to be up to date when that target is built. You go to the target pane. You go to the direct dependencies panel. You click the plus button. Chris Espinosa And the other targets in that project, including the ones from project references, will show up. You select the one that you care about, and you add it to the list.

When that framework target, for example, is added to the direct dependency list of the application, that means when you build the application, it will automatically make sure that that framework is up to date and build it if necessary. Chris Espinosa If you update and rebuild the framework and it's newer than your application, when you rebuild your application, it will relink with that framework. You have to create this dependency manually. Chris Espinosa Otherwise, it will just take the latest version of that framework, no matter whether it's up to date or not.

That is a great way to get build errors, which is to forget to create the dependency, to make a change in your framework, to make a corresponding change in your application, and then to rebuild your application. Because without that, without having had the framework rebuilt, the application won't be picking up the latest version of the framework. Create the dependency, and it will.

[Transcript missing]

You can do better than that, though. You can build one framework that is shared among multiple applications. As long as all of the applications have the same relative path to refer to that framework, you can deliver, say, a folder called applications, which is parallel to a folder called libraries, and all those applications can use all the libraries in the library folder. Chris Espinosa If you look at the Xcode Developer folder, that is exactly how we structure it. Developer Library has a lot of shared frameworks that are shared among all of the various pieces of the Xcode development environment.

The way we do that is with the dynamic library install name on the frameworks using the RPath methodology. RPath means whoever is invoking me, give me a relative path to them. Chris Espinosa So on each shared framework target, you define its dynamic library. The dynamic library install name as relative to the RPath.

And then on every application that wants to invoke those frameworks, you set its run path search path. This is where it defines its RPath to its framework directory, either within itself or relative to a common location. You can come up after and ask us details on this. There are a couple of good resources on the web to tell you how to do this. Chris Espinosa We went through this in an exclusive way.

Chris Espinosa We went through this in an exclusive way. excruciating detail last year at WWDC. So you can go look at my presentation with Rick Ballard's demo from last year on ADC on iTunes and see this in excruciating detail. This is the primary thing you have to do if you have multiple applications sharing multiple frameworks in a common location.

Now, the techniques I've showed you, making a cross-project reference, creating a target dependency in a cross-project reference, putting the build product into a link phase or something like that, putting the build product into a copy bundle resources phase, these can be used for all sorts of architectures, all sorts of layouts of your project. Chris Espinosa If you have a static library that you're using in multiple projects, you can build it once and then just include it as if it were a pre-built binary in multiple projects using this technique.

Chris Espinosa If you have an aggregate target, you can create an aggregate target which is just a target that consists of other targets being built in a specific order. Chris Espinosa You can use this technique to make the aggregate target dependent upon all of the other targets built in a particular order if you really need to build something like that.

You can create a project that has an application and a bunch of plug-ins, and part of the app needs to be built, and then the plug-ins need to be linked against it, and then the plug-ins need to be copied into the application. You use this technique to do that.

But once again, the best way to get the hang of how this works is to actually see it. So we're going to take that static library we built, and we're going to build it into an iPhone application, and then we're going to build it into a Mac OS X application as well.

So we're going to get the Ytap application. This is the iPhone sample code that you get, except we've extracted all of the common code out of it. And what we're going to do, the first thing is we're going to take that Ytap support project that we built, we're going to drag the project icon from it and go drop it.

And just say yes to the sheet. All the defaults are correct. And now you see that the Ytap support project is a cross-project reference in the Ytap application project. You turn it down, and you see it's build product right there. Chris Espinosa Yeah, can you drag? There we go. Okay.

So you see Ytap is the application project, Ytap support is the cross-project reference, and the libytapsupport.a is the build product that we're building. Now, um, If you go down to the target, open that up, this is our one target, you see the link binary with libraries build phase. Let's, yeah, you just drag that down, drop it in.

And that has made it so that we're going to link the application with the static library pre-built by the other project. Now that's great, but that implies that that app, that static library has already been built. If we want to force it to be built, we've got to create the target dependency. So we double click our target, go to the general pane. Now first, I want to take a little digression here. I want to show you a new cool thing.

How many people hate how you have to add frameworks to an application in Xcode? Not as many as I'd expected, but there's an all-new way. There's a linked libraries pane here that shows you what all the libraries you're linked with now, and you see the required. That's the pop-up for required and weak.

with the magical third column that NS TableView gives us. If you press the plus button, This is a list of all of the frameworks in your current SDK, or all of your SDKs.

[Transcript missing]

Now we're using the... Did you build the library for the... Okay, that's simulator. Looks like it's not finding the headers in the common build directory.

Luckily, we have our build system expert here to debug this. Make sure that the common build directory is set up, because that's my next slide. I'd prefer that we save questions for the end. We're going to have a lot of time for questions. Actually, if we can go back to the slides, I'll just finish up with the slides. Oh, he did it. Never mind. Yay. Okay. Back to the demo machine.

So this is the Ytap application. Run that one in client. Okay, run that one in server, that's fine. Okay, this is an application that does nothing by itself. So now what we're going to do is open up another project. This is a Mac OS X application that's written to be like the Ytap application on the iPhone, but it's a Mac OS X app that uses the same static library. And so we're going to go through the same steps. We're going to add the cross-project reference.

We're going to disclose it, find that static library, add that static library, Now we double click the target, create the cross project reference. You do this enough, it really gets to be second nature. And then build and go. Now this is the one where it had the stale reference. I think that it's getting the file from the wrong location. Notice how he's doing his forensics. We should have made this a debugging the build system session.

Now this worked last time. I'll say, let's go back to the slides, and he'll say, I've got it working. So, two project reference tips. One is that if you have multiple projects that are building build products that each other need to refer to, the best and perhaps the only successful way to do it is if you have a shared build directory. If you saw when he went back to Xcode Preferences, to the Build tab, and made sure that we were using a shared build directory, that is the way the projects communicate within each other. All of the build products are in a flat build directory.

That's fairly important to maintain. The second thing is that if you have projects that are referring to each other, they need to have a consistent set of configuration names. Because when you build the debug configuration of one project and it has a dependency on a... another target, it's going to go build the debug configuration of that target.

If you have one project where your configurations are development and deployment, and another project where your configurations are debug and release, they're not going to know how to line up with each other. So, it's really important to keep your configuration names in a coherent space. So, while he's wrapping up on the great demo that I put together and subjected him to running through when it was broken, I want to recap what we've done. We did a brief review, projects, targets, build phases.

And executables and build products are separate from products and targets. Common terminology. Lot new in Xcode 3.1. Support for weak frameworks, support for active architecture, support for choosing your SDK in the pop-up, choosing your active architecture in the pop-up, the new overview SDK, some nice little things like being able to see the SDK and the architecture in a tooltip on every build step. And of course, the whole structure of SDKs which now have the build tools embedded within them for long-term flexibility.

Important things like how to set the deployment target and the SDK in relation to each other so that you can deploy on one version, but take advantage of features in new versions. And then advanced techniques of creating cross-project references of using the build products in different build phases of the model of the model of the model of the model of creating project dependencies and then how to set up the dynamic library references so if you embed shared libraries or frameworks in applications, the applications can reach in and use those frameworks. Okay? Oh, he's got it now. Now we can go back. This is the big finish.

Build succeeded. And that one is client. So now we've got two applications, and they're both connected. One running on the Mac, one running in the simulator. And if you click on one, it sends a signal over Wi-Fi inside the Mac to the other. So this is the same code built once for the static library that is being deployed both to the Mac side with a Cocoa application and to the iPhone simulator side with an iPhone Cocoa Touch application. Common code using common frameworks with only slight differences between the two being built twice with cross-project references and target references. Okay. And with that, Tavares Ford is going to come up, or Michael Jurowicz is going to come up and lead some Q&A for us.