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: wwdc2006-306
$eventId
ID of event: wwdc2006
$eventContentId
ID of session without event part: 306
$eventShortId
Shortened ID of event: wwdc06
$year
Year of session: 2006
$extension
Extension of original filename: mov
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: ...

WWDC06 • Session 306

Xcode: Creating Complex Projects

Development Tools • 1:14:16

Complex applications often require complex Xcode projects. Xcode's user interface and build system are designed to help you cope with complexity in target organization, settings, SDKs, and project references. Learn practical strategies and step-by-step procedures for managing your growing application with Xcode.

Speaker: Anders Bertelrud

Unlisted on Apple Developer site

Transcript

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

Good morning. I'm Anders on the Xcode team. And welcome to this hands-on session, 306, Creating Complex Xcode Projects. This morning we're going to explore some of the more advanced features in Xcode that will help you deal with complexity in your projects. And it is a hands-on session. The information about materials online are here. Even if you don't have that downloaded and ready to go, I'm sure you'll get a lot out of the session just by following along. Again, my name is Anders.

And this is a hands-on session, but I want to start out with a little bit of theory for a few minutes. So we'll make sure that we're on the same page with the concepts. So first of all, why? Why have this session? Well, Xcode has a lot of features to make it pretty simple to get started with the project.

We have a lot of good project templates. There are even more in the Leopard preview than there were in Tiger. And many things are fairly straightforward. But there are also a lot of more subtle features that are really useful once your project gets more complicated. So we're going to talk a little bit about that.

First of all, though, what would make a project complex? Well, some of the things are shown on the slide. You might have lots of different cross-project references. You might have custom targets, custom shell scripts. You may even have a custom build rule that maps your custom file type to your own compiler, that kind of thing. These are some of the things that would indicate a project is a little bit more complicated and can take advantage of some of these more advanced features.

So what we're going to go through is we're going to take a project, a sample project, and just do a series of transformations to it that illustrate some of these features and help you to see how to apply those in your own projects. We're going to start off by talking about build settings. Pretty simple topic, but there are some nuances there that you can take advantage of.

We're going to talk a little bit about connecting multiple projects together. And then how to embed a framework inside of an application, which is something that a lot of people want to do. And then finally, we're going to talk a little bit about building deployment products, in this case a disk image.

So let's start off with build settings. Well, pretty simple, right? Debugging equals yes, debug format equals dwarf, those kinds of things. But there is a fairly powerful feature in that you can substitute any value in a build setting that you want. This can also be pretty simple. Product name can include the version number, those kinds of things.

One thing I wanted to point out here, which I've seen a lot of questions about on the mailing lists, is that Xcode itself, uses the same sort of make style notation with parentheses, $x, as you see here, to expand the value of another build setting. But if you are doing custom shell scripts, then keep in mind that the syntax you use would be the one for that shell script.

So in the case of the shell itself, you would use $brace. This is particularly important where you're typing shell code into Xcode, because Xcode just invokes the shell and passes it to the shell. So it passes down whatever text you type. Xcode does pass the environment, the build settings in the environment, because that's the lingua franca of scripts. So Python and Ruby and all these shell scripts that you might invoke as part of your build process, they typically all have access to the Unix environment.

And so Xcode uses that to pass down the build settings. Build settings, again, are things like the product name, things like the path where you want to output your product, those kinds of things. It's an open-ended naming scheme, so you can come up with your own names, you know, my compiler settings, and you can reference that from one of the standard build settings.

They're organized into precedence levels, as you might imagine and probably know. And here briefly are the precedence levels. We have the environment variables that Xcode inherits are at the bottom. So this is typically stuff like home, right, which is something that's set for any time you log in.

Above that come the built-in defaults. There are certain defaults for whether a certain warning is turned on or off. There are certain default build directories. One of the defaults is that the suffix for an application is .app. So that's built-in. Above that are the Xcode preferences themselves. You can say that you want a certain source tree, which is just a location on your disk. You define this in the preference panel on Xcode, and you have access to it through your build settings.

Project settings come above that. These are what you set in the info panel for the project, the blue project icon up at the top of the project window. An example would be the project version. If you have a marketing version, that's typically the same for all the targets in your project. So you would set that in the project itself and not ones for each individual target.

Target settings come above that, and that would include things like a product name. If you have three targets in your application, in your project, and each of those targets builds a separate application, each would have a separate name. So that's an example of the kind of setting that goes at the target settings level.

You could set the value of any setting at any level, but some make more sense than others. And above that are the temporary overrides. One doesn't always think about this, but anything you pass on the command line to Xcode build actually overrides anything. So this is just like in Make or in Ant or any of these other build systems.

So, again, the president is as high as the lowest. And this is just briefly to make sure we're on the same page here before the hands-on. Build configurations are sets of customized build settings. So I might say that these three settings make up what's special about my debug build. And these other three settings make up what's special about my release build. Typically, you would turn off debugging for release, you would turn it on for debug, etc. And they consist of a name, which is unique within the project and shared by all targets in the project.

New projects, as you may know, come with a debug and a release pre-configured. Here again, it's an open-ended scheme, so you can create any names that you want. And the key thing to remember, though, is only one is active at a time. You're either building for debug or for release at any given time. You can build for one first and then for the other. That's particularly easy with the Xcode build command line tool. But at any given time, you're only building for one or the other.

And these build configurations, you can set them in the Xcode GUI, but what's actually very convenient and what's new in Xcode 2.3, which almost all of you already have, I think, that was last year, is to be able to define style sheets, which are just text files where you define these build settings. That can be really nice because we support comments in there. We also let you check them because they're just text files. You can check them into an SEM system and keep track of them very easily.

And also, you can use include syntax to include the contents of one and the other. So they're really like style sheets for build settings, and they can define any setting at all in there. We'll see that in the hands-on in a little bit. They're, again, great for factoring out settings that are common across a large number of projects, which is why it applies to the complex projects.

