Determine OS during runtime
Asked Answered
T

5

8

Neither ISO C nor POSIX offer functionality to determine the underlying OS during runtime. From a theoretical point of view, it doesn't matter since C offers wrappers for the most common system calls, and from a nit-picking point of view, there doesn't even have to be an underlying OS.

However, in many real-world scenarios, it has proven helpful to know more about the host environment than C is willing to share, e.g. in order to find out where to store config files or how to call select(), so:

Is there an idiomatic way for an application written in C to determine the underlying OS during runtime?

At least, can I easily decide between Linux, Windows, BSD and MacOS?

My current guess is to check for the existence of certain files/directories, such as C:\ or /, but this approach seems unreliable. Maybe querying a series of such sources may help to establish the notion of "OS fingerprints", thus increasing reliability. Anyway, I'm looking forward to your suggestions.

Tinytinya answered 3/1, 2012 at 1:21 Comment(19)
Er, you know this information at compile timeIlan
How does determining the OS at runtime help you write a select() call correctly?Saliva
+1, @David. At least for differences like Linux vs. Windows vs. Mac OS X, etc. I guess a runtime way to differentiate between different versions of each of those might be what the OP is looking for, but the answer to that would be specific to each operating system, presumably.Jevon
@David: I don't like #ifdef.Tinytinya
Attempt to run the program for some time. If it gets killed in a crash, you're on Windows. If the OS gets updated to 5G or a cat, you're on a Mac. If you get hacked after 180 days, it's Linux. Otherwise it's BSD.Saliva
You do not 'really' know this information at compile-time. You can run windows binaries on wine+linux, you can run linux binaries on solaris, you can run linux binaries on some BSDs.Billiton
@Tinytinya Well, #ifdef is essential here, you must learn to get along with it even if you cannot bring yourself to like itIlan
@rsaxvc, but as far as your app is concerned, wine+linux is windows, running linux binaries on solaris is linux, and running them on BSD is still linux.Jevon
@Billiton Then it's up to the emulator to do a good job of being the emulated system. When you are running on Wine the OS is Windows from the point of view of the program.Ilan
@ David Heffernan: What do you mean? None of those are emulators.Billiton
@Carl - but you may need to change runtime behaviour of os-specifics to deal with it. Look at the proc filesystem - different on many unices, so you have to deal with it at runtime if you're doing binary compatability.Billiton
wine even tells you by its name: Wine Is Not an EmulatorTinytinya
@Billiton - sure, but if you're writing an app that you intend to run in these emulated environments, you need to take that into account. If you write a Windows app that doesn't work in Wine, it just means that Wine isn't doing a good enough job.Jevon
@CarlNorum - I know, that's what I said, which is why you might need to know the OS at runtime instead of compile-time. (Personally, I'd rather just compile it twice and wrap up the os-specifics)Billiton
@Billiton Sure it's an emulator. It emulates Windows on systems that are not Windows. The WINE people don't like the negative connotations of the word and in particular the expectation that an emulator performs poorly. But it is an emulator in just the same way as WOW64 is an emulator.Ilan
@DavidHeffernan - Poor example - in WOW64, the CPU is directly executing x86-32 instructions, just like it does on WINE. What WINE is, is a set of libraries that implement the WINAPI on a different backend. No emulation in either (unless you mean WOW64 on Itanium...)Billiton
@DavidHeffernan - I guess this is really just semantics and not terribly related to the question at hand.Billiton
@Billiton Ah, you define emulation to mean emulation of hardware. A more general definition, the one I'm using, includes emulation of software. Microsoft's description of WOW64 starts like this: WOW64 is the x86 emulator that allows 32-bit Windows-based applications to run seamlessly on 64-bit Windows. Yes this is not related to Q. Feel free to tidy up.Ilan
I'm still trying to figure out why you'd dislike #ifdef, but be perfectly content to use if. Any insight on that?Selfimmolating
I
7

Actually, most systems have a uname command which shows the current kernel in use. On Mac OS, this is usually "Darwin", on Linux it's just plain "Linux", on Windows it's "ERROR" and FreeBSD will return "FreeBSD".

More complete list of uname outputs

I'm pretty sure that there's a C equivalent for uname, so you won't need system()

Illustration answered 3/1, 2012 at 1:28 Comment(4)
Looks like I beat all of you :-)Illustration
@Tom Are you sure about what happens on Windows? For all C compilers?Ilan
@DavidHeffernan Haha, I'm sure it won't return the string "ERROR". However, the results on Windows vary a lot. As far as I know only cygwin returns a proper uname, but some compilers may actually compile it. Because of this, uname is unreliable when ran under Wine or Crossover.Illustration
@TomvanderWoerdt - I posted one saying 'you're right, can't be done for all OSs', but then realized the OP was only asking about BSD/OSX/Windows/Linux.Billiton
D
4

IF you are on a POSIX system, you can call uname() from <sys/utsname.h>.

This obviously isn't 100% portable, but I don't think there will be any method that can grant that at runtime.

see the man page for details

Danialah answered 3/1, 2012 at 1:30 Comment(0)
H
1

Runtime isn't the time to determine this, being that without epic kludges binaries for one platform won't run on another, you should just use #ifdefs around the platform sensitive code.

Hartle answered 3/1, 2012 at 2:0 Comment(2)
-1 because the question was about how to determine the operating system at runtime, not whether or not you should do it.Semiprofessional
Yeah, but that doesn't help the OP. For the VAST majority of cases an object emitted for FreeBSD won't work on Linux anyway (Which holds for most of his cases) so doing this at runtime is the least of his woes.Hartle
O
1

The accepted answer states uname, but doesn't provide a minimal working example, so here it is for anyone interested-hope it will save you the time it took for me:

#include <stdio.h>
#include <stdlib.h>
#include <sys/utsname.h>

int main(void) {
   struct utsname buffer;
   if (uname(&buffer) != 0) {
      perror("uname");
      exit(0);
   }
   printf("OS: %s\n", buffer.sysname);

   return 0;
}

(Possible) Output:

OS: Linux

PS: Unfortunately, this uses a POSIX header: Compilation fails due to missing file sys/utsname.h, which most probably won't work in Windows.

Olympiaolympiad answered 20/11, 2018 at 15:0 Comment(1)
error C1083: Cannot open include file: 'sys/utsname.h': No such file or directory. On Linux this works, but not on Windows.Conjugated
H
-2
if (strchr(getenv("PATH"),'\\'))
    puts("You may be on windows...");

Even do I agree that "Runtime isn't the time to determine this..."

Hemichordate answered 19/4, 2017 at 6:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.