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

WWDC05 • Session 404

Moving to gcc 4.0

Development Tools • 45:51

Xcode 2's new compiler, gcc 4.0, offers great benefits such as faster compilation speeds, better code generation, and 64-bit support. We'll cover each of gcc 4.0's new capabilities in detail, in addition to talking about techniques for moving from gcc 3.3 (the default compiler in Panther). Learn how to take advantage of all gcc has to offer.

Speaker: Geoff Keating

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 afternoon. So, I'm Geoffrey Keating, and this talk is Moving to gcc 4.0, talk 404, session not found. So we have a new compiler. You've probably already noticed. gcc 4.0 shipped with TigerGM, and you have a slightly newer version on the DVDs that were handed out to you earlier.

So I'm going to talk a bit about it today. So I'm going to cover three basic topics. First, why should you move to 4.0? What new features or speed improvements or bug fixes are in 4.0 that might make you want to move? And of course, what new features might cause you to need to move, even if you're not particularly enthusiastic about it? We're also going to talk about some of the consequences of all of the improvements that we've made. Some of the new features are things that really might affect you, things that you might want to use, or things that maybe now you can take away some of the workarounds that you've been using before.

I'm also going to talk about bug fixes. We have a lot of bug fixes in gcc 4.0. It's a really incredibly stable compiler. But some of the bug fixes are things where the compiler was improperly accepting code that really it shouldn't have ever been accepting. And so I'm going to go through a bunch of those and show you how to fix your code if you've accidentally been using some of these cases.

The -- probably the most important reason why you might want to move to gcc 4.0 is because it is the only supported compiler for building Intel applications at present. There are going to be other compilers from third-party vendors, but this is Apple's compiler. Another reason why you might need to move to 4.0 is because it's required for building 64-bit executables. So Intel or 64-bit, if you need it, you have to use 4.0.

A reason that you might want to move to 4.0 is because it's faster. Gcc 4.0 is a noticeably quicker compiler than gcc 3.3. We've been continuing our program of speed improvements. You can see from the graphs there, it's between 15% faster and about 5%, depending on what kind of code you're using. So these are significant improvements. It's 15% is big enough to be noticeable. So if you move to 4.0, your productivity will improve a bit because of the faster turnaround times. And so that in itself is, you know, a reason to consider moving.

Gcc 4.0 also has slightly better code generation. We've completely rewritten many of the optimizers. In Xcode 2.0, shipped with Tiger, it was about the same speed as 3.3, right? And we've been continuing to improve it, and now it's slightly faster on a random industry standard benchmark that just happens to come in floating flavors.

Another big feature with 4.0 is the shared C++ runtime. It's available in Panther 10.3.9 with the software update and in Tiger and later. The big benefit of the shared C++ runtime is a significant reduction in application size, between 200K and a megabyte or so. This gives you faster app loading and faster switching between applications, which is a significant improvement to the user responsibility of your application.

It also, because there's now a single dynamic library, it means we can occasionally fix bugs in your operating system releases and automatically transfer those improvements to your application. And it also means we could do some things which were only possible when you had a single bunch of code managing the C++ runtime. In particular, we've improved correctness with streams. So now output from multiple dynamic libraries in your application gets interleaved properly.

So I said that was available only on 10.3.9 and later. So let's talk about what gcc 4.0 will actually build code for. You can see there the big target of gcc 4.0 is that you can use gcc 4.0 with the universal SDK to build Intel binaries. gcc 4.0 also supports 10.4 and 10.3.9, either using the Mac OS X deployment target method or using the SDKs.

And it also goes back to 10-- well, in theory to 10.0 for C and Objective-C. Once you go back to Jaguar, there's a few bugs that need workarounds and that kind of thing. We don't have C++ support for gcc 4.0 on early versions of Panther on Jaguar on Puma.

You can compare this to the other columns in the table, and you see that 3.3 doesn't support Intel binaries, and previous versions of the compiler are no longer really supported for using the new SDKs. They still continue to work fine when using SDKs for old versions of the operating system.

So another consequence of the switch over to the Dynamics C++ standard library is that you might notice when the first time you try to build your app with 4.0 is that a lot of the old templates used to include libs to C++.a directly as part of the list of Xcode libraries to link in.