If you have 15 interrelated projects and you have a setting like the copyright string that's common to all of them, you might want to factor that out into a build setting, into a build context. You can also use the build configuration file and reference that file from all those projects.

And a tip here is it's actually easy to select a bunch of build settings in the inspector, and then you can just drag them off in a text file, and they show up as X equals Y pairs. And that's a great way to start populating your XC config file.

How does that fit into the precedent stack we talked about? I've called out here the target project settings because that's where they fit in. Specifically, we slide those apart and the target settings can have an XC config file that it's based on. So what you do is you say, well, my target has its own settings, but it's also based on this other style sheet. And the same thing at the project level. So that's how the inheritance works there. The target settings will override what's in the style sheet for the target and then that in turn overrides the project, etc. So something to keep in mind as we're editing these projects.

Value substitution is more powerful than you might at first think about, in particular because you can construct the name of a build setting through substitution. So here is a small example where we're actually constructing our own build setting called other C flags, GCC3 and 4. We're setting, Xcode knows nothing about those, we're setting the standard one to just choose the value of one or two of those, one of the two at build time.

So this is pretty powerful, you can do this with any setting at all. You can make it conditional on the context in which it's invoked. And the message there again is that the expansion, the substitution happens as it's needed and it happens repeatedly, meaning that the same expression can evaluate to different things in different contexts. For example, if you create a build rule to process an input file, the expression that evaluates the name of the input file will be different for every time it's invoked. It's a simple case of that.

So build settings on the knobs and switches, build configurations, group them together into sort of logical collections, and build phases are the steps you go through when you build, right? So just copying headers, processing resources, those kinds of things. Some of them are very flexible and are used in particular for complicated projects, like the copy arbitrary files phase, where you can just copy any file or folder from any place to another. And also to run a custom script. This doesn't have to be a shell script. You could type the name of any interpreter you want, Perl, Python, Ruby, whatever. So you can actually tie in very nicely if you have some custom scripts.

So that's a bit about build settings. We'll talk briefly about managing multiple projects. Well, why have multiple projects, right? Obviously, if I have 20 projects, that's more complicated than 10. Well, if you think about coding, it's not necessarily the case. You could have, you know, one function that's just really gnarly, but if you split it up, then you could actually achieve some simplicity.

So that's one thing. It's also easy to reuse if you have a framework or library containing some common functionality for your company. You may want to split that out, not into just a separate target, but even a separate framework, because you could mail it to somebody or check that in separately to an SCM system or whatever. And you can refactor an existing project to split it out into sub-projects, but you could also separate them out from the start if you know that you're going to have a reusable framework.

It's a good idea, because it doesn't mean that you have to reuse it. You can still use it just for that one other project. And the way we do this is with the project references. Just like any other file reference, you just reference another project, and you can set some options, per-user options on the project, or you can set them for all users, as we'll show in the hands-on. One of the things to think about when using multiple projects is that Xcode, it works best if you have a shared build location. There are several ways to set that, and we'll explore one that you may not have tried that's particularly useful.

This means that all the sub-projects will put their own sub-projects in the same sub-project. So if you have a project that's a common location, you can set that as a common location, and you can set that as a common location, and you can set that as a common location, and you can set that as a common location, where they can be found by Xcode, by the other projects. And one great way to do that is to set that in an XC config file. We're going to see that.

Embedding tools and frameworks. Why would you want to do that? Well, one thing is that, if you remember back in 1984, you could actually take the Mac Paint icon and drag it off onto another disk and you could actually run it. And it's a great thing for users.

If you have an app that's simple enough where you don't have to install kernel extensions and things like that, where you can actually embed all the resources inside the app, including frameworks and tools and those things, that's a great thing for users because it's simple. You can install it simply, you can uninstall it simply, and you can upgrade it just by replacing the icon. So there are some benefits to doing that, if you can do that in your case.

How that works under the hood is that normally frameworks are looked up by path. For all the system frameworks, that's an absolute path: system, library, frameworks, app kit, that kind of thing. But there are two special prefixes. One is @executable_path. We're going to talk about this in the hands-on. That has been there since the first days of Mac OS X. The other one is @loaderpath, which is new in Tiger and also, of course, works in Leopard.

And that actually lets you not only be relative to the main application, but relative to whoever is linking against the framework. So you could actually embed a framework inside of a bundle, or you can embed a framework inside of another framework without knowing where the application lives. There is also... Thank you.

There is also a tool called install_name_tool. Which is a command line tool that lets you get at the real details of how a framework is built. You can actually change the name after the fact. It's easier to change it before you build it, as we're going to do in the demo.

And the thing about how this works is that the framework contains the name of where it's going to be found. The application copies that when you link against it. The framework, the application copies that path into the application. And then at runtime, the application will use that to look up the framework. of the framework.

And you can embed various things. That's for frameworks and dynamic libraries. You can, of course, also embed tools and scripts and all kinds of other things that your application needs to run. And you can embed them, as I said, into applications and also frameworks and plugins. Don't embed the system frameworks, though.

I mean, that might be obvious, but it's not a good idea to embed something like Foundation, right? We want to be able to update that when the next version of Mac OS X comes out. And I'm sure there are some licensing issues there, too. So, something to think about. Okay, so that was a little bit of theory to make sure we're on the same page. Let's go to the demo machine for hands-on, and let's try this out.

Okay, great, we're live. So hopefully most of you have downloaded the materials for this class here. Let's go ahead and double-click the disk image here. This is the disk image that's posted on the developer.apple.com/wwdc2006 as an associated material for this session. We have here a top-level folder. I'm just going to double-click on that.

I'm going to put this in list mode just to make it a little bit easier. And sorry if the type is too small here. I'll read the names that I'm selecting here for those of you in the back. I'm going to expand the first milestone. There are five milestones and then the complete one here. Under the first milestone, that's actually our starting point.

