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-003
$eventId
ID of event: wwdc2005
$eventContentId
ID of session without event part: 003
$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 003

Extending Your Application to Run on an Intel-based Macintosh

General • 41:58

During this session, we'll take a well-known Mac OS X application and update it to run on an Intel-based Macintosh. We'll also give you tips, offer hints, and describe building, testing, and debugging in detail.

Speakers: Eric Albert, Ronnie Misra

Unlisted on Apple Developer site

Transcript

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

Hi there. I'm Eric Albert. Over there is Ronnie Misra. We're members of Apple's Core Technologies team. And today we're going to talk to you about extending your application to run on the Intel-based Macintoshes that we just announced yesterday. So what this means is we're going to take you through the entire process of taking an application whose authors actually hadn't even contemplated the existence of such machines.

And we're going to make it build, move it to GCC4, make it run, take you through the debugging process, through the testing process, and then talk about all of the things that we ran into along the way and a few additional things that you might run into when you try to move your applications to our Intel-based systems.

So first of all, the things that you may have to do when moving any application, or that you're going to have to do when moving any application. Step one, make it build. In a lot of cases, actually, this is the most challenging thing, because the first step here is move it to GCC 4. And if you're building with CodeWare today, or if you're building with GCC 3.3, then actually you can do this today without even installing Xcode 2.1.

You can do it on the shipping version of Tiger. You can do it in Xcode 2.1 without building Universal. But you have to move your application to GCC 4. And whether you do that with an Xcode or with Makefiles, whatever works for your project as you build today. Second, you have to make your build environment work on our Intel-based systems.

So if you're using Xcode, that's really simple. It works. Just install Xcode 2.1. Everything's there. If you are not using Xcode, however, if you're using configure scripts or Makefiles, or if you have custom build tools to pre- or post-process files or to construct parts of your build environment, then you're going to have to make those work before you can actually get to the point of making your application work. In some cases, you may be able to run some build tools translated. But in a lot of cases, you're just going to have to rebuild them for Intel-based systems or rebuild them as Universal binaries.

And then go from there. And once that's done, to actually get your application to build on Intel-based systems or with the 10.4 Universal SDK, we have a few small API changes. And when I say small here, I really, honestly, truly mean small. Just a couple targeted things that affect a few people that you may have to adopt to allow your applications to work on these systems. Once all of that's done and you have an application that builds, then you can start building your application. And then you can start building your application.

And that's great. You can then go ahead and run it. And chances are reasonably good that it'll just launch. And then you see what breaks. Unfortunately, there isn't any sort of magic pixie dust that you can drop on your application to find all of the endiness problems that you might run into or anything like that.

Instead, really, you run through it. You do a full QA pass. You test all of the features. And you see what works and what doesn't, what draws correctly and what doesn't. Ideally, all of it will be just fine. But, you know, chances are there might be. There's a couple of things here and there that you need to patch up. And the way to do that is just to run through everything. So how hard is all of this? Well.

It's not very hard at all. You heard at the keynote, of course, about Mathematica, and that was two hours. That was exceptional. I know I've talked to a lot of people who have actually moved their applications over to our Intel-based systems already and have said, wow, how on earth did it take the Mathematica people so long? Mine came up in 15 minutes.

Eric Albert, Ronnie Misra Well, for some people, that may be true. For others, it may take a little bit longer. So I'm not going to stand up here and say this is incredibly easy or anything like that. For some people, it may be simple. For others, it may be a larger amount of work.

It really depends on your code base, depends on what your application is doing. But in general, it just isn't that hard. Like Steve said, this is not the Mac OS 9 to Mac OS X transition all over again. It should be a lot easier than that. Eric Albert, Ronnie Misra So, what we're actually going to do... Eric Albert, Ronnie Misra ...is show you today is Firefox.

We're going to move Firefox to our Intel-based systems. So if you aren't familiar with Firefox, it's probably the world's second most popular web browser. It comes from the Mozilla Foundation. The reason why we could work on it is because it's entirely open source. So you can actually go and grab the source code. In fact, after this, you can go and grab the source code and make the changes that we talk about here. And then you'll actually be able to bring it up on our systems.

So Firefox consists of four million lines of code. The authors, of course, never had to think about these systems. So there isn't really anything in there that would contemplate being run on Mac OS X on Intel. And with that much code, you'd think that there are a lot of problems.

But in fact, we're actually going to take you through it over the course of this session. So, step one. When you go to the Mozilla website and you grab the Firefox source code, ...so, step one. When you go to the Mozilla website and you grab the Firefox source code, ...then the first thing that you have to do is actually download and install something called "Think" ...and then install a bunch of open source libraries that come from Think.

If you aren't familiar with Think, it's a package management system ...that lets you install a variety of open source packages, applications, libraries, and other things like that on Mac OS X. It isn't the only package management system. There are others which are either easier or harder, depending on a variety of things, ...to make run on our Intel-based systems. But since Think is the one that Firefox uses, then that's the one that we're going to show you.

And when you download the Think code and you start the install, then, well, you get this right away. Checking system i386 Apple Darwin 8.1.0, Think is currently not supported on x86 Darwin. Darn it. Various parts of Think hardcode PowerPC and assume to run on a PowerPC-based operating system. Use Think on this system at your own risk. That just isn't to please me.

That just isn't too promising. We don't really like the sound of that. So, step one is to make this stop happening. When you get error messages like this, and Ronnie will cover some similar cases in the Firefox code later, ...the easiest thing to do, or the best thing to do when you start out, is search through the source code, ...figure out where this error message is coming from, find the case that's actually triggering it, ...fix that case, and then move on. Hopefully things will run a lot better.

In this case, we search for the error message, find it in a Perl module file inside the Think code. Think actually largely consists of Perl code. And we see here there's this case where they check the host name of the system. And they say, "Okay, if we're running on any random version of this Darwin x86 thing that Apple has provided for a number of years, ...which not all that many people have actually used, then we're going to say, 'Okay, it isn't supported,' and slightly worse, ...as far as we're concerned, we're going to default to trying to act like we're on Jaguar." But, well, this isn't Jaguar anymore.

This is Mac OS X on Intel-based Macintoshes running Tiger. So we have to add a new case for this. And it says, "Okay, if our platform is actually Darwin 8.1.0, then copy what Think currently has for Tiger," ...which says this brand new system is still being tested but should work. And hopefully it'll work once we're done. And then use the current Think Tiger distribution. So when we add that, we get past that first stage and we move on. And Think starts compiling. We get past the configure script. And it's building and we get a compiler error.

And this error, "Array type has incomplete element type," Well, this is not Intel-specific. In fact, this is just something that needs a fix for GCC4. Today doesn't entirely know about GCC4. GCC4 is the compiler for Intel-based Macintoshes. So we're going to have to fix this. And when we fix that and move on, that's it. We're done. So an entire package management system for Mac OS X. Two changes. One to the configure script. One to one of the files.

And at this point, actually, we have -- we can install the four libraries that Firefox needs. We can build them for Intel. And then we can move on to Firefox itself. And now then over to Ronnie. All right. So I wish I could say that it was as easy to port Firefox, just two changes, but unfortunately, that's not the case. Let's see what actually happens when we start to compile it. We're going to need to switch to the computers to see this.

So, I guess I should have given this introduction while we were all waiting. I'm not actually going to compile most of the code right here, right now, because that would take forever. Instead, I have sort of canned output from Make Files, and I already have diffs ready for us to see. So I just wanted to point that out right now so that you guys don't think that I'm trying to pull the wool over your eyes.

It does take a while to build Firefox. I think it takes about half an hour for a full build. And I have to do this several times over the presentation. So with that, let's see what happens when we just type make.

