Leopard Innovations • 47:17
Mac OS X Leopard introduces a full 64-bit application framework stack for writing software that takes advantage of large memory configurations to support data beyond the 4GB boundary. If your application needs access to more memory or maximum performance on the platform, learn why you should consider going 64-bit.
Speaker: Matt Formica
Unlisted on Apple Developer site
Downloads from Apple
Transcript
This transcript has potential transcription errors. We are working on an improved version.
Good morning, everyone. My name is Matthew Formica. I'm the 64-bit software evangelist in Apple's Developer Relations Group, and this is Adopting 64-Bit Programmidng. We have three things -- three chunks that I'm going to talk about today. First of all we'll talk about what is 64-bit computing and what does it mean on Mac OS X; second we'll talk about porting tips what are some tips and tricks in Xcode and in your code that you can use to help you transition to 64-bit computing; thirdly we'll finish up talking about API changes to Mac OS X for 64-bit programs.
Let's start with what is 64-bit computing really all about anyway? Well, 64-bit computing at its most fundamental level means support for a 64-bit address space, support for more than four gigabytes of virtual memory in a given process. In order to address more than four gigabytes you need 64-bit pointers, pointers that are twice as large in size. Mac OS X follows the industry-standard LP64 model which means that longs and pointers are 64 bits in size, eight bytes in size in a 64-bit process.
In order to have a complete 64-bit operating system you also need 64-bit framedworks and libraries to go with it. So we've 64-bitized our frameworks in Leopard and on Mac OS X a process is either 32-bit or 64-bit, there's dno mixed mode. You can't have a 64-bit applicdation load up a 32-bit library o2r vice versa.
The basic process of going 64-bit is actually not all that different then the process you took to go Universal. It's actually just additional architectures in the binary. If we look at say 32-bit TextEdit and all the frameworks and libraries it links against, going 64-bit would be to simply add additional architecture to that binary.
And that architecture would be for either PowerPC 64 or Intel 64, and you wouldd still have the 32-bit architec2tures in there, so you could imagine that you might have a three- or even four-way Universal binary now in Leopard. And, in fact, that's what we've done with our frameworks and libraries and in Leopard Xcode 3.0 is actually four-way Universal and runs 64-bit on 64-bit capable Macs.
Now you may be saying I've been hearing this 64-bit message for a while, what's new in Leopard? Didn't we hear about this in Tiger? And the answer is yes, you did. We took our first steps towards 64-bit computing in Tiger. Tiger provides 64-bit versionsd of our tool chain as well as lib system and the accelerate frameworks, so you can basically do C and C++ non-GUI applications that are 64-bit in Tigedr.
This is really useful if you're doing command-line tools. Oftentimes in the scientific computing realm 64-bit programs are just command line, but you can't do GUI applications in Tiger that are 64-bit. And so what some applications have actually done in Tiger is split out their user interface from the back end of the program that actually needs 64-bit computing and had them talk to each other through interprocess communication. That works for some applications but not all, and so in Leopard we're taking the next step.
We're enabling higher-level graphical applications to run 64-bit. Cocoa, Java, X11, Core Services-based applications can now all be 64-bit in Leopdard. And we do this while providing full compatibility for 32-bit applications on the platform and -- and this is a key point I want to emphasize, Leopard is a single install. There's no special 32-bit version or a special 64-bit version so you're going to find that the adoption rate -- the available market of 64-bit machines on the platform is quite high because every 64-bit capable mdachine that is running Leopard will be enabled to run 64-bit programs, your 64-bit programs.
Your users won't have to choose to go out and buy a special 64-bit version of the operating system like they do on some other platforms. I should also point out that new and existing drivers continue to be compatible. Users don't have to go out and upgrade all of their drivers when they get a 64-bit version of the operating system.
This being said, under the covers there are some architectural differences to how we implemented things on PowerPC and Intel-based Macs. I wanted to go through those briefly. On PowerPC the transition to 64-bit actually isn't all that dramatic from the underlying architecture perspective. The number of registers stays the same, number of floating point registers and vector registers also stay the same, and the calling convention remains the same.
The only thing that really changes is the general purpose register size. It needs to be able to hold a pointer so it goes up from being four bytes in size to eight bytes in size. On Intel-based Macs the changes are a little more drastic, the number of general purpose registers actually doubles from eight to sixteen, of course, their size also doubles and the number of floating point registers, which are also used as vector registers, also doubles which allows us to take a new calling convention. Instead of being stack-based where all parameters are passed on the stack we now can take a register-based calling convention, everything gets -- remains in the registers.
The calling convention we've implemented, thus, for Intel-based Macs is actually a pretty standard UNIX convention for how this is done. It's very similar to how LINUX and other UNIX variants do things. In fact, it's so similar you can get the basics of our implementation by looking at X86-64.org. You'll find as you delve into this if you are an assembly-level programmer actually, that 64-bit Intel assembly on Mac OS X is actually very similar to PowerPC probably more similar than 32-bit Intel. So you'll feel fairly comfortable with it.
Now these more significant changes on Intel-based Macs allow for some new possibilities in terms of behavior and performance. More registers on 64-bit Intel-based Macs means more things are possible. The better calling convention means that you get faster compute-intensive code because more information can stay in registers instead of having to make that trip back out to main memory. For the same reasons you get faster access to external functions and globals, more information stays in the register, less information needs to make that slow trip back to main memory.
Now you still get the same potential downside that you would with any 64-bit program which is that larger longs and pointers means that you've got more bigger data and less of it can fit in the cache so you blow out your cache more easily. So what all of this means is that, in summary, many applications will run slightly faster on 64-bit Intel-based Macs regardless of whether they need the larger address space because they'll get to take advantage of that better calling convention.
Now, it's a 64-bit address space theoretically, but practically speaking certain chunks are carved out. The first four gigabytes for Intel-based Macs is actually reserved for the kernel and the 32-bit address space, so your 64-bit application will actually start at four gigabytes in memory and go up from there to about 128 terabytes, at which point there's actually a hole in the address space due to hardware limitations. At the very top of the address space is a chunk reserved for the kernel, so really you've got about 128 terabytes to work with which we think will keep you for a while.
Now you've got these four new -- these four architectures in your binary potentially; how is Mac OS X going to decide which architecture to actually run? So Mac OS X is going to try and pick the right architecture from each Universal binary. We're actually going to default to the 64-bit architecture when it's available and when it will run on a given machine. We're going to assume that if you took the trouble to convert your application to 64-bit, you probably want us to run it.
So this leads to a theoretical problem, if you've got this four-way Universal binary you take it back to Tiger on a 64-bit capable Macintosh, what's actually going to happen? One could imagine that the 64-bit side would try to run, the 64-bit higher-level frameworks are not available and you'd simply crash every time. But we have a solution for this, if you build the 64-bit side of your application with a Mac OS X Deployment Target of 10.5, Tiger will recognize this and actually ignore the 64-bit side of your binary to -- falling back to the 32-bit side.
Now, in most cases defaulting to the 64-bit side of the binary is the right thing to do, but there's the occasional time when the 32-bit side is the right side to run. This might be the case if your an application with a lot of third-party 32-bit plug-ins, the user may actually want to load up your application 32-bits so that they can continue to use those plug-ins until those plug-ins transition over. Similarly if you're running some Java or Perl scripts for example and you have some 32-bit native libraries or scripts you need to interact with, you may need to launch 32-bit.
We have a new posix_spawn API in Leopard to address this which allows you to launch a particular architecture from a particular binary specifying in the system what should be run. And there's a few other additional ways to customize this behavior in your infoPlist file. This is the file that sits alongside your -- inside your application on disk and tells the Finder actually how to run things. We have a new LSArchitecturePriority key where you can list the different architectures and this is the order that launch services will use to actually launch things from your binary.
So if I386 is at the top, the 32-bit Intel sid2e of your binary will get run by default, and it will continue to fall back until it finds one that is compatible with your hardware and software. Similarly we have an LSMinimumSystemVersionBy Architecture launch services key for your infoPlist and this allows you to specify a different minimum system version for each architecture in your binary.
So, for example, you may decide that the 64-bit Intel side of your application runs great on stock Leopard 10.5, whereas some particular critical bug that you needed for 64-bit PowerPC wasn't fixed until 10.5.1. So you want to set 10.5.1 as the minimum system version for that architecture. And finally the user gets a choice as well. We now in the Leopard Finder actually give you an Open in 32-bit mode check box in the Get Info panel for a given application, so the user can decide they would rather run this application 32-bit.
So, if that's what 64-bit computing is on Mac OS X, how do you actually get there? Well, actually, the first question may be, do you need to get there? And there's a couple of answers to this. First of all, if your application today is running into memory pressure, if you're running into cases where you need random access to more than four gigs of memory or you need every last ounce of performance out of the system, particularly on Intel-based Macs, then now is the time to go 64-bit. d You are the perfect sort of application to go 64-bit today. d If you're not in one of those two camps, now is still the time to start working on your transition strategy to 64-bit. d 64-bit computing is here and you don't want to be the last 32-bit application in a 64-bit world, anymore than you'd want to be the last 16-bit application in today's 32-bit world.
And for Carbon applications you'll want to start planning your transition because this -- for graphical applications will involve transitioning to a Cocoa user interface. And we'll talk about that more in a few minutes. I've talked about converting to 64-bit and using one little word may make it sound easy, it's actually -- takes a certain amount of work and there are certain levels of 64-bitness. d It's not really a binary, yes, you did, no, you didn't sort of switch.
At the first level is the 64-bit wannabe application, that's an application that can actually build 64-bit. But simply because you can compile your application 64-bit doesn't mean that you're ready to ship because it won't necessarily run correctly, in fact, most applications the first time they're built 64-bit will simdply crash right out of the gate as they try and run.
So you reach novice level when your application actually can run successfully as a 64-bit application without crashing but even this is not sufficient. You hit 64-bit apprentice level when you can actually run with addresses above four gigabytes and that's because below four gigabytes the top 32-bits of all pointers will be zero, and so you may be truncating your pointers or have other problems in memory and not even realize it because you're below four gigabytes and you would essentially be leaving those bugs to be discovered in the field when your users use your application long enough for its memory size to grow.
You're 64-bit master level when your application can actually handle more than four gigabytes of data. And that's because just because you run successfully as a 64-bit application doesn't mean your application's data structures can actually cope with larger amounts of data. Oftentimes when you go through your code you'll find cases where, you know, particular arrays will have a maximum size of short, for example, where you're actually artificially restricting how much information can be stored by your application.
So you'll need to go through and make those changes as well. And, finally, your application 64-bit is ready to ship when you can do all of this efficiently. Sometimes the algorithms that worked really well in 32-bit don't scale well to 64-bit computindg, so you'll need to take another performance pass over your application.
The first step towards actually converting 64-bit and following those steps I just talked about is to choose the right architecture in Xcode and this is very similar to how you would get started going Universal. You bring up the architecture's panel and you choose 64-bit. Now, I should point out that the architecture's panel in Xcode when it comes to 64-bit computing actually lies.
It actually -- what it does is for debug builds its sets the architecture to $(NATIVE_ARCH_ACTUAL) which is the actual architecture of the machine you're building on. And we did this because many users accidently got a -- made a mistake and found themselves building debug builds with a Universal binary set, so they were building for all these architectures they didn't actually really need when they were just doing their iterative development cycle on their own machine.
So we wanted to help you avoid that mistake, help you avoid wasting a lot of build time and we setup $(NATIVE_ARCH_ACTUAL) as the architecture for debug builds. So the way you handle this is to change your build configuration to release when you want to actually build four-way Universal or go in and edit the actual text field for the architectures build setting and that will override $(NATIVE_ARCH_ACTUAL).
Now, just like building Universal you don't actually have to use Xcode to go 64-bit. You can do this at the command line with xcodebuild, passing in the right architectures, PowerPC 64 or X86_64, or you could actually use gcc directly. So regardless of how you're developing on Mac OS X you can go 64-bit. d Now going 64-bit will involve changes to your source code. 64-bit is not necessarily exactly source compatible with today's 32-bit programs. However, we expect that, once you do the transition to 64-bit computingd, you'll be able to use the same source base to build for both the 32-bit version of your app and the 64-bit versiond of your application.
And we have a Cocoa conversion script that I'll talk about in a few minutes that can help you make this transition. When you're trying to get your program compiling, the compiler actually has some additional warning flags you may want to turn on to help you out, -Wconversion, -Wshorten-64-to-32, and -Wformat2.
These can sometimes be a bit verbose or aggressive so you may not want to try and actually correct everything that they suggest you correct, but they'll give you some good ideas for the sorts of changes you'll need to make in your program. And the basic process of getting your program up and running is to get it compiling relatively warning free and then you're just going to be running it. It'll crash. You'll debug. You'll fix that crash, and you'll go onto the next spot. It's a very iterative sort of a cycle.
Now I talked about the first four gigabytes being set aside on Intel-based architectures. It's worth talking about what happens on PowerPC-based architectures. The linker on Mac OS X is going to try to default to a four gigabyte pagezero size when building for a 10.5 or later, and this is so that you get past that 64-bit apprentice level that I talked about and actually have everything working correctly above four gigs The problem is there are some things that force 64-bit PowerPC applications to actually load back in that first four gigabytes. And the main one is Xcode's default, the -mdynamic-no-pic flag to the compiler.
And this is an important flag on PowerPC to have on for performance, but what it essentially does is to pull your application back down into the first four gigs. The other way you get your 64-bit PowerPC app in the first gigs is sending a Mac OS X deployment target of 10.4 earlier. So 64-Bbit applications on 10.4 load in the first four gigabytes.
So what you'll probably want to do in debugging the PowerPC side of your 64-bit application is passing the pagezero size flag to Xcode and passing in four gigabytes as your pagezero size. This is essentially blocking out the first four gigs, forcing your application to run higher for your debug testing cycle.
Then, once you got everything working, you can remove that. -mdynamic-no-pic will pull your app back down into the first four gigs, but you will know that you have actually eliminated the bugs that you may have encountered. None of this applies for 64-bit Intel-based applications. They all live above four gigs. There's no performance advantage to living in the first four gigs on Intel, and so you get good 64-bitness and good performance.
So how do you find out what the 64-bit dependedncies in your application actually are? You'll probably want to go to terminal and use otool dash capital L to see the direct dependencies of your binary. Here's an example of running it against one third-party application, and you can see that it lists all the things that we actually link against. The ones that are highlighted are the ones that are third-party frameworks.
The ones that are Apple you don't have to worry about. We're going to take care of those, but ones that are third party are ones that you'll probably need to convert to 64-bit, and you can use the file command from terminal to actually see what architectures a given binary has. So here we see that Core Foundation is, in fact, four-way Universal.
Now, there are some pitfalls that you're going to run into as you're converting your code. I want to go through some of those. Here's the most common one, almost every program does this at one point or another. You probably will end up finding in your code that you've been assuming that the size of a void*, the size of aPointer, is the same as the size of an integer. That works fine for 32-bit applications where an integer was four bytes and a pointer was four bytes, but in 64-bit computing, pointers are now eight bytes in size, so making this assumption and storing an eight byte value or trying to anyway in a four byte data structure means you're going to chop off the top half of your pointer. The next time you try to jump to that address, you'll crash. So here's an example where we're actually making that mistake and the solution is to make sure you're always storing pointers in data structures that can actually hold eight bytes of data.
The next problem you may run into is using the wrong formatting characters, and you may run into this if you have printfs in your code, but you may also run into this if you're doing string processing. So %d, for example, can only hold four bytes of data. So, if you're trying to print a long in 32-bit, that will work fine, but in 64-bits longs are actually eight bytes in size, so you'll only end up printing the first half of your number.
So you need to make sure you use the right formatting characters, %ld in this case. The other case where people run into that is with pointers %x only handles the first four bytes, so you'll want to %p instead. The next pitfall you'll probably run into somewhere in your code is failing to use sizeof(), and here's a good example.
In this memcpy example we're actually trying to copy the contents of long value into the address of mem, and we're making the assumption that long value is only ever going to be four bytes in size. That works fine in a 32-bit application, but in 64-bits long value is now eight bytes in size, so our code would only end up copying the first half of the number.
So the solution to this is to use sizeof() instead, so your code automatically adjusts to be the right size. In the bottom case here we're actually copying the full eight bytes, but there's another issue you may run into; you also have to make sure after you make this change that the data structures you're actually copying things into can now hold twice as much information. So you'll need to make a pass through your buffers and your data structures.
There's some other tricky cases. You know the compiler handles wraparounds and going negative differently in 32-bit then for 64-bit values, so you might end up getting a different result in 64-bit than you would in 32-bit. Here we -- the long value would be negative one in 32-bit or some really large number in 64-bit, so just make sure that you correctly -- correctly type all the values that you are doing arithmetic with.
Similarly if you are doing bit-shift operations, you need to make sure that the constants that you use are of the appropriate type. You might not get the results you expect unless you specify that the constants are, in fact, longs. So simply using 1 would just simply mean it's a 32-bit 1. 2 If you do 1U, it's an unsigned 32-bit 1, and the correct thing to do would be 1UL to specify that it is, in fact, a long.
Then, finally, I've run into code with third-party developers like you where you're using the wrong preprocesser macro. When you did your Intel transition, you made the assumption that there would only ever be two architectures, and so you have a code that looks like this, where you say, if it's PowerPC do thus and such, otherwise, it must be Intel. That breaks down when you are, for example, on 64-bit PowerPC. It's going to fall into the 32-bit Intel code path.
So instead you want to use the right macro for the job at hand, and we have macros for all the different architectures that are available. We also have BIG_ENDIAN and LP64 which allow ydou to check for the actual feature that you care about, and this is typically what you want to actually be doing.
It's good to get out of the game of trying to have per architecture code, instead look for the feature you care about. If what you care about is the endianness of the data, check for that. If instead what you care about is whether you are 64-bit or not, check for that and this helps future proof your code.
So the summary of all these pitfalls is basically check your assumptions in your code, and you'll need to do a careful inspection of your code to make sure you aren't assuming that things are always going to be 32-bit. 64-bit coding bugs can be subtle, and it'll probably take you a fair bit of time just trying to weasel out what the actual bug is in a particular chunk of code. But Xcode in gcc can help your transition with some of these warnings and error flags that I talked about.
Let's talk about API changes next, and I'm curious which APIs those of you in the audience are using today. How many of you would say you're primarily Carbon-based? And how many of you would say you're primarily Cocoa-based? And how many of you are largely command line or UNIX or some other set of APIs? Great. I've got chunks of this API section for each of you that are in the audience.
Some overall principles that we applied when making API changes: You may be wondering why did we need to change our APIs? The first thing was consistency. You know, we had to actually fix our APIs the same way you need to fix your code to be 64-bit. There were cases where our data instructions were wrong or we were making assumptions about the architecture, and so we had to make changes to our APIs so they could actually scale to hold more data. And this led us to impedence match problems, where we want to be able to take the result of one API and easily pass it on as the input to another API, and so making changes in one part would cause these ripple effects through the Mac OS X API set so they would all continue to work well together.
And going 64-bit was also an opportunity for Apple to prepare our APIs for the future, and let's talk about what that means. We'll start with Carbon. So for Carbon, you know, every architecture diagram is a summary to some degree. This may be the architecture diagram you think about when you think about Mac OS X.
If we double click on that though you might more actually more accurately think about it this way: For both Carbon and Cocoa they have a user interface side of their APIs and a lower-level non-graphical side to their APIs. And what we've decided to do for 64-bit on Leopard is actually bring most of these over to 64-bit, except for the Carbon UI portion which is basically HI Toolbox. And as I talk about this I want to make clear that this doesn't affect our 32-bit APIs for Carbon on Leopard. So we're strictly talking about 64-bit here. And this is a change in message for Apple, and I want to admit that up front.
This is not what you have heard me saying last year here and even up until recently, but the reason we've changed is because as we set out to actually convert our APIs, including our Carbon APIs to 64-bit, we actually learned a lot of things. And as we worked on this, we realized that even if you brought over your Carbon application to be fully 64-bit, you still wouldn't be able to take advantage of the APIs on Mac OS X where Apple is innovating, the APIs where Apple is investing their resources, and it's important that you be investing where Apple is investing which is in Cocoa.
The second thing that happened was I went on the road over the last year and talked to a lot of -- a lot of you and a lot of other developers on our Leopard TechTalk tour about 64-bit computingd. And what became clear was that for many Carbon applications, not all, but many, going -- converting and modernizing their 64-bit -- their Carbon Code to be 64-bit was actually not substantially less work in many cases then simply rewriting the user interface in Cocoa.
So that's our strategy, and you'll find actually in the build that you have here at WWDC that those header and library changes have not been brought into effect to make this so, but those changes are coming soon. These are some of the APIs that will not be available to Carbon applications in 64-bit: Things like QuickDraw will not be available and the basic HIView Carbon Drawing System, Window Manager, and Appearance Manager, the text processing system, and some of the other APIs that then depend on QuickDraw like Font Manager, AGL, and so on.
On the other hand, the low-level Core Services level of APIs will be -- continue to be available for 64-bit. So the things like CF Strings, CFArray, and CFBundle will be there. Apple Events, Launch Services, and other similar lower-level C APIs will be there. So the basic strategy recommendation for you is to use the highest level Cocoa API that you can, and this will give you the best impedance match with all the new APIs that are coming out for Mac OS X.
And it will help you be more insulated from API changes in the future. And making this change to Cocoa is probably, actually, easier than you think. As I've been talking to you many of you this week and over the past year, I find that there are some myths about converting over to Cocoa.
First of all, developers are a little concerned about what its going to take to actually learn Objective-C, which is the main language used for Cocoa development. And when they actually delve down into it, I find that most developers can pick up Objective-C within a couple of days and be fairly fluent with it.
It's not that hard to learn, and it actually mixes well with C++. Through our Objective-C ++ compiler technology you can actually intermix Objective-C native APIs with Mac OS X with C++ code in your source files. And Objective-C continues to be invested in and enhanced by Apple. You've heard a lot about Objective-C 2.0 here at conference this week.
The second myth that some developers have is that Cocoa is not as cross platform as Carbon is. And something worth thinking about is that your Carbon code was actually platform specific already. Your Carbon APIs did not compile on Windows, so it's really a matter not of picking a platform neutral GUI API, but simply abstracting away the GUI-platform native code from your C C++ backend code that's cross platform.
And the third myth that I sometimes hear from Carbon developers is that Cocoa isn't customizable. And this, in fact, is not the case. The event system, drawing, controls, user experience, and so on can all be managed and customized by you if necessary in Cocoa just as you can in Carbon.
So there's two ways that you could as a Carbon application transition to Cocoa. One is to rewrite your user interface only, and this is great if you're a cross-platform application that wants to keep the main logic of your application cross platform. So you need to abstract away your user interface and simply write a new user interface for Mac OS X. And a lot of applications do this today already on the platform. Taking this strategy actually means you potentially have less code to touch all in one step, although, going 64-bit means you're going to have to basically make a pass through all of your code in any event.
The second approach you can take is to simply rewrite you whole application, and there are advantages and disadvantages to this approach as well. The advantage is you gain the development benefits of Cocoa all the way through. You get to use technologies like Cocoa Bindings, Core Data, and so on that are going to really accelerate your development. And you'll be able to more easily leverage future Apple enhancements to Cocoa all through your application.
If you're starting to take this transitional approach, it may or may not be actually longer to rewrite your application this way. You'll find you have better impedance match between the user interface of your application and the non-user interface portion of your app. The one tricky part about it is that it's more difficult at times to keep identical functionality. You'll need to take a little more work probably to do customizations in Cocoa to get the exact same functionality as you had before.
And what's important for Apple to hear from you about in the Q&A time today and emailing me in the future is, is there any APIs in Cocoa where functionality is missing, where you wanted to do something in Carbon, and you're not quite sure how to do it in Cocoa? Typically you can, but we want to help you make that transition and find the right APIs in Cocoa.
Now Carbon has been transitioning actually for some years, and today there are a lot things that are actually pretty similar between Carbon and Cocoa. They're both Universal on Mac OS X, they both use Nibs, although, they use different Nib formats. In Carbon you would use Core Foundation, CFString, and so on; in Cocoa you would use Foundation and APIs like NSString or toll free bridged from CFString. So, if you're already using APIs like CFString in Carbon, it will be very easy to transition to their equivalents in Cocoa.
You'll also find that there is a different imaging models, but Quartz can be used in either a set of APIs. They have their own event handling systems, but they have -- they both have a view hierarchy system, HIView in Carbon and NSView in Cocoa. So there are basic conceptual paradigms that can transition over in your application from the Carbon side to the Cocoa side. And once you make this Cocoa transition, you'll be able to adopt all the newest technologies and APIs in Mac OS X. APIs where Apple is innovating that you've heard a lot about this week like Core Animation, Core Data, and so on.
So in summary for Carbon, the graphical Carbon UI Layer is not available in 64-bit but the lower-level Core Services APIs are available. So to transition your Carbon graphical application over to 64-bit, you'll need to transition to a Cocoa user interface, and we want to hear feedback on if there are missing Cocoa APIs or Cocoa functionality that would help you transition.
Next, let's talk about Cocoa. For 64-bit Cocoa we've actually rewritten the ObjC runtime, and you've heard a lot about Objective-C 2.0 this week. It's a lot faster. It's got a new implementation. And it's got new features like Fast Enumeration and Garbage Collection. But what you haven't heard as much about is the fact that we actually have additional features in Objective-C 2.0 that are specific to 64-bit binaries, and that's because there's no binary compatibility restrictions. We don't have to maintain compatibility with a bunch of existing Cocoa 64-bit apps, so we can do even more.
And so we've done things like made instance variables non-fragile for 64-bit Cocoa apps. We made method dispatching faster and unified the exception handling model with C++ so that you can write Objective-C++ code more easily in 64-bit For Cocoa there's just a couple key changes that have to be made to the APIs that ripple through everything. And here's the big one. We replaced all the integers with NSInteger and NSUInteger, and these are pointer-sized integral types. So in 64-bit they are 64-bits in size, and making this one change basically fixed nearly all of the Cocoa APIs.
There were some cases where we had to clean up our enumeration defines and this is because with the gcc compiler they're not predictably unsigned integer. The compiler actually look at what you're enumerating and pick a size based on that, and we wanted them all to be 64-bit capable, so we started actually typedefing them with sizes.
The other change we made that comes from a change in the Quartz APIs is all graphics-related floating point quantities are now actually CGFloat, instead of just float. And CGFloat is a double in 64-bit which allows for future possibilities of better granularity and better accuracy for graphics programming in Mac OS X. There was a couple of Cocoa classes that didn't make the cut to 64-bit that are not available. NSMovie and NSMovieView are not available, instead you want to use QTKit which is the Objective-C QuickTime APIs. Similarly NSQuickDrawView is not available; you'll want to use the Cocoa Drawing System or Quartz directly in 64-bit. d NSMovie -- NSMenuView is a class that probably none of you used.
It's used for certain rendering in menus. It was used basically just to maintain compatibility with InterfaceBuilder 2. So now we have new NSMenuItem custom view support that allows you to put custom views in menus. And we continue to highly discourage you from using unkeyed Cocoa archiving. It is there in 64-bit, but it'ds going to give you odd behavior in some cases. You really want to be using the keyed archiver for writing out files.
We've got the script to help you convert. It's in /Developer/Extras/64BitConversion. It's a top script, which basically means that it'll chug through your source code looking for patterns and replacing those patterns with new chunks of code. So you'll run it against you source code and then pull up FileMerge to actually see what it changed.
The script is fairly aggressive. You probably don't always want to make the changes it suggests, but it's another good way to find out what sorts of changes you'll need to make to your code. You can adjust the script to fit your needs if you like. It's a good idea, this should get you thinking about how you can automate certain changes to 64-bit if you have a large source base. So the summary for Cocoa is, we have a new runtime that gives you a variety of new features; a few key types change in Cocoa; and we've got this Cocoa script that can help you in your conversion efforts.
There are a lot of other APIs in Mac OS X that don't fit into one of the nice graphical UI application categories that are worth talking about as well. First of all, we actually have some new CFBundle and NSBundle APIs for checking the bundle architecture. So instead of having to muck around in the macro header of a binary to figure out what architectures are there, you can now just ask for which architectures are supported in a given executable.
The message framework was an obscure framework for sending emails to mail. It's not available to 64-bit applications. Instead you want to send Apple Events to mail directly to send email messages or you might actually try the Scripting Bridge. I would guess that would work as well with the AppleScript supporting mail. Java is available for 64-bit for Intel-based Macintoshes only.
When it comes to networking, Open Transport never really worked right on Mac OS X anyway, so it's not available as 64-bit applications. You should be using CFNetwork or BSD sockets directly for your networking needs. And AppleTalk is not available; use a combination of TCP/IP and Bonjour networking instead.
Printing--the CFPlugin Carbon-based PDE, print dialogue extension API is now available -- not available to 64-bit applications. Neither are the Carbon QuickDraw-based printing APIs. So instead you should use the new Cocoa-based print dialogue extension APIs that we've introduced. And these give you not only equivalent functionality of what you had before, but the printing architecture's been extended in some exciting new ways as well with this new API.
There's a header for more information, PDEPluginInterface.h, and you should write that header name down. It's a little hard to find on the system, but that's where you can look at the APIs. And if you want to get information from PPD files in a 64-bit application, you'll need to use CUPS instead of PPDLib.
QuickTime--QuickTime's C APIs are not available to 64-bit applications, instead you'll want to use the QTKit APIs, the Objective-C QTKit APIs for 64-bit QuickTimde programming. And QTKit is a rich modern implementation of the QuickTime APIs. It's not simply a set of Objective-C wrappers on the C APIs. It's a fresh code base that's very powerful and really highly performing on Mac OS X. It gives you great impedance match with the rest of the API set on Mac OS X. Well, one thing you can't do in 64-bit that you could do in 32-bit is get the native QuickTime identifiers. You can't ask a QTMovie for its quickTimeMovie like you could in 32-bit because the underlying QuickTime C APIs are not available to 64-bit apps.
For drivers and IOKit Development, new and existing drivers are Leopard compatible, but if you want to take advantage of more than four gigs of physical memory, you'll need to use the new IODMACommand APIs, and additionally, if you're writing a custom user client, we've got a new client API in Leopard to support 64-bit client apps to enable easy communication between the application and your kernel extension.
Some closing thoughts. Going 64-bit I like to encourage developers to think of it as an opportunity. It's an opportunity to remove old compatibility hacks from your code. You know, if you think about it, if you're a 64-bit application running on Leopard, you know the user's got modern hardware and they're running a modern OS, so all those workarounds for 10.2, all those custom code paths for 10.3, and hacks for 10.4 can all be ripped out of your code. And the other thing to think about is that this is an opportunity to prepare your application to easily adopt the other new technologies and APIs you've been hearing about all week in Leopard. Because a lot of the work you need to do to easily plug into those other APIs is the same work you would need to do to go 64-bit.
So, in summary, Leopard is a fully 64-bit enabled operating system, and if you need more memory or max. performance, now's the time to go 64-bit. And even, if you don't, now's the time to start planning your transition so you can be 64-bit one day.d We talked about how to update your code to be 64-bit clean, andd one big new message is, if you're Carbon, you'll need to transition to a Cocoa user interface.
I'm the 64-bit evangelist, so you can email me with further comments after this session. We have a variety of bits of documentation that are available particularly on the attendee website, not all of this updated docs are actually on the Leopard Beta that you have, and we also have a 64-bit Lab downstairs right after this session. So, if you don't get your questions answered here, that would be the place to do that.