And there is this little project called GlutMech. Now Glut is an OpenGL utility toolkit that's open source. We ship some developer examples. What I did was I took one of the examples out of just developer examples and I actually pared it down a little bit. It had lots of targets and demos all in it. I just focused on one of them just to make things simple for this session. So if you all have opened the Creating Complex Projects folder here, let's go ahead and take the GlutMech project folder underneath the Complex Projects one and drag that off to the desktop.

And the other ones are milestones. As we're going to do that, we're going to take the GlutMech project folder and drag it off to the desktop. And as we do various things to this project this morning, I've saved snapshots of exactly what the project state is. So if you fall behind at any point, you can just grab one of them. I'll announce when we get to the milestones and just copy that over and then start and catch up from that point. There is one other folder here that contains useful materials, which is Other, Creating Complex Projects, Other.

I'm going to go ahead and double click on that and then put that into list mode also. This contains some code clippings. This session would be about twice as long if we had to type in and get correct all the stuff that we're going to do to this project here. So for some of the things that involve source code changes and scripts, I've actually precooked those into little code clippings.

So what I'm going to do here is just on my machine, turn the toolbar off because I have a little bit of a smaller resolution here. I'm going to go ahead and put the folder into the dock. That's a good idea here. This is the folder containing the other resources, again, out of the disk image. I'm going to do that just because we're going to refer to that from time to other, and then that's an easy way to get to it. I'm going to do the same with the copy of the project glutmech that we put on the desktop.

So those of you who are following along in your PowerBooks here, do you have the Gluckmeck project and the other resources in? Okay. This is again in the disk image. If you look in the disk image, there's a top-level folder. And under that top-level folder are all the milestones. And what I did was I grabbed the GlutMec project out of milestone one. And I also grabbed the Complex Projects underbar other folder underneath there and I put that in the doc.

So we're going to open up the GlutMech project. And this is a demo that shows a little mech kind of a thing. I guess it's a robot of some kind on the screen. Let's go ahead and double click and open the project. And this will launch Xcode. And we're going to see my network connection went down. No, it's up.

Okay, so this opens the project on the screen. We just close the finder window behind it. So right now, this is just showing the project. I'm using the default Xcode layout, but I've increased the font size a bit. It will, of course, look different on your screen if you've customized Xcode. We see here that there is a debug.

If you can see this, a debug configuration by default. A couple of source files. Let's go ahead and build and run this. And just to see what we have here. A little bit of a demo. Okay, cool. We can have some shading. Turns out you can hit the arrow keys and rotate left and right. But it just kind of sits there, right? So we'd like to move this thing around a little bit. So let's see here.

First of all, we're going to go ahead and create an XC config file for this. So far, I haven't made any changes to the project, right? So now begins the fun. So let me first show, if I double click on the project icon and then go to the build tab, I see the build settings that are already set up for this project at the project level. So these are the ones that all the targets would inherit. So again, you can double click on the project icon itself, the blue one.

Everybody with me so far? Okay. Here we see all the build settings. This will look a bit different if you're on Leopard Preview. We actually have some nice little banners in between the different sections now. So it's a bit easier to find. You can see the customized ones are in bold. And you see things like the SDK, which are typically set at the project level because typically all the targets in the project would be using either 10.4 or 10.3 or 10.5. or whatever you choose as your target.

Similarly, if I open up the target itself, I can double-click on it here. These are the settings at the target level. And I see here, for example, the product name is one of the typical things that is customized at the target level. Because typically, if I have different apps or different frameworks, they'll have different names.

And what I mentioned was that underneath this level we can actually slide in the style sheet that we can reuse in different projects or targets. So to do that, I can go to the File menu and go ahead and choose New File. And then if you scroll down to the bottom of the alert panel here, or the dialog box, you see under the Xcode heading, there is configuration settings file. So again, I went to the file menu and I just said new file.

And then scroll down to the bottom and we have the configuration settings file. Everybody with me? Okay. I'm going to choose next. And you can give any name you want to this file. It doesn't really matter. I'm going to call it common settings. You can call it anything you like. I'm going to uncheck the checkbox for adding it to the glutmack target because I want to add it to the project as a whole. I want to base the project on the settings file.

So we uncheck the checkbox for the target and we click finish. So this gives me now an empty text file. This is where I could prototype by opening an inspector, selecting a bunch of settings and drag them off into here. But I've actually prepared a little clipping that's fairly heavily commented. Anders Bertelrud So at this point, if you go back down into your doc and click on the folder where we put the resources, the Creating Complex Projects underbar other, which contains the resources for this session.

Under the code clippings, you'll find the code clipping number one contains the contents of this XC config file. So the easiest way in this session here is to just click and drag. So I'm clicking and dragging the clipping here. So I'm going to bring it over to the text field in Xcode in the text editor here. And you'll see the little plus icon.

[Transcript missing]

So we populated our XC config file here. I'm going to choose save. So go ahead and choose save. Flea you've all caught up with me at this point. And if not, we're going to get to milestone two here in a bit. So don't worry about that. I'm going to go ahead and close this. So far I've just created this file. I haven't yet told Xcode where to use that.

To do that, I'm going to open up the info panel on the project. So we can select the project, and then you can use any of the ways to open the info panel. Click on the info toolbar, or if you want, you can just double-click on this, and that opens the info panel. So we're choosing show info on the project. And we looked at this before. This just shows the customized settings and the inherited ones.

The bottom here is probably hard to see because it doesn't actually scale. I'm not running Leopard here, so I don't have the resolution-dependent UI. There's another entry now that shows up in the pop-up down here. When I add an XC config file, Xcode notices that, and it will show that in the pop-up for the info panel. And so now I can say that instead of being based on no style sheet, I'm actually based on the common setting style sheet here. So I'm going to go ahead and do that and close this.