[Transcript missing]

So here's the file merge output for my changes to the configure script. As you can see, the changes are pretty small. I basically just copied the PowerPC case and changed the architecture for i386.

So I'll turn it back over to Eric who can...

[Transcript missing]

Okay, so here's that same bit of code. Instead of accessing the fields directly, I'm using these APIs called getAliasSizeFromPointer to access the size of an alias record. Unfortunately, these APIs are relatively new. They don't exist on Panther.

So if you want your code to continue to compile and run on Panther, you'll want to make a macro to do the same thing. Here I've done that using the availability macros. I define a macro called getAliasSizeFromPointer, which does the same thing that this code used to do. So this allows you to continue to compile on earlier OSs.

[Transcript missing]

Firefox builds this internal tool called ASDecode, which is used to decode Apple single files. It throws an assertion. So let's figure out what's going on there. Here's the bit of code that throws the assertion. You can see that it's not finding the magic number that it expects.

If we look slightly earlier in the code, you can see here's a structure. It has multi-byte types. These types in Apple single files are defined to be Big-Endian. So when running ASDecode on this platform, it sees the little-Endian version -- or, sorry, it sees a swapped version of those fields.

So -- In the next phase, we'll make the changes required for proper Endian access to these fields. You'll see that I'm using the OS swap routines. OS swap big to host int32 takes in an integer that's known to be big Endian and converts it to the host Endianness, whether that be little or big. So the interesting thing to note here is it does absolutely nothing on PowerPC, so there's no performance impact to using this in your existing PowerPC code.

So I don't have header guards around this to say if big Endian. So I had to use these macros a couple places in the code. Here's using the 16-bit version instead of the 32-bit version. The prototypes come from this header, which you'll want to include. We also--well, Eric will talk more about this. Amen.

So what he was showing here is swap as needed. And when you have to swap data, there are actually four different headers in the system that define various swapping APIs. So there's nsbyteorder.h in Foundation. There's endian.h, which is in CarbonCore, cfbyteorder.h in Core Foundation, and osbyteorder.h, which is in user include libkern.

Essentially, they all end up calling the same thing. You can call whichever one you're the most comfortable with. So if you're writing Objective-C code, for example, then you may want to use nsbydoordor.h just because that's part of foundation. If you're writing Carbon code, then you can use ndn.h.

The important thing here is use the functions and macros that we provide for swapping because when we sit down and take a look at performance on the system and work on improving it in a variety of places, these are the things that we optimize. If you write your own swapping code, then it may turn out to be slower. And particularly in those rare cases, or hopefully rare cases, where you have to swap a lot, then you really want to be using our APIs.

The second thing here, again, is we recommend that you don't add #if statements for big-endian or little-endian when you write your swapping code. Because all of these, if you are swapping from a target architecture that's the same as your host architecture, will do absolutely nothing. The compiler will simply optimize that out. It'll vanish from your code. And then you'll have much cleaner code than you would if you actually said if big-endian, then swap else little-endian do nothing or something like that.

So now that we have our swapping straight, then on to Ronnie for the next step. Ronnie Misra Okay. So after making this change, we get past the ASD code problem. And we encounter this error. The build system is mostly makefiles, but they build some of their targets with Xcode.

And makefiles driving Xcode and scripts driving Xcode will not be the same. So the scripts driving Xcode will probably have to be adapted for Xcode 2.1. Xcode 2.1 has support for build configurations that require a change to where build targets actually land in the build directory. So let's take a look at what those changes look like.

Now again, Firefox is an open source app, and they want people to compile it on all sorts of OSes. So I wanted to make these changes work, continue to work on older versions of the OS and older versions of Xcode. So you'll see here I've introduced a new variable called builder, which is by default dot, and if I detect that the Xcode version is greater than or equal to 620, which is the build number that Xcode reports, then I use the appropriate directory for the build style. And here I've made the changes that actually reference that variable.

