aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2023-03-13 13:08:19 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2023-03-13 13:08:19 +0200
commitf1aada8cc6419c3c9934fa880c8f6e5c59e23385 (patch)
treec38f275a43b0e73d9e96946fb47c4300b2eb4c2f
parent5537c333656c193e352d9606d4cd1e5c52bbe94a (diff)
Windowsos-release
-rw-r--r--libbutl/host-os-release.cxx85
-rw-r--r--libbutl/host-os-release.hxx13
-rw-r--r--tests/host-os-release/driver.cxx2
-rw-r--r--tests/host-os-release/testscript17
4 files changed, 115 insertions, 2 deletions
diff --git a/libbutl/host-os-release.cxx b/libbutl/host-os-release.cxx
index fff05f7..f13f62c 100644
--- a/libbutl/host-os-release.cxx
+++ b/libbutl/host-os-release.cxx
@@ -8,11 +8,16 @@
#include <libbutl/path.hxx>
#include <libbutl/path-io.hxx>
+#include <libbutl/utility.hxx>
#include <libbutl/process.hxx>
#include <libbutl/fdstream.hxx>
#include <libbutl/filesystem.hxx> // file_exists()
#include <libbutl/string-parser.hxx> // parse_quoted()
+#ifdef _WIN32
+# include <libbutl/win32-utility.hxx>
+#endif
+
using namespace std;
namespace butl
@@ -201,6 +206,83 @@ namespace butl
}
}
+ static os_release
+ host_os_release_windows ()
+ {
+#ifdef _WIN32
+ // The straightforward way to get the version would be the GetVersionEx()
+ // Win32 function. However, if the application is built with a certain
+ // assembly manifest, this function will return the version the
+ // application was built for rather than what's actually running.
+ //
+ // The other plausible options are to call the `ver` program and parse it
+ // output (of questionable regularity) or to call RtlGetVersion(). The
+ // latter combined with GetProcAddress() seems to be a widely-used
+ // approach, so we are going with that (seeing that we employ a similar
+ // technique in quite a few places).
+ //
+ HMODULE nh (GetModuleHandle ("ntdll.dll"));
+ if (nh == nullptr)
+ throw runtime_error ("unable to get handle to ntdll.dll");
+
+ using RtlGetVersion = LONG /*NTSTATUS*/ (WINAPI*)(PRTL_OSVERSIONINFOW);
+
+ RtlGetVersion gv (
+ function_cast<RtlGetVersion> (
+ GetProcAddress (nh, "RtlGetVersion")));
+
+ // RtlGetVersion() is available from Windows 2000 which is way before
+ // anything we might possibly care about (e.g., XP or 7).
+ //
+ if (gv == nullptr)
+ throw runtime_error ("unable to get address of RtlGetVersion()");
+
+ RTL_OSVERSIONINFOW vi;
+ vi.dwOSVersionInfoSize = sizeof (vi);
+ gv (&vi); // Always succeeds, according to documentation.
+
+ // Ok, the real mess starts here. Here is how the commonly known Windows
+ // versions correspond to the major/minor/build numbers and how we will
+ // map them (note that there are also Server versions in the mix; see the
+ // OSVERSIONINFOEXW struct documentation for the complete picture):
+ //
+ // major minor build mapped
+ // Windows 11 10 0 >=22000 11
+ // Windows 10 10 0 <22000 10
+ // Windows 8.1 6 3 8.1
+ // Windows 8 6 2 8
+ // Windows 7 6 1 7
+ // Windows Vista 6 0 6
+ // Windows XP Pro/64-bit 5 2 5.2
+ // Windows XP 5 1 5.1
+ // Windows 2000 5 0 5
+ //
+ // Based on this it's probably not wise to try to map any future versions
+ // automatically.
+ //
+ string v;
+ if (vi.dwMajorVersion == 10 && vi.dwMinorVersion == 0)
+ {
+ v = vi.dwBuildNumber >= 22000 ? "11" : "10";
+ }
+ else if (vi.dwMajorVersion == 6 && vi.dwMinorVersion == 3) v = "8.1";
+ else if (vi.dwMajorVersion == 6 && vi.dwMinorVersion == 2) v = "8";
+ else if (vi.dwMajorVersion == 6 && vi.dwMinorVersion == 1) v = "7";
+ else if (vi.dwMajorVersion == 6 && vi.dwMinorVersion == 0) v = "6";
+ else if (vi.dwMajorVersion == 5 && vi.dwMinorVersion == 2) v = "5.2";
+ else if (vi.dwMajorVersion == 5 && vi.dwMinorVersion == 1) v = "5.1";
+ else if (vi.dwMajorVersion == 5 && vi.dwMinorVersion == 0) v = "5";
+ else throw ("unknown windows version " +
+ std::to_string (vi.dwMajorVersion) + '.' +
+ std::to_string (vi.dwMinorVersion) + '.' +
+ std::to_string (vi.dwBuildNumber));
+
+ return os_release {"windows", {}, move (v), "", "Windows", "", ""};
+#else
+ throw runtime_error ("unexpected host operating system");
+#endif
+ }
+
optional<os_release>
host_os_release (const target_triplet& h)
{
@@ -213,6 +295,9 @@ namespace butl
if (c == "macos")
return host_os_release_macos ();
+ if (c == "windows")
+ return host_os_release_windows ();
+
if (c == "bsd")
{
// @@ TODO: ideally we would want to run uname and obtain the actual
diff --git a/libbutl/host-os-release.hxx b/libbutl/host-os-release.hxx
index 9fd24a2..058afdc 100644
--- a/libbutl/host-os-release.hxx
+++ b/libbutl/host-os-release.hxx
@@ -38,6 +38,19 @@ namespace butl
// Note that for Mac OS, the version is the Mac OS version (as printed by
// sw_vers) rather than Darwin version (as printed by uname).
//
+ // For Windows we currently do not distinguish the Server edition and the
+ // version mapping is as follows:
+ //
+ // Windows 11 11
+ // Windows 10 10
+ // Windows 8.1 8.1
+ // Windows 8 8
+ // Windows 7 7
+ // Windows Vista 6
+ // Windows XP Pro/64-bit 5.2
+ // Windows XP 5.1
+ // Windows 2000 5
+ //
// Note that version_id may be empty, for example, on Debian testing:
//
// {"debian", {}, "", "",
diff --git a/tests/host-os-release/driver.cxx b/tests/host-os-release/driver.cxx
index 3b40634..249cbff 100644
--- a/tests/host-os-release/driver.cxx
+++ b/tests/host-os-release/driver.cxx
@@ -1,4 +1,4 @@
-// file : host-os-release/driver.cxx -*- C++ -*-
+// file : tests/host-os-release/driver.cxx -*- C++ -*-
// license : MIT; see accompanying LICENSE file
#include <libbutl/host-os-release.hxx>
diff --git a/tests/host-os-release/testscript b/tests/host-os-release/testscript
index c340da3..a18aa74 100644
--- a/tests/host-os-release/testscript
+++ b/tests/host-os-release/testscript
@@ -1,4 +1,4 @@
-# file : bpkg/host-os-release.test.testscript
+# file : tests/host-os-release/testscript
# license : MIT; see accompanying LICENSE file
: linux
@@ -206,3 +206,18 @@ if ($build.host.system == 'freebsd')
EOO
}
+
+: windows
+:
+if ($build.host.system == 'windows')
+{
+ $* $build.host >>~/EOO/
+ windows
+
+ /[0-9]+(\.[0-9]+)?/
+
+ Windows
+
+
+ EOO
+}