And actually, if I choose info again, you'll see that the path has now changed for the output location to reflect this sum root variable that I set. Now it's going to go into this Xcode builds directory that I just created, or that I just specified. Xcode's going to create it for me when I build.

So that's really all we have to do, but we can't really tell that we're using it yet, so we're going to open up the source code now. And now comes the first source code edit. We defined this preprocessor setting in this XC config file, so let's go ahead and use it.

And I have, ahead of time, figured out where the line number should be. So go ahead and open up the other folder for the resources again, the code clippings folder. I'll keep referring to this code clippings folder again, or the other folder. So good idea to put that in the doc if you haven't already, just so we can get back to it really quickly.

And let's go ahead and add some code now. And to make this simple, I'm going to specify the line number. It's real simple if you use the find menu and then choose go to line at the bottom here, because then we can actually jump to a particular line number pretty simply. This go to panel has a radio button.

You can choose to jump to a character offset or line. Please make sure that you're not going to be able to see the line number. And make sure that it's set on line so that you don't jump to character position 1730. We're going to go to line 1730 and click select. And then you should see this call to glut create menu and then this pound if def animation here. Are you with me so far? Okay.

At line 1730, I'm going to take clipping number 2. Again, I'm just clicking down on clipping number 2 and hovering, and then just holding the mouse button down, right? And I get the plus sign, the green plus sign on my cursor here telling me that it's going to drop the text in there.

I'm going to go ahead and position the... If you notice, the insertion point actually follows me around as I'm dragging the mouse. I'm still holding the cursor down, the mouse button down, and the insertion point is following me around under the cursor with the green plus. A lot going on here.

In front of line 1730, I'm going to let go of the mouse button, and it's going to just add the contents of that clipping. So in your code, you would obviously type this kind of stuff in, but I just wanted to make it a bit simpler here and cut down on the potential for error.

So what I'm doing here is I'm just using this preprocessor macro that I set in my build setting in my XC config file. Pretty simple. But it still shows how to use some of these complex features together. Okay. I'm just going to go ahead and click build and go, and it's going to ask me to save.

And then it's starting up the GlutMag here. And I have some network timeout on this machine here. I had this a little bit earlier. There we go. What it did now was to just add a little menu item that just shows this version. So 0.1 pre-alpha. So it's the same thing as before.

But one interesting thing is that the XC config file, as you would imagine, is tied into the dependency analysis. So you just go ahead and quit here and click quit from the menu. You get the menu in this little app by just clicking. You don't have to right-click or anything. It's a little bit non-standard. But it's a demo app. Now what I'm going to go ahead and do is go ahead and close the source code.

And let's double-click to open up the common settings configuration file again. So this is just the file that we created earlier with the code in it. And I'm just going to change my string here now to say, well, I've done some work and, you know, I feel good about this. This is a version 0.2 pre-alpha, right? So we're still not quite ready to ship, but almost getting there, right? So I just made one change to the, not the source code file, but the build settings file. And I click Build and Go. Click Yes to save.

And then Xcode builds it and runs it again. And now when I open up the menu, of course, it says version 0.2 pre-alpha. So the XC config file is considered to be a source file, just like any. And when you make changes to it, that affects the dependency analysis. Because it's a style sheet file, and if you base the entire project on it, of course, if you make a change, you may have to recompile a lot of different files if they all get affected.

So we've actually reached milestone two. We've created now a XeConfig file. We've populated it with some interesting settings, such as setting a preprocessor macro and setting the shared build location. And then we've shown how that gets used in the code and how that ties into the dependency analysis. So onward to milestone two.

And if you fell behind there, you can just go ahead and drag milestone two now out of the disk image. If you go back down to the disk image here, you'll find again all the milestones are there. Let me show you here. So, milestone two, at this point you would take the GlutMec project. That's exactly the state that I've arrived at now as we've gone through this transformation.

Okay, so now let's make it a little bit more interesting. We're going to go ahead and create another project, or take another project, in this case an open source project, a pretty nifty one, and then what we want to do is to connect that into our demo and then show how to link against that and embed that and take advantage of that.

And again, what we want to do is to make this robot get some life, right? It's just kind of sitting up there right now. So that's the project for the end of the day here, for the end of the session. So to do that, I'm going to leave the GlutMec project window where it is, just in the upper left corner here.

Let's go back down to the other folder again, the one I keep referring to. That's what contains all the ingredients here if this was a cooking show. This would be sort of the row of bowls of ready-made things here. Is everybody back down to this other folder here? Okay. There is a disk image which contains the project. Okay.

So this is an open source project that you can find on the -- there's a link to the Pixel Ballistics website here. It's a great little project, and just go ahead and double-click on the disk image. It's the exact disk image from their site, and I encourage you all to go to that site and read up more about this.

What I'm going to do in this case is to go ahead and do what you would do in your own project to leverage this, take the source code and incorporate it with your project. So if you have a separate subproject, just to keep it separate, so if there is an update to this other project or if you make changes that you want to contribute back to the community, we should keep it separate from the project that we're working on here.

So there are a couple of different ways to get back to the source folder for my GlutMec project. I have here now the original for the Lua project, and I want to get back to the GlutMec project. One nifty way you might not know about is to go back to the title bar here. So if you hold down the command key and you click the left mouse button, and then you'll see here the whole ancestry of where the project lives.

I can actually just select the project folder here and open that in the finder. So that's a fairly neat way to go back to the finder view of the project folder that not all of you might know about. So on the left here now I have my GlutMec source code project.

On the right, I have the disk image. And hopefully you all have caught up with me at this point here. Again, the Lua disk image with the source folder in the top level. I'm just going to create in my project, go ahead and from the file menu we say new folder. I'm just going to call mine subprojects. You don't actually have to create a new folder. You can call it anything you like just to keep things organized a little bit. So we've all created the extra subprojects folder here in the GlutMech project. Double click on that.