And after that, we actually get a binary. And here I'm running that binary in GDB, just sort of expecting that it's going to crash.

[Transcript missing]

RegParm isn't supported on our platform right now. If you do intro library calls, some of the registers get corrupted. And so for now, I'm just going to turn that off.

So here are the diffs to turn it off. Basically, I've just added a section to the end of their--or added a check to the end of their pound diffs to make sure that we're not on Mac OS when using regparm. And after that, we compile again and we run again. You'll see I'm running it in GDB again. That takes a little while to launch because it runs-- or it uses a lot of libraries.

And look at that. Back there, there's actually a Firefox window. So we've brought it up with relatively few changes, but of course, I wouldn't ship it at this point because we haven't really done any testing. The first thing we're going to try to do is access some plug-ins. I've got this bookmarked already.

[Transcript missing]

EBP minus 56 is this value. And one thing that I should mention about the ROS is our stacks are 16-byte aligned. The OS actually requires that because we use these instructions in various bits of code in ROS, and so code that manipulates the stack has to be aware of this. Firefox is not aware. If we look in the back trace -- oops, wrong window.

There's this JavaScript invoke stuff which calls into their XPC layer, which we will see here, manipulates the stack. XPTC invoke by index sets up a custom stack before calling out to JavaScript code. And we're going to have to change that to be where to keep the stack aligned.

So those changes are here. I've added support for saving the stack away and making sure that it's 16 byte aligned and restoring the stack. Again, this probably won't affect most of you, but I just wanted to point it out here for those of you that it does affect.

But the more general problem of optimizing code, you may have a lot of code that you've optimized for other Intel-based operating systems or even for Mac OS X on PowerPC. You'll want to reexamine some of those optimizations because some of your assumptions may not be true on this platform, and Eric will talk more about that.

So we went through actually two significantly different steps here. The first one is adopting build configurations. And hopefully we can get the slides back up here. I can talk about them anyway. So as Ronnie mentioned, the new build configurations feature of Xcode 2.1, which actually satisfies a need that a lot of people have been asking for for a long time, which is to keep different copies for debug and release builds of your binary around so when you change that setting, then you don't have to rebuild everything from scratch.

It's absolutely terrific, but it can be a little bit tricky at times if you have projects that use Makefiles that need to reference things out of the build, or if you have shell scripts that need to reference things that have already been built. So if you have either of those and they interact with your Xcode build results, then you may have to make some slight changes to them to actually adopt build configurations.

And next, after that, adhere to the Mac OS X ABI. So there's some documentation about the ABI in the universal binary programming guidelines that you've now all received. The two things that we covered here-- first, don't use the regparm attribute today. It doesn't work on our current systems, and that's something that certainly we'll take a look at in the future. And secondly, maintain 16-byte stack alignment.

So if you do any custom stack manipulation, if you're doing custom code to call between languages or anything like that, then you may have code, like what Ronnie showed with Firefox, that ends up manipulating the stack. And essentially, the stack always has to be 16-byte aligned at the point of the call instruction.

Otherwise, because the compiler actually, for us, generates vector instructions by default, then subsequent code may crash because it's assuming that the stack is aligned, and therefore that it can use the aligned versions of the vector instructions. Now, back to Ronnie for the next step. Okay, so I'm launching the executable again in GDB.

So the next thing I want to look at is plug-in support. It seems like plugins sort of just work. And as you can see, it found the QuickTime plugin. It found its default plugin. But if we look down at the bottom of the list, it also found the Shockwave plugin. Shockwave is only built for PowerPC currently, so we want to change the code in Firefox to detect that it's not a legal plugin for this architecture. So let's take a look at that code.

So here's the code in Firefox to detect whether something is a plugin file. It already has some checks to make sure that it has the right creator type and : Thank you, Eric. I'm going to start off by saying thank you to all of you for joining us today.

So I've included some new headers, and I've added this new function called isPluginLoadable, which takes a--

