• Advertisement
Sign in to follow this  

[C++] "standardized" macro's to detect OS?

This topic is 3035 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I find the macro's to detect operating system with an #ifdef confusing, because I see different things being used. For Windows, is it _WIN32, WIN32, _MSDOS or MSDOS? What about 64-bit Windows, does "WIN32" still work there? For Linux, is it _GNUC_, UNIX, LINUX, POSIX, or what? And what is it for Mac? I don't have a Mac to develop on to try it but I might need it one day. I assume there doesn't really exist any reliable standard for it, but which combination would work best? Also, do there exist ways to detect with macro's what you're adding to the linker parameters of the compiler? For example, if I link to "boost_filesystem", it could use a boost implementation for browsing files, if not it could use a native one like win32 or posix code or a dummy implementation that says "not supported".

Share this post


Link to post
Share on other sites
Advertisement
This site has a good listing of predefined macros. As to what the best subsets are to maximize detection reliability, but minimize size, I'll leave that an open question :)

Share this post


Link to post
Share on other sites
Quote:
Original post by mattd
This site has a good listing of predefined macros. As to what the best subsets are to maximize detection reliability, but minimize size, I'll leave that an open question :)


Nice! They list more than enough operating systems in there :)
Very handy.

Share this post


Link to post
Share on other sites
Actually, you could get some guidance for that 'but which macros' open question by looking at how something like boost does it.

Share this post


Link to post
Share on other sites
Quote:
Original post by mattd
Actually, you could get some guidance for that 'but which macros' open question by looking at how something like boost does it.
I am not sure that is such a good idea - boost has some of the most convoluted platform and feature detection on the planet. Granted, they need it, but it should be complete overkill for a game project.

I usually stick with a simple (and so far reliable):
#if defined( WIN32 )
#elif defined( __APPLE__ )
#else /* some flavour of unix */
#endif

Of course, if you want to detect minor platforms, then you need to do a bit more work.

Share this post


Link to post
Share on other sites
Quote:
Original post by swiftcoder
I am not sure that is such a good idea - boost has some of the most convoluted platform and feature detection on the planet.

Quote:
I usually stick with a simple (and so far reliable):

Did you actually look at the header file that he linked to? What boost does isn't very different from what you do, except that it handles more platforms than you do.

Share this post


Link to post
Share on other sites
Quote:
Original post by SiCrane
Did you actually look at the header file that he linked to? What boost does isn't very different from what you do, except that it handles more platforms than you do.
Yes, but blindly copying from that header without familiarity for the platforms involved is dangerous. For instance, their Mac path supports classic-mac as well as OS X, which is something that one won't notice without mac experience, and almost certainly isn't what one intends.

Share this post


Link to post
Share on other sites
That's seems like a very different statement than "the most convoluted platform and feature detection on the planet."

Share this post


Link to post
Share on other sites
Quote:
Original post by SiCrane
That's seems like a very different statement than "the most convoluted platform and feature detection on the planet."
That header file is just the tip of the iceberg. There are detection headers for each platform, plus feature detection for endianess, integer types, system header files, etc.

But, to be fair, I did overstate that a little - sarcasm is a dangerous thing on the internet [smile]

Share this post


Link to post
Share on other sites
By more than a little if you just after you say it you then suggest to do things the exact same way.

Share this post


Link to post
Share on other sites
Quote:
Original post by swiftcoder
I usually stick with a simple (and so far reliable):

Aye to that. Supporting as much as three platforms is already a maintenance nightmare. Trying to support the 3876 different flavours of Unix and whatnot, all individually, is just... crazy. Simple is good.

I'm even going further and only distinguish "Windows" and "Posix" (and "Posix" really means "Linux" in this context). Obviously, which platforms are important and which ones aren't depends a lot on your personal needs. For me, Linux has to work, as it's the server platform. Making it a secondary client platform too does not involve *that* much extra pain, after this.
Apple would, in my opinion, require too much extra hassle for being worth it, and the remaining Unix flavours are out of the question anyway. It doesn't really matter whether they're great operating systems and so much better than Windows, if only a handful of people use them.

Supporting platforms is a question of development and maintenance cost versus possible revenue. If only 0.01% of all people use a particular platform at all, then unless you're a millionaire and only program for fun, it's no good supporting it.
Imagine your game is *really* successful and you have a $100,000 revenue with your Windows build. Let's assume porting to some exotic platform will require another 4-5 weeks of extra work, including error testing and everything. Let's say the market share on desktops is about 0.1% (seeing that Linux is said to only have 1% desktop share in 2009, I think that's a reasonable assumption). That means that if your sales are equally successful on that platform, you get $100 extra. So, that's 4-5 weeks of work for $100. Now, let there be regular updates, and your're screwed.

Someone of Stardock software (I think it was their CEO, but could be wrong) once said something similar regarding the Chinese market (the famous "ignore the pirates" interview). His reasoning, while maybe debatable, surely has a point. Plus, the fact that his company is still in business after decades somehow proves him right, too.

Share this post


Link to post
Share on other sites
I've always only used libraries that work on many platforms (SDL, OpenGL and boost, but boost only on linux because installing it on linux is merely a simple command of the package manager, while getting boosts libraries to work on Dev-C++ in Windows is hell and I don't want to spend the time on that). Windows and Linux must work by default for me, because I work mainly on Linux and want to allow Windows users to run it too. The fact that with those libs it works for Mac too is nice, but I've never been able to test it myself due to not having a Mac (but I have received reports by email from Mac users who managed to compile my code a few times, which is great).

