diff --git a/lib/std/target.zig b/lib/std/target.zig index 2b3518bc92..2b4ac5ad53 100644 --- a/lib/std/target.zig +++ b/lib/std/target.zig @@ -109,6 +109,20 @@ pub const Target = struct { /// Latest Windows version that the Zig Standard Library is aware of pub const latest = WindowsVersion.win10_20h1; + /// Compared against build numbers reported by the runtime to distinguish win10 versions, + /// where 0x0A000000 + index corresponds to the WindowsVersion u32 value. + pub const known_win10_build_numbers = [_]u32{ + 10240, //win10 + 10586, //win10_th2 + 14393, //win_rs1 + 15063, //win_rs2 + 16299, //win_rs3 + 17134, //win_rs4 + 17763, //win_rs5 + 18362, //win_19h1 + 19041, //win_20h1 + }; + pub const Range = struct { min: WindowsVersion, max: WindowsVersion, diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig index ea1e3c87a2..ad33508905 100644 --- a/lib/std/zig/system.zig +++ b/lib/std/zig/system.zig @@ -14,6 +14,7 @@ const process = std.process; const Target = std.Target; const CrossTarget = std.zig.CrossTarget; const macos = @import("system/macos.zig"); +pub const windows = @import("system/windows.zig"); pub const getSDKPath = macos.getSDKPath; @@ -249,43 +250,9 @@ pub const NativeTargetInfo = struct { } }, .windows => { - var version_info: std.os.windows.RTL_OSVERSIONINFOW = undefined; - version_info.dwOSVersionInfoSize = @sizeOf(@TypeOf(version_info)); - - switch (std.os.windows.ntdll.RtlGetVersion(&version_info)) { - .SUCCESS => {}, - else => unreachable, - } - - // Starting from the system infos build a NTDDI-like version - // constant whose format is: - // B0 B1 B2 B3 - // `---` `` ``--> Sub-version (Starting from Windows 10 onwards) - // \ `--> Service pack (Always zero in the constants defined) - // `--> OS version (Major & minor) - const os_ver: u16 = @intCast(u16, version_info.dwMajorVersion & 0xff) << 8 | - @intCast(u16, version_info.dwMinorVersion & 0xff); - const sp_ver: u8 = 0; - const sub_ver: u8 = if (os_ver >= 0x0A00) subver: { - // There's no other way to obtain this info beside - // checking the build number against a known set of - // values - const known_build_numbers = [_]u32{ - 10240, 10586, 14393, 15063, 16299, 17134, 17763, - 18362, 19041, - }; - var last_idx: usize = 0; - for (known_build_numbers) |build, i| { - if (version_info.dwBuildNumber >= build) - last_idx = i; - } - break :subver @truncate(u8, last_idx); - } else 0; - - const version: u32 = @as(u32, os_ver) << 16 | @as(u32, sp_ver) << 8 | sub_ver; - - os.version_range.windows.max = @intToEnum(Target.Os.WindowsVersion, version); - os.version_range.windows.min = @intToEnum(Target.Os.WindowsVersion, version); + const detected_version = windows.detectRuntimeVersion(); + os.version_range.windows.min = detected_version; + os.version_range.windows.max = detected_version; }, .macos => { var scbuf: [32]u8 = undefined; diff --git a/lib/std/zig/system/windows.zig b/lib/std/zig/system/windows.zig new file mode 100644 index 0000000000..d32b28f607 --- /dev/null +++ b/lib/std/zig/system/windows.zig @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. +const std = @import("std"); + +pub const WindowsVersion = std.Target.Os.WindowsVersion; + +/// Returns the highest known WindowsVersion deduced from reported runtime information. +/// Discards information about in-between versions we don't differentiate. +pub fn detectRuntimeVersion() WindowsVersion { + var version_info: std.os.windows.RTL_OSVERSIONINFOW = undefined; + version_info.dwOSVersionInfoSize = @sizeOf(@TypeOf(version_info)); + + switch (std.os.windows.ntdll.RtlGetVersion(&version_info)) { + .SUCCESS => {}, + else => unreachable, + } + + // Starting from the system infos build a NTDDI-like version + // constant whose format is: + // B0 B1 B2 B3 + // `---` `` ``--> Sub-version (Starting from Windows 10 onwards) + // \ `--> Service pack (Always zero in the constants defined) + // `--> OS version (Major & minor) + const os_ver: u16 = @intCast(u16, version_info.dwMajorVersion & 0xff) << 8 | + @intCast(u16, version_info.dwMinorVersion & 0xff); + const sp_ver: u8 = 0; + const sub_ver: u8 = if (os_ver >= 0x0A00) subver: { + // There's no other way to obtain this info beside + // checking the build number against a known set of + // values + var last_idx: usize = 0; + for (WindowsVersion.known_win10_build_numbers) |build, i| { + if (version_info.dwBuildNumber >= build) + last_idx = i; + } + break :subver @truncate(u8, last_idx); + } else 0; + + const version: u32 = @as(u32, os_ver) << 16 | @as(u16, sp_ver) << 8 | sub_ver; + + return @intToEnum(WindowsVersion, version); +}