Search code examples
cc-preprocessormultiplatform

Multiplatform support, preprocesser or linking with individual libraries


I'm working on a homebrew game for the GBA, and was thinking about porting it to the PC (likely using SDL) as well. I haven't dealt with the problem of multiplatform support before, so I don't really have any experience.

I came up with two possible ways of going about it, but both have drawbacks, and I don't know if there is a way better solution I'm missing out on.

First would use the preprocessor. A header file would be included in all files which would #define GBA, and based on whether it is defined, the appropriate headers will be included and the appropriate platform specific code will be compiled for the platform.

I would implement it something like

/* GBA definition is in platform.h */
/* Example.c */

void example()
#ifdef GBA
{
    /* GBA specific implementation goes here */
}
#else
{
    /* PC specific implementation goes here */
}
#endif

The drawback I see here is for a large project, this can get very messy and is frankly kind of ugly and difficult to read.

The other option I can think of is creating static libraries for each platform. Therefore the main source code for both platforms will be the same, increasing ease of simultaneous development, and when building for GBA or PC, the appropriate libraries and settings will be specified and that's it.

The obvious drawback here is that if there needs to be a change in the implementation of something in the library, if something needs to be added, or anything really regarding the library, it needs to be maintained and rebuilt constantly, along with the main actual program.

If there is a better way to approach this, what would it be? If the ways I mentioned are the standard way of doing it, which is more common / better for long term development?


Solution

  • Here's what I would do [and have done]. Doing [a lot of] #ifdef/#else/#endif sequences is hard to maintain. Trust me, I've done it, until I found better ways. Below is a way I've used in the past. There are other similar approaches.

    Here is the generic code:

    // example.c -- generic code
    
    #ifdef _USE_GBA_
    #include <example_gba.c>
    #endif
    
    #ifdef _USE_SDL_
    #include <example_sdl.c>
    #endif
    
    void
    example(void)
    {
        // NOTE: this will get optimized using tail recursion into a jump or
        // example_dep will get inlined here
        example_dep();
    }
    

    Here is the GBA specific code:

    // example_gba.c -- GBA specific code
    
    static void
    example_dep(void)
    {
        // ...
    }
    

    Here is the SDL code:

    // example_sdl.c -- SDL specific code
    
    static void
    example_dep(void)
    {
        // ...
    }