This is no longer necessary and, in fact, no longer possible because a .a file is not a shared library. So you'll see it comes up in Xcode as red, meaning the file is no longer there, and so what you should simply do is just delete it. You don't need it anymore. The compiler will automatically link in the C++ standard library when you link C++ code.

Another big feature in gcc 4.0 is 128-bit long double. It gives you 53 extra bits of precision compared to the regular double precision floating point values. This is going to be part of the permanent API on PowerPC Mac OS, and the support functions are available in 10.3.9 and later.

Compilers before gcc 4.0 warned on every use of long double, so long as you didn't switch the warning off, you shouldn't have any instances of that in your code. So the switchover will be relatively transparent to you. Unfortunately, this is not the same as the Intel long double, which, although it's 128 bits on a Macintosh platform, is only really an 80-bit floating point value inside, and a completely different internal format. So you can't just copy structures and such between the two systems and have them work.

Another of the big improvements in GCC 4.0 is better CPU support. We have automatic vectorization starting to become useful for real applications. We have vectorized inline memory operations like memset and memcopy so that when you switch on, so that if you allow the compiler to use vector instructions, it'll automatically use vectorized versions of these when it inlines so you don't have to go back to scalar code for the inline versions. Obviously, if you use the out-of-line copies in the system, that'll work just fine, and that'll be vectorized just fine anyway because the system will have the latest versions.

In Xcode 2.0 in Panther, we added a nice UI so that you can create universal executables for each processor. So in previous talks, you'll have heard about how you can create a universal executable that has both PowerPC and Intel code on it. You don't have to just stop at one flavor of PowerPC.

You can have 64-bit PowerPC, you can have PowerPC that's 32-bit and tuned for g3, g4, or g5, and you can have Intel code all in the same binary. So that would give you what we call a five-way universal binary. That might be going a little bit too far, unless you have a really performance-critical application where it really matters that g5 and g4 are different.

You can access this support in Xcode 2.0 by finding the architecture build setting and double-clicking on it or clicking on edit. And that pops up this dialog box, which is not to scale. And so you can simply pick what architectures you want. Unfortunately, in Xcode 2.1, this support was simplified to make it easier to find the Intel settings. So in Xcode 2.1, the dialog box only offers PowerPC, which is 32-bit G3, and Intel support.

But you can still hit enter on the field and add the other targets by hand. So for instance, you can add PPC64 to build your program as a 64-bit executable. And you can add a range of other targets. You can add PPC970, meaning a G5, and so on.

And so you can simply add all five settings in there. And Xcode will automatically build your executable and tune it for each target individually. This lets you use autovectorization most efficiently. With autovectorization, the compiler really needs to be told that it's allowed to use all of the vector instructions. Otherwise, it can't autovectorize anything.

So what we recommend is that you do try to tell the compiler that the whole object file is only going to run on a g4 or only going to run on a g5, if that's what the case actually is. So if you have an object file that contains all of your AlteVec code and then the rest of your app calls into that but only on a g4, then tell the compiler that this file can run -- that it's allowed to use AlteVec instructions throughout that file.

We would prefer that you try not to switch on the Altevec intrinsics for files that are supposed to run on a g3. To do this, the compiler assumes that some of the code is obviously Altevec and therefore has to run on a g4, and then some of the code is not Altevec and therefore it mustn't have any Altevec instructions in it because it's running on a g3. And so the compiler has to disable some optimizations to do that. So it's better to try and separate your code so you have Altevec in one file and not Altevec or can run on a g3 in other files.

Another big advantage of this compiler is we have new and better warnings. Lots of them. Lots and lots of them. So we know there's a lot, but please read them. A lot of these warnings really are trying to point out problems in your code. So you should look at them and you should try and fix them if possible. Because there are so many new warnings, you may not be able to fix them all right away.

So if you have a W error, warnings as errors, in your build settings, you might want to consider temporarily removing it to get your program going with gcc 4.0. We have a new warning for Objective C that warns about strict selector matching. If at all possible, you should switch this on.

It catches a bunch of real bugs, and we're particularly highlighting it because a lot of the bugs are otherwise difficult to find in your program. You should also watch for warnings that say, if this code is reached, the program will abort. It means that your program really will abort when it reaches that code. So what you need to do is either remove the warning or check to see that the code is never executed.

