Error: `#elif with no expression` - happens only on Windows - c++

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.

#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.)

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 ||).

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.

Related

How to get rid of warnings that precompiler definitions are not definied

There is a file that I downloaded from the Unity web-site
#pragma once
// Standard base includes, defines that indicate our current platform, etc.
#include <stddef.h>
// Which platform we are on?
// UNITY_WIN - Windows (regular win32)
// UNITY_OSX - Mac OS X
// UNITY_LINUX - Linux
// UNITY_IOS - iOS
// UNITY_TVOS - tvOS
// UNITY_ANDROID - Android
// UNITY_METRO - WSA or UWP
// UNITY_WEBGL - WebGL
#if _MSC_VER
#define UNITY_WIN 1
#elif defined(__APPLE__)
#if TARGET_OS_TV //'TARGET_OS_TV' is not defined, evaluates to 0
#define UNITY_TVOS 1
#elif TARGET_OS_IOS //'TARGET_OS_IOS' is not defined, evaluates to 0
#define UNITY_IOS 1
#else
#define UNITY_OSX 1 //'UNITY_OSX' macro redefined
#endif
#elif defined(__ANDROID__)
#define UNITY_ANDROID 1
#elif defined(UNITY_METRO) || defined(UNITY_LINUX) || defined(UNITY_WEBGL)
// these are defined externally
#elif defined(__EMSCRIPTEN__)
// this is already defined in Unity 5.6
#define UNITY_WEBGL 1
#else
#error "Unknown platform!"
#endif
...
The problem is that when I try to include the file in my XCode project I got a warning (put them in comments)
...
#if TARGET_OS_TV //'TARGET_OS_TV' is not defined, evaluates to 0
#define UNITY_TVOS 1
#elif TARGET_OS_IOS //'TARGET_OS_IOS' is not defined, evaluates to 0
#define UNITY_IOS 1
#else
#define UNITY_OSX 1 //'UNITY_OSX' macro redefined
#endif
...
I tried to use #pragma warning(suppress: 4101) and a few similar approaches, but it doesn't help
UPD
...
#ifdef TARGET_OS_TV
#define UNITY_TVOS 1
#elif TARGET_OS_IOS //'TARGET_OS_IOS' is not defined, evaluates to 0
#define UNITY_IOS 1
#else
#define UNITY_OSX 1
#endif
...
Using ifdef helps to get rid of the first warning, but the second one is still in place
UPD2
...
#ifdef TARGET_OS_TV
#define UNITY_TVOS 1
#elifdef TARGET_OS_IOS //Invalid preprocessing directive
#define UNITY_IOS 1
#else
#define UNITY_OSX 1
#endif
...
You should not use #if to test an undefined macro. The warning implies that you should use #ifdef instead.
You may not define a previously defined macro. You could first undefined the old definition, but that's rarely a good idea.
Using ifdef helps to get rid of the first warning, but the second one is still in place
In c++23 you will be able to use #elifdef instead.
Otherwise, you can use #elif defined(the_macro).

error C1189: #error : Please define your platform

I have this err when I build on visual studio ultimate2010, can you have me fix this error, thanks so much!
Error 1 error C1189: #error : Please define your
platform. d:\dzz\src\flexengine\fxcore\platform.h 28 1 battleserver
#pragma once
// 平台定义
#if defined __APPLE__
#include "AvailabilityMacros.h"
#include "TargetConditionals.h"
#if TARGET_OS_IPHONE
/* if compiling for iPhone */
#define PLATFORM_IPHONE 1
#else
#define PLATFORM_MACOSX 1
#endif
#elif TARGET_OS_IPHONE
#define PLATFORM_IPHONE 1
#elif ANDROID
#define PLATFORM_ANDROID 1
#elif _WINDOWS
#define PLATFORM_WINDOWS 1
#elif (defined(__linux__))
#define PLATFORM_LINUX 1
#elif (defined(unix))
#define PLATFORM_UNIX 1
#else
#error Please define your platform.
#endif
// 64位检测
#if defined(__x86_64__) || defined(_M_X64) || defined(__LP64__) || defined(__POWERPC64__) || defined( _WIN64 )
#define PLATFORM_64 1
#elif defined(__i386__) || defined(_M_IX86) || defined(_M_PPC) || defined(__LP32__) || defined(__POWERPC__) || IPHONE || ANDROID
#define PLATFORM_32 1
#else
#define PLATFORM_32 1
// #error Please define your platform.
#endif
// 是否支持异常
#if PLATFORM_WINDOWS
#define PLATFORM_EXCEPTIONS 1
#else
#define PLATFORM_EXCEPTIONS 0
#endif
// Platform specific include.
#if PLATFORM_WINDOWS
#include "platform_windows.h"
#elif PLATFORM_IPHONE
#include "platform_iphone.h"
#elif PLATFORM_MACOSX
#include "platform_macosx.h"
#elif PLATFORM_ANDROID
#include "platform_android.h"
#elif PLATFORM_LINUX
#include "platform_linux.h"
#else
#error Unknown platform.
#endif
It appears that this platform.h attempts to use pre-defined macros to detect the target platform. However, it tries to use _WINDOWS macro to detect windows, which is apparently a pre-processor macro supported by the Watcom compiler.
Your options:
Since the library that you use apparently only supports the watcom compiler on windows, you could use that instead of visual studio. If you choose to use VS, there may be other issues down the line that need to be fixed to support it besides this one.
You could work around the issue by defining the macro yourself.
You could fix the header to work with visual studio by replacing #elif _WINDOWS with #elif _WIN32. See macros pre-defined by visual studio.
I recommend going with the latter approach, however porting the library to VS may (or may not) involve a non-trivial amount of work.

How to Detect the OS in C at running time

