Question

I'm trying to compile a project using a library I made on Windows, using MinGW 4.8.1 x86. The project compiles fine on Linux.

Common.hpp is included before everything else, and defines some macros depending on the current OS. Then ConsoleFmt.hpp is included, and it includes a file depending on the previously defined macros.

I'm getting an error, however - here's the code and the error message:


Common.hpp

#if (__linux || __unix || __posix)
    #define SSVU_OS_LINUX
#elif (_WIN64 || _WIN32)
    #define SSVU_OS_WINDOWS
#else
    #define SSVU_OS_UNKNOWN
#endif

ConsoleFmt.hpp

#include "Common.hpp"

#ifdef SSVU_OS_LINUX
    #include "SSVUtils/Core/ConsoleFmt/Internal/ConsoleFmtImplUnix.hpp"
#elif SSVU_OS_WINDOWS
    #include "SSVUtils/Core/ConsoleFmt/Internal/ConsoleFmtImplWin.hpp"
#else
    #include "SSVUtils/Core/ConsoleFmt/Internal/ConsoleFmtImplNull.hpp"
#endif

Error:

error: #elif with no expression:

#elif SSVU_OS_WINDOWS

Is my code invalid or is there a bug in MinGW? I think I'm using #elif correctly.

Was it helpful?

Solution 2

The safe solution, IMO, is to define SSVU_OS_* in such a way that it doesn't matter whether you use #if or #ifdef.

#if (__linux || __unix || __posix)
    #define SSVU_OS_LINUX 1
#elif (_WIN64 || _WIN32)
    #define SSVU_OS_WINDOWS 1
#else
    #define SSVU_OS_UNKNOWN 1
#endif

This lets your #ifdef/#elif work already as it is. For consistency, you can then clean that up to

#if SSVU_OS_LINUX
    #include "SSVUtils/Core/ConsoleFmt/Internal/ConsoleFmtImplUnix.hpp"
#elif SSVU_OS_WINDOWS
    #include "SSVUtils/Core/ConsoleFmt/Internal/ConsoleFmtImplWin.hpp"
#else
    #include "SSVUtils/Core/ConsoleFmt/Internal/ConsoleFmtImplNull.hpp"
#endif

but it isn't strictly necessary.

Making sure your macros work without needing #ifdef/defined checks allows for simpler expressions if you combine multiple checks (like you already do with the macros of others: you check multiple using ||).

OTHER TIPS

#elif is a contraction of #else and #if, not #else and #ifdef, so your line should read:

#elif defined(SSVU_OS_WINDOWS)

Edit: Because undefined macros expand to 0 in #if expressions, you could also use the original variant and define the active macro with a value of 1. (As hvd has just posted and explained.)

To explain why it works in Linux but fails in Windows:

#elif (_WIN64 || _WIN32)

If _WIN64 has been defined then it gets replaced, e.g. if these had been defined

#define _WIN64
#define _WIN32

then the first line expands to

#elif ( || )

which would generate an error. However, if those tokens were not defined at all, they get replaced by 0:

#elif (0 || 0)

which is OK.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top