Static linking nightmares

Posted by pulkomandy on Mon May 31 11:25:58 2010  •  Comments (0)  • 

I recently ported Reloaded, an Amstrad CPC emulator, to Windows. This turned out to be more complicated than expected, and I encoutered problems for which I can't find any proper solution on the internet, so I decided to tell you how I solved them.

Step one : SDL and wxWidgets

Reloaded is a very special project. It started its life as a fork of the Caprice32 emulator. Caprice was an emulator designed for Windows, but later ported to Linux using SDL to render the screen. SDL didn't provide support for anything else than pixels, and we wanted complex windows, so we decided to use wxWidgets. After some hacks, we got that running : SDL was used for sound and timers, and wxWidgets for display rendering.

It worked quite fine on Linux, but when trying to run it on Windows, I encountered a problem : both SDL and wxWidgets are trying to define the WinMain function to do some special inits and call the application's main. Of course, having two WinMains didn't please my compiler.

wxWidgets offers a nice way to solve that : their WinMain is defined in the macro IMPLEMENT_APP, which is easy to replace with something else if you want so (you have to do somme inits by yourself, but that's ok). SDL, however, doesn't allow you to do so : as soon as you #include SDL.h, it is not possible anymore to define WinMain yourself!

Reloaded is now using Portaudio for sound and doesn't rely on SDL anymore. I also had to disable OpenGL as our code used SDL_Surfaces, and rewrite some timer handling to use native windows functions.

Step 2 : getting it to link

Another particularity of Reloaded is the way its built : we wanted to create a platform-independant core, and a gui part that wraps around it and provide the windows and graphical stuff. This allows for really easy porting : you have very little things to alter in the core and only mess with rewriting the GUI part.

This was counting without autotools limitations : to build these files properly, we had to use different defines on each side. The core will have to look for portaudio includes while the gui will want wxWidgets. We solved that by building them into two separate .a static libraries, then linking these libs to a single executable.

Again, this was working well on Linux, but Windows strangely failed to link the thing, giving undefined references to portaudio and some other DLLs we are using. Also, I was getting an "undefined reference to main" for no apparent reason (as there was a WinMain function in my program). After some searching, I found I was supposed to add -lmingw32 _before_ my .a in g++ command line, or else the runtime loader wouldn't find WinMain. But doing so would result in undefined reference to every possible function in nwxWidgets.

After a full week of trial and error, I finally managed to get it working : you have to link -lmingw32 first, then your static libs (in the right order so they can link to each other), and finally link wxWidgets and other stuff you need.

I don't know why the gcc tools want the static libs to be in the right order while dynamic one will not care, I think that's not very practical and even annoying. But I hope this article will help you solve the same kind of problem, shouldyou ever encounter it.

Leave a comment

Name: Mail: