Thread overview
SDLmain and portability
Oct 24, 2004
Mike Parker
Oct 24, 2004
Ilya Minkov
October 24, 2004
Using SDL on platforms other than Linux and Windows
has a problem in how it uses a new "main" function...


The usual SDL relies on the C preprocessor to redefine
"main" as "SDL_main", and they supply a main of their
own in the SDLmain library for the applications to use.
(this is a gross hack, and requires main() to be written
as "int main(int argc, char *argv[])" always or it breaks)

The current Windows implementation of SDL-in-D tries to
duplicate the behaviour of this code, but in D instead.
For Mac OS X for instance, this code is in Objective-C so
duplicating it in D is not easy! And it still needs to be
called *before* the usual startup code, but after D's main.
(that starts up the garbage collector and such D things)


In GLUT, which uses less hacks to do things, you simply do:

>   glutInit(&argc, &argv);


With SDL, one has to patch the SDLmain library to call
it something other than main (and the Windows variants):

> version (Windows) {
> 
> // in modified SDLmain library:
> extern (C) int D_console_main (int argc, char **argv);
> 
> }
> version (darwin) {
> 
> // in modified SDLmain library:
> extern (C) int D_main (int argc, char **argv);
> 
> }

And then add a utility wrapper to call this new SDL main:

> import std.string;
> 
> int SDL_InitApplication(char[][] args)
> {
>     char*[] c_args = new char*[args.length];
>     foreach (int i, char[] arg; args) {
>         c_args[i] = toStringz(arg);
>     }
> 
>     int argc = c_args.length;
>     char **argv = cast(char**) c_args;
> 
>     version (Windows)
>         return D_console_main(argc, argv);
>     else version (darwin)         return D_main(argc, argv);
>     else
>         return SDL_main(argc, argv);
> }

Finally, the main program is declared something like:

> import sdl.main;
>
> extern(C)
> int SDL_main(int argc, char **argv)
> {
>     try
>     {
>         /* Load SDL dynamic link library */
>         if (SDL_Init(SDL_INIT_NOPARACHUTE) < 0)
>             throw new Error("Error loading SDL");
> 
>         version(Windows)
>             SDL_SetModuleHandle(GetModuleHandle(null));
> 
>         // do stuff
>     }
>     finally
>     {
>         SDL_Quit();
>     }
> }
> 
> int main(char[][] args)
> {
>     return SDL_InitApplication(args);
> }

Skipping the SDL_main part makes the application unportable...

SDL_Init and SDL_Quit can be put in the sdl.sdl module in D,
but that just makes SDL different from the C version I think ?
(and since most example code is in C, it's nice if it's similar)
Other D implementations stuck it in: static this() and ~this()

--anders

PS. This works in Mac OS X, just need to test with Windows/Linux.

October 24, 2004
Anders F Björklund wrote:


> 
> Skipping the SDL_main part makes the application unportable...

I disagree with this. There are several applications around the web that  skip SDL_main entirely. This is often the case when SDL is buried inside a custom framework. The only portability issue is WinMain vs. main on Windows. SDL_main is just a convenience, and without it you really only lose redirection of stdout and stderr.

In other words, there's no need for SDL_main functionality in a D binding at all.
October 24, 2004
Mike Parker wrote:

>> Skipping the SDL_main part makes the application unportable...
> 
> In other words, there's no need for SDL_main functionality in a D binding at all.

Unless you want the application to work on Mac OS X (maybe others?)

On Linux, SDL_main isn't needed at all (usually not even used)...

On Windows, it mostly calls SDL_SetModuleHandle(GetModuleHandle(NULL));
and loads the SDL.DLL with SDL_Init(SDL_INIT_NOPARACHUTE) and sets up
SDL_Quit to run on exit. All these can be work-aliked in D as well...

On Mac OS X, the SDLMain functions sets up a bunch of required Cocoa
and Objective-C structures, without which the program will just crash!


Besides just redirecting stdout/stderr, that is. (like you mentioned)

--anders
October 24, 2004
Anders F Björklund schrieb:

> Using SDL on platforms other than Linux and Windows
> has a problem in how it uses a new "main" function...

True.

> The usual SDL relies on the C preprocessor to redefine
> "main" as "SDL_main", and they supply a main of their
> own in the SDLmain library for the applications to use.
> (this is a gross hack, and requires main() to be written
> as "int main(int argc, char *argv[])" always or it breaks)

Yup, one very questionable practice. Another questionable practice is using bitfields for flags, but it's another question and it can be tanslated well.

> The current Windows implementation of SDL-in-D tries to
> duplicate the behaviour of this code, but in D instead.
> For Mac OS X for instance, this code is in Objective-C so
> duplicating it in D is not easy! And it still needs to be
> called *before* the usual startup code, but after D's main.
> (that starts up the garbage collector and such D things)

What would be the problem of first writing the code you need in Objective C, callable by C, and call it from D? We could also ask the SDL people whether they would want to include such code into the DLL/SO to make porting to other languages easier.

Another way was shown by Owen "resistor", who says: "Luckily the ObjC runtime is done in pure C, so it [bridging from D to Objective-C] is at least theoretically doable." Short afterwards, he writes: "I've succeeded in bridging some of the most critical Objective-C internals
(classes and objects), and am proud to say that I am now able to introspect the ObjC runtime from D.  I ported O'Reilly 'Inside the
ObjC Runtime' introspector to D, and it works beautifully!" The code is in the thread called "Docoa, Take 2" on D.gnu newsgroup.

> SDL_Init and SDL_Quit can be put in the sdl.sdl module in D,
> but that just makes SDL different from the C version I think ?
> (and since most example code is in C, it's nice if it's similar)
> Other D implementations stuck it in: static this() and ~this()

Perhaps i'm dumb but i don't see why it wouldn't work in this() and ~this()?

Otherwise, i don't think that a difference at initailization would be a problem. It is another language library port, so it may be expected to have some (documented) differencies.

-eye
October 25, 2004
Ilya Minkov wrote:

> Yup, one very questionable practice. Another questionable practice is using bitfields for flags, but it's another question and it can be tanslated well.

The third thing I find questionable is using C macros
for main function entries, in the header file itself.
(such as LoadBMP or BlitSurface, for instance)

> What would be the problem of first writing the code you need in Objective C, callable by C, and call it from D? We could also ask the SDL people whether they would want to include such code into the DLL/SO to make porting to other languages easier.

That's what I did. Or actually I just called the old code "D_main",
and included that SDLMain.o in a library called libSDLmain_d.a...

> Perhaps i'm dumb but i don't see why it wouldn't work in this() and ~this()?

It worked just fine, at least once the Windows code was versioned :-)

> Otherwise, i don't think that a difference at initailization would be a problem. It is another language library port, so it may be expected to have some (documented) differencies.

But main problem is that the C library "D_main" must be called before
the static constructor is invoked, or SDL won't be setup correctly...

Moving that "magic" out of the library made it easier to troubleshoot?

--anders