While you're looking at your build settings, there are some really old flags that no longer do anything. So you might want to consider removing them. For instance, wno-precomp. We haven't had precomp support in the compiler since gcc 3.1, so you don't need to disable any warnings about it. Those warnings are long gone.

There are a collection of flags about coalescing. Coalescing is the internal linkage system that gcc uses to ensure that in a C++ application, the duplicate function definitions are removed. It's the default. It's been the default for quite some time now, and the flags to switch it on and off are -- the flags to switch it on are no longer necessary, and they have been removed.

Also, if you've been tweaking the optimization settings in your project, so for instance, you've been changing the inlining parameters, then you really want to revisit that for gcc 4.0. We've completely revised all the optimizers, so what these parameters mean now is no longer what they used to mean, and some of these parameters have been removed altogether. So you probably want to start by removing all of those settings and then adding them back in as you find performance problems with probably new settings.

So let's talk about Code Warrior Assembler because I know that's a topic that people really seem to like in gcc 3.3 especially if you have to move from Code Warrior to gcc 4.0 in a single jump. So we've improved the support a bit. We've improved it a bit, some in Xcode 2.0, and we've further improved it in Xcode 2.1. Gcc now better analyzes the instruction streams, so it knows which registers are used, it knows what instructions you're using, it has an idea of which registers are outputs and which registers are inputs. So a lot of bugs in that area have gone away.

The big Objective C++ improvement is that instance variables now run constructors. So, you can take all of those complex C++ types from the C++ standard library and put them inside your Objective C objects. So, this is a significant advance if you're using Objective C++ a lot. It does require you to switch on a new flag, which is named something almost intuitive. And unfortunately, because this requires the Objective C runtime to actually call the constructors, it requires support from it. And that support's only available in Tiger. So, you can use this immediately if you're only targeting Tiger or later. Otherwise, you'll have to wait until you can.

So we also made a bunch of improvements involving symbol visibility. First of all, the old syntax of private extern is still available. It actually works a bit better than it ever used to before. But the recommended syntax is that you use gcc standard attribute syntax. You get two choices, hidden, which means private extern, and default, which means not.

But we don't recommend that you go through and individually attach the hidden attribute to all of the things you don't want exported. Normally, from a management perspective, it's a lot easier if you make everything hidden by default and only make visible the things that you really expected to make visible. So there's a checkbox in Xcode, symbols hidden by default, a very intuitive name.

And then to make the things visible, you just add the attribute and you say the visibility is default. The big improvement that we've made is that this also now works on C++ classes. So when you have your framework that's exporting C++ classes to your application, you can use this to control which classes really get exported.

We also switched it on by default for applications because if the linker and the dynamic linker know that this symbol can't be exported, then it can use a faster calling sequence, which actually significantly improves your app's performance. This worked great except in two situations. If you have plug-ins that actually try to reference symbols from your application, then this isn't going to work if they're hidden.

And if you use dynamic cast between classes that are in the inner framework and also possibly defined in your application, they'll be treated as different classes and therefore it won't work right. So if you want to do that, you need to switch it off. And you can do this in Xcode. These two buttons here, and in particular the top one, symbols hidden by default, will be on by default for an application, so you just switch it off.

If you do that, you probably also want to make sure that the inline functions hidden checkbox is switched on. Unless you're actually comparing the address to the address of the function between a dial and your application, then it's much more efficient to have the functions -- to have inline functions be hidden. It means the linker can make a direct call to them instead of having to potentially look at a framework. You can find these two by typing hidden into the fairly large code generation set of compiler options.

I said earlier we fixed bugs. We fixed lots of bugs. We fixed maybe thousands of bugs. Most of these bugs you will never notice that they were fixed, or if you do, it's only as a relief that you can finally stop worrying about it. Some of the bugs, as I said before, are about code that was accepted before incorrectly, that should never have been accepted, and that now we've managed, and that now the compiler properly creates an error message for. So I'm going to run you through a bunch of examples.

Although this is not really a hands-on talk, we do have sample code for each of the examples, so you don't need to take notes for each example. You can get the sample code at the URL at the bottom, and you may -- and -- but you don't need to get it right now. We're going to be -- I'm going to be showing you them all on the screen.

So the first example that I'm going to talk about is the one that most people seem to hit. It's about dependent name lookup. So C++ has this concept when you're using templates of a dependent name. The different--a dependent name is something that in some way depends on a template parameter. So in this case, the template parameter is T. If a name is dependent on a template parameter, then the compiler can't--then the compiler can't and in fact mustn't look it up until the template is instantiated.

