C++ Platform specific includes - c++

I'm working on a multi-platform project. I want a simple and quick way of managing OS-specific includes, preferably without any external tools.
I would like something like this (which I'm well aware won't work)
#define PLATFORM_A 1
#define PLATFORM_B 2
#ifndef TARGET_PLATFORM
//ERROR
#endif
#if TARGET_PLATFORM == PLATFORM_A
#define DIR "a"
#elif TARGET_PLATFORM == PLATFORM_B
#define DIR "b"
#define PLATFORM_INCLUDE(file) \
#include "platforms/" DIR "/" file

One set up I see fairly frequently is as follows:
// platform.h
#if defined PLATFORM_A
#include "platform_a.h"
#elif defined PLATFORM_B
#include "platform_b.h"
#else
// #pragma error or whatever
#endif
Then #include "platform.h" where necessary.

If you have same file tree for different platfroms you could specify only file name for include file in the source code and use platform dependent include directory. This directory could be easily configured by environment variable.

You can have preprocessor directives defined by the platform itself. In this way you can use:
#ifndef MAC // MAC performs #define MAC
#ifndef WINDOWS // Windows performs #define WINDOWS
#ifndef UNIX // Unix performs #define UNIX
// ERROR
#endif
#endif
#endif

Try using + between your strings. That should be the C++ syntax.
So something like:
#define PLATFORM_INCLUDE(file) \
#include "platforms/" + DIR + "/" file

Related

How I can check that the system that I build is for linux or not? [duplicate]