And then we have an empty folder. Let's go ahead and take the source code for Lua. And this is a distribution of Lua, I should say, that has the standard Lua, which is a little embeddable scripting language used by actually a lot of different software systems these days.

Pretty popular and gaining popularity. This also contains an Objective-C bridge for that, which is pretty nice. You can translate from plists into Lua scripts and all that kind of stuff. I'm just going to rename my source folder here to be Lua. You don't have to do that. It doesn't really matter. Okay, I like to keep things neat and tidy here.

If you double-click on the Lua folder we copied, you'll see that there is already a Lua OBSI Bridge Xcode project in there. This may not have been the case for other open source. There may have been a Makefile in there, there may have been other kinds of things. Xcode lets you create targets that wrap Makefiles in an Xcode target, that wrap Ant files and other kinds of build systems. In this case, I wanted to show an example of a nicely configured project.

It's already available on the web here. I'm going to double-click and get the Lua OBSI Bridge project. I'm going to drag it over to the right here. So at this point, we have our two projects open, but they're not yet connected, right? What we did was we copied the source code for the Lua project into the main project, and we've opened them up, but they're not yet connected.

So, I want to show a couple of things about this project as it came pre-configured from the website. If I click on "Get Info" here, go ahead and select the top-level project here icon, the blue icon, and then click "Info". Under the "Configurations" tab, if you click on "Configurations" here, You'll see that there are already three configurations set up. And there's actually one set up for embedding already, but I want to debug this and go ahead and embed the debug version. So I'm going to edit that one.

Multiple projects work a lot better if you have the same names for your configurations for the different projects that are involved. You can call them anything you like, but it works better if you have to set up fewer things if they're all called the same, because Xcode will automatically find them. So I'm going to go ahead and rename this. Go ahead and double-click on the configuration called Development. I'm just going to type Debug here with a capital D.

And similarly, we're going to rename deployment to release. If you create a new project in Xcode 2.3 or 2.4 or 3.0, it will already come with debug and release by default. But older versions of Xcode and project builder before it would have created development and deployment configurations. So now we've renamed the deployment, the development to debug and the deployment configuration to release. This doesn't change the actual settings that are contained in them, just the name of them.

So now we've renamed the deployment, the development to debug and the deployment configuration to release. This doesn't change the actual settings that are contained in them, just the name of them. command line tool. And then finally, an aggregate target that actually is set up to depend on the other four, which is just a way to build them all together. Let's go ahead and inspect the framework target. And to do that, we're going to go ahead and just click on the LuaObsi Bridge framework target underneath my targets here.

[Transcript missing]

I'm going to choose Customize Settings here. Now, I'm running Xcode 2.3 on Tiger here just to sort of show the baseline that will support this. In other words, you don't actually need any of the software that we've made available at this conference, Xcode 2.4 or Leopard Preview, in order to apply all these things on your own projects.

If you are running Leopard Preview, this is called User-Defined Settings. The Customize Settings is called User-Defined Settings now. We felt that was probably a little bit clearer of a name. This again just shows all the bold ones, all the ones that are set at this level. The other ones shown are the ones that are inherited from those lower levels on the diagram, or the stack that I had on the slide.

What we see here is that there are some absolute paths, but these are not actually absolute. If I double-click on this, it actually shows me that this is a build setting, source root in this case, that's being expanded. And it's just that the value I see is the one that will actually get used. If I move the project, this would change.

The installation directory is an add executable underbar path. This is a variable for the dynamic loader at runtime. The add executable path is the thing that gets replaced with whatever place your application happens to live. This application uses @executablepath, which works way back on Mac OS X. I'm going to change this to @loaderpath, which is the newer one that works on Tiger and later, which lets the framework be embedded into anything, not just an application, into another framework, into a plugin, etc. To do that, I just double-click on this. If you double-click on the name here, I get a sheet that comes down. I don't know if everybody can read that.

I'm going to type in @loader_path instead of @executable_path. So I'm not changing the slashes or the dot dots or anything. I'm just typing the word loader as opposed to executable. And the subtle difference there being the executable is the main program for your application. The loader is whatever Mako image is loading this other embedded thing, whether that's a dynamic library or an executable or anything. So it's more general purpose. Okay, so I've changed the installation directory.

From @executable_path/.../frameworks to @loader_path/.../frameworks. And I'm going to show you a little bit what this means on the disk a little bit later on. Many of you, I'm sure, know the dot dot and the shell notation means to go up one directory. So what this does is it goes up one directory out of where the executable lives in your application wrapper. and then down into a new directory called frameworks.

There is one more thing I want to do here, and that is that we added an XEConfig file to the main project, and one of the things I mentioned was that you can use that to share settings between different projects. So we're going to do that here by just adding the same file, a reference to the same file, into this Lua project. So we'll have both projects referencing the same underlying style sheet of settings, if you will. There are many ways to do this. You probably know you can use the project. You can say, let's see, maybe it's not project. Huh.

I always context click, that's why I don't know these things. I can right click on the project and there's the Add submenu. I personally just find that more convenient. I can add using existing files. I'm going to show you something you might not know actually. I can just take the reference over in my main project. Again, my main project is on the left. The Lua project is on the right.

Just go ahead and make the XEConfig file that you created earlier, go ahead and make sure that shows up here in the main project. I'm just going to drag this over and just drop it. And you see the plus sign showed up. I'll do that again a bit slower so you can see. I'm just going to grab the common settings XEConfig file, drag it over to the other project, the Lua project.

Because the green little plus icon shows up on the pointer, the mouse pointer here, it means that I'm going to copy a reference. In this case, I'm dragging the reference, not the file itself. So I'm going to copy the reference, but both copies are going to point to the same file on disk.