Now I'm starting to need things not supported by the libraries mentioned above, and I didn't manage to find small libraries (= libraries that don't include a complete GUI like GTK) that can do it, so I need to implement them myself for each platform. I mean things like, storing persistant data in the folders the OS provides for that (appdata or my documents in windows, /etc/ and ~/ in linux), browsing which files are in a certain folder, hopefully the clipboard one day, etc...

And that's why I'm needing the #ifdefs now... But I also don't need more than just linux, Windows, and maybe Mac some day.

Share this post


Link to post
Share on other sites
Just a quick question about macros. I know some compilers support the __func__ macro for getting the current function/method name, but is there any macro that will return the name of the current class?

For example:

class MyClass
{
public:
void SomeMethod();
};

void MyClass::SomeMethod()
{
cout << "The class that this method belongs to is: " << __CLASS__ << endl;
}





Calling "SomeMethod()" would print out: "The class that this method belongs to is: MyClass"

Share this post


Link to post
Share on other sites
You might want to take a look at how Ogre3D does it, particularly at OgrePlatform.h. It isn't too complicated and Ogre3D supports Windows, Linux and OSX.

Share this post


Link to post
Share on other sites
Quote:
Original post by scarypajamas
Just a quick question about macros. I know some compilers support the __func__ macro for getting the current function/method name
Be aware that __func__ is a predefined identifier from C99, not C++ (though some C++ compilers allow it). Some compilers also define __PRETTY_FUNCTION__ with a full method signature, or __FUNCTION__ with just the function name. You typically have to perform some compiler identification to figure out the best one to use at compile-time...
Quote:
but is there any macro that will return the name of the current class?
No, though the suggestion rears its head once in a while on the GCC wishlists.

Share this post


Link to post
Share on other sites
You should be able to parse the decorated function name and extract the class name without too much difficulty. The decorated names are platform-dependent (actually, compiler-dependent), though.

Share this post


Link to post
Share on other sites
Quote:
.Original post by samoth
3876 different flavours of Unix and whatnot

No, not even in C++. I've never seen different mainstream flavours having different standard macros in gcc set.


Quote:
Simple is good.

Yes.


Quote:
I'm even going further and only distinguish "Windows" and "Posix" (and "Posix" really means "Linux" in this context). Obviously, which platforms are important and which ones aren't depends a lot on your personal needs. For me, Linux has to work, as it's the server platform. Making it a secondary client platform too does not involve *that* much extra pain, after this.
Apple would, in my opinion, require too much extra hassle for being worth it, and the remaining Unix flavours are out of the question anyway. It doesn't really matter whether they're great operating systems and so much better than Windows, if only a handful of people use them.

That is true.

I usually look at http://predef.sf.net, cherry pick for my targets, and in the #else I #error:

#if MARIO
// specific to platform mario
#elif LUIGI
// specific to platform luigi
#else
# error 'unsupported platform'
#endif


But about 99.934% of my C++ code is not platform specific anyways. I think the last time I used this was when I wrote a huge array (tested succesfully with 32GiB of data on 32bit platforms) implementation using linux mmaps.

Share this post


Link to post
Share on other sites
Quote:
Original post by phresnel
Quote:
.Original post by samoth
3876 different flavours of Unix and whatnot

No, not even in C++. I've never seen different mainstream flavours having different standard macros in gcc set.
Huh? Many distros have different paths for various headers, or move definitions around between headers (i.e. <malloc.h> or <stdlib.h> for malloc). Not to mention endianess, different versions of installed packages, and so on.
Quote:
But about 99.934% of my C++ code is not platform specific anyways.
Ja, I find this to be the case as well. Unfortunately, as soon as you start interacting with the UI or system tools, you land in the world of configuration hell...

Share this post


Link to post
Share on other sites
Quote:
Original post by swiftcoder
Quote:
Original post by phresnel
Quote:
.Original post by samoth
3876 different flavours of Unix and whatnot

No, not even in C++. I've never seen different mainstream flavours having different standard macros in gcc set.
Huh? Many distros have different paths for various headers,

You shall not #include fully qualified filenames:

#include "/usr/include/stdlib.h" // no
#include <stdlib.h> // yes



Quote:
Original post by swiftcoder
or move definitions around between headers (i.e. <malloc.h> or <stdlib.h> for malloc).


Never heard of that. I guess because ...

Quote:
C99 - ISO/IEC 9899:TC2
7.20 General utilities <stdlib.h>
7.20.3 Memory management functions

[...]malloc[...]
Quote:
C++2003 - ISO/IEC 14882:2003(E)
20.4.6 C Library

  Table 33 - header <cstdlib> synopsis
Type Name(s)
----------------------------
Functions calloc malloc
free realloc
Quote:
POSIX - The Open Group Base Specifications Issue 6 - IEEE Std 1003.1, 2004 Edition
NAME
    malloc - a memory allocator

SYNOPSIS
    #include <stdlib.h>
void *malloc(size_t size);



Quote:
Original post by swiftcoder
Not to mention endianess, different versions of installed packages, and so on.

But this is not a Linux specific problem, and installed packages don't contribute to what GCC or MSVC or any other C++ compiler #define by default. Also, #including the correct file is a build problem, not a sourcecode problem, hence you should tell the compiler in the build-configuration or on the commandline where to find the proper headers. The latter can still happen in a version independent manner, e.g. with SDL:
   g++ $(sdl-config --cflags --libs) mySdlCode.cc

So no need to hardcode /usr/lib/libsdl.xyz.a and assume a specific version.


Quote:
Original post by swiftcoder
Quote:
But about 99.934% of my C++ code is not platform specific anyways.
Ja, I find this to be the case as well. Unfortunately, as soon as you start interacting with the UI

Pardon, no (Qt, wxWidgets, et al).


Quote:
Original post by swiftcoder
or system tools, you land in the world of configuration hell...

That is true, but still not specific to Linux. Also note that in that, Linux tries to obey POSIX, and hence system near functions are pretty distro safe.

[Edited by - phresnel on November 2, 2009 9:24:37 AM]

Share this post


Link to post
Share on other sites
Quote:
Quote:
or move definitions around between headers (i.e. <malloc.h> or <stdlib.h> for malloc).
Never heard of that. I guess because ...

You can still run into trouble in practice because it's not fully defined which system headers include others for their internal use; if forgetting an #include, things might work on one platform but fail on another.

Share this post


Link to post
Share on other sites
Quote:
Original post by phresnel
Quote:
Original post by swiftcoder
or move definitions around between headers (i.e. <malloc.h> or <stdlib.h> for malloc).

Never heard of that. I guess because...
Linux vs BSD/Mac seems to have some fairly major issues between the standard C headers. I don't pretend to know whether or not either is standard conforming in this respect.
Quote:
Quote:
Original post by swiftcoder
Not to mention endianess, different versions of installed packages, and so on.

But this is not a Linux specific problem
I was never talking about linux in isolation, because I don't have the liberty of working in such a homogeneous environment. Beyond that I don't agree that linux is as homogenous as you suggest. Distros are constantly evolving, and not all along the same paths. At any one time, you may need to support 2-3 stable versions + development branch for each of several major distros, all of which ship with different versions of GCC, boost, etc.

We would all love to live in a world where everyone ran Debian-stable, but my experience has been that corporations/institutions tend to place tight controls on their linux environments and upgrade schedules, with the result that many of them run ancient versions of everything. On the Windows side, this doesn't matter much, since it is a pretty unchanging platform, but linux is another story entirely...

Share this post


Link to post
Share on other sites
Do you really need these? I make multi-platform software without using platform specific #defines. I use portable headers (with the pimpl idiom to avoid the need for inclusion of platform headers for member variables) and platform specific .cpp files. So I have message_box.hpp, message_box.win32.cpp, message_box.osx.cpp etc. Then it's just a matter of only compiling the appropriate .cpp files.

I've been able to avoid the use of #ifdefs for platform support this way - although I do use headers that platform switch internally (e.g. boost/cstdint.hpp).



Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement