Sdlmain

A recent thread on mingw-users mailing list brought the following
problems up when linking a SDL application:

  1. ‘main’ function is overridden in a way that subverts a typical valid
    C ‘main’ entry function.
  2. By overwriting ‘main’, linkage and linking library order is enforced
    in a non-natural way.
  3. sdlmain is called conditionally depending on how a user links his
    application.

I’m proposing and strongly encouraging to remove the ‘main’/'sdlmain’
overloading in SDL 1.3 since I see only problems associated with it, and
few benefits compared to current initialization of SDL and improving it.

Knowing that I’ve noticed that some initialization, depending on
architecture, seems to be necessary (such as BeOS); here are
nevertheless my points:

  1. ‘main’ is standard C function whose prototype is exactly:
    int main(int, char**, char**).
    Because of C linkage and the non-enforcement of C parameter types, we
    usually just use ‘int main(int, char**)’; but any parameter list should
    be valid and accepted. SDL (SDL_main.h precisely) currently denies this.
    The only requirement in C is that ‘main’ returns ‘int’.

  2. Because of redefining ‘main’ to ‘sdlmain’, linking a SDL application
    (under mingw) becomes “gcc foobar.c -lmingw32 -lSDLmain -lSDL” when it
    should naturally just be “gcc foobar -lSDL”. This is confusing for new
    users as many do not know the internals of gcc’s expansion of the
    commandline to something similar to "ld crtX.o foobar.o (user libs) (gcc
    libs)"
    In a normal case, crtX calls ‘main’, which if not found, mingw32 calls
    WinMain.
    In SDL’s case, crtX calls ‘main’, which is found in mingw32, which calls
    WinMain. In case WinMain is defined in foobar.c, I believe that
    SDLmain’s WinMain is not called.

  3. In the case SDL is wrapped in a user library, then SDLMain is not
    called unless foobar.c has an "include <SDL.h>"
    e.g.

  • foolib.a is wrapper library that suppresses the need for final
    application to require SDL headers to be installed(*). foobar.c will not
    have “include <SDL.h>”, but rather “include <foolib.h>”, ‘main’ will not
    be redefined, linking will be “gcc foobar.c -lfoolib” and of course
    ’sdlmain’ will not be called.
  1. If linking to SDL and another library (libfoo.a) that redefines
    ’main’ (the latter would receive the same criticism from my behalf,
    btw), then which ‘main’ will be linked? Either ‘sdlmain’, or
    ’libfoomain’. It will depend on which header is specified first.

  2. SDL_Init is used for initialization. Why then hijack ‘main’ if we
    require SDL_Init to be first called anyway?

  3. If hijacking ‘main’ is required (maybe BeOS), then do it. But in case
    where it brings nothing special (in current svn SDL 1.3 it often just
    does commandline arg parsing!), then remove it completely!

(*) In the case of a foolib DLL, even the SDL libraries are not required
during linking since there are no unresolved functions permitted in a
DLL. Note: SDL.dll might be required to run (but not link) application.

Hello !

  1. ‘main’ is standard C function whose prototype is exactly:
    int main(int, char**, char**).

What would be this second char** ?

The good thing about SDLmain is you can use it.
But you are not forced to use it. For me years ago
as a C/C++ beginner it was better and easier just
to use int main … then using int WinMain …
I do not know what BeOS needs.

That way i can write code that “just works” on all
the plattforms and i do not have to think about
what main definition i need on what plattform.

But when you have special needs you do not need to use
SDLmain.

CU

Le Mardi 4 Juillet 2006 13:14, Julien Lecomte a ?crit?:
[…]

I’m proposing and strongly encouraging to remove the ‘main’/'sdlmain’
overloading in SDL 1.3 since I see only problems associated with it, and
few benefits compared to current initialization of SDL and improving it.

Being a windows noob, I don’t know what’s the problem with simply omitting the
SDLmain linkage? You are not enforced to use it, are you?

Johannes

Hello !

I the only thing i would like to get
changed in SDL 1.2 is to be able
to dynamically change wether
Messages for stdout and stderr are print
to files or not. I do not recall at the
moment if SDL uses the console for
output when using -mconsole.

But maybe it is not possible to make this
dynamically.

