tags:

views:

113

answers:

1

SDL on OS X uses preprocessor tricks to overload main() with their own entry point, written in Objective C, which calls the user's main.

These tricks make the lives of non-C SDL users (e.g: the Haskell bindings) very difficult.

Is there a good reason for this?

Why couldn't SDL do the objective-C Cocoa initialization in SDL_init?

+2  A: 

The approach for Mac OS X is not much different from the approach for other non-Linux platforms (Windows, old Mac, BeOS). You could ask the SDL developers themselves why they did it this way, but I can see several reasons they may have chosen to do this:

  • This keeps the dependencies of SDL code, which is focused on initializing SDL-specific subsystems (video, audio, timing, etc.) limited to the specific subsystems that SDL is especially designed to work with. I.e. this way, SDL stays lean and mean.
  • It avoids having to introduce a new platform-specific subsystem for application initialization. Not everyone is going to want the bare-bones application object and menu that SDL sets up for Mac apps, not by a long shot – so if you were going to put it into SDL_init, you'd need to make it an optional subsystem so as not to inconvenience developers who don't need it.
  • It handles inversion of control correctly, which is how Mac OS X and other application frameworks typically operate, while maintaining the operational semantics of SDL routines. SDL_init assumes it's going to be returning to the caller after initialization is complete, but if you tried naively to create an application object in SDL_init and invoke [app run] on it to finish initializing the application and launching, you'd never return. If you didn't call run there, you'd have to create a separate SDL function to set up the application run loop. This could complicate the SDL library quite a bit. The approach that was chosen avoids all this, by letting the framework take care of all the application set up first, and invoke the SDL_main() routine from applicationDidFinishLaunching.
  • It makes it easy to convert SDL demos coded on Linux over to Mac OS X. You don't even have to rename main – the preprocessor renaming of main() to SDL_main() takes care of that for you!

I'm guessing the last of these reasons is the primary driver behind the redefinition of main in SDL_main.h, which I agree is an ugly hack.

If you're prepared to give up that level of cross-platform portability for your library and apps, I'd suggest simply modifying your SDL_main.h to remove the following line:

#define main SDL_main

and removing the following from the SDLMain.m in your project:

#ifdef main
#  undef main
#endif

You shouldn't even need to recompile SDL if you do this. Note that SDLMain.m is already set up to invoke SDL_main() without the preprocessor hack, and nothing else in SDL is going to use this, so in this way you can you simply provide SDL_main() as your game's entry point.

If you want to go the other way, taking over main() yourself, you'd still want to get rid of the #define main SDL_main hack in SDL_main.h, but other than that, you're not beholden to the main() that SDL provides for you. First, note that SDLMain.{h,m} are not part of the library proper; you must include them separately in your project. Second, note the following comments in SDLMain.h:

/*   SDLMain.m - main entry point for our Cocoa-ized SDL app
       Initial Version: Darrell Walisser <[email protected]>
       Non-NIB-Code & other changes: Max Horn <[email protected]>

     Feel free to customize this file to suit your needs
*/

That sounds to me like an invitation to go roll your own if these aren't working for you, starting with SDLMain.{h,m} as a model. And if you're rolling your own, you can do what you want! For that matter, you could write the equivalent of SDLMain.m in Haskell, using HOC, if that's what you want. Unless you're a whiz with HOC, though, I'd keep it simple.

Owen S.