I know it isn't simple, I've been researching it for a while, and now I'm almost sure that there's no completely safe way of doing so. But here is it.
I looking for a way of knowing which is the Operating System that my application is running on. Up to now, I got this:
#if defined(__WIN64__) || defined(__WIN64) || defined(WIN64)
#define NLF_OS_WINDOWS
#define NLF_OS_64BITS
#elif defined(__WIN32__) || defined(__WIN32) || defined(WIN32)
#define NLF_OS_WINDOWS
#define NLF_OS_32BITS
#elif defined(unix) || defined(__unix__) || defined(__unix)
#define NLF_OS_UNIX
#if defined(__APPLE__)
#define NLF_OS_APPLE
#define NLF_OS_BITS_UNIDENTIFIED
#include <TargetConditionals.h>
#if TARGET_OS_IPHONE && TARGET_IPHONE_SIMULATOR
#define NLF_OS_SIMULATOR
#elif TARGET_OS_IPHONE
#define NLF_OS_IPHONE
#else
#define NLF_OS_OSX
#endif
#elif defined(__linux__) || defined(__linux) || defined(linux)
#define NLF_OS_LINUX
#if defined(i386) || defined(__i386) || defined(__i386__)
#define NLF_OS_32BITS
#elif defined(amd64) || defined(__amd64) || defined(__amd64__)
#define NLF_OS_64BITS
#endif
#elif defined(__FreeBSD__) || defined(__FreeBSD) || defined(FreeBSD)
#define NLF_OS_FREEBSD
#if defined(i386) || defined(__i386) || defined(__i386__)
#define NLF_OS_32BITS
#elif defined(amd64) || defined(__amd64) || defined(__amd64__)
#define NLF_OS_64BITS
#endif
#endif
#else
#define NLF_OS_UNIDENTIFIED
#define NLF_OS_BITS_UNIDENTIFIED
#endif
It has already helped, but it only tells me what is the system when I'm compiling the application. But, since I want to cross-compile what I'm doing, it would be tremendously useful if I could provide to the app a way to know which is the current running system. Get it?
May be I may use the libraries sys/"something" (like sys/types.h and sys/stat.h) to do some ugly stuff, but I barely know any of those things.
PS.: A C++ solution isn't exactly what I want, but at this high I'm on it ^^"
Just finally answering this question.
The answer is: you don't need to. I've noticed that. The defines already works just fine. If you're compiling a C code for another platform, the cross compiler will take care of redefining de defines, so your system will always know what system is if you use the preprocessor directives.
But if for, some reason you really need it, you'll have to do ugly stuff. Like use a system("uname -a > my_file"); and then reading my_file content, and then try another command if this one do not works.
Mainly, you don't need it =)

C++ Shared Library Macro

I have a C++ shared library. The library has files to be exported. I was using Qt, which makes it quite easy, but I can't use it anymore. So I need a pure C++ variant that covers it for Linux and Windows. So I came up with the following macro definitions.
Pure C++
#if defined(_WIN32) || defined(_WIN64) || defined(WIN32) || defined(WIN64)
// Microsoft
#define MY_SHARED_EXPORT __declspec(dllexport)
#elif defined(__linux__) || defined(UNIX) || defined(__unix__) || defined(LINUX)
// GCC
#define MY_SHARED_EXPORT __attribute__((visibility("default")))
#else
// do nothing and hope for the best?
#define MY_SHARED_EXPORT
#pragma WARNING: Unknown dynamic link import/export semantics.
#endif
Qt C++
#if defined(MY_LIBRARY)
# define MY_SHARED_EXPORT Q_DECL_EXPORT
#else
# define MY_SHARED_EXPORT Q_DECL_IMPORT
#endif
Currently I'm using the Qt C++ variant.
My question is if it is safe to replace the Qt variant, as seen above, with the pure C++ variant. And are they equivalent?
Any help is appreciated, thanks in advance.
It's safe to define your own import/export macros. But the one you posted is not equivalent to Qt one because you did not handle the import. It should be:
#if defined(_WIN32) || defined(_WIN64) || defined(WIN32) || defined(WIN64)
// Microsoft
#if defined(MY_LIBRARY)
#define MY_SHARED_EXPORT __declspec(dllexport)
#else
#define MY_SHARED_IMPORT __declspec(dllimport)
#endif
#elif defined(__linux__) || defined(UNIX) || defined(__unix__) || defined(LINUX)
// GCC
#if defined(MY_LIBRARY)
#define MY_SHARED_EXPORT __attribute__((visibility("default")))
#else
#define MY_SHARED_IMPORT
#endif
#else
// do nothing and hope for the best?
#define MY_SHARED_EXPORT
#pragma WARNING: Unknown dynamic link import/export semantics.
#endif
I'm not 100% sure __attribute__((visibility("default"))) applies to Linux. In my mind, this was for iOS.
As commented by Rafael, the easiest is probably to simply go to Qt sources (qglobal.h) and copy/paste Q_DECL_EXPORT/Q_DECL_IMPORT from here to your own header file and then include it from your environment.

Determining when cross compiling for 32 bit from 64-bit in preprocessor?

I used the answer from Determining 32 vs 64 bit in C++ to make this:
#ifndef AVUNA_CFG
#define AVUNA_CFG
#if _WIN32 || _WIN64
#if _WIN64
#define BIT64
#else
#define BIT32
#endif
#endif
// Check GCC
#if __GNUC__
#if __x86_64__ || __ppc64__
#define BIT64
#else
#define BIT32
#endif
#endif
#endif
However, this doesn't seem to work when specifying -m32 to GCC for cross compiling, so it always says BIT64. Is there any defines I can use for this purpose?
I ended up using an Eclipse-define because I have two different run configurations for 32/64-bit cross compile. Works well.