CU

Le Mardi 4 Juillet 2006 15:23, Torsten Giebl a ?crit?:

I the only thing i would like to get
changed in SDL 1.2 is to be able
to dynamically change wether
Messages for stdout and stderr are print
to files or not. I do not recall at the
moment if SDL uses the console for
output when using -mconsole.

But maybe it is not possible to make this
dynamically.

Dynamical redirection is possible (in C, C++ at least).

What about an env var to prevent redirection?

Johannes.

envp: pointer to environment block.

It’s the original environment variables that were in use during launch
of process.
Not all implementations return it, and very few people use it, that’s
why we usually never see it. Implementations that don’t return envp
return a null pointer instead to avoid a segfault if trying to access it.

mingw, msys and my linux-box (a gnu-linux LFS) return envp.
e.g:On 04/07/2006 15:12, Torsten Giebl wrote:

  1. ‘main’ is standard C function whose prototype is exactly:
    int main(int, char**, char**).

What would be this second char** ?


#include <stdio.h>

int main(int argc, char* argv[], char* envp[])
{
int i = 0;

if (!envp)
printf(“your implementation doesn’t return envp)\n”);
else
while (envp[i])
{ printf("%2d) %s\n", i, envp[i]); i++; }
return 0;
}

The good thing about SDLmain is you can use it.
But you are not forced to use it. For me years ago
If you can opt-in or opt-out SDLmain, and using SDLmain brings nothing;
then why have it?

as a C/C++ beginner it was better and easier just
to use int main … then using int WinMain …
And more portable :wink:
The runtime library should be in charge not a user library.

I do not know what BeOS needs.
Neither do I, that’s why I put the conditional.

That way i can write code that “just works” on all
the platforms and i do not have to think about
what main definition i need on what platform.
Having a prototype in SDL_main.h denies portability since compiler will
usually check prototype and declaration matches and either throw a
warning in best of cases and a error in worst.
The C linker does not do type checking.

Anyway, if SDL_main must stay or not, it should be fixed in current
implementation:

  • not define a prototype (line 52 of SDL_main.h)
  • call SDL_main with (argc, argv, 0) if SDL can’t provide envp to avoid
    a segfault, or with a envp if it can.

I’ll point out that this fix also “breaks” a ‘main’ in a C++ file; since
’main’ is renamed ‘SDL_main’ the compiler will not think of it as
needing C linkage thus no implicit “extern C”.
C++ users will have to declare ‘main’ explicitly as "extern “C"
main(…)”; which is counter-intuitive but implementation correct, and
also why I strongly encourage removing SDL_main altogether.
The last point is mentioned in SDL_main.h (line 41), but who reads
header files apart from insomniacs?
There is solution to avoid this; but I’ll not even mention it since it’s
even more messy!

Le Mardi 4 Juillet 2006 15:23, Torsten Giebl a ?crit :

I the only thing i would like to get
changed in SDL 1.2 is to be able
to dynamically change whether
Messages for stdout and stderr are print
to files or not. I do not recall at the
moment if SDL uses the console for
output when using -mconsole.
-mconsole just prevents a console from being opened at start of program.
It doesn’t define anything or change linking in any way apart from what
I said above.

But maybe it is not possible to make this
dynamically.

Dynamical redirection is possible (in C, C++ at least).

What about an env var to prevent redirection?
I don’t know, I never use SDL’s redirection; but I’ve seen that it seems
to have been removed from SDL 1.3. Yeah!On 04/07/2006 16:19, Johannes Schmidt wrote:

Hello !

-mconsole just prevents a console from being opened at start of program.
It doesn’t define anything or change linking in any way apart from what
I said above.

You do not understand me right. For me it would be usefull, when
your app is a console app so compiling with -mconsole to have the
output on that console and when compiling in Windowed Mode
with -mwindows the files should be created. I do not know
if it is possible to detect this at runtime.

CU

Hello !

If SDLmain has bugs or problems, they should be fixed.

For me SDLmain is perfect and also other
Toolkits use some kind of SDLmain for example FLTK.

SDLmain can be used, it makes your life easier,
but you do not have to use it. You have the freedom.

If not your main function would look like this:

