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.
My problem is very much related the post
Defined macro not recognized
I wrote a CMakeLists file to be able to build my project for OS X (Eclipse mostly but sometimes used Xcode) and Windows (Visual Studio). The issue showed up today when creating my project for Windows + MinGW. I was using the defined _WIN32 to enable some functions when I was in windows, i.e.
bool Normal::HasNaNs() const
{
#ifdef _WIN32
return _isnan(x) || _isnan(y) || _isnan(z);
#else
return isnan(x) || isnan(y) || isnan(z);
#endif
}
However, with the combo Eclipse+MinGW the code is entering the ifdef part instead of (what I was hoping/thinking should be correct) entering the else part. I think Visual is the only one having the _isnan() function.
So, what would be a more robust way to check for Windows+VS, Windows+MinGW, OSX ?
_MSC_VER is the best way to check if you're being compiled by Visual Studio:
https://msdn.microsoft.com/en-us/library/b0084kay.aspx
For checking for MinGW (please see comment for more info), you can use:
#ifdef __GNUC__
#ifdef __MINGW32__
as per this answer:
https://stackoverflow.com/a/17493838/493106
and then __APPLE__ for os x.
https://stackoverflow.com/a/2166491/493106
Similarly to the directive:
#if defined(__linux__)
....
#else
...
#endif
used to switch from something for Linux to something for other O.S., how can I set in C++ to switch from a Kit for Embedded System to a Kit for Desktop?
#if defined(...what instruction...)
?
I don't know if there is a define that every embedded system will have (I doubt there is one). However, you could always use your own defines like:
#define __IS_EMBEDDED__
or
#define __IS_DESKTOP__
and then check those at the appropriate places:
#if defined(__IS_EMBEDDED__)
...
#else
...
#endif
Depending on the system you build your software for, you can activate the appropriate defines. An elegant method to achieve this would be to pass the defines as compiler flags as suggested in the comment by #Murphy.
Porting my project from Qt4 to Qt5.1, I get this error from a Qt file:
C:\Qt\Qt5.1.1\5.1.1\mingw48_32\include\QtGui\qopenglversionfunctions.h:785: error: expected unqualified-id before ')' token
void (QOPENGLF_APIENTRYP MemoryBarrier)(GLbitfield barriers);
^
This is the chain of defines:
#define QOPENGLF_APIENTRYP QOPENGLF_APIENTRY *
#define QOPENGLF_APIENTRY APIENTRY
#define APIENTRY WINAPI
#define WINAPI __stdcall
I noticed that the "MemoryBarrier" token is present in the libQt5OpenGLExtensionsd.a library. Should I include it, even if in the original Qt4 project nothing related to OpenGL was used?
Platform:
Windows 7
MinGW 4.8
Qt 4.8 --> Qt 5.1
Besides the bug in MinGW 4.8.1 with uint64_t in io.h, there is also this one in QT 5.2.1 still. I came across this today when trying to compile QT 5.2.1 with MinGW 4.8.1, so I thought I would post my solution as well.
I don't know what the official fix will be for QT, but for my needs I did it like this:
in src/gui/opengl/qopengl.h line 49:
// Windows always needs this to ensure that APIENTRY gets defined
#if defined(Q_OS_WIN)
# include <QtCore/qt_windows.h>
#endif
I just undefined the windows MemoryBarrier macro there:
// Windows always needs this to ensure that APIENTRY gets defined
#if defined(Q_OS_WIN)
# include <QtCore/qt_windows.h>
# undef MemoryBarrier
#endif
I noticed that the "MemoryBarrier" token is present in the
libQt5OpenGLExtensionsd.a library. Should I include it, even if in the
original Qt4 project nothing related to OpenGL was used?
No, those are not related. OpenGLExtension is compiled after QtGui.
What you are hitting unfortunately is that there is a MemoryBarrier() already defined on Windows, and hence there is a clash for that and what qt is having. You can find the official Windows documentation for that:
http://msdn.microsoft.com/en-us/library/windows/apps/ms684208(v=vs.85).aspx
I have just discussed this with Gunnar, the QtGui maintainer, and I am planning to submit a change to Gerrit to address your issue.
We had used something like this in our project a couple of years ago when we were writing thread-safe singletons based on QtCore:
#if defined __GNUC__ && __GNUC__ >= 4 && __GNUC_MINOR__ >= 4
#define __MEMBARRIER __sync_synchronize();
#elif defined _MSC_VER && defined _WIN64
#define __MEMBARRIER MemoryBarrier();
#else
#define __MEMBARRIER
#endif
Qt may need to check ifdef MINGW/GCC/VERSION and undef the MemoryBarrier define.
EDIT: This was fixed about half a year ago. See the following Gerrit review and the corresponding bug report for details:
https://codereview.qt-project.org/#change,68156
and
https://bugreports.qt.io/browse/QTBUG-34080
So, update to Qt 5.2.0 and it will work. Failing that, you can try to backport it.
I run into the same problem. I could compile and run with just commenting out the problematic line:
// void (QOPENGLF_APIENTRYP MemoryBarrier)(GLbitfield barriers);
In file C:/Qt/Qt5.1.1/5.1.1/mingw48_32/include/QtGui/qopenglversionfunctions.h:785
My application does not use any OpenGL stuff. Let's hope they fix it soon ;-)
Since the accepted answer doesn't seem to help when one tries to build the QT library on it's own and Laszlo Pap claims that thie other solution is not a proper fix, I tried to find a way to fix it correctly. On Google I found a posting where it was said that MemoryBarrier is not implemented in MingW and there was a patch for it.
So I tried to incorporate the fix into opengl.h and hope that this is the correct way as simply commenting out the lines may cause problems later on.
#ifndef QT_NO_OPENGL
// Windows always needs this to ensure that APIENTRY gets defined
#if defined(Q_OS_WIN)
# include <QtCore/qt_windows.h>
#if defined(__MINGW32__) && defined(MemoryBarrier)
#undef MemoryBarrier
__CRT_INLINE void MemoryBarrier(void)
{
long Barrier = 0;
__asm__ __volatile__("xchgl %%eax,%0 "
:"=r" (Barrier));
}
#endif
#endif
To handle platform specific code between Mac and Windows, WIN32 and APPLE are the terms to use, right?
So, thw code would look like this:
#ifdef _WIN32
// Windows code
#endif
#ifdef __APPLE__
// Mac code
#endif
What about Linux ?
How can i do that for all three? right
It's similar:
#ifdef __linux__
// Linux code
#endif
Since you are going to have either one of these three defined at a time, this should be ok for all three.
List of defines.