One small step for a man, one giant leap for Mac-kind
In order to work on Natural Selection 2 regardless of where I am, I recently decided to get a new laptop. I bought my last laptop around when we started working on NS2, and at that time I went for the cheapest system I could find. I’ve often found that the adage of "you get what you pay for" rings true, and it certainly was in this case; a year later my brand new laptop was unusable, even after resuscitating it with numerous hardware transplants.
This wasn’t the first time this has happened to me, so with this laptop I decided to go all out and get something quality, even if it cost more up front; the time (and possibly data) loss resulting from faulty hardware can be just as significant. My brand-new Macbook Pro (with the 17" matte display!) arrived last month and I immediately installed Vista via Bootcamp and setup my Windows development tools.
One of our goals is to make Natural Selection 2 and the toolset work natively across Windows, OS X and Linux. With this in mind, whenever I write code I try to keep portability in mind. This factored into our decision to use wxWidgets to build all of our tools and to keep any platform specific code (Direct3D for example) abstracted so that it can easily be replaced. This has all existed in the theoretical realm though, because I’ve never actually ported anything to OS X or Linux.
Since I have a shiny new computer that runs OS X, I figured it was time to put that to the test. While a complete port is out of the question at the moment, I wanted to get my foot in the door so I could begin to understand the issues, like how to organize the files that contain platform-specific code, any gotchas associated with wxWidgets, etc.
For my weekend porting project I decided to tackle the Builder application. This is our tool which is responsible for automatically converting all of our art assets into game ready formats. Of all of our projects, this particular one depends on the fewest libraries (just wxWidgets) and only has a small bit of Windows specific code which is isolated in a single class. I also spent a lot of effort when writing the Builder to make it platform independent, so I was looking forward to seeing the fruits of that labor.
Ultimately, getting the Builder running on OS X was a pretty easy process, although it took me both Saturday and Sunday to get it worked out. The first step was compiling wxWidgets for the Mac, which turned out to be pretty simple with the supplied config script and make file. Then came the task of creating my own make file for compiling and linking our project. I haven’t written a make file since college, and a make file for a real project is quite a bit different than the ones I had done in the past or the simple samples you can find on the Internet. Presumably this is why there are so many alternatives out there to writing the makefile by hand (icompile, bakefiles, automake or using XCode) I looked into these a bit, but ultimately decided I’d have an easier time just writing the makefile myself.
Once I had the makefile sorted out, I quickly found a number of places where my C++ code wasn’t portable to the g++ compiler. I also discovered a few errors in the code which hadn’t been caught by Microsoft compiler. These were all really easy to fix, and was exactly the kind of knowledge I was hoping to discover with this process.
The final step was linking and creating a usable OS X executable file. The linking process gave me the most trouble, because I made the rookie debugging mistake of getting hung up on one possible explanation of what I was seeing. At the end of my linking process, I was left with the single error message "Undefined symbol _main". Since the main function is supplied by wxWidgets I figured this was a problem with the way I compiled the library or how I was linking to it. A few hours of head banging later I took a step back from the problem and realized the "main" function was there, but the way my code was written put it inside a namespace. Moving it outside the namespace fixed the linker problem and I had an executable file at last.
Unfortunately this executable file didn’t behave like a normal OS X program. When it started, I would see the window for the Builder, but there was no menu at the top of the screen and the window didn’t respond to any mouse clicks. I was lucky with this problem, and after a little bit of research I stumbled across the solution; OS X applications are actually directories, and inside that directory is where the actual executable image goes. With a few quick changes to my makefile, everything was packaged properly and I could run the Builder properly!
There are a few bits of the Builder that don’t work properly on the Mac yet, but I’ll be working on those soon. I also haven’t rewritten the platform specific piece (which detects when files on disk have been modified), but I do have a good solution now for how to organize these files in our code base.
People often think that Direct3D is the biggest barrier to porting a game engine, but we actually have very little Direct3D code. Direct3D represents only about 2,500 lines of code out of almost 100,000 in the engine. The bigger task is all of the small things, and this process has helped me flush about a bunch of them that should make things smoother going forward.
We’re not sure if we’ll have enough time to release an OS X or Linux version simultaneously with the Windows version, but it’s something we’re very interested in doing. But I’m feeling good about the portability of the engine, and since our entire game is written in Lua it doesn’t need to be ported at all!