If it's not dependent, the compiler looks it up right away. Previous versions of the compiler didn't get this quite right. It would tend to delay looking up nearly everything until the template was instantiated. This meant that names which were not dependent would be--would sometimes be looked up in the wrong context. Gcc now gets this right.

In this example here, though, this is an example of some code that would have been accepted with 3.3 and that is no longer accepted, and you get an error message. As you can see there, class local was not declared in this scope. When that happens-- so the problem here is that class local is dependent-- is not explicitly dependent on the template parameter t.

and is not otherwise visible because it's only visible in this other class, "SomeClass," which itself is dependent, and therefore not part of the names that the compiler will look up. So what you have to do to fix this is you've got to make "classLocalBe" a dependent name. And at this point, you can probably forget most of that long explanation. All you really need to know is that when you get this error message, you need to insert this in front of the name. Nine times out of ten, that will fix your problem, and you don't need to think about it any further.

Along with the other template improvements, we've now-- gcc now properly checks for the presence or absence of the type name keyword. And in fact, it won't parse your class properly if you don't have it there. So it does give a helpful error message to basically tell you to use type name. And so you actually do need to do that.

And of course, you just add it in. Likewise, gcc needs proper use of the template keyword. When you have an example here of--when you have a case here of a template function inside a class--sorry, inside an expression like that, the C++ standard requires that you use the template keyword before the function to let the compiler know that the thing that is the template is the function and that this zero is not supposed to be attached to something else. And so, simply add it.

Let's see. So another case where the compiler is improved in C++ is that it's now better at detecting--it now properly implements the C++ rules for in-class initialization of static members. There are two rules that you need to be particularly aware of. First of all, you're only allowed to have a static constant member like this in a class with an initializer.

If the actual type is an integer type, as an extension, gcc allows floating point types. It does not allow pointers or other such -- or classes or anything like that. So what you need to do is, if you have code that does this, the compiler will tell you that you can't do that, and you need to take the initialization out of the class. So you simply remove the initializer from the class and then place it in the definition.

Another case where the compiler is improved is in the case of members which actually are integers. So here we have an int. You're allowed to do this. That's fine. However, this is not a definition of the variable. It just declares that the variable exists and that it's always going to have that value. So GCC has become better about optimizing.

And so now, sometimes you're going to see an error message from the linker saying that this variable is undefined. And it's actually right. You haven't provided a definition. So you need to make sure you provide one. And the syntax for that looks like this. You don't continue to add the initializer because you've already got one in the class. But you do need to mention it somewhere.

Another case where the compiler better adheres to this standard is in the case of access checking and copy constructors. So, let's see. So here we have a case where we have a private copy constructor for the class A. So whenever the compiler needs to make a temporary for a class and copy the old -- and copy some other copy of the class into it, it needs to use the copy constructor.

Making it private says that it's not allowed to do this, that there shouldn't be temporaries floating around that are generated by the compiler or by the user, that you want to in some way control the use of this class. So in this case here, we have a function which takes a reference to one of these classes, and it's being called with a newly created copy.

Iso C++ says that when this happens, an extra temporary is created. So first you get a copy created with the default constructor, then you get another temporary created, and that's what's actually passed-- that's what the reference is taken, and that's what the reference to is taken and is passed to the function.

The ISO C++ standard also says that you don't have to actually call the copy constructor. You can just use the one copy. But it says that if the copy constructor may not be called, then the compiler must not accept this code. Previously, gcc 3.3 was eliminating the extra copy and then also forgetting to check that the copy constructor could still have been called if it needed to. So gcc 4.0 no longer does this. It properly verifies that the copy constructor is visible.

So if you have code like this, what you need to do to fix it is to avoid the creation of the temporary copy to make sure that all of your copies are actually named. And that's easy enough to do. You simply have a variable, a named variable that's going to be the thing that's created, and you pass that to the function instead. That way there's only one copy of this class and the copy constructor need not be called.

Another thing that the ISO C++ standard says, which is a little pedantic, but it does say it, is that there is only one acceptable syntax for making a function an abstract virtual function. You say virtual int, and then you declare the function, and then you say equals 0.