[Transcript missing]

we cause the code that supports CFM plug-ins to not be turned on for the native build on Intel because we don't support CFM on native processes running plug-ins. CFM apps will continue to run under the translator and CFM plug-ins will work there but not here. And here I've added in a check to my new function to make sure that we check the architecture before adding any plug-in to our plug-in list.

So with that, I'll hand it back over to Eric. ERIC ALTER: OK. So again, what he showed you here was load the right plugins for the system. So an application can only load plugins of the same architecture as the application itself, which means that if your application is running translated, then it can load PowerPC plugins.

If your application is running natively, then it can load Intel plugins. And if you try to actually call NSBundleLoad or CFBundleLoad executable on a bundle of the wrong architecture, one that you can't load, then, well, it'll simply fail to load, and you'll probably get an error message in the console.

And just your application's behavior won't be quite as nice as it would otherwise be. So the best thing to do then is to actually check the type of the plugin that you're trying to load. And don't try to load CFM plugins in your Intel build. And don't try to load Maco PowerPC thin plugins when running natively.

So unfortunately, as he showed you, the code for that is currently a little bit messy. You have to poke at the Mac OS headers. Hopefully, we'll have a better solution for you in the future where you can actually determine what architectures are contained within an executable file. And now that we have the right plugins loading, then off to the next step. Okay. Well, so here I'm running the app, and you see the plugins actually work. Here's a QuickTime trailer that I cached from our trailer site.

[Transcript missing]

We can go to some of the news sites. You can see that people were talking about Apple's big move when I cached this page. But when we browse to some of the other sites on Google News, we get a crash. So this is a crash in font handling code. If we look at the code, It's parsing font data. One of the things that we mention in our guide is that font data is always big endian on this platform.

So when you have code that directly references fields for low-level parts of a font, you'll want to adapt those to properly deal with endianness. We'll take a look at the changes to do that. So here I'm making use of the OS swap macros again. With these changes, we're pretty much done. I'm going to run the binary again.

Of course, when I say done, we haven't really done any extensive testing. And after we go to more websites, we'll probably find more problems. But all in all, it was a relatively easy process to port this app. And it's generally pretty stable now. Here we can go to that Google News page, which crashed before. And just to be more thorough, I found this font test page on the web.

[Transcript missing]

So this last step here, read and write data in the right Endianness. So some data is always Big Endian. I was trying to think of any cases in the system where we have data that's always Little Endian today, but I don't believe we do. At least I'm pretty certain that we haven't--if we do, we haven't introduced any new ones with this release.

So the data that's always Big Endian, all of this is mentioned in the Universal Binary Programming Guide. So low-level font data, and by that I mean if you're actually poking at the font fields directly rather than using the higher-level ATS APIs. ColorSync profile element data is always Big Endian. Very low-level finder information, and by that I mean if you're calling get-attr-list, not if you're calling fscatalog-info or anything above that. And as I mentioned before, QuickDraw picture bounds, which you may notice if you haven't actually updated your code to call QD get-picture bounds.

So that's it. At that point, we have a web browser. We have a major Mac OS X application that we have been extended to run on Intel. So to run once more through the steps that you should follow to bring your application over to our platform, first, again, move it to GCC 4.

[Transcript missing]

Really? Just run through everything? See what you've got? I mean, like the example that Ronnie showed, you hand it out to people and they will find bugs, and then you'll fix them. And in general, the fixes just aren't all that hard. It's, "Oh, okay, so we crash here because this needs to be bytes swapped. Great. Here's a bytes swap.

Wonderful. You're pretty confident that it works." I mean, one of the wonderful things that we've found in making changes for this platform is that

[Transcript missing]

So a few other common issues that I wanted to touch on that we actually didn't hit in the process of moving Firefox to our Intel-based systems.