I need my code to do different things based on the operating system on which it gets compiled. I'm looking for something like this:
#ifdef OSisWindows
// do Windows-specific stuff
#else
// do Unix-specific stuff
#endif
Is there a way to do this? Is there a better way to do the same thing?
The Predefined Macros for OS site has a very complete list of checks. Here are a few of them, with links to where they're found:
Windows
_WIN32   Both 32 bit and 64 bit
_WIN64   64 bit only
__CYGWIN__
Unix (Linux, *BSD, but not Mac OS X)
See this related question on some of the pitfalls of using this check.
unix
__unix
__unix__
Mac OS X
__APPLE__ Also used for classic
__MACH__
Both are defined; checking for either should work.
Linux
__linux__
linux Obsolete (not POSIX compliant)
__linux Obsolete (not POSIX compliant)
FreeBSD
__FreeBSD__
Android
__ANDROID__
show GCC defines on Windows:
gcc -dM -E - <NUL:
on Linux:
gcc -dM -E - </dev/null
Predefined macros in MinGW:
WIN32 _WIN32 __WIN32 __WIN32__ __MINGW32__ WINNT __WINNT __WINNT__ _X86_ i386 __i386
on UNIXes:
unix __unix__ __unix
Based on nadeausoftware and Lambda Fairy's answer.
#include <stdio.h>
/**
* Determination a platform of an operation system
* Fully supported supported only GNU GCC/G++, partially on Clang/LLVM
*/
#if defined(_WIN32)
#define PLATFORM_NAME "windows" // Windows
#elif defined(_WIN64)
#define PLATFORM_NAME "windows" // Windows
#elif defined(__CYGWIN__) && !defined(_WIN32)
#define PLATFORM_NAME "windows" // Windows (Cygwin POSIX under Microsoft Window)
#elif defined(__ANDROID__)
#define PLATFORM_NAME "android" // Android (implies Linux, so it must come first)
#elif defined(__linux__)
#define PLATFORM_NAME "linux" // Debian, Ubuntu, Gentoo, Fedora, openSUSE, RedHat, Centos and other
#elif defined(__unix__) || !defined(__APPLE__) && defined(__MACH__)
#include <sys/param.h>
#if defined(BSD)
#define PLATFORM_NAME "bsd" // FreeBSD, NetBSD, OpenBSD, DragonFly BSD
#endif
#elif defined(__hpux)
#define PLATFORM_NAME "hp-ux" // HP-UX
#elif defined(_AIX)
#define PLATFORM_NAME "aix" // IBM AIX
#elif defined(__APPLE__) && defined(__MACH__) // Apple OSX and iOS (Darwin)
#include <TargetConditionals.h>
#if TARGET_IPHONE_SIMULATOR == 1
#define PLATFORM_NAME "ios" // Apple iOS
#elif TARGET_OS_IPHONE == 1
#define PLATFORM_NAME "ios" // Apple iOS
#elif TARGET_OS_MAC == 1
#define PLATFORM_NAME "osx" // Apple OSX
#endif
#elif defined(__sun) && defined(__SVR4)
#define PLATFORM_NAME "solaris" // Oracle Solaris, Open Indiana
#else
#define PLATFORM_NAME NULL
#endif
// Return a name of platform, if determined, otherwise - an empty string
const char *get_platform_name() {
return (PLATFORM_NAME == NULL) ? "" : PLATFORM_NAME;
}
int main(int argc, char *argv[]) {
puts(get_platform_name());
return 0;
}
Tested with GCC and clang on:
Debian 8
Windows (MinGW)
Windows (Cygwin)
Microsoft C/C++ compiler (MSVC) Predefined Macros can be found here
I think you are looking for:
_WIN32 - Defined as 1 when the compilation target is 32-bit ARM, 64-bit ARM, x86, or x64. Otherwise, undefined
_WIN64 - Defined as 1 when the compilation target is 64-bit ARM or x64. Otherwise, undefined.
gcc compiler PreDefined MAcros can be found here
I think you are looking for:
__GNUC__
__GNUC_MINOR__
__GNUC_PATCHLEVEL__
Do a google for your appropriate compilers pre-defined.
In most cases it is better to check whether a given functionality is present or not. For example: if the function pipe() exists or not.
#ifdef _WIN32
// do something for windows like include <windows.h>
#elif defined __unix__
// do something for unix like include <unistd.h>
#elif defined __APPLE__
// do something for mac
#endif
On MinGW, the _WIN32 define check isn't working. Here's a solution:
#if defined(_WIN32) || defined(__CYGWIN__)
// Windows (x86 or x64)
// ...
#elif defined(__linux__)
// Linux
// ...
#elif defined(__APPLE__) && defined(__MACH__)
// Mac OS
// ...
#elif defined(unix) || defined(__unix__) || defined(__unix)
// Unix like OS
// ...
#else
#error Unknown environment!
#endif
For more information please look: https://sourceforge.net/p/predef/wiki/OperatingSystems/
There is no standard macro that is set according to C standard. Some C compilers will set one on some platforms (e.g. Apple's patched GCC sets a macro to indicate that it is compiling on an Apple system and for the Darwin platform). Your platform and/or your C compiler might set something as well, but there is no general way.
Like hayalci said, it's best to have these macros set in your build process somehow. It is easy to define a macro with most compilers without modifying the code. You can simply pass -D MACRO to GCC, i.e.
gcc -D Windows
gcc -D UNIX
And in your code:
#if defined(Windows)
// do some cool Windows stuff
#elif defined(UNIX)
// do some cool Unix stuff
#else
# error Unsupported operating system
#endif
Sorry for the external reference, but I think it is suited to your question:
C/C++ tip: How to detect the operating system type using compiler predefined macros
You can use Boost.Predef which contains various predefined macros for the target platform including the OS (BOOST_OS_*). Yes boost is often thought as a C++ library, but this one is a preprocessor header that works with C as well!
This library defines a set of compiler, architecture, operating system, library, and other version numbers from the information it can gather of C, C++, Objective C, and Objective C++ predefined macros or those defined in generally available headers. The idea for this library grew out of a proposal to extend the Boost Config library to provide more, and consistent, information than the feature definitions it supports. What follows is an edited version of that brief proposal.
For example
#include <boost/predef.h>
// or just include the necessary header
// #include <boost/predef/os.h>
#if BOOST_OS_WINDOWS
#elif BOOST_OS_ANDROID
#elif BOOST_OS_LINUX
#elif BOOST_OS_BSD
#elif BOOST_OS_AIX
#elif BOOST_OS_HAIKU
...
#endif
The full list can be found in BOOST_OS operating system macros
Demo on Godbolt
See also How to get platform IDs from boost?
Use #define OSsymbol and #ifdef OSsymbol
where OSsymbol is a #define'able symbol identifying your target OS.
Typically you would include a central header file defining the selected OS symbol and use OS-specific include and library directories to compile and build.
You did not specify your development environment, but I'm pretty sure your compiler provides global defines for common platforms and OSes.
See also http://en.wikibooks.org/wiki/C_Programming/Preprocessor
Just to sum it all up, here are a bunch of helpful links.
GCC Common Predefined Macros
SourceForge predefined Operating Systems
MSDN Predefined Macros
The Much-Linked NaudeaSoftware Page
Wikipedia!!!
SourceForge's "Overview of pre-defined compiler macros for standards, compilers, operating systems, and hardware architectures."
FreeBSD's "Differentiating Operating Systems"
All kinds of predefined macros
libportable
I did not find Haiku definition here. To be complete, Haiku-os definition is simple __HAIKU__
Some compilers will generate #defines that can help you with this. Read the compiler documentation to determine what they are. MSVC defines one that's __WIN32__, GCC has some you can see with touch foo.h; gcc -dM foo.h
You can use pre-processor directives as warning or error to check at compile time you don't need to run this program at all just simply compile it .
#if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__)
#error Windows_OS
#elif defined(__linux__)
#error Linux_OS
#elif defined(__APPLE__) && defined(__MACH__)
#error Mach_OS
#elif defined(unix) || defined(__unix__) || defined(__unix)
#error Unix_OS
#else
#error Unknown_OS
#endif
#include <stdio.h>
int main(void)
{
return 0;
}
I wrote an small library to get the operating system you are on, it can be installed using clib (The C package manager), so it is really simple to use it as a dependency for your projects.
Install
$ clib install abranhe/os.c
Usage
#include <stdio.h>
#include "os.h"
int main()
{
printf("%s\n", operating_system());
// macOS
return 0;
}
It returns a string (char*) with the name of the operating system you are using, for further information about this project check it out the documentation on Github.

#error you must define the platform macro

I have a project that I compile and it gives me following errors as:
In file included from c:/acrobatxsdk/Adobe/Acrobat 10 SDK/Version 1/PluginSupport/Headers/API/PIMain.c:21:0:
c:/acrobatxsdk/Adobe/Acrobat 10 SDK/Version 1/PluginSupport/Headers/API/Environ.h:37:2: error: #error You must define the PLATFORM macro
c:/acrobatxsdk/Adobe/Acrobat 10 SDK/Version 1/PluginSupport/Headers/API/Environ.h:41:10: error: #include expects "FILENAME" or <FILENAME>
c:/acrobatxsdk/Adobe/Acrobat 10 SDK/Version 1/PluginSupport/Headers/API/Environ.h:52:2: error: #error PLATFORM failed to #define ACCB1
The PIMain.c looks like this :
#if WIN_PLATFORM
#include "WinCalls.h"
#elif MAC_PLATFORM
#include "MacCalls.h"
#elif UNIX_PLATFORM
#include "UnixCalls.h"
#else
#error platform not defined
#endif
I have come to know that the only amendment if required is to be made in Environ.h , can some one suggest how?
Environ.h is looking for the PLATFORM directive and there is a preprocessor or compile time flag to "throw" an error if you do not define it. See how the #error directive works here (MSDN link).
I found the code for Environ.h:
#ifndef PLATFORM
#ifdef WIN_ENV
#define PLATFORM "winpltfm.h"
#elif __OS2__
#define PLATFORM "os2pltfm.h"
#elif defined(unix) || defined(__unix)
#define PLATFORM "UnixPlatform.h"
#else
#error You must define the PLATFORM macro
#endif
#endif
You apparently are not running on a supported platform.

c++ #ifdef Mac OS X question

I am fairly new to C++. I am currently working on a group project and we want to make our classes compatible with both the lab computers (Windows) and my computer (Mac OS X).
Here is what we have been putting at the top of our files:
#ifdef TARGET_OS_X
# include <GLUT/glut.h>
# include <OpenGL/OpenGL.h>
#elif defined _WIN32 || defined _WIN64
# include <GL\glut.h>
#endif
I realize this question has been asked before but my searches have been giving me conflicting answers such as "_MAC", "TARGET_MAC_OS", "MACINTOSH", etc. What is the current and correct declaration to put in the #ifdef statement to make this compatible with Mac? Right now it is not working.
Thank you!
According to this answer:
#ifdef __APPLE__
#include "TargetConditionals.h"
#ifdef TARGET_OS_IPHONE
// iOS
#elif TARGET_IPHONE_SIMULATOR
// iOS Simulator
#elif TARGET_OS_MAC
// Other kinds of Mac OS
#else
// Unsupported platform
#endif
#endif
So in short:
#ifdef __APPLE__
#include "TargetConditionals.h"
#ifdef TARGET_OS_MAC
#include <GLUT/glut.h>
#include <OpenGL/OpenGL.h>
#endif
#elif defined _WIN32 || defined _WIN64
#include <GL\glut.h>
#endif
It depends on the compiler. #ifdef __APPLE__ works for gcc.
According to Microsoft, _WIN32 will cover both the 32-bit and 64-bit versions of Windows. And __APPLE__ works for Clang (at least in Mavericks). So one correct way to write the ifdefs above is:
#ifdef __APPLE__
DoSomething();
#elif _WIN32
DoSomethingElse();
#else
GenerateErrorOrIgnore
Small correction: #ifdef TARGET_OS_MAC will get you always true on both OS X and iOS, as it is defines either 0 or 1 depending on platform, but when APPLE is defined, TARGET_OS_MAC is defined as well, so checking it inside the #ifdef APPLE is worthless.
You might want to use #if TARGET_OS_MAC instead. Same for all TARGET_* macros.

Which macro to wrap Mac OS X specific code in C/C++

While reading various C and C++ sources, I have encountered two macros __APPLE__ and __OSX__. I found plenty of use of __OSX__ in various codes, especially those originating from *BSD systems.
However, sometimes I find that testing __OSX__ only is not sufficient and I have to complete tests with __APPLE__ macro.
The Porting Command Line Unix Tools to Mac OS X guides specifies __APPLE__ and additionally __APPLE_CC__ but does not mention __OSX__.
The Porting from GCC guide says:
Use #ifdef __GNUC__ to wrap any GCC-specific code.
Use #ifdef __APPLE_CC__ to wrap any Mac OS X-specific code.
Again, no mention about __OSX__ macro.
What macro is predefined on Mac OS X platform and XCode development environment that should be used to distinguish OSX-specific code in C/C++ programs?
Where is the __OSX__ macro defined? Is it *BSD specific macro?
It all depends.
Each macro specifies something different in meaning.
See: https://developer.apple.com/library/mac/documentation/Porting/Conceptual/PortingUnix/compiling/compiling.html#//apple_ref/doc/uid/TP40002850-SW13
__APPLE__
This macro is defined in any Apple computer.
__APPLE_CC__
This macro is set to an integer that represents the version number of
the compiler. This lets you distinguish, for example, between compilers
based on the same version of GCC, but with different bug fixes or features.
Larger values denote later compilers.
__OSX__
Presumably the OS is a particular variant of OS X
So given the above definitions I would use __APPLE__ to distinguish apple specific code.
Here is a nice list of macros for operating systems.
There's little info on __OSX__ on the web. You'll be safe with __APPLE__.
I normally use __MACH__ for this. It's been defined since the earliest version of OS X (and even before, presumably).
If you want to exclude the possibility that you might be compiling for some other OS that uses the Mach kernel then you can use #scravy's suggestion of:
#if defined(__APPLE__) && defined(__MACH__)
Note also that if you're compiling generic C/C++ code, i.e. no Apple-speacific headers, so you are just interested in pre-defined compiler macros, you can check these as follows:
$ gcc -dM -E - < /dev/null | egrep -i 'os_|mac|apple'
#define __APPLE_CC__ 6000
#define __APPLE__ 1
#define __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ 120000
#define __ENVIRONMENT_OS_VERSION_MIN_REQUIRED__ 120000
#define __MACH__ 1
#define __VERSION__ "Apple LLVM 13.1.6 (clang-1316.0.21.2.3)"
#define __apple_build_version__ 13160021
Use
#if defined(__APPLE__) && defined(__MACH__)
to distinguish Apple operating systems.
You can further use TARGET_OS_MAC and TARGET_OS_IPHONE to distinguish between macOS and iOS.
Full example:
#if defined(__APPLE__) && defined(__MACH__)
/* Apple OSX and iOS (Darwin). */
#include <TargetConditionals.h>
#if TARGET_IPHONE_SIMULATOR == 1
/* iOS in Xcode simulator */
#elif TARGET_OS_IPHONE == 1
/* iOS */
#elif TARGET_OS_MAC == 1
/* macOS */
#endif
#endif
Regarding the question of "where does __OSX__ come from?":
Some on-line lists of compiler macros (like this one) list __MACOSX__. Some forum comments (like these) claim __OSX__ exists. These are incorrect. There are no such macros predefined by OSX compilers, but they may be defined by specific project Makefiles and platform-detector scripts like GNU autoconf.
Source: http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system
Update – the above link is broken, see version in web archive: https://web.archive.org/web/20180331065236/http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system#OSXiOSandDarwin
For anyone coming across this question >= 2019, I found there's a header "Availability.h".
In that header, are #defines like:
#define __MAC_10_0 1000
#define __MAC_10_1 1010
#define __MAC_10_2 1020
#define __MAC_10_3 1030
#define __MAC_10_4 1040
#define __MAC_10_5 1050
#define __MAC_10_6 1060
#define __MAC_10_7 1070
#define __MAC_10_8 1080
#define __MAC_10_9 1090
#define __MAC_10_10 101000
#define __MAC_10_10_2 101002
#define __MAC_10_10_3 101003
#define __MAC_10_11 101100
#define __MAC_10_11_2 101102
So you CAN tell if you're compiling on a particular MacOS platform.
See http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system#OSXiOSandDarwin
#ifdef __APPLE__
#include <TargetConditionals.h>
#if TARGET_OS_MAC
...
#endif /* TARGET_OS_MAC */
#endif /* __APPLE__ */
Note that __OSX__ does NOT exist, at least as of Xcode 9.
Also note that it is #if TARGET_OS_MAC not #ifdef. It is always defined, but is 0 when not macOS.

How can I #include a file whose name is built up from a macro?

On a cross-platform project, I want to #include a header file whose name contains the name of the platform. I have a #define macro for the platform.
So for example, for
#define PLATFORM win32
I want
#include "engine\win32\devices_win32.h"
while for
#define PLATFORM linux
I want
#include "engine\linux\devices_linux.h"
I'm going with Richard Pennington's answer, minus one line of code - it works for me!
#define PLATFORM Linux
#define xstr(x) #x
#define str(x) xstr(x)
#define sub(x) x
#include str(sub(engine/PLATFORM/devices_)PLATFORM.h)
Usually, you would do something more like:
#ifdef WIN32
#include "devices_win32.h"
#endif
#ifdef LINUX
#include "devices_linux.h"
#endif
...rather than having a single PLATFORM definition which can be set differently depending on the platform.
#define PLATFORM Linux
#define xstr(x) #x
#define str(x) xstr(x)
#define sub(x) x
#define FILE str(sub(engine/PLATFORM/devices_)PLATFORM.h)
#include FILE
I'm not sure I'd use it, though. ;-)
I had to use Linux rather than linux because linux is defined as 1 in my compiler.
Well in practice, this could be achieved using something like
#define PLATFORM win32
#define INCLUDE_FILE devices_ ## PLATFORM
#define QUOTED_INCLUDE_FILE #INCLUDE_FILE
#include QUOTED_INCLUDE_FILE
but the the following rule would prevent you from doing this:
C comments and predefined macro names are not recognized inside a #include' directive in which the file name is delimited with <' and `>'.
C comments and predefined macro names are never recognized within a character or string constant. (Strictly speaking, this is the rule, not an exception, but it is worth noting here anyway.)