Things that are not exactly the same as equals 0 are not acceptable substitutes. So you can't say 0 plus 0, and you can't say null. So gcc now correctly checks for this and will give you a convenient warning message saying it really expected to see a 0 there. And the answer is very simple. If it needs a 0 there, that's what you should put.

Another thing that is involved in the syntax of C++ that's a little bit more serious is that when you call new and you're creating a new array, The syntax of C++ doesn't permit you to put parentheses around the name of the class. If you do put parens around, that's actually trying to be a slightly different syntax where the placement new operator. So gcc 4.0 now correctly detects this case and doesn't let you do it. And the solution is very simple. Simply delete the parentheses, and then the compiler will be happy.

Another case where the compiler has become more strict about a C++ construct is default parameters. In C++, you're only allowed to declare a default parameter once. You can declare it -- ideally, you should declare it the first time you mention the function that has the parameter. That way it can be used later on. What you can't do is do it in both places.

So in this case here, we've got a function that has a default parameter, and it's got it twice. And ISO C++ says you can't do that. Once you've said that a function -- once you've given a default parameter once, afterwards, you need to simply just declare the parameter, and just declare that parameter, and the default will be taken from the previous time the function was seen.

Another place where gcc now more correctly interprets the standard in an important way is in reinterpret cast. The compiler used to allow a reinterpret cast that was a no operation. So if you had an int and you cast it again to an int, it would let that happen. C++ doesn't permit you to do this. It requires that a reinterpret cast actually do something. The thing that a reinterpret cast -- a cast that doesn't do anything is a static cast or a cast that casts between two integer types. So we now correctly check for that.

Finally, one more place the C++ compiler became more strict is in the use of the offsetof expression. Offsetof is supposed to be a constant. You can see in this example, which was accepted by gcc 3.3, that the actual offset is going to depend on this index parameter to the function, which is not really constant at all.

So gcc now correctly detects this case. To fix this, you need to actually make the computation of the index part yourself. So instead of putting the index inside the offsetof construct, you need to move it out and multiply it by the appropriate size to get the right value.

Um, so you've already ported your app to gcc 4.0 using xcode 2.0 that shipped with Tiger. And you're done, right? Well, we did make one change to xcode 2.1. It's a trivial change, and it shouldn't be much of a problem, but it is a small change. When you first declare something in a namespace, you're supposed to just use the name as a thing that you declare. You're not allowed to use the double colon operator.

So gcc now correctly checks for this as part of wider changes to interpret the colon colon operator properly, and now doesn't let you do it. And the solution to that is very simple. You're already in this namespace, you're declaring something in the namespace, you don't need to qualify it. You can just delete it. And that will make the error message go away.

So that was the C++ part of this talk done, almost. But we still have some KEXT issues to talk about. KEXT didn't change significantly in the compiler, but there are two things that you should know about. First of all, static local variables like this. You can see here we've got a variable named x inside a function. And it's of type class 1, and class 1 has a constructor. Not a particularly trivial constructor either, it actually does some computation. So in gcc 4.0, this constructor is now thread safe.

If you're doing this in an application, gcc will carefully lock around the first initialization of the variable x, make sure that x is only initialized once, and so on. In an app, this is great. In a KEXT, you probably don't want the compiler inserting random locks in the middle of your KEXT. The compiler can't really actually make the locks do the right thing inside the kernel, and it's really impossible for it to try. I mean, this could be in some interrupt routine, and it really can't lock or block or wait or do anything.

So for KEXTs, we didn't put in the runtime support for this. So you'll get two undefined symbols, cxa guard acquire and cxa guard release. What this means is you've got a static initializer, and the compiler would like to make it thread-safe but can't. So there's two possible solutions to this. One solution, simply move the static variable out so that it's no longer inside the function. Then it gets initialized at KEXT load time, and everything's fine because KEXT load time is single-threaded.

Another possible solution is that if you really know that this is safe and you don't want to move it out, you can use the no thread safe statics option, which is available as a checkbox in Xcode 2.1. Of course, if you do this, you do run the risk that you might have two threads going through the initialization, producing results which are at best indeterminate, so you want to make sure that it's really safe.

The other kext-related change involves member function pointers. Previously, the compiler would let you take the address of a member function, and you'd kind of get something very much like a real function pointer, but not quite. That wasn't working very well, so it was removed. So in this case here, we have--we're trying to pass an interrupt handler to a routine that will actually call it when the interrupt happens. And you can see we're taking the address of a member function. So in the new scheme, this is done with a macro.

The macro is called osMemberFunctionCast, and all you need to do is instead of--is--and it takes a pointer to member function. So--and it takes a pointer to member and returns a simple pointer to function. You do need to pass it the actual root--the object that you're taking--an example of an object that you're taking the address of the member function in. This is so it can find which virtual function out of a class hierarchy is the actual one to call--is the actual correct one to call.

So, that's the C++ stuff done. If you've been asleep waiting for me to talk about C, now is your time to wake up. There are a few simple C changes as well. First of all, local static function declarations. You used to be able to write code like this. And what we eventually worked out that gcc was doing when you did this was that it would be binding--it would look for some other function as a file scope static function.

This is not exactly the same as what happens if you have a static variable inside a function, so--and it caused some other problems, so this extension has now been removed. So if you have code that does this, you need to make a very simple change, which is instead of putting the static function declaration inside the function, just move it out. So this is now standard C and will work fine everywhere.

Another change that was made to better support interprocedural optimizations, in standard C, once you're not permitted to declare something extern and then later static. So GCC no longer permits this and will give you a helpful error message saying that you've done this. And there are two possible solutions to this again. One possible solution is to simply remove the previous external definition, so you just declare it static the first time. Another possible solution is to interchange the two. If you say static and later extern, then in standard C that means it's still static.

Another simple syntax change that we made is about labels at the end of a block. In standard C syntax, you're not allowed to have a label as the very last thing in a block. You have to have a label is always followed by a statement. If you don't have any particular statement to put there, there's a statement that does nothing, the null statement, which is just represented by a single semicolon, and that's what you should use.

Let's talk about L values. L values are things that are on the left-hand side of an assignment operator, thus the L. Previously, gcc had this fairly interesting extension where it would let you put all kinds of things on the left-hand side of an assignment operator. It would let you put casts, it would let you put conditional expressions, it would let you put comma expressions, and it would, in each of these cases, it would do something that mostly made sense. For instance, in the example of the conditional expression, it would pick one of the two and assign to it.

The problem with this is that in C++, this doesn't do what it used to do anymore. It doesn't guarantee that standard behavior continues to work the same way. In certain cases, temporaries wouldn't get created. In certain cases, the wrong overloaded function would be chosen. So we had to take it out. It's available in the current gcc 4.0 in C and I believe in C++ as a warning. In the future, it will go away completely. So now is a great time to fix this.

So the fix is always very simple. Instead of having full variables in these expressions on the left-hand side, simply take their address, do your conditional operation or your cast or your comma operation to the address, and then dereference it. So what that looks like is you add a bunch of ampersands and stars.

So as I said, gcc 4.0, we have a new optimization infrastructure using tree SSA. We think it's great. It's going to be -- in the future, it's going to lead us to significant improvements in performance. But because we rewrote everything, some things that were never -- are never really defined by the C standard or by the C language now no longer do what they used to do.

They're still not defined, and now they're not defined and they do something different. You don't really want to be having not defined behavior in your program. So in this case here is an example of a place where you might have accidentally done this. This is not -- gives undefined behavior because you're only allowed to reference a variable in -- between sequence points, which is a complicated term defined in the ISOC standard, to give it the same value.

So in this example, the question is, does the plus plus happen before or after the first I parameter is evaluated? Geoff Keating And the answer is, it's not defined. It can be either one. It can be -- it can even be both. So occasionally, your code's behavior may change if you have this.

The best way to find such cases is to switch on warnings. GCC will give you a very convenient warning. Operation on I might be undefined. When you say such a warning, it means you've done something like this. So what you want to do is you want to split this up into multiple statements so that the compiler knows what order things should be done in. So in this example here, you see that the code is not defined. You just want to move the I plus plus out to either before or pos -- to after or possibly before the call of the function.

Um, another case where the optimizers have now become smarter, and that might lead to different behavior in your code, is this case here. We have a variable named "x" that hasn't been declared volatile. We have a cast to make it to the address of the variable, with a typo on the slide, sorry. We have a cast of the address of the variable to make it volatile, but the compiler still knows that it can look through the cast and it can see the original variable is not volatile, so it knows that the original variable can't change behind its back.