#ifdef _WIN32
int WinMain …
#else if BEOS
int BeMain …
#else
.
.
.
#endif

I would suggest to add an option to sdl-config to let
out SDLmain and the other things then, for example
–no-SDLmain

sdl-config --cxxflags --libs --no-SDLmain

CU

Hello !

I would suggest to add an option to sdl-config to let
out SDLmain and the other things then, for example --no-SDLmain

sdl-config --cxxflags --libs --no-SDLmain

Also i would add an option to sdl-config
like --use-console, so that on Windows
the coder can create a console app easily.

CU

I suggest to see how this is done in Allegro:
int main(void)
{
allegro_init();
/* more stuff goes here */

return 0;
}
END_OF_MAIN()

END_OF_MAIN is a special macro which is different for different
platforms. See Allegro’s headers for more info.

I don’t see why you need to detect this at runtime; after all, you’ve
decided to link either in console or windows mode, so you know if you
have a console or not.

Since you know if you’ll have a console or not, you can compile two
SDLmain libraries (one with --disable-stdio-redirect, see FAQ:
http://www.libsdl.org/cgi/docwiki.cgi/FAQ_20Console) which I’ll name
libSDLconsole and libSDLwindows, and use the correct one at link time.

You can then use two different command lines for two different targets:
$ gcc -mconsole foobar.c -lmingw32 -lSDLconsole -lSDL
$ gcc -mwindows foobar.c -lmingw32 -lSDLwindows -lSDL

If you nevertheless want to detect this at runtime, you can detect a
console at runtime with GetConsoleWindow, but this is non portable
(windows specific and WinXP or better).On 04/07/2006 17:39, Torsten Giebl wrote:

Hello !

-mconsole just prevents a console from being opened at start of program.
It doesn’t define anything or change linking in any way apart from what
I said above.

You do not understand me right. For me it would be usefull, when
your app is a console app so compiling with -mconsole to have the
output on that console and when compiling in Windowed Mode
with -mwindows the files should be created. I do not know
if it is possible to detect this at runtime.


#define _WIN32_WINNT 0x0500

#include <stdio.h>
#include <windows.h>
int main(void)
{
if (GetConsoleWindow())
printf(“console\n”);
else
printf(“not console\n”);
return 0;
}

Julien Lecomte wrote:

Since you know if you’ll have a console or not, you can compile two
SDLmain libraries (one with --disable-stdio-redirect, see FAQ:
http://www.libsdl.org/cgi/docwiki.cgi/FAQ_20Console) which I’ll name
libSDLconsole and libSDLwindows, and use the correct one at link time.

You can then use two different command lines for two different targets:
$ gcc -mconsole foobar.c -lmingw32 -lSDLconsole -lSDL
$ gcc -mwindows foobar.c -lmingw32 -lSDLwindows -lSDL

This is exactly what the Visual C++ versions do. There is a version
with, and without stdio console support.

Pete.

  1. If hijacking ‘main’ is required (maybe BeOS), then do it. But in case
    where it brings nothing special (in current svn SDL 1.3 it often just
    does commandline arg parsing!), then remove it completely!

It’s meant to give you a standard “main” function, as opposed to
WinMain. If mingw provides this, then you shouldn’t need SDL_main on
that platform.

–ryan.

Le 4 juil. 06 ? 17:46, Torsten Giebl a ?crit :

SDLmain can be used, it makes your life easier,
but you do not have to use it. You have the freedom.

This is not true. On osx you have to use it because sdl is based on
Cocoa which requires control inversion (i.e. Cocoa forces you to
enter a function that never returns to handle input). Would the osx
driver be based on Carbon you wouldn’t be forced to use sdlmain.

I have nothing against sdlmain if it simplifies multiplatform setup.
However when you are forced to use it, it can get in the way in some
cases, one example being in bindings to higher level languages that
have toplevel loops (ocaml, lisp, python, etc).

Daniel

P.S. I could give a hand on a carbon based driver for 1.3.

I’ve never really studied the SDLmain implementation - I’ve just put up with
it. I would however like to get rid of it, just for the sake of having one
less library to link to.

How much of SDLmain could be moved into SDL_Init()?

If all you want to do is get rid of WinMain, with my own projects under VC++
Express, I’ve found that you can implement in a shared library a WinMain of
your own, which just calls the user’s main() with a converted argument list.
No “#define main sdlmain” required.

Having both functions defined works as expected:

  • If the user is building a console app, the main() is executed, and
    WinMain() ignored.
  • If the user is building a GUI app, the main() is called by WinMain().

i.e. a standard “main”, regardless of build type.

I’d love it if such a thing were possible on all platforms/compilers, but I
don’t have the experience to know. It could have the same problem as SDLmain
under mingw.

Pete

“Ryan C. Gordon” wrote in message
news:44AAA15A.6050401 at icculus.org…>

  1. If hijacking ‘main’ is required (maybe BeOS), then do it. But in case
    where it brings nothing special (in current svn SDL 1.3 it often just
    does commandline arg parsing!), then remove it completely!

It’s meant to give you a standard “main” function, as opposed to
WinMain. If mingw provides this, then you shouldn’t need SDL_main on
that platform.

–ryan.

I suggest to see how this is done in Allegro:
int main(void)
{
allegro_init();
/* more stuff goes here */

return 0;
}
END_OF_MAIN()

END_OF_MAIN is a special macro which is different for different
platforms. See Allegro’s headers for more info.

Did all missed this message?
OK, I explain more.

alconfig.h:
#ifndef END_OF_MAIN
#define END_OF_MAIN()
#endif

alunix.h
#ifdef ALLEGRO_WITH_MAGIC_MAIN

#ifndef ALLEGRO_NO_MAGIC_MAIN
#define ALLEGRO_MAGIC_MAIN
#define main _mangled_main
#undef END_OF_MAIN
#define END_OF_MAIN() void _mangled_main_address = (void) _mangled_main;
#else
#undef END_OF_MAIN
#define END_OF_MAIN() void *_mangled_main_address;
#endif

#endif

alwin.h:
#if (!defined ALLEGRO_NO_MAGIC_MAIN) && (!defined ALLEGRO_SRC)

#define ALLEGRO_MAGIC_MAIN
#define main _mangled_main
#undef END_OF_MAIN

/* disable strict pointer typing because of the vague prototype below */
#define NO_STRICT

#ifdef __cplusplus
extern “C” int __stdcall WinMain(void *hInst, void *hPrev, char
*Cmd, int nShow);
#endif

#define END_OF_MAIN()

int __stdcall WinMain(void *hInst, void *hPrev, char *Cmd, int nShow)
{
return _WinMain((void *)_mangled_main, hInst, hPrev, Cmd, nShow);
}

#endif

There are also alqnx.h, alosx.h and almaccfg.h where the same stuff is defined.

This way Allegro devs avoided special static library like sdlmain.lib.

P.S.: ALLEGRO_WITH_MAGIC_MAIN and ALLEGRO_NO_MAGIC_MAIN are reserved
for user to allow forcing of specific main definition.–
Roman Kyrylych (??? ???)

Hello !

I suggest to see how this is done in Allegro:
int main(void) {
allegro_init(); /* more stuff goes here */

return 0; }
END_OF_MAIN()

END_OF_MAIN is a special macro which is different for different
platforms. See Allegro’s headers for more info.

Did all missed this message?
OK, I explain more.

Exactly, i also used ALLEGRO.

CU

Hello !

I suggest to see how this is done in Allegro:
int main(void) {
allegro_init(); /* more stuff goes here */

return 0; }
END_OF_MAIN()

END_OF_MAIN is a special macro which is different for different
platforms. See Allegro’s headers for more info.

Did all missed this message?
OK, I explain more.

That would be an option for SDL1.3 to do it, if all
the compilers that SDL supports allow this.

CU

I suggest to see how this is done in Allegro:
int main(void) {
allegro_init(); /* more stuff goes here */

return 0; }
END_OF_MAIN()

END_OF_MAIN is a special macro which is different for different
platforms. See Allegro’s headers for more info.

Did all missed this message?
OK, I explain more.

That would be an option for SDL1.3 to do it, if all
the compilers that SDL supports allow this.

It would be nice!
Are there any differences between Allegro and SDL in compiler support
except that Allegro supports DJGPP (and DOS platform)?–
Roman Kyrylych (??? ???)