Porting SDL applications to OS/2

From EDM2
Revision as of 15:46, 3 April 2005 by Doodle (Talk | contribs)

Jump to: navigation, search

Porting SDL applications to OS/2

Requirements

To port SDL applications to OS/2, you'll need the latest SDL binaries and header files from netlabs.org. Currently the OpenWatcom compiler is the compiler for the OS/2 port of SDL, but it should also work with GCC.

Using the OpenWatcom compiler

There are some requirements and tricks with using the OpenWatcom compiler to port SDL applications. You should note the followings things.

Use the -ei switch for the OpenWatcom C compiler

You have to use the -ei switch for the OpenWatcom C compiler to have the size of enums equal to the size of ints. This is a requirement of SDL itself.

Use the -5s switch for the OpenWatcom C compiler

Starting with the build of 2005.03.30. of SDL/2, the calling convention has been changed to be stack-based (switch -5s) instead of the previous register-based one (switch -5r or simply -5).

Although the register-based version was faster (in theory), the calling convention has been changed to be compatible with GCC, so people using GCC can use SDL.DLL without problems, even where SDL calls into the GCC code (e.g. audio mixer callback), because now both of them use the very same convention.

So, don't forget to use the -5s switch for the OpenWatcom C compiler if you use that to compile your SDL application!

Wrapping the SDL_Quit() function

The OS/2 version of SDL is compiled into a DLL file. This DLL file has all the SDL functions exported by name. In order to be able to use this DLL from most of the available compilers, these exports are using the _Syscall calling convention. This leads to problems with some SDL apps, where they assume that the calling convention of the API is the same as the calling convention of their runtime library. For example, the following line is very usual in SDL applications:

...
atexit(SDL_Quit);
...

This should be worked around by creating a wrapper function for SDL_Quit, and using that one, this way:

#ifdef __WATCOMC__
void SDL_Quit_Wrapper()
{
   SDL_Quit();
}
#endif
...
#ifdef __WATCOMC__
atexit(SDL_Quit_Wrapper);
#else
atexit(SDL_Quit);
#endif;

Using the GNU C Compiler

It was reported that some (or maybe all) of the GNU C compilers (GCC) available for OS/2 can not handle the SDL.LIB file included in the SDL DevPack. The problem is that the SDL.LIB file was created directly from the SDL.DLL file, using the IMPLIB.EXE tool from the OS/2 Developer's Toolkit, and the GCC does not recognize it to be a valid library file.

There is a workaround, which is reported to work in this case. One has to create a GCC-compatible library file (.a), using the EMXIMP tool, and link against that file:

emximp -o sdl.imp sdl.lib
emximp -o sdl.a sdl.imp

If you plan on using SDL's multithreading capabilities (e.g. if you want to include "SDL_thread.h"), be sure that enable multithreading with -Zmt on your GCC commandline, otherwise you'll get an error because _beginthread() and _endthread() will not be defined.

General tips and tricks

Morph your program to a PM program at runtime

Most SDL applications assume that they can write to STDOUT, and the user will see it. In OS/2, you have to compile your application to a PM application in order to be able to have a PM Window, but the STDOUT will go to NULL in this case. The solution is to compile your code to a VIO application, and morph the application to a PM one dynamically, at runtime, before calling SDL_Init().

Once you have your text output back, you might use it for showing debug messages. If you do so, it's a good idea to make the STDOUT and STDERR unbuffered, so the debug messages will be shown right at the time when the printf() is called, so every message will be visible even in case of a crash.

Here is an example code on how to morph your VIO application to a PM one dynamically, at runtime, and how to set STDOUT and STDERR unbuffered:

#define INCL_DOS
#include <os2.h>
#include <stdio.h>

...

void MorphToPM()
{
  PPIB pib;
  PTIB tib;

  DosGetInfoBlocks(&tib, &pib);

  // Change flag from VIO to PM:
  if (pib->pib_ultype==2) pib->pib_ultype = 3;
}

...

int main(int argc, char *argv[])
{
  MorphToPM(); // Morph the VIO application to a PM one to be able to use Win* functions

  // Make stdout and stderr unbuffered
  setbuf( stdout, NULL );
  setbuf( stderr, NULL );
 
  /* Initialize SDL */
  if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
     fprintf(stderr, "Couldn't initialize SDL: %s\n",SDL_GetError());
     exit(1);
  }
  
...