www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - SDLmain and portability

reply =?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= <afb algonet.se> writes:
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.
Oct 24 2004
next sibling parent reply Mike Parker <aldacron71 yahoo.com> writes:
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.
Oct 24 2004
parent =?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= <afb algonet.se> writes:
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
Oct 24 2004
prev sibling parent reply Ilya Minkov <minkov cs.tum.edu> writes:
Anders F Bj=F6rklund 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=20 using bitfields for flags, but it's another question and it can be=20 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=20 Objective C, callable by C, and call it from D? We could also ask the=20 SDL people whether they would want to include such code into the DLL/SO=20 to make porting to other languages easier. Another way was shown by Owen "resistor", who says: "Luckily the ObjC=20 runtime is done in pure C, so it [bridging from D to Objective-C] is at=20 least theoretically doable." Short afterwards, he writes: "I've=20 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=20 introspect the ObjC runtime from D. I ported O'Reilly 'Inside the ObjC Runtime' introspector to D, and it works beautifully!" The code is=20 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=20 problem. It is another language library port, so it may be expected to=20 have some (documented) differencies. -eye
Oct 24 2004
parent =?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= <afb algonet.se> writes:
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
Oct 24 2004