So it will compile this code into an infinite loop, when what you probably wanted was for it to actually test "x" every time, so that you could say, "Change x in the debugger and let the program continue." The solution to this is very simple. If you need a variable to be volatile, just declare it as volatile originally, and then everything will just work.

The last change that we made is that, well, we changed the version number. The version number is 4.0. If you've been testing for different GCC version numbers, you might have accidentally been using a construct like this, where you check to see if the minor version number is greater than or equal to 1.

Well, so 4.0 is greater than 3, but .0 is not greater than 1. So if you were using a construct like this, it won't work. So be aware of this in your code. If you see anything like this, you need to change it to explicitly check that it's 3.1 or higher than .1 or higher than 3.

So, that's the end of the code examples, and remember they are all in the sample code, so you don't need to panic if you missed one in the middle, with an explanation that's even better than the one I just gave you. So we made a few minor changes as well. Framework header searching now actually searches for frameworks.

First of all, a framework is supposed to be an atomic unit. There's no such thing as an override framework or a delta framework or part of a framework. So when GCC finds a framework, it stops looking for files in that framework later on. So if you've been overriding system headers or system frameworks by copying one header file and then into a framework structure, your program will no longer work because it'll find that one header file no problems, but it won't find anything else in the framework. So you need to either copy the whole framework or use some other mechanism.

Another improvement that we made is that gcc no longer searches for frameworks in directory specified with -i, and it no longer searches for regular headers in frameworks specified with -f. So -i and -f are no longer the same thing. They now actually mean look for frameworks or look for headers. This helps to reduce the number of headers that are accidentally found, but it does mean that if you've been using them interchangeably, you need to now work out which ones hold which.

And there were some minor changes. So Objective C now properly detects selector matching. I mentioned the warning flag earlier, but there's also other detection involved that -- where it actually -- where the runtime behavior is improved. We made some changes about better detection of things that were supposed to be void and aren't, functions that were supposed to return void and that were actually trying to return a value, functions that were supposed to return a value and are actually returning void. Zero messages for these are all really straightforward and more or less paraphrase what's on the screen there.

So we should also mention that one of the significant changes in Xcode 2.1 is that it's based on final fsf gcc 4.0, which, as at the time the CDs were printed, was the latest gcc version -- the latest fsf gcc release that you could get. And we should also mention that it's a fully open source project.

The source code is available at the -- with all the other WWDC 2005 sources. And we should -- and if you want to make some small minor change that -- to your local copy, you can download the source and build it. Of course, we caution that we're not going to maintain your local change, so that's kind of your responsibility. So we caution against making significant changes and then trapping yourself into one version of the compiler.

So, in summary, move to gcc 4.0. Not only does it let you build Intel apps, build 64-bit apps, run faster, it also has thousands of bug fixes in it. It has better optimizations and it runs faster. So it's our best compiler yet. Geoff Keating You may have to adjust your code a little bit, but the changes--the long list that I've added, most of those problems are rare. There have been large projects built that have had none of these problems and that have just worked.

When you do find these problems, as you can see from the examples, many of these are really easy to fix. You just add a couple of characters. So--and hopefully you can remember some of those error messages and some of those situations and go back and look at the sample code. And with any luck, you'll get it. you'll be able to see what those few character changes are.

So at this point, I believe we have plenty of time for questions. Oh, but first, So if the presentation didn't fully answer your problems with gcc 4.0 or if you have further questions, first of all, don't forget the sample code. I know I've mentioned it three times already, but it's really very helpful.

That's available on the WDC website at the same URL as all the other sample code documentation and other resources. There's also the gcc 4.0 release notes. There's also information about the new C++ ABI and what you can rely on in that ABI. There's the gcc manual, which tells you all of these option names, what they exactly do, and a large number of other options that there's far too little time for me to talk about here. So that's all available at the website.

In addition, there are some related sessions that I should particularly mention. There is a lab, the Xcode and Tools lab. It's just across the way. All you have to do is walk across the corridor, and there will be people there who can help you. In addition, if none of that seems to help or you just want to tell us how wonderful the compiler is, there's the Development Tools Feedback Forum Friday at 5:00.

And finally, if all else fails, you can contact Matthew, who is not me. or anybody else in or we have or DTS in general, ADC in general, we have lots of people who are quite happy to help you to take your bug reports, to assist you with migration, to suggest strategies.