First of all, file formatting compatibilities. So if you don't use NS Coding or Cocos Archiving, if you don't use a text-based file format, if you don't already have cross-platform code to read and write files, then you may have to do some work to ensure that you always write your file formats in exactly the same way when running on PowerPC-based systems or on Intel-based systems. Because, you know, it would be really nice if your users could actually copy those files between the two.

Second, networking issues. One thing that we've seen all the time is that people assume that, or have been able to assume for years, that, hey, PowerPC byte order is the same as networking byte order, so I don't actually need to do any sort of byte swapping when dealing with the network.

That's no longer the case, or still the case. PowerPC byte order is the same. But on Intel-based systems, the byte ordering is different from network byte order, so you may have to add some swapping code there. Integer divide by zero. Because Firefox is already cross-platform, then presumably they've already taken care of all of these cases. But integer divide by zero is fatal on all Intel systems. And so in those cases, you just have to check for zero and return zero I'm sorry.

Some color drawing problems. So we were rather fortunate that we didn't see any with Firefox. But OpenGL, Core Graphics, and Quickdraw, all of those APIs, if you have color drawing problems, you may need some changes. All of this is covered, again, in our documentation. But in a lot of cases, drawing code will simply work out of the box. If it doesn't, there are a few small things that you may need to tweak.

Undefined or implementation-defined code. So things that the compiler doesn't necessarily warn you about doing. Things that are undefined with numeric calculations. Things that are out of range can return different results than they used to on PowerPC. And in those cases, well, hey, it's a great way to track down these bugs that may have been in your application for a long time where you were getting unexpected values. Custom resources, Apple events, or pasteboard types.

I'm not sure if anyone so far has actually talked about the Core NDE and APIs for flipping resources, Apple events, or pasteboard data. All of that's covered pretty thoroughly in the universal binary guide. But if you have custom resource types, not ones that are standard in the system, or if you have custom Apple event or pasteboard types, then you may need to write some additional code to deal with those either between processes or when reading them off of disk.

And finally, we hit this all the time, remember to test the result on both architects. We are providing, or we will be providing, either both systems for a long time. And so you actually have to run your app in both cases. It's quite possible that when you make a change to run better on Intel-based systems that you inadvertently say, swap all the time. And then you move back to PowerPC and realize, well, actually swapping all the time was wrong because the data was right in the first place. And so now you get your $4 billion value on a PowerPC-based system instead.

So. So that's the first thing. The second thing is that you can actually do some more work. So you can do some more work on your own. You can do some more work on your own. And then you can do some more work on your own. So that's the first thing.

So more information throughout the rest of the week. We have documentation. This says sample code. I'm not sure how much, if any, sample code we have specifically dealing with this transition online yet. But I presume we'll have some soon. We have other resources at that page. We have a few other related sessions that I really do want to call out, because these are really important if you're thinking-- as you're working on transitioning to this platform. So first, moving to GCC 4. If you aren't currently building with GCC 4, there's a session tomorrow at 5:00 that will be incredibly helpful. I strongly suggest going. It's a wonderful compiler, but there are some changes that you may have to make as you move to it.

Code with Apple's Image and Signal Processing APIs for Maximum Performance. I don't know how they got that many letters in their title. But this is a session on Friday that's going to talk about all kinds of performance-related issues, but one of them is migrating AltaVec code to SSE, SSE2, and SSE3. And if you have AltaVec code in your products today, then that'll be very, very helpful.

Swimming with Shark. Shark runs great for us on our Intel-based systems. If you go to the session, then hopefully you'll get to see what it's like on there. And finally, our Universal Binary Lab, which is downstairs on the first floor, which is going to be open all week.

I believe it's open until midnight tonight. This is a great opportunity for you to bring your code by, and a lot of us are there helping people move their applications. And it's been just wonderful so far to see all kinds of people come by and say, Hey, you know, in 15 minutes... or half an hour or an hour or so, then I was able to get everything running. So hopefully you'll get a chance to do the same.