Apple Developer Tools • 1:02:13
This session highlights improvements in Apple's IDE that bring you significant advantages for Carbon development. We demonstrate the improved importer and compiler compatibility and how it makes it easy to import existing projects. We show you how to work with existing source frameworks and resources, and how to optimize your project for build speed and turnaround time. Topics such as Mach-O and system libraries are addressed. We also show you how Interface Builder can be used to create state-of-the-art user interfaces for Carbon applications and to set up Carbon Events.
Speakers: Chris Espinosa, Scott Tooker
Unlisted on Apple Developer site
Transcript
This transcript was generated using Whisper, it may have transcription errors.
Good morning, everybody. This is session 307, Apple Tools for Carbon Development. I'm Chris Espinosa. I've been with the development tools team working on Xcode specifically for the last six months or so. I've been working with development tools in specifics since... 93, I guess, and I've been working at Apple since the Carter administration. There we go.
Trying to figure out where to point my clicker. It doesn't point. There we go. Okay. What we're going to cover this morning is an overview of Apple tools. You've probably seen three or four of these overviews of Apple tools, but we're going to do it from a Carbon perspective this morning. We're only going to be talking about Carbon applications. The process of bringing a project, whether it be a project builder project or a Code Warrior project into Xcode. Getting your code to build with the Xcode IDE and with the GCC compiler.
Some hints and tips for optimizing the build time and the turnaround time, how you can take advantage of the Xcode features. A little bit about Xcode support for Mac resources, if you have resource-based Carbon projects, which most of you do. And just a little bit about designing Carbon interfaces with Interface Builder. There are other sessions on Interface Builder, and there's a really great session on building a modern Mac application, which we'll cover using NIBS and Interface Builders later on that I'll point you to, but I'm just going to do a brief overview of that.
Now, I want to do the standard disclaimer here. I am talking about Xcode, and I'm talking about Carbon. The fact that I'm talking about those two things does not mean that we are killing everything else that I'm not talking about. We are not killing Cocoa Development. We are not killing Objective-C. We are not killing AppleScript. We are not killing Java or EOF or anything like that. The fact that I fail to talk about something does not signal its imminent demise. I just want to make that clear.
So the tools you've already seen in a couple of sessions, the Xcode integrated development environment, and you've seen a lot of the great features of that, the code sense feature, the great indexing, the great workflow and navigation. It's a project manager and build system. It's got an integrated code editor and an integrated debugger. The debugger I'm going to show you tomorrow. We're just going to build today.
Interface Builder is another key tool. It's primarily a Cocoa development tool, but we are moving more and more to using Interface Builder as the principal design tool for Carbon. And if you want to get at certain new Aqua elements through the Carbon toolbox, the best way to do them, in some ways the only way to do that, is to use Interface Builder to design nibs in order to get at those objects.
And then there are some performance tools, And all these performance tools work with your Carbon applications. The sampler performance analysis tools, the malloc debug memory analyzer, the object analyzer that is primarily for Objective-C, and then the chud low-level machine tools will analyze anything as long as it's expressed in bytes.
But Xcode is not a world unto itself. Xcode supports the external editor model that Code Warrior and BBEdit do. So, for example, if you like the Xcode build environment but prefer your old familiar editor like BBEdit or like Emacs, you can use either of those text editors as your code editor inside Xcode. We integrate with other editors you like. And if you still have resources, sadly, ResEdit has not made the transition to Mac OS X, but there are some very, very good tools from third parties, the Constructor from Metrowerks and Resourcerer that you can use on your resource files if you want to edit your Mac Resourcer. And if you double-click your resources in Xcode, it'll launch Constructor or launch Resourcer, and you can edit them there and go right back to Xcode. So we integrate with all these other tools. It's not a stovepipe technology. We're open with other tools. Similarly, we're open with source code control systems. If you happen to have your code checked into a CVS or Perforce repository, we'll integrate nicely with that on the atomic day-by-day check-in, check-out, modify cycle. and we integrate nicely with the administration management tools. Perforce is showing a very good one in their booth today, and there are a couple of third-party and shareware CVS integration tools, management tools that we integrate with.
Xcode loves Carbon. We're working very, very hard to make Xcode a great development environment for your application. We're making it easy to import Carbon projects wherever they come from, Project Builder or Code Warrior. It compiles Mac resource files, whether they be.R or.R SRC files, ties in with existing resource editors in a seamless way. It supports building Nib files if you are moving to Nib files in Interface Builder. It's the best way to use the new HI elements and the best way to use Carbon events. And it supports combining Carbon and Cocoa in the same application. There are a lot of new APIs that we have that are Cocoa only and you can get to them from Carbon using Objective C++. And if you want to take your existing Carbon app and start using some of the unique and interesting Cocoa features, Xcode is the best way to start doing that. So let's look at bringing a project into Xcode. There are a few simple steps. First, you need you have a Carbon application. If you have a Mac OS 9 application that's still based on Interface Lab, first thing you've got to do is carbonize it before you can bring it into Xcode because Mac OS X applications must be Carbon to run in Mac OS X native. And if you've got a 9 application, carbonize it on 9 first, and then you can bring it into Xcode on Mac OS X. Then you need to bring it into Maco. Maco is the code format for Mac OS X. EFM is for Mac OS 9 and for Classic. If you're going to be building a Mac OS X application, we really strongly recommend you move it into the Mac OS format to take most advantage of Mac OS X and to take most advantage of Xcode. Most of the rapid turnaround features like fix and continue and zero link only work in the Mac OS format. Then you need to adjust your build settings to get your project to build. Build settings are always very fussy, and working in Xcode is no exception. So when you move a project either from Project Builder or from Code Warrior into Xcode, you're going to be spending most of your time tweaking your build settings, making sure that you're building what you want to build when. And then the last step is when you finally get your project building, you're going to have to look at your source code because the GCC 3.3 compiler has some differences from GCC 3.1, which Project Builder used, and it has some differences from the Code Warrior WCC compiler and you're going to need to make some changes in your source code in order to cope with that. In the demo we're going to do today, we're going to make exactly four changes in the source code to bring a large Code Warrior project over into Xcode.
So first step, carbonizing your application. I really shouldn't have to say this. We've been talking about this for three or four years now. Just the quick steps. You should have done this years ago if you've still got a Mac OS 9 only, interface live only application. You isolate your Mac OS usage to just the subset supported by CarbonLib. You modernize it to use new APIs. You remove the linkages to interface live and start using CarbonLib or its stub instead. We still have posted this tool that will look at your application and tell you what Carbon APIs you are using and not using that will help you make this transition. If you haven't done that now, do that now, and then come back at the end of the session and we'll talk. up.
The next thing is converting to Mach-O. If you have a project builder application, it's already Mach-O. If you have a CodeWarrior application, I recommend the best thing to do is to change your project from CFM to Mach-O in the CodeWarrior environment where it's familiar, where you've got more control over things, where you don't have to be changing three variables at the same time. CodeWarrior does a good job of building Mach-O applications.
So if you just go into the target settings panel and change the linker setting to Mac OS X PowerPC Mach O, that will get you a Mach O application and that will start bringing in all of the changes you need to make in order to make a Mach O application. If you have a very simple application that doesn't load shared libraries, it doesn't bring in static libraries, it doesn't call plug-ins, if basically all it does is hit main and then run, there's very, very little to do. It's just a binary loader format. If you happen to have something that uses a plug-in architecture, if you do some dynamic loading, you'll have to migrate the APIs that you call in order to load those plugins from CodeFragment Manager APIs to the MachO APIs. What we recommend is to use the CF plug-in architecture in core foundation. And CF plug-in is a way to dynamically load plug-ins that could be either CFM or MachO. And what that allows you to do is maintain compatibility with existing CFM plugins but also support Mako plugins as well. The only hard part is that if those plugins, the CFM plugins, happen to call back into your application and expect you to be a CFM application, that's a particularly difficult case. If you want to come to one of the feedback forums or down to the porting lab or catch me afterwards, we have some techniques to deal with that. They just involve making a lot of CFM glue looks like a CFM link library in your application that calls in to the Mako. It's a tough problem, but a lot of people don't have it.
If you have a Project Builder project, importing into Xcode is very easy. It's drag and drop. Xcode is upward compatible from Project Builder files. Only if you start using some new Xcode features, then does your project file become Xcode only. If you just bring it from Project Builder into Xcode and build it, and you don't switch to new compilers, and you don't turn on features like fix and continue or zero link, then you can take that project file and share it with a Project Builder user. although once you start using Xcode, your desire to do that is going to be very, very dampened, believe me. It's just a much nicer environment to work with. But let's talk about where your code really is now.
Most of you have Code Warrior projects. Let's talk about the steps in bringing a Code Warrior project into Xcode, and especially doing so in a way that lets other Code Warrior users continue to use the same source space. We know that nobody switches whole hog, but there is probably going to be a transition period where some users are using Code Warrior, some users are using Xcode. You can do that successfully with the two environments. It's not an automatic process, but it's a lot easier than you think. We've taken great pains to make it very smooth. The first thing is that you should import your projects bottom up. If your project is a tree of projects that first you start with some shared static libraries and then you build some dynamic plug-ins and then you build your precompiled headers and then on top of that your main application and then there's this side little runtime thing that you build, it's best to start at the lowest levels and convert those projects one by one so you can bring those executables in to the higher levels of the project.
The second thing you do is after you import is that you need to move from the Code Warrior style precompiled header mechanism to the Xcode style precompiled header mechanism. The two compilers have somewhat different mechanisms and you're going to get no joy in anything until you deal with the headers. Because until you get your precompiled headers right you won't get the speed advantages of Xcode and you're going to get a lot of build failures and it's not going to be fun.
The third thing is if you happen to be using the Power Plant application framework, there are a small number of changes you need to make in Power Plant for Power Plant to be compiled by the GCC 3.3 compiler and build against the Apple standard libraries. A very small number of changes. The Power Plant sources are really very clean and the GCC compiler is really quite compatible. There are just a couple of changes you need to make and we'll show you.
Then the fourth thing is you need to fix your target settings to get rid of some link errors and make sure that Xcode is building your project properly. And then once you build, then you need to make a couple of changes in the resource files in order to work with the developer release version of Xcode. We're going to get these worked out by the time Xcode 1.0 ships, but right now there are some things you have to do to the resource files to bring them in.
And then you get to work on warnings and errors, real differences between the compilers. Usually these are things that Metrowerks was lenient about, that GCC is stricter about. Sometimes it's things that Metrowerks supported or used in a different way that GCC interprets in a different way, often gray areas in the standards. For most mainstream standards-compliant C and C++ code, you can compile tens of thousands of lines without seeing an error. Thank you.
So to do this demo, I'm going to bring up the useful and lovely Scott Tooker, who has put together an example of he did the importer that imports Code Warrior projects and he's going to take an example of a fairly interesting Code Warrior project. Thanks, Chris. It's a little bit of a misnomer to say I did the importer. I basically took an old version of the importer and made it work a lot better.
So what I'm going to show you here today is we wanted to find a project that we would bring over and just show the whole import process from importing to then going through and fixing all the problems to actually running the application. And so we picked Appearance Demo, which is a common Power Plant example. And so just for those of you who have never seen it, which is probably not very many, this is Appearance Demo. So it's basically a showcase for all of the Power Plant widgets. And we thought this was a good example because it's small, but it also uses Power Plant, like many of you. And we wanted to show that Xcode can work with Power Plant. You can run Power Plant, and it just runs and works. So let me put that. So the first thing we're going to do is launch Xcode. We're going to import the project. So you just say import code where your project.
Let me choose. So you see here I have a path to -- unlike project builder, we take the actual code warrior project file. And also you can change them if you want, although you can just -- by default it's just the same. We also have this import global source trees. We support source trees now. So if you have source trees in code warrior, we can pull them over at the per app level. In fact, the importer creates a source tree to deal with the compiler relative paths you may have in your Code Warrior project.
So what we're doing here is we are using Apple Script to launch Code Warrior and then ask it, OK, I want an XML version of the project. Then we take that XML and we go scanning through it and find all your files. And because Project Builder likes to have all the headers in the project, it likes to be very explicit, we actually then-- wow. Sorry, I've never actually done it on a fast machine.
I thought I'd have more time. But CX code's really fast. But anyway, just to finish up, we actually bring in all that stuff. So by this time, what we're asking you is, OK, we want to know your encoding. I recommend that for the older projects, especially older projects, that you just go ahead with the Mac OS Roman encoding, because that's probably what CodeWarrior was-- when you created the files, that's what CodeWarrior was using. So let's go ahead and start with the target. You'll notice that you get a native target. So we're not using the old project builder targets here. We're using the new native Xcode targets. And the first thing we're going to want to do is set up the prefix header. As Chris mentioned, the precompiled support right now is a bit different from Code Warrior. So there's some things you need to do to make it work well. So the first thing we're going to do is we're just going to double check and see what the prefix file is. Oops. Of course, if Scott could type, life would be better. So as you can see, we bring over the prefix header, So it's appearance, demo, Mach, prefix. And we actually add this to your target. So let me just move this out of-- let's close this for a second. And let me just find the prefix. So there it is.
And so you can see it's right here. But if we go and try to build-- I'm not even going to try to build it, because what's going to happen is it's going to fail, because it's going to bring in MSL. The importer by default doesn't bring over MSL stuff. So what we need to do is we need to replace this prefix file with one that doesn't use MSL. We want to use the system libraries instead. So what I'm going to do is I'm going to fake out-- I'm going to fake out Xcode. OK. And while Scott's doing that, if we could go back to the slides.
Hey, this isn't easy. There we go. There we go. So Scott's going to be Julia Child and work in the kitchen for a little while while I talk about how the importer works. This went a lot faster because we were doing this on a PowerBook in rehearsal, so we had time to fill. So as Scott said, the importer AppleScript's code warrior to generate an XML file from the project file, and then it imports that, and then it walks the tree and looks for the header files and imports them, and then it also converts any.PLC files it finds. It has CodeWarrior compile them into info.plists and then imports those info.plists. So it gets as much content from your project as it can in one go.
What it doesn't handle is it doesn't handle MetroWork precompiled-headed binaries. The binary formats for the two compilers are different for precompiled headers, so we don't import those at all. It doesn't really handle non-source files in your project tree, So if you have documentation files or HTML files or things like that, we bring them over and add them to the project, but we don't necessarily hook them in anywhere interesting. It will not bring over CFM libraries or stubs in your target. Xcode is a Mako-only build environment, so we just ignore anything we find that happens to be CFM. And currently, it doesn't bring over inter-target dependencies. If you have one target that depends on another target, we're not going to link up the binaries because the binary was the binary that was created by Code Warrior in the place Code Warrior created it. Xcode is going to create a different binary in a different place, so you have to wire those up yourselves afterwards. words.
Let me talk about precompiled headers while Scott's putting that together. Code Warrior has a concept that they will precompile anything, a.h file,.pch file. They'll even precompile C and C++ files. Anything you can throw at the compiler, they will precompile for you, either from a menu item or from a directive inside a file or from a special precompiled header target in a project. What you usually end up doing if you want to have a different phase to pre-precompile your headers is you have like a library target that builds a null library with the name like throw me away later. And in the course of doing that, it precompiles your headers and deposits them in a certain location where other targets expect them. Well, Xcode works in a completely different way. It's really much simpler. You take your prefix file, and every target has a prefix file, and if you check a checkbox, it precompiles that prefix file when it needs to for that target. That's all you need to do, really. You don't have to set up special targets and special projects to build it. The build system manages when your PCH file needs to be rebuilt. If it needs to be rebuilt, it rebuilds it.
If it doesn't, it doesn't. So it's pretty simple. All you need to do is figure out the content you need to have in your prefix file, put it in a prefix file, put that prefix file into your settings, and then check the checkbox and you've got precompiled headers automatically.
So if we can go back to the -- Okay. Finder is being a little flaky, so we'll move on. So what I wanted to go over now is there actually -- because this is a preview, we haven't had a chance to completely move over to all the new build settings. So I just wanted to go through a couple things that you're going to need to do manually that when we were doing this, we ran into and want to make sure you understand. The first one is the C language standard. By default, currently it comes up as C99. Well, for older projects, we recommend that you set it to compiler default, especially if you're using C++, you'll get all these errors and warnings about, oh, well, C99 doesn't make any sense for C++. Another thing is that, for example, in this particular case, Code Warrior will force C++. Well, the importer interprets that as saying, oh, use dash X C++, which will force C++. But it turned out that they were all C++ files, So you can just get rid of that in many cases. Also the F exceptions and F RTTI options in the other C flags are just not needed because we turn those things on by default. And then finally there is one kind of thing we're going to fix but you have to fix now yourself, which is if you go... To get your precompiled header to build properly, if you're only using C++, currently what we've found is that you're going to need to tell Xcode that you only want a C++ dialect. It actually turns out with our precompiled technology, because we have under the covers multiple different compilers, we have to say which dialects you want to. For the final one, we'll take care of this automatically. For the majority of cases right now, you have to set it. And then finally, one of the new features you've been hearing about is zero link. Well, unfortunately, the compiler didn't-- the importer didn't quite get the ability to set that for you up automatically, but it's really simple. So I'm going to go through that now. If we just go to the project inspector and go to styles-- so we just want to add one.
thing, which is -- let me find ZeroLink. It's under the standard build settings. You can just type in zero. There it is. You just want to check that on. And notice I'm doing this in the development build style. If you haven't heard, we have these build styles that overlay our targets. The idea here is we only want to use ZeroLink when you're doing your debugging and you're developing. When you actually go to make a deployment build, you want to make sure ZeroLink is off because we don't want you shipping apps that are not properly linked. So let me go ahead and -- we will build.
So just to give a more detailed-- oh, the build failed. Why? Oh, of course. This is part of the demo. We expected a failure at this point. We expected a failure? We didn't expect this failure. OK. Actually, we expected this failure later. We expected this failure later. Yeah. So what we expected to be able to show you was that PowerPoint isn't quite happy with-- let me try one thing real quick here. Let's just try to clean it. You're right. Why is it trying to do this now? I know. Because the demo gods hate us. Why is Finder hanging on me? Because the demo gods hate me. OK. Fine. So we'll go to slides. Yes.
So this is a power plant application, and the failure you were supposed to see was not the failure that we're going to address in three slides. - Go back, go back, go back, go back. This is the failure you're supposed to see. So what you'll notice here is we have a bunch of failures that are in Lstream. This is inside of Power Plant. This is not any of our code in the example. And so what we're going to have to do is now Chris can take, while I switch the new Power Plant stuff into place, Chris can go through the changes you'll have to make to Power Plant, which are really minor. OK. Back to the slides.
So the errors you saw up there the second time when we got the correct errors on the screen were some differences between the GCC compiler's interpretation of the power plant source code and the MetaWorks compiler's interpretation of the power plant source code, especially when it relates to how they use system headers. Since what we've done for you is migrate you from the MSL Mach O headers to the actual Apple standard library headers, there are a couple of library differences that make a difference when using Power Plant, and there's one thing where GCC interprets what you do differently. What we document in the transition book, which I'll tell you about later, and what you need to do to your Power Plant sources is you need to make four clean, compatible changes to your Power Plant sources, and then GCC can compile any Power Plant application. There are some changes to the LException class, which subclasses the system exception class, and the system exception class has throw specializers on its destructor and its what method. So you need to add those to the power plant LException class so that it will match the underlying system exception class.
There's a place in lgatabscontrolimp.cp where it uses multiple instances of a local declaration inside cases of a switch statement, and GCC doesn't like the way the code works there, and it requests that you move the local declaration outside the individual cases, so that's fairly easy to do. And in lstream.h, the streaming operators for long double and short double are already declared elsewhere in the Apple headers, so you get a multiple definition if they're redeclared in the power plant headers. So you need to just case those out. And usually we do a pound if not GNU C, then include those so that your PowerPlant sources can be compiled and built by CodeWarrior still, even when you're also building them with GCC. So this is pretty much all the source changes we have to do, and they're all in PowerPlant to make the appearance demo run. So what Scott's doing is he's actually switching over to a fixed version of Power Plant, and then he's going to rebuild. Which I have already done. And now he's rebuilt, and all of those compiler errors have gone away. And now he gets the errors we saw before, which are resource errors. At the bottom it says, "Error file resmerger.c failed to open source file -39." So if we can go back to the slides now.
Skip that and come back, because he says, we're going to see this later. So this is the error we're seeing now. There is a bug in the res merger tool, which if you ask it to generate data fork resource files and you provide heterogeneous input that's mixed data force and resource fork, resource files, it gets confused and fails. And we will fix that by Xcode 1.0 by Panther. But for now, if you're bringing a project in that has resource files and the fork in which the resource files originate is different from the fork in which you want the resource files to go and to build a Mac OS X package application, you generally want your resources to go in the data fork of the resource files in the resource folder. Then you're going to have to do some massaging of your resources in order to get them to build with Xcode. And what we did here was we basically took all the.rsrc and.ppob files both in the appearance demo itself and in Power Plant itself and we just derezzed them into.rs and brought them in. And that has some extra advantages because then the indexer in Xcode can search them and you can have them in text form and you can check them in more easily to Perforce or CVS which are not really resource fork aware. So what we've done here is we've We've moved all those.Rsrc files into.R files to get around the resource error. Now we're going to go back to get past the resource error. This time you can watch it build. So if you notice, really fast there, we did the resing. And so now it's going and merging the resources.
See, this is where we have the time to now talk. Right? And so you'll notice as we come in, just like Code Warrior, we have this little code column. So you can see the code, and you can sort by that while we're going on. We also provide these check marks to indicate what needs to be built. To the right of the code here, you'll notice we have errors and warnings on a per file basis. So this is a substantial amount of Code Warrior code, both the appearance demo itself and the entire power plant framework that's compiling without error in GCC with very few changes.
So our challenges so far have been get the header files right, and we've done that. Get the sources right, and we've done that. And get the resources right, and we've done that. And once we have all of the binaries in place, then the linker kicks in. And getting the linker right is the last phase before you have a running application and can debug. So now we're linking, and we will see-- - The build succeeded. - The build succeeded. But it lies. And it lies because we turned zero link on. Zero link defers link errors to execution time. So now if you try to run it, Thanks, and thanks. And then-- oh, no. Didn't run. It didn't run. Let's check the run log. So what you'll see is you'll see this unknown symbol, and then some bizarre name. Really what it comes down to is currently in the pre-release, when you use ZeroLink in your C++ application, you have to link against the standard C++ library. For the final release, we should be able to take care of this automatically. But for now, you're going to need to set this in other linker flags. So I'll take you through that right now.
If we go back here, what I can do is let's just bring up the standard build settings. We'll look for link. Oops, not link, link. Let's see. So I will be brave. One other thing you will have to do is usually you have to touch a file. There's a few dependency cases that we don't deal with in the preview.
Build succeeded again, and now we can run. And it launches. There you go. And lest you say, oh, but Scott, but Scott, this was built with Xcode. Oh, it must look different. Mm-hmm. You swapped the power plant. Yeah. So that's why I decided it's too good for my-- yeah. So-- Back to the slides. Back to the slides. Yes, back to the slides.
Just one clarification there. That actually didn't, what it was running into there did not have to do with the changes we made to Power Plant. It's with some other issues that we know about. Yeah. So in linking, the last step is that the importer maps your key target settings.
It tries to read as much as it can from your project builder project file and translate it into the linker flags that you need to set in your Xcode file. There are some things we need. Right now you need to include dash else std c++ in your linker flags. We'll take care of that for you in the 1.0 version.
An important thing is that often the importer, if you've built a Mach-O project and you've left.a files sitting around, the importer will bring in a lot of CodeWarrior.a files. And if those have been linked with the CodeWarrior linker, then the Apple Mach-O linker is not necessarily going to like them. So you need to throw out the.a files that have been imported. And if they're built by subprojects, then you need to re-add those into your project. So that's what I was talking about before. If you're building from the bottom up, you need to rewire all of the subsidiary parts back into your project as you built it. In the 1.0 version, we expect to have much better inter-target dependencies and inter-project dependencies. Do more of that for you automatically. But with the disks you have in hand, that work you need to do manually. And then the main thing is you notice that the first time we built it, it said build succeeded.
It linked. it tried to launch and then got a run failure. You're going to see that a lot if you have ZeroLink turned on. So what we recommend doing is, if you have a build succeed using ZeroLink, what we recommend you do is that you switch over to the deployment build style, which turns off ZeroLink, try building again, and then you'll see your real link errors. You want to know about those link errors because they are link errors. They're things that will happen at runtime, either early or late, depending upon what they are. But don't take build succeeded as everything's fixed. Always go to the deployment style and try a build there just to make sure it works.
Okay? Development and deployment styles are really, really powerful, and they'll make it a lot easier for you to work with multiple targets in Xcode than you've had it before in Code Warrior. Development and deployment styles, as Anders explained yesterday, are extra sets of flags that override other settings in your target. And what that lets you do is it lets you have a debug version, a profile version, a beta test version, and a final version of your application with the same target without having to have four separate targets. And what that means is if you need to change a target setting or if you need to add a file to a target, you don't need to change it in four separate places. You just change it in your one target, and then that is layered on top of by the four different build styles. It really makes it a lot easier to manage your target. So we recommend that instead of, you know, when we import your Code Warrior projects, we're going to import all of your targets even if there's a debug version and a production version. What we recommend you do is that you essentially delete the debug target from your Xcode project. Just use the production one and then set all of your debug settings in the development build style of the production target. And that way you'll only have one target to manage, much less complexity, and you'll have much better control over what you want in your debug targets. Thank you. Okay, we've talked about that. We've done that demo. Now let's talk a little bit more about the compiler. The compilers are different. The MWCC compiler comes from a long, long line of very good quality Metrowerks compilers.
They've been working on it for a long time. They've been keeping up with the standards. They've got really good C and C++ parsing and really good code generation. But it is a separate world from the GCC code stream, which has been worked on for a similarly long time by different people, sometimes with different objectives. And even though there are common standards that unite the two compilers, there are a lot of things the standard doesn't address, and there are a lot of places where both compilers are nonstandard that you will find when you bring your source code from one compiler to another. The first things you'll notice is that GCC philosophically opposed to pragmas, preferring you to do all of your control of code generation on the command line or in our case in the target settings. And since Code Warrior is very seldom used with the command line, they use pragmas for almost everything to control their code generation. So the major change you're going to need to make is things that that you used to express in pragmas in Code Warrior, you will have to translate when possible to per target or per file build settings in Xcode. Second thing is that the warnings are very different. Even people moving from Project Builder to Code Warrior, Project Builder to Xcode are going to note that GCC 3.3 is a lot more picky about throwing warnings for example, promotion of signed to unsigned integer in a parameter list. You're going to get a lot more warnings when you build your project. Now, what you could do is just turn off all warnings and get a much cleaner build. We don't recommend that. GCC's warnings are correct. They may be pedantic. They may be irritating, but they are correct. They're often things you need to look at in your code. And I've had more than one case recently of somebody saying, my code doesn't work. It breaks here when I do this.
And then when we go and turn warnings back on, we see that the compiler was complaining that you did this in your code, and we're just going to do the best we can, but it might not work at runtime, and of course it didn't. So ignore compiler warnings at your peril. They're really important. They really do mean something. And the third thing you'll notice is that if you do inlining in order to reduce your source code bulk but try to get some good optimization out of it, the inlining philosophies of the two compilers are different.
The Code Warrior compiler has inline thresholds by depth of repeated inline inclusion. The GCC compiler has its inlining threshold cut off by the bulk of the size of the inlined function. And you may need to adjust your parameters up or down to make sure that what you want to get inlined does get inlined, and what you don't want to get inlined because of code bloat falls outside the threshold.
There are some other differences, and these are a little more serious. If you've been using Code Warrior for a long time, you probably have put C++ code into.C files, because Code Warrior doesn't care. Now, GCC does care, and GCC in its native state will tell you if you use C++-isms, that is things that are specifically C++ and not just C99 extensions to C to make it look more like C++, it will warn you if you try to declare a class in a.c file. It will give an error if you try to declare a class in a.c file. Once again, you can cheat and turn on -x C++ and GCC will happily interpret all your.c files as C++, but the rest of Xcode, which doesn't get information on the compiler from which language semantics you used for which specific file may get confused. For example, the debugger applies debugging semantics to your source code based on its extension. And so if you have a class declared in a.c file, the debugger is not necessarily going to see that well or clearly. So I really recommend that if you have C++ file, C++ code, you change it to.cp files, and if you have just straight C code, you can leave that in.c files. That's probably the number one thing we see in projects moving over from Code Warrior is C++ code in C files. GCC differs where the standards are undefined. The order of calling C++ static initializers, especially if you're moving from CFM to Maco where the order of library initialization may also be different. If your code relies on a specific order of initialization of static initializers, there will probably be problems, and you'll need to work those out and debug those very carefully. You can have some fine-grained control over it by link order, but it's something that you need to expect is that your static initializers may not be called in the deterministic order you saw, mainly because Mako loads modules lazily and dynamically, whereas CFM did everything all up front. The second thing is that there is some disagreement on how you pass structs and unions that are packed into quantities smaller than four bytes. There are some differences there. Most of these differences are not clearly documented either in the Code Warrior documentation or the GCC documentation. You can join some of the Apple mailing lists or look on Usenet for either of the CodeWarrior groups, CodeWarrior.Mac or CompSysMacProgrammingCodeWarrior. Both of those have pretty long discussions of the differences between GCC and the CodeWarrior compiler in these respects. And finally, GCC uses the C and C++, in fact it supplies the C and C++ standard libraries with Mac OS X in both static and dynamic form, and Code Warrior supplies its own libraries, the Metrowerks Standard Libraries, or MSL, that go with the compiler and heretofore have been statically linked into your applications. When you move from Code Warrior to GCC, you are moving from the MSL Standard Libraries to the Apple Standard Libraries, and there are some big differences there you need to know about. The good news is that if you're building for Mac O, the MSL standard libraries are essentially a thin layer on the Apple standard libraries. So most of the behavior is the same except for a small layer of differences.
The other good news is that MSL has been supporting WChart and WString, wide character support in C and C++ for many years, but they couldn't supply it in their Maco libraries because it wasn't in the underlying Apple libraries as of Jaguar. It's now there in Panther, so if you have programs that have relied on WCHAR and WString support in MSL and you couldn't go to Mach-O because of that, you can do that now in Panther because that supports in the underlying library and it's taken advantage of by the MSL standard libraries. And this is a good implementation of WCHAR and WString. It's the Citrus project. It's been heavily tested in NetBSD. It's not something we invented ourself. It's really good code.
Another thing you'll run into is that Apple libraries tend to use the global namespace, not the STD namespace for many things. Many things that Metrowerks standard libraries put in the STD namespace. This may mean that you need to make some changes to your code if you're expecting things to be in the STD namespace. It may mean that you need to change some conflicts where things that you have in your code will conflict with things that are now in the global namespace that you expected to be safely partitioned in the STD namespace. If you're using the standard template libraries, Metrowerks STL has some very useful functions for debugging that you invoke if you set a macro. Setting that macro is innocent in Apple's STL. It does nothing. You lose that debugging capability, but it causes no harm.
And then Apple libraries don't have certain Metrowerks extensions that they've added over the years. For example, FS spec versions of the POSIX file system calls. Since we're an underlying UNIX operating system, we really do expect you to start using some of the underlying file calls or use Carbon. You know, use all Carbon or all UNIX and not necessarily this strange mix of making a POSIX call with an FS spec as your file reference.
We've added some compatibility features to make it easier to bring large quantities of code over from Code Warrior to GCC. One of them is we've added some pragma support, not a lot, but it's getting better. We've added MetroWorks-style inline assembly. If you happen to have the inline PowerPC assembler code, you can bring that in from your Code Warrior project to your Xcode project. We've brought several large projects over, one of them the Mac MAME video game environment, which is tens, hundreds of thousands of lines of inline assembly, and we compile that. So if you've got a lot of inline assembly, don't worry about bringing that over from Code Warrior. We can read it.
Now once you're in Xcode, you want to take advantage of the Xcode features. The reason to bring your project over is not because you're bored with Code Warrior, but because we've shown you some compelling things in Xcode, such as the zero link, the predictive compilation, the fix and continue, the debugging things I'll show you tomorrow that you really want to take advantage of. How do you turn those on? Well, it's really pretty simple. The prerequisites are you have to use native projects, which are done by default when you it in with the importer. If you're bringing in a project builder project, you have to upgrade your targets from Jam-based targets to native targets.
And to get most of these features, you have to move to the GCC 3.3 compiler, which you can use in the project settings dialog. Just change your compiler to system default or GCC 3.3. Once you're You move to the GCC style precompiled headers to get GCC's performance. If you don't move to the precompiled headers, the compiler is really slow. It's just as slow as turning off precompiled headers in Metrowerks.
The other thing is that using precompiled headers just from frameworks gets you a lot, but the more of your project headers you can precompile, the better. Really, the more headers you precompile, the faster it is. You can enable predictive compilation, and that means we will fire up the compiler in the background while you type, and that will really get you a speed benefit.
As I said the other day, when you include carbon-carbon.h in any source file, The headers that are brought in are three and a half megabytes of source. Now, most of you don't have anywhere near that in an individual C file. So the ratio of headers to source in a given compilation unit, it's huge. And the more of that we can do ahead of time, the faster the couple hundred, couple thousand lines of actual C, C++ we need to compile will go. So predictive compilation will really speed up your turnaround time by doing most of the work in the background while you're typing. Zero link speeds up your fix, build, link, relaunch cycle by not having to relink all of those modules that haven't changed. It's really a lot faster. I mean, it can cut a 30-second link down to 10 seconds. Okay.
Fix and continue can cut that down to zero seconds by actually not having to have you stop the application in the debugger, quit it, fix it, and relaunch it. If you can fix something without quitting, then that saves both the quit time and the relaunch time and all the time it takes to get back to that point in your program where you're doing your diagnostics. And then if you happen to have C++ projects and big C++ projects, distributed builds can really help you with your large world builds. It's not necessarily good for incremental compilations. It's not that great for C code because C is not computationally intensive to compile and sometimes the network transfer time will exceed that. But if you have big, big C++ files that take a long time for the compiler to work on, if you can send those out to multiple compilers in parallel, you see some quantum increases in your build time by turning on distributed builds.
Let me talk a little bit about packaging and localization, because it's the last thing you need to do. If you're bringing a project over, a Carbon project over to Xcode, you may also be making the transition from a two-fork resource-based file to a packaged file. Let me walk through a little bit of that.
When you package your target, you pick what you're going to be doing, an application, a plug-in, a shared library, a framework, a tool. In Xcode, you pick that up front. Right now, we don't have the capability to change the target style once you've built the target. So you need to know what you're doing up front, and it's kind of hard to change from a static library to a shared library. And right now, we don't have a capability of cloning targets. So just make sure to know what you're doing ahead of time. Most targets are packages.
Almost everything except a static link library and a Unix tool will not create a single file, but will create a folder with a bunch of files in it. And the trick in packaging is figuring out what files to put where in that package. Tech note 2015 explains all about the various package styles and what they are. If you don't know what I'm talking about, read that tech note first.
Xcode puts things where they belong in your package automatically. Right now it doesn't have a copy files build phase like Project Builder did that lets you do manual overrides. We will add that by the 1.0. But right now if you put a resource file, if you put a header file, if you put compiled code into your project, Xcode will put it into the right place in your package automatically because it knows the rules by which packages should be built. It takes all the target settings from the target settings and the project settings. It builds those into the info.plist file. It puts the info.plist file where it belongs. It really takes a lot of the manual effort out of that.
Working with resources. As I said, we read.R files and we read.RCRC files. We also will read PPoB files and merge them into your resources file. And we interact with resourcer, constructor, and interface builder. If you're localizing your resources, localizing resources in a packaged application is different than what you used to do in CFM. In CFM what you used to do was you'd have one two-fork file with all of your code and then the resources for one language, and then you'd produce another file with the same code and the resources for a different language, and then you'd produce another file with the same code and the resources for a third language. Well, the way you do it on Mac OS X is that you have one folder hierarchy called a package and it has one copy of the code over here and then it has different folders called.lproj folders for your different languages. And your resources, your nibs, your strings, anything language dependent goes in the.lproj folders. It's a different way of thinking. You deliver one binary that's multilingual rather than localizing your binaries. Mac OS X apps are multilingual by default and the way you make them multilingual is you take a file that has language dependent constructs in it like a strings file or a nib file or a resource file, you go to its inspector and you look at this thing called localization variance and you can add a locale and it makes a clone of that file that you then localize and then it puts each of those into the right lproj folder. So Xcode does this for you automatically. It will manage your hierarchy of localized versions. You can start with English and then localize from there.
Let me talk briefly about Interface Builder for Carbon. Eric did a great demo of the new stuff in Interface Builder. Interface Builder is the Aqua design tool, the Aqua design tool. And as we evolve Aqua for both Carbon and Cocoa, we evolve Interface Builder to give you access to those. And there's going to be more on Interface Builder and Carbon in the Building a Modern Mac Application session, which I'll tell you about later, but I just want to retouch on some of the things that Eric talked about. New in Interface Builder for Carbon is support for new Carbon controls like the HI image view, the HI search field, the HI scroll view, and the HI text view. You can drop these into your nib files directly from Interface Builder for your Carbon application.
We've also added the tiny controls if you're building very small pallets. We're going to start using these in the Panther version of Xcode because they're very, very useful for things like inspector panels where you want to pack a lot of buttons into a small space. These are now on the pallet for Interface Builder for your Carbon applications.
and new are control properties. This is static information that you can enter into Interface Builder that lives behind an object that when you load that object from the nib, these constants are already set in that object. So your APIs can query that object that it loaded from the nib and get these constant values from it. So if you want to parameterize things or if you want to preset titles or if you want to have alternates or anything your API wants to do with information that you would normally put in a resource fork, you can put them behind the objects in your nib file. And this is a very powerful thing that will give you back in nibs some of the things that you used to have in resources.
And finally, because we've changed the format of the nib file for Panther, there's some fairly strong nib file compatibility checking that you can do in Interface Builder itself that you can tell when you're building it whether you're using Panther-specific functions, whether you're using Jaguar-specific functions, and how backwards compatible your nib will be. So you can be careful about not accidentally constructing an application where all your your code might run fine on Jaguar, but it loads a nib that happens to exploit Panther's specific functionality, so your application will fail when it runs on Panther.
Okay, just about right on time, going to wrap up. Hope you've learned from this session that we've given a lot of thought in Xcode to your Carbon applications, especially bringing your Carbon applications over from where they exist now, which is most likely in CodeWarrior. We build C++ code really well. We adhere to the standards. We build it fast. We build good code. We build good applications that adhere to the Mac OS X standards.
We build packages. We use resources. We use NIBs. You're going to find that Xcode is the best way to build your Carbon applications on Mac OS X. There's a lot more you need to learn than just listening to my presentation. There's a lot of documentation in the Xcode tool package. There's a lot of documentation in the system overview. For the CVS and Perforce integration, you can go to the CVS and Perforce sites for those. The most important book to cover what I've been talking about today moving projects from Code Warrior to Project Builder. It's not on your distribution, but it's in your ADC account. Log into your ADC account and you can download it from the Downloads folder. You can also get hard copies of it down in our porting lab, which is -- it's called the Mac OS X Laboratory down on the second floor -- down on the first floor.
Integrating Carbon and Cocoa in your application is a really interesting book if you want to start learning how to take advantage of some of the Cocoa functions from your Carbon application. And then, of course, the definitive guide to the Mako runtime architecture and the GNU C, C++, Objective-C compiler.
If you're moving to Mako and GCC for the first time, those are going to be indispensable resources. Of course, there are Xcode interface builder release notes on the distribution you have. and there are some places to go for tech notes, tech Q&As, and sample code. They're all on the ADC homepage. page.
Godfried de Georgie is the champion for this technology. Contact him if you have questions. We have the development tools engineering feedback, which is at [email protected]. Please post bug reports. We want to make this a great Carbon development environment, and if there is something that we're being bonehead about or we've forgotten about in Carbon development, please let us know. We'll try to get it in by the 1-0. And look at the mailing lists on list.apple.com or the Usenet groups. I'm going to be living on CompSys Mac Programmer for the next few weeks, listening to what you have to say about it if you happen to be on Usenet. Here's some great sessions to go to. Feedback Forum 9 today, 2 o'clock. Let us know how we're doing. Debugging services for Mac OS X. This is the overview of Xcode and GDB. It's today at 3.30. That's not going to be a carbon-oriented session. That's going to be a GDB-oriented session. Debugging and tuning Carbon applications.
I'll be in the big room tomorrow morning, 9 o'clock, and we're going to show you some great debugging features for Carbon applications using Xcode. Software testing tools. There's some fun stuff going on there for automated testing of your Carbon application using Apple tools and using third-party applications. That's tomorrow at 10.30. And the session I was referring to before, how to write a modern Carbon application. If you've been using basically the same APIs resources for the past nine years and you don't know what NIBs are and you don't know what HIV is, there's a completely different way to write a great Carbon application and you should learn about that two o'clock tomorrow afternoon.