So that means that I can define my settings just once and reuse them in both projects. So let go of the mouse and now we get the same sheet that we get whenever we add a file. I'm going to choose not to copy the item into the Lua project. And of course that's because we want to share this one file. So make sure the copy items is unchecked.

I want the text encoding to be UTF-8, just to be sure I can type any kind of script, any kind of characters into the names there. I'm going to uncheck all of the targets that were checked by default. Xcode by default will check the target that is capable, the first target that is capable of accepting a file of this type.

We're going to uncheck this because we don't actually want to copy the XC config file into the framework. We want to just base the project on it. Uncheck copy items, uncheck all the targets, set the text encoding to UTF-8. Does everybody's panel look like this? Those who are still with me. And we click Add. So now we've just added another reference to the same file.

And now, we can go ahead and build this, but to show you something even more interesting, I'm actually going to go ahead and go to the next milestone. We haven't yet built the project. We haven't yet connected the projects together. So right now we have, again, the GlutMAC application project, just the same mold as before.

We've now copied our Lua project in there, configured it, set it up to use the same style sheet, the same config file, and so it's going to inherit the same settings as the other project, but they're not yet linked together. So now we're at milestone three, and anybody who ran into trouble there, you can start now with milestone three if you want.

Milestone 3 contains both of these projects underneath the main source folder. So now let's link them together. Let's take the main project, we take the Lua project, we connect them together. So to do that, I'm going to use another little trick that you may not know about. This is the sort of advanced trick session here.

So if you go to the Lua Bridge project, just click and press on the icon here, the blue project icon. This now results in a reference to the project coming under my mouse. So now I can take this one and just drag and drop it underneath. Let me put it under the frameworks phase, the frameworks group of my main project.

So everybody see that? I just clicked and pressed on the title bar. Again, you can go to the finder, you can find the project icon and drag it that way. It doesn't really matter. Now I'm going to go ahead and release the mouse button. And again I get this add project, add to project sheet. Again, I want to make sure the copy items is unchecked. I don't want to make another copy of the Lua project.

I just want to link them. Text encoding in this case actually doesn't really matter. Xcode handles that on its own. It does use UTF-8 for projects. You can have anything you like in a target name, any kind of a language. I'm going to uncheck the target checkbox here again.

We're going to go ahead and set up the target to link against the framework, but I want to show you how to do that in a different way. So uncheck copy items, make sure the text, well actually you can leave the text encoding alone, and uncheck the target checkbox. And then click add.

Okay? So now So now, this blue icon here hopefully shows up well. If I disclose the blue icon, you see now these targets again that are produced by this sub-project. They're shown in red because they haven't been built yet. They don't exist on disk yet. So they'll turn black again once we build the project.

So we could go back to the Lua project here and click build and build it. But because we're going to treat this as a sub-project, we'd rather just set up the whole chain so that the Lua project is built automatically. So what we're going to do here is to open up the target, the GlutMech target underneath the main project here.

You'll see this build phase that I talked about before called link binary with libraries. That's the last step here. So what I'm going to do is just click and drag on the first of these red icons here, the Lua-Odyssey Bridge Framework. And again, I got that by twisting open the blue project icon here.

So I'm going to just drag and drop that. So now I've configured the demo application to link against this framework, the product of this sub-target here. So that's one thing. I want my application to link against it. But I also want to embed a copy. And so to do that, I go ahead and I select the target, the GlutMech target, and I go ahead and choose Add. I'm doing this in the context menu now. And say New Build Phase.

I'm going to create one of these Copy Files build phases that let me copy arbitrary files to arbitrary locations because what we're going to do is we're going to take the framework and we're going to just copy it into the application wrapper. Okay, so that created a new copy files phase at the bottom of my list here.

And it also opens up the inspector because odds are I'm going to want to configure it. And I do. The destination can be an absolute path or it can be expressed in terms of build settings. We have a list of particularly popular destinations, one of which is frameworks. So this refers to a frameworks subfolder inside your application wrapper which relates to the add loader path that we had before. If you remember we went dot dot to go up one level and then down into frameworks.

So this is the corresponding part here. We're saying the framework is going to show up one level up from the executable and then down into the framework subfolder. And here we're actually configuring it to copy it into the framework subfolder. Those two need to match. Anders Bertelrud I'm going to close the info window.

And then, so far the copy files phase is empty. We're just going to take the same icon as before under the blue LuaObsi bridge project reference here that's disclosed. We see the four targets. Just going to copy that, drag that down into the copy files phase. So now, that's the second step, right? So we made the application link against the framework. We made the application copy the framework into itself.

And the third thing is we want the Lua framework to be built whenever we build the application. Okay, to do that, we open up the info panel. I'm just going to double-click on the GlutMech target. And here I see the direct dependencies, meaning these are the other things that this target directly depends on. And whatever those in turn depend on, of course, I indirectly depend on. So I click the plus button at the bottom here.

I can give you some time to bring up this panel and click the plus button. Now a sheet comes down and the sheet shows me all the targets in my own project that I could depend on that would not create a circular reference. So if a target is missing from there and you say, "Hmm, I wonder why," right? One reason might be that it would create a circular reference. Depending on the version of Xcode, it might actually show a dimmed, I think it does in newer versions, which is sort of more useful. What I see here, though, is also I see my project references and I disclose this.

Again, I can see the products built by those projects, those sub-projects. So again, we pick our old friend here, the Lua-Obs-Ubridge framework, and we click "Add to Target." So now we've done all three. We made the application link against the framework. We've set up the application to copy the framework into itself. And we've set up the application target to depend on the up-to-date state of the application.

And we've set up the application to build the framework target. So now all we have to do is say "Build and Go." So I don't know if you noticed here, but on the right-hand side, it's actually building now the other project because they're connected now and we set up the dependency. And we have a build failure. What happened? Hmm.

I wonder what we did. So let's go ahead and make sure that we set up the build configuration. We forgot one step, didn't we? Remember how I added the XC config file to the subproject? Well, sure, that means that the subproject has access to it. But we didn't actually tell Xcode to use it yet, because we might want to use it for the target or for the project or wherever. So what we have to do is to go back and we have to say that the Lua project is based on the common setting. So let's go back to the Lua project.

What I did here, if you didn't see it, was I double-clicked on the very top level icon, just the one that represents the project. At the very bottom here, it should say based on common settings. Common settings should show up because we already added that reference to the project. So now, if we go back to our main application demo, and the demo gods are with me, or the hands-on gods are with me, I guess, we'll see it linking, and we'll see it starting it up.

Okay, there we go. What's this? It's still just sitting there. Well, okay, so great. We actually have the application linking us to framework, embedding against the framework, but we're not actually calling it yet. So that's the last step. That's actually the easy part. So let's go ahead and quit this. I wanted to show you quickly though, if we go up to products, this is not a step that we do. You don't have to follow this if you don't want to. I just wanted to show, I'm going to select the product here in the Glut products.

I'm going to choose reveal and finder. This gets me to where it got built in the build folder. And you'll see that LuaObsi bridge is sitting right next to it because we defined the shared build folder. If I show package contents on this application here, you'll see, I'm going to put it in list mode, makes it easier to see. Under contents, we have Mac OS, which is a standard Mac OS X way of packaging an application. The executable lives down here in the Mac OS folder.

The dot dot gets us up one level. Out of the Mac OS folder and into contents. And then the framework part gets us down into the framework. So this is what Mac OS X does when it actually goes to try to find this Lua framework. It says, okay, loader path, and then dot dot up, and then down into frameworks.

And down in the frameworks, we find now the Lua framework that got embedded. So great. Everything looks good on disk. Let's modify the code. And this is actually milestone four now. So we've reached milestone four. If you didn't follow, you can go ahead and copy milestone four out, and I've set the project up to be exactly like it is here.

So, I'm just going to close a couple of these folders just to get us back to a fairly clean state. And... Now let's go ahead and modify the code. There's just one source file in this demo, which is pretty simple. So just double-click on it. This is the one we modified before to add our menu item.

Now we're going to make a couple of edits to make things a bit more interesting. Again, if you click on the doc and you go to your resources folder, you'll find clippings 3, 4, 5, and 6, and we're going to put those into various places in the code.

So this is not as tricky as it sounds. I put the line number actually in the name of each clipping, so this should be pretty straightforward. Just position the window so that the resources folder is available here and the source code is also available. It should be easier for you because you have a smaller typeface probably than I do. You can fit more on the screen. Under the Find menu, choose Go to Line.

And then make sure it's online. The first one is line 63. I'm going to select that. And again, these line numbers are part of the name of the clipping in the file system, so you should be able to catch up if you fall a little bit behind. Here again, I'm just going to take each clipping and just insert it at that line. So line 63 means insert it at the beginning of line 63, the way I have the insertion point here. And I just let go. This just includes the headers from the embedded framework. Pretty simple stuff.

I'm going to go to line 1744. Again, I'm reading this from the name of the clipping. So, if you are a few seconds behind, then just read it from the name of the clipping. This is the main part here. I just wrote this. Just took an hour or so to write a little bit of code.

I'm not going to explain it in particular now, but it's pretty heavily commented. It's specific to the Lua open source framework that we're using. If you're embedding something else, you would, of course, have your own code here. So this is just to make things a little bit more interesting for the demo.

Clipping 5 is at 1852. And this is just-- now we've added the pound includes. We've added some extra functions that we'll call our framework and do something interesting. What I'm actually doing is I'm going to be calling this little Lua script. It's a scripting language, right? So I'll be calling this little script every time through the animation loop, because we want to move these arms of this robot and whatnot. And if you were developing a game, you would, of course, be checking for hit testing. And did somebody fire a rocket? That kind of stuff.

[Transcript missing]

We're not quite done. We're going to do one more interesting thing. Can I have the slides, please? Okay, great. So that was a little bit about showing you a bit how to use some build settings, something you might not know, set an Xe config file, share it among multiple projects, take two projects, connect them together, and set it up so that one builds a framework and the other one embeds it in it. That's pretty straightforward. One of the things that's interesting is when it gets to deployment. Well, now, okay, so now you've worked on this, you've written, you know, 100,000 lines of script code that does all kinds of advanced artificial intelligence for the game.

You want to ship this out to customers or beta testers or whatnot. One good way to do that is to use a disk image, and we'll show how to automate that. You saw a great demo actually on Monday, I think, which was to use an automated workflow to tie into Xcode to build a disk image. That's a great way to do it. That does mean that you have to invoke the workflow manually. You can set up a target to actually build the disk image automatically, too, so that's another way to do it.

And why use disk images? Well, if you have a simple enough product that you're deploying, such as just an application or a couple of applications, it's a great thing to use a disk image. One is that Mac OS X applications are wrapped, so they're actually a tree of folders. You can't really send that across the Internet too well.

So, you know, enough said. Disk images survive transport across the Internet. And something you might have seen in third-party applications is you can have a custom background image. You can have a custom background image and custom colors and layout. And also, you can actually -- I've even seen a Sim link or an alias to the application folder and a little background image that says, like, you know, "Drag this icon over here," right? So that's a pretty simple thing for a user to see when installing it.

So, how do we create these? Well, there's a GUI tool which is great. It's called Disk Utility. It lets you just select a folder and create a disk image from it. But there's also a command line tool, and that's what's interesting from an Xcode perspective, right? Because Xcode is pretty much tuned to invoking command line tools from various scripts and targets, etc.

There's this tool called HDI Util, which I forget what the HDI stands for now, but I'm sure probably many of you know. It's called HDI Util, and there's a man page for it. I'm just going to show a little bit of how to use that, and I'm sure there are other tools as well and scripts that people have written.

