How to detect current operating system at runtime in c++? - c++

I want to detect which operating system my .exe is being run on, so that I could perform specific operations depending on the underlying operating system. I want it to be just for windows and mac.

I want to detect which operating system my .exe is being run on
(notice that on MacOSX executable files are traditionally not suffixed with .exe; that convention is specific to Windows)
You cannot detect that in pure standard C++11 at runtime (so your question makes technically no sense), because the C++11 standard n3337 does not know about operating systems (some C++ source code may be compiled for the bare metal). I would recommend conditional compilation (e.g. #if) and using operating system specific headers (and configuring your build automation to detect them). Some C++ frameworks (boost, poco, Qt....) could be helpful, but you need to decide to choose one (they might try to provide some common abstractions above several OSes, but the evil is still in the details, e.g. file paths are still different on Windows and on MacOSX).
MicroSoft Windows has its own API, called WinAPI (which is only, in practice, used by Windows. Perhaps some day ReactOS would implement most of that API), documented here. MacOSX is more or less conforming to POSIX, which is a standard API about a family of OSes (but Windows don't care much about that standard).
If you want to learn more about OSes in general (a sensible thing to do), read for example Operating Systems: Three Easy Pieces (freely downloadable textbook).
In practice, an executable file compiled from C++ source code is specific to the operating system it is designed to run on, and its file format is also specific to some OS (e.g. PE on Windows, ELF on Linux, Mach-O on MacOSX...). So a Windows executable won't run on MacOSX and vice versa (the fat binary idea is out of fashion in 2018). You probably would adjust your build procedure (e.g. your Makefile, or with cmake, ninja, etc...) for your OS. That build procedure might (and often does) pass extra compilation flags (e.g. some -DBUILD_FOR_MACOSX compiler flag for your preprocessor, if building for MacOSX; then you might -in few places- use some preprocessor directive like #if BUILD_FOR_MACOSX in your C++ source code) specific to the target operating system. You could even customize your build so that on MacOSX some for-macosx.cc C++ file is compiled (and its object file linked into) your software, but on Windows you'll use some other for_windows.cc C++ file. Sometimes, the build procedure is flexible enough to auto-detect at build time what is the operating system (but how to do that is a different question. The GNU autoconf could be inspirational).
Once your build procedure has been configured for (or has auto-detected) your operating system, you could use preprocessor conditional facilities to #include appropriate system-specific headers and to compile calls to OS specific functions (such as POSIX uname) querying further at runtime about the OS.
Some compilers predefine a set of preprocessor symbols, and that set depends upon the target operating system and processor and of your compiler. If you use GCC, you might create some empty file empty.cc and compile it with g++ -c -C -E -dM (perhaps also with other relevant flags, e.g. -std=c++11) to find out which set of preprocessor symbols are predefined in your case.
Consider studying the source code (including the build procedure!) of some cross-platform free software projects (e.g. on github or somewhere else) for inspiration. You can also find many resources about multi-platform C++ builds (e.g. this one and many others).

There are various ways you could do it, like testing for the presence of a C:\Windows directory to detect Windows (edit: if the OS accepts a path like that at all then it's at least part of the DOS family), but none of them are foolproof. Here's one way (although it's cheating):
#include<boost/predef.h>
enum class OperatingSystem {
// ...
Windows
// ...
};
OperatingSystem DetectOperatingSystem()
{
#ifdef BOOST_OS_WINDOWS
return OperatingSystem::Windows;
#endif
}
Also, if you just want a name to show the user, then on POSIX systems you can use uname(2).

To solve this kind of problem you would need to check both at compile time and at run time. You are going to need different code for different both systems. You are going to need Windoze code to check the Windoze version and Mac code to check the Mac version.
You are going to have to use
#if defined ()
at compile time to check which of the two you are on. Then have separate code for each to get the version.

Related

Identify the platform linux or windows using C/C++ code [duplicate]

This question already has answers here:
How to detect reliably Mac OS X, iOS, Linux, Windows in C preprocessor? [duplicate]
(3 answers)
Closed 5 years ago.
I was asked in an interview to how would you identify the platform only by providing runnable C code?
The code must be runnable in both platform(i.e no special header files function used to check)?
a quick google search shows this
#if defined(_WIN64)
/* Microsoft Windows (64-bit). ------------------------------ */
#elif defined(_WIN32)
/* Microsoft Windows (32-bit). ------------------------------ */
#endif
OS identification macros are predefined by all C/C++ compilers to enable #if/#endif sets to wrap OS-specific code. This is often necessary in cross-platform code that must use low-level library functions for fast disk I/O, inter-process communications, or threads. While differences between Windows and other OSes are acute, even differences among UNIX-style OSes can require #if/#endif constructs. This article surveys common compilers and shows how to use predefined macros to detect common OSes at compile time.
http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system
The question is wierd. You can't provide an executable which
can run on multiple platforms. So the obvious answer is:
compile it on one platform: if it runs, that's the platform
you're on; if it doesn't you're on some other platform.
Supposing that you do have separate executables, there's really
no real answer. For starters, what do you consider "a different
platform"? Are Linux on a Sparc and Linux on a PC different
platforms? What about two different versions of Linux? What
about running under CygWin? Regardless of how you define it,
though, you'll probably need a separate test for each platform.
But the question is silly, because, except for considering
different versions different platforms, you'll need a distinct
executable for each platform, which means that you have to
distinguish at compile time anyway
Just for the record: for starters, I'd use boost::filesystem,
and try to read directories "c:\\" and "/usr". In theory,
you could have a directory named "c:\\" in the current
directory under Unix, or a directory named "/usr" in C: under
Windows, but the odds are definitely against it. Otherwise, try
various files in "/proc/myPID". The
directory will almost certainly not exist under Windows, and
even if it does, it won't have the dynamic structure it has
under various Unix. And the structure varies from one Unix to
the next, so you should even be able to distinguish between
Solaris and Linux.
If the comparison is just between Windows and Linux on a PC, of
course, the simplest is to compile in 32 bit mode, and take the
address of a local variable. If it's greater than 0x8000000,
you're under Linux; if it's less, Windows.
That's a bit vague. A binary won't run in both systems unless you run under Wine (then see http://wiki.winehq.org/DeveloperFaq#detect-wine ).
At compile time you can check for #defines specific to Windows or Linux, but arguably that's compiler- and supported-Standards-specific, so I'm not sure if you're "allowed" to do that for the purposes of the interview question (i.e. it's arguably in there with your "no special header files function used to check" restriction).
In general I don't think it makes any sense to do in preference to compile-time checks, and it might not work under Wine, but you could use dlsym() to check yourself for symbols known to be present on only one of the Operating Systems, or look at your own executable image to see what it is.
Practically, it's also very likely you can inspect your environment variables and make a pretty good determination based on that, though someone might be able to deliberately fool your program into an incorrect assessment, or your determination method might break in future versions of the Operating Systems, under different shells etc..
At run-time, you could e.g. stat("/dev", &buf), which should only work on Linux. Trying to popen(3) say uname is another plausible approach: you'll be able to read "linux\n" iff you're on Linux, while a cygwin-like environment apparently reports NT, see here too.
Most of the common methods make the determination at compile time.
If you really insist on making the determination at run time, you could attempt to use a device (for one possibility) that exists on one but not the other (e.g., attempting to open a file named /dev/null should work on Linux but normally fail on Windows).
Aside from the usual MACRO invocations:
#ifdef _WIN32
...
#if defined (_MSC_VER)
...
#ifdef __unix__
...
You could simply use the getenv() function and test for some variables set like SHELL or WINDIR. Interesting cases to decide:
mingw 32/64 under windows 32/64
cygwin 32/64 under windows 32/64
wine under linux 32/64
Of course, "Windows" environment variables can be set in Linux too - and vice-versa.
If you considering only the Linux platform or the Windows platform, this code will be work as needed to you on C and C++.
#include <stdio.h>
#if defined(__linux__) // any linux distribution
#define PLATFORM "linux"
#elif defined(_WIN32) // any windows system
#define PLATFORM "windows"
#else
#define PLATFORM "Is not linux or windows"
#endif
int main(int argc, char *argv[]) {
puts(PLATFORM);
return 0;
}
A full answer with an example see there https://stackoverflow.com/a/42040445/6003870
Every platform has own pre processor directive defined. You have to write the codes within it it.
How do I check OS with a preprocessor directive?
Please follow above link. It may be repeated question.

(C/C++) How to generate executable file that can run on both Windows and Linux?

I'm new in programming. From what i know, a program that is compiled in Linux should not be able to run in Windows. So, if we want to run the same program in both platform, we need to compile the source code under both platform, and create 2 different executable files.
Recently I am studying the source code of an open source, cross-platform Java GUI application. I'm surprised to find that the backend engine of that GUI application is a small executable file generated from C++ codes. No matter users use that application in Windows or Linux, the Java GUI will call the same executable file in the bin folder.
I just want to know, how can that executable file run on both Windows and Linux?
I'm also interested to create a cross-platform Java GUI application using a C++ program as the engine. That C++ program is only available for Linux only. I've been googling for a while and i found that I need to use Cygwin to port it to Windows. However, if i use Cygwin, i will end up having 2 different executable files.
How can i combine the Windows executable file with the Linux executable file? Is it possible to generate a single executable file that can run on both platform?
Thanks.
Ok, kids.
Yes, you CAN write a multi-platform binary, but it's difficult. It's called a Fat Binary, and it used to common enough in the 1980's although I haven't seen it done in decades. https://en.wikipedia.org/wiki/Fat_binary
Basically, you compile the machine code for each platform you want to run on and then hand-link the code with different entry points. While the Wikipedia article merely describes packing different architectures into the same binary, its actually possible to make one binary that runs on different operating systems so long as the entry points for the operating systems don't collide.
Some executable formats were intentionally designed to allow this. For example, MZ, NE, LX and PE can be overlaid. Old OS/2 programs sometimes did this... they rarely contained an entire program for both operating systems, but when run on DOS would print a message telling you that you were using the wrong operating system for the program.
As far as Linux and Windows in one binary: While you can't do an ELF and PE, I believe it might be doable with a PIE or a COFF and a PE or COM. Older Linux will run COFF binaries, which PE is descended from, so it seems you might be able to create a universal binary if newer versions of Linux will still run these. I can't say for sure this would work, but it seems plausible.
Another caveat: Usually you need to put a jump in the code right at the beginning to skip past the other operating system's entry point, headers, etc. because you can't locate your code there (obviously).
The problem with this in modern computing is that most anti-virus software will incorrectly identify this as a virus. It used to be common that viruses would attack binaries by inserting such a jump at the beginning of an executable that jumped to the end of the binary, tacking their own code onto the end of the binary, then inserting another jump back to the main executable code. Since you need to do something more-or-less similar to support multiple platforms in one binary, most AV software will heuristically identify this as a virus and quarantine your executable.
So in short: YES it can be done for (some) combinations of platforms. It is not impossible, but you would have to be insane to do it.
The simple answer is, is that you can't.
The PE (Windows) and ELF (Linux) binary executable formats are totally different.
Not to mention that a C/C++ Program requires linking to libraries that won't be available on either platform simultaneously.
However, you could use Wine on Linux to run the Windows executable providing it doesn't attempt exotic Windows specific calls.
Or you could choose to use a more "common" cross-platform language such as a CLI language (C#/IronPython/Java etc.) that .NET for Windows and Mono for linux/others supports.
There is no way to have a single native executable compiled from C++ source that works on different platforms. I don't believe you that the same executable file is run on Windows and Linux, as you state in your second paragraph.
Simply put, it is not possible to run the same executable on different platforms. It is true for Windows, Linux, or any other UNIX platform.
The idea of having a single executable is nothing new and is the idea behind Java Runtime and Windows .Net (Mono for Linux). These themselves rely on different executables compiled on the specific machines.
No matter users use that application in Windows or Linux, the Java GUI
will call the same executable file in the bin folder.
They might simply be using relavant paths to these executables, and these executables are probably compiled separately on different platforms. Hard to tell without looking at the code.
Cygwin is a command line interface on windows that provides UNIX look and feel.
One option to try would be Wine which is a program for Linux to run windows programs on Linux.
It may be possible, if the OSes are on the same platform.
However, Linux can run on a variety of platforms with different processors: VAX, MAC, PC, Sun, etc.
One problem is that an executable contains assembly (machine code) instructions specific to a processor. The machine code for adding a register using ARM processor may be different than a Motorola, Intel or Sun processor. So with this context, one executable may not be guaranteed to run on different platforms.
Another issue is that the Run-Time library may also make calls to specific OS functions (like file open, displaying text, etc.) Some operating systems may not supply the same functionality; while others have a different method to execute the same functionality. An OS on an embedded platform may not support a file system. Windows Vista may block calls from unsecure MSDOS requests.
Other languages become platform independent by generating code which is executed by a "virtual machine". The code is not directly executed by a processor.
The traditional method for porting C and C++ methods is to provide the source and let the customers build the software on their platform. Other delivery processes is to create an executable for every supported platform; this becomes a maintenance nightmare.
You can't do that....i.e. you can't run the same executable on both Unix as well as Windows.
Windows uses executable files, while Unix used elf file format. They are basically different. Unlike the counterpart Java where you can run the same executable( bytecode) on both machines, which in turn uses an interpreter(the JVM) to execute.
Now, said that you have two options...
Either you can actually install C compilers on both windows and linux(unix) and then compile your code on both of them.
Or you can install 'Wine', a porting software on linux which will be able to actually run windows executable file on linux by windows emulation.
Probably, option no 2 would be better suited...Its your call...
Regards,
Can't you make a C++ program load it's respective existing libraries using #ifdef?
I think that's the C++ solution to cross platform binaries. However the code needs to be adjusted to work with both or all chosen libraries.
However without a java front end or a 2 different binaries or a bat and a sh or a program like wine you won't be able to run the respective binary.
If you create a well behaved MS Windows application, it can run unmodified on Linux x86 platforms using the wine utility.
Wine is a compatibility layer which provides Win32 and associated runtime library calls so that the program thinks it is running on MS Windows, but the wine layer translates those into Linuxisms with really good performance.
More detail at http://www.winehq.org/

C Program Portability

As we know java is a platform independent language due to JVM it's program can run at any OS.
What about C/C++? could C/C++ exe run at any OS ? Could we have done something about this(Like write once run anywhere)? please clear my doubt about this.
Thanks
No - an executable is built for a specific operating system and hardware (CPU) architecture.
If you are carefull not to use any OS specific functions, or any assumptions about word size etc, then c++ source can be recompiled to run anywhere.
C and C++ are traditionally transformed into machine code for a particular CPU type/family, and packed within a format that a particular operating system can start.
There's nothing stopping anyone from making a C or C++ compiler that compiles code to run on a virtual machine in the same sense that java source code is compiled to byte code intended to run on the jvm. Someone
(The usefulness of doing so is another matter though, and e.g. while it's quite far from standard C++, C++/.CLI compiles a C++ like language to run on .NET)
Theorically, C programs only need a compiler that produce executable binaries for the target platform. That's why C is used in almost any embedded platform.
Practically, that require a separate compilation for each target platform.
C++ is another beast, clearly more complex and rich of features. Depending on the platform, you might or not have a compiler for C++, and if you have, embedded platform often require (for often non-obvious and sometimes critiquables reasons) that some C++ features are deactivated.
So with C++ you still "can" compile for any target platform, because it is a system programming language, like C (meaning that you're "close to the metal" with those languages).
However, there are still some problems you have to solve if you want to target some platforms :
some platform constructors will not allow you to run binaries on their platforms, only to sue their "secured" virtual-machine based language (whatever it is);
some platform constructors will provide compilers for their platforms, but with limited features, making them too poor to use for industrial developpement;
So theorically, C and C++ can run anywhere, if you compile for the target and that you use only cross-platform code/library.
In practice, it depends on the context.
Executable programs are platform and OS dependent. There are emulators in some OS that allows to run executables of other platforms (such as wine, dosbox etc. and of course VMWare) but this is an emulation/virtualization only.
Each operating system has it's own executable format, so you have to compile your C(++) program separately for each OS. If you use cross platform libraries, you can easily recompile your program without having to change your code a lot.

The difference between a program in C++ developed under Windows and Linux

What's the difference between a program developed in C++ under Windows and Linux?
Why can't a program developed under Windows in C++ be used under Linux?
Windows and Linux use different container formats to hold the executable code (PE vs ELF).
Windows and Linux have completely different APIs (except for trivial programs that only use the CRT and STL)
Windows and Linux have a completely different directory structure
You could write a program that can use either set of APIs (for example, using Qt), and that can handle either directory structure, but you still won't be able to run the same file on both operating systems because of the differing container formats.
This can be solved by using Wine.
Native programs are not compatible because Windows has a completely different set of API's than Linux, for one. As others have mentioned, each platform uses a different executable format as well. Also both platforms have their own set of libraries that programs will be linked against and/or share. For example, a Windows program will typically be developed in Visual Studio using windows-specific libraries such as MFC, Win32 API, etc. These libraries are not available in linux, so the program will not even compile unless care is taken to make sure cross-platform libraries (such as QT) are used.
If you are careful, however, you can use cross-platform libraries in your code and you can get the same program to compile under both platforms. For such a program you would need to carefully put any platform-specific details (file system locations, etc) in their own files. Then, you would need to setup the proper #define statements and/or makefile directives to ensure the proper files are included in the build for each platform.
Of course, if you use a "cross-platform" language such as Java or Python, and do not use any platform-specific code in your implementation, then your program can run under both environments.
Note Although the executable formats are different, some programs developed on Windows can be executed under Linux using an emulator called WINE.
In a nutshell,
Windows runs PE format executables
Linux runs ELF format executables
Furthermore, even if there were a tool to convert between PE and ELF, the program instructions necessary to interface with the operating system are completely different between Windows and Linux. Only the most restricted computation-only code (that only does calculations and doesn't interact with the operating system at all) could be ported between systems without special action. However, this is rarely done.
I believe some versions of Linux allow you to directly load device drivers designed for Windows without recompiling. However, this is an extremely special purpose application and the technique is not generally used.
Each operating system defines an API. If you code to call the Win32 API, it won't be there on Linux. If you code to the POSIX API, it won't jump right out at you in Windows.
To learn more about this, download a significant open source program (for example, Perl or Python) and see how its 'configure' script makes arrangements to compile in either place.
When a C++ program is compiled on a platform, it ultimately changes into a form that machine can understand (i.e. Machine code). Under the hood, the program uses system calls to perform privileged action. These system calls are implemented via methods or APIs. These methods differ from platform to platform. Hence on every platform, the compiled code is different. There are many cross-compilers available if you want to compile your code for a different platform.
Not to be overly pedantic, but developing a program is different than building it and executing it. In many cases, a program written on one operating system can be built and compiled to execute on another. Other programs, as others have pointed out, rely on certain functionality provided only by a particular OS or libraries resident only on that OS. As a result, it must be built and run on that OS.
C++ is itself portable. But some C++ libraries are not. If a C++ program uses some libraries, which are not portable, then this program is not portable.
For example, a C++ program uses MFC to draw the GUI stuff, because MFC is supported only in Windows, so this C++ program cannot be compiled or run on Linux directly.
There are two major reasons.
Theoretically, the same program (source code) for some languages like C, can run on both Windows and Linux. But the compilation only differs; this means you have to compile the same source code file for each platform.
But actually, each operating system has a different set of APIs. And different techniques to get job done faster... Which usually attract developers to use them. And they don't stick to standards, so they lose portability.
This was for native programs... Anyway, there are the Java and Python languages... They are truly cross-platform, but you have to sacrifice speed for sake of portability.
This is a large topic.
First, Windows and Linux aren't binary comparable. This means that even the simplest of programs will not be recognized from one machine to the other. This is why interpreted languages like PHP, Perl, Python and Java are becoming so popular, but even these don't all support the same set of features on each platform.
Library dependence / OS support: Any significantly complicated program will need to access the system is some way, and many of the features available on one system are not available on the other. There are a million examples; just look on so for the Linux equivalent of blank or Windows equivalent of blank. Moving beyond OS support applications are built mostly on top of libraries of functions and some of those are just not available on both systems.

Platform C Preprocessor Definitions

I'm writing a small library in C++ that I need to be able to build on quite a few different platforms, including iPhone, Windows, Linux, Mac and Symbian S60. I've written most of the code so that it is platform-agnostic but there are some portions that must be written on a per-platform basis.
Currently I accomplish this by including a different header depending on the current platform but I'm having trouble fleshing this out because I'm not sure what preprocessor definitions are defined for all platforms. For windows I can generally rely on seeing WIN32 or _WIN32. For Linux I can rely on seeing _UNIX_ but I am less certain about the other platforms or their 64-bit variants. Does anyone have a list of the different definitions found on platforms or will I have to resort to a config file or gcc parameter?
I have this sourceforge pre-compiler page in my bookmarks.
The definitions are going to be purely up to your compiler vendor. If you are using the same compiler (say, gcc) on all your platforms then you will have a little bit easier time of it.
You might also want to try to instead organize your project such that most of the .h files are not platform dependent. Split your implementation (cpp files) into separate files; one for the nonspecific stuff and one for each platform. The platform specific ones can include 'private' headers that only make sense for that platform. You may have to make adapter functions to get something like this to work 100% (when the system libs take slightly differed arguments) but I have found it to be really helpful in the end, and bringing on a new platform is a whole lot easier in the future.
Neither the C nor the C++ standards define such symbols, so you are going to be at the mercy of specific C or C++ implementations. A list of commonly used symbols would be a useful thing to have, but unfortunately I haven't got one.
I don't think there exists a universal list of platform defines judging by the fact that every cross-platform library I have seen has an ad-hoc config.h full of these stuff. But you can consider looking at the ones used by fairly portable libraries like libpng, zlib etc.
Here's the one used by libpng
If you want to look through the default preprocessor symbols for a given system on which you have GCC (e.g. Mac OS X, iOS, Linux), you can get a complete list from the command-line thus:
echo 'main(){}' | cpp -dM
These are often of limited use however, as at the stage of the compilation at which the preprocessor operates, most of the symbols identify the operating system and CPU type of only the system hosting the compiler, rather than the system being targeted (e.g. when cross-compiling for iOS). On Mac OS X and iOS, the right way to determine the compile-time characteristics of the system being targeted is
#include <TargetConditionals.h>
This will pick up TargetConditionals.h from the Platform and SDK currently in use, and then you can determine (e.g.) endianness and some other characteristics from some of the Macros. (Look through TargetConditionals.h to see what kinds of info you can glean.)