Custom targets are perfect for this. A custom target is just a black box that says, you know what, instead of building an application or framework or whatnot, let's just invoke this script. It could be Ruby or Perl or Python or anything. And it's a very simple way to do that.

You can just click on it, and it's going to give you a little bit of information. You can also see that it's a little bit of a manual, and it's going to give you a little bit of information about what you're going to be doing. And you can go ahead and do anything and see what it does, and then it comes back to Xcode and says, yep, I'm done. And this is really a great tie-in if you have very custom things you want to do. And let's go back to the hands-on and then go actually do it. So if I could have the demo machine, please.

You know, a guy is still standing here. Well, we need to improve that script. He should have gone off and hunted down some other robots by now. Okay, so let's quit this. I'm now starting out with Milestone 5, so even if you haven't followed anything up to this point, you can still start with just Milestone 5. Just drag the GlutMech project out and you could be with me for the home run here.

So we have our GlutMech project. I could even close the Lua project on the right here because my main project is still referencing it. Xcode will open it in the background. It won't open the UI for it unless you ask for it, but it will open the project in the background and build it and whatnot. And any errors will show up in the main project.

What I want to do is to create this target to produce a disk image. So we select the target here, the targets smart group. I'm going to go ahead and use context menu. You can use the project menu if you want. Just create a new target. I'm going to say add new target.

And we see all kinds of different target templates that Xcode provides. Up at the top, we see some special ones, which are sort of oddball cases, but very useful ones, especially for complex projects. The fourth one there is a shell script target. It's a little bit of a misnomer, I suppose.

It comes preconfigured for a shell script, actually shell script. It could be actually any script. You can modify that to run any script that you might already have in any interpreted language that you can run from the command line. Go ahead and select shell script target and click next.

We get to name our target and call it anything. I'm going to call mine create disk image. I couldn't think of anything funny for that one, so I'm going to go ahead and just be boring. We're going to add it to the GlutMag project. If we had more than one project open here, we would see everything in the list, all of them.

But we just have the one, so we're just going to create it there. Now you see that it showed up underneath the GlutMag target. It has a different icon. It just has a generic target icon because it's a generic target. It does whatever our script tells it to do.

Xcode opened the info panel for us right away. We're going to take that opportunity to go ahead and set up the dependency. What we want, and this is the nice thing with using the targets and dependencies here, we want to set up our disk image target so that it depends on the application target, which if you remember, still depends on the Lua target.

So we have this little three-step chain of targets all depending on each other in a chain. So whenever I update the disk image, it's going to first see if the app is up to date, and that's going to first see if the framework is up to date. So that's pretty nice. So click on the plus button. Now we see that the GlutMAC target shows up as a possible dependency, as do all the ones in the subproject. We're just going to pick the GlutMAC target, the one from our project itself, and click Add Target.

So right now we have, we're inspecting the Create Disk Image target. We're going to go ahead and change target to new one, and we have it set up to depend on the application. And then I'm going to go ahead and disclose this target, and I see that it's set up to depend on the application, which I just did.

And there's a script phase here, a run script phase. I'm going to go ahead and double-click that. And by default, it's set up to invoke /bin/sh, which is the standard system shell, and shell script goes here. So I'm going to run a little script here. I'm going to go ahead and select. Let's go ahead and select and delete everything in that right now.

Because we have our last and final clipping, is number 7, if you go back down to the doc or to your, wherever you put your other resources folder here that I said we'd be mentioning over and over again. Take Clipping, Code Clipping 7, click and drag, and you drop it on top of this script phase. And we get the script. It looks a little bit hairy right now. I've written this to be fairly bulletproof.

And you can look at it later if you want. It removes a whole bunch of things that might have been there from before and cleans everything up. And then it creates a new little structure to mirror what's going to be on the disk. And then it uses HDI Util Create, as you can see here.

And finally, the exit dollar parenthesis is actually a subtle thing. Xcode says build succeeded if the script you invoke returns exit code zero. That's a convention in the terminal layer of the Xcode. And that's what we're going to do. We're going to do a command line utilities. Exit code zero means all OK, no problem. Anything else means something bad happened.

So if your script returns zero, Xcode is going to say, OK, that succeeded. So if you invoke a subscript, a subshell, that returns something non-zero, but then you return zero, Xcode is not going to know about that subshell. It's just going to say, OK, zero, everything's fine. So by saying exit dollar parenthesis, this is shell script notation.

It just says, well, whatever the last guy said, I'm going to pass it on to you. So if the creation fails, we will actually be able to pass that back to Xcode, who can show that to you as an error. So that's kind of a useful tip. OK, so now we just have to make the create disk image target active.

[Transcript missing]

There's no Q&A because this is a hands-on session, but I invite you to come down to the Mac OS X lab. I'm going to be going down there right after this session. For some of these kinds of cases involving complex projects, it's sometimes better just to be able to take a look at the project and the particular situation you have.

I'm going to be down in the Mac OS X open lab, the Xcode lab, and I will be down there until a little bit after lunch. So please feel free to come down and bring your PowerBooks and we'll get your questions answered and look at your particular case. I also would refer you to our developer tools software evangelist for any other questions, Matthew Formica. You have his email address there.

Again, if you didn't download the samples and follow along, they're all available on the developer.apple.com/wwc2006 website associated with this session. This is session 306, creating complex projects. So if you didn't follow along today, you can download the disk image with all the milestones and I put a readme in there showing what exactly we did to the project at each stage. So you can learn from that. There are also two great sessions that are going to be coming. One is the, of course, the developer feedback forum.

Always love to hear what you guys think we should be doing and what we're doing right and what we can work on. And that's on Friday. And there's also the accelerating development of complex projects session, which a colleague of mine is going to be holding. That's on Friday. I think that's actually the last session slot of the conference, but there'll be a very worthwhile one to go to.