summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author5an7y <[email protected]>2026-06-23 10:38:40 -0700
committer5an7y <[email protected]>2026-06-23 10:38:40 -0700
commitceceab78412feefd2f343a0e3bc07f1262665b62 (patch)
tree046ae1a9f147f5be0fec14f8cd7b9c97a8791296
parentbe91bbd2dc4478a57a4007fc32fe320da79f85e1 (diff)
Auto-discover _NT_TARGET_VERSION; remove the TargetVersion axis
- Remove the -TargetVersion parameter and all its plumbing from Build-Samples.ps1 (restoring the original hard-coded -p:TargetVersion=Windows10), and drop the TargetVersions column from exclusions.csv and Import-SampleExclusions. Only _NT_TARGET_VERSION remains exposed. - Add Get-NtTargetVersions.ps1, which auto-discovers the valid _NT_TARGET_VERSION values (and their NTDDI codes) by parsing the active WDK's DriverGeneral.xml rule. Build-Samples.ps1 uses it to validate -NtTargetVersion, default to the latest, and map to the msbuild code, so a new WDK version needs no script change (accepts '10.0.<build>' or the short '<build>' tag). - CI: ci.yml and ci-pr.yml gain a 'discover' job that emits the newest-N versions as JSON; the build matrix consumes it via fromJSON, so there is no hand-maintained version list anywhere. Build-ChangedSamples.ps1 treats Get-NtTargetVersions.ps1 as a full-build trigger. - Docs updated accordingly. Co-authored-by: Copilot <[email protected]>
-rw-r--r--.github/scripts/Build-ChangedSamples.ps12
-rw-r--r--.github/workflows/ci-pr.yml33
-rw-r--r--.github/workflows/ci.yml33
-rw-r--r--Build-Samples.ps1112
-rw-r--r--Building-Locally.md55
-rw-r--r--Get-NtTargetVersions.ps1100
-rw-r--r--exclusions.csv40
7 files changed, 235 insertions, 140 deletions
diff --git a/.github/scripts/Build-ChangedSamples.ps1 b/.github/scripts/Build-ChangedSamples.ps1
index 3e91eb88..f03f93f3 100644
--- a/.github/scripts/Build-ChangedSamples.ps1
+++ b/.github/scripts/Build-ChangedSamples.ps1
@@ -22,7 +22,7 @@ foreach ($file in $ChangedFiles) {
$filename = Split-Path $file -Leaf
# Files that can affect how every sample is built should trigger a full build
- if ($filename -eq "Build-Samples.ps1" -or $filename -eq "exclusions.csv" -or $filename -eq "Directory.Build.props" -or $filename -eq "packages.config") {
+ if ($filename -eq "Build-Samples.ps1" -or $filename -eq "Get-NtTargetVersions.ps1" -or $filename -eq "exclusions.csv" -or $filename -eq "Directory.Build.props" -or $filename -eq "packages.config") {
$buildAll = $true
}
if ($dir -like "$root\.github\scripts" -or $dir -like "$root\.github\scripts\*") {
diff --git a/.github/workflows/ci-pr.yml b/.github/workflows/ci-pr.yml
index 7983c8dd..8119c94c 100644
--- a/.github/workflows/ci-pr.yml
+++ b/.github/workflows/ci-pr.yml
@@ -8,20 +8,39 @@ on:
- '**.md'
- 'LICENSE'
jobs:
+ # Auto-discover the available _NT_TARGET_VERSION values from the active WDK so the build
+ # matrix never needs a hand-maintained version list. Change -Newest to build more/fewer.
+ discover:
+ name: discover _NT_TARGET_VERSIONs
+ runs-on: windows-2025-vs2026
+ outputs:
+ versions: ${{ steps.nt.outputs.versions }}
+ steps:
+ - name: Check out repository code
+ uses: actions/checkout@v4
+
+ - name: Install Nuget Packages
+ run: nuget restore .\packages.config -PackagesDirectory .\packages\
+
+ - name: Discover the newest _NT_TARGET_VERSION values
+ id: nt
+ shell: pwsh
+ run: |
+ $json = .\Get-NtTargetVersions.ps1 -Newest 4 -AsMatrixJson
+ "versions=$json" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
+ Write-Host "Discovered _NT_TARGET_VERSION matrix: $json"
+
build:
name: build ${{ matrix.nt.tag }} ${{ matrix.configuration }} ${{ matrix.platform }}
+ needs: discover
strategy:
fail-fast: false
matrix:
configuration: [Debug, Release]
platform: [x64, arm64]
- # _NT_TARGET_VERSION = the WDK library version drivers link against (newest first).
- # Each { version, tag } runs as its own parallel job; trim this list to reduce CI load.
- nt:
- - { version: '10.0.28000', tag: '28000' }
- - { version: '10.0.26100', tag: '26100' }
- - { version: '10.0.22621', tag: '22621' }
- - { version: '10.0.22000', tag: '22000' }
+ # _NT_TARGET_VERSION values are auto-discovered by the 'discover' job from the active
+ # WDK, so there is no version list to maintain here.
+ nt: ${{ fromJSON(needs.discover.outputs.versions) }}
runs-on: windows-2025-vs2026
steps:
- name: Check out repository code
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 022ae4f6..de856d55 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -11,20 +11,39 @@ on:
# Runs every Saturday at 00:00 PST (08:00 UTC)
- cron: '0 8 * * 6'
jobs:
+ # Auto-discover the available _NT_TARGET_VERSION values from the active WDK so the build
+ # matrix never needs a hand-maintained version list. Change -Newest to build more/fewer.
+ discover:
+ name: discover _NT_TARGET_VERSIONs
+ runs-on: windows-2025-vs2026
+ outputs:
+ versions: ${{ steps.nt.outputs.versions }}
+ steps:
+ - name: Check out repository code
+ uses: actions/checkout@v4
+
+ - name: Install Nuget Packages
+ run: nuget restore .\packages.config -PackagesDirectory .\packages\
+
+ - name: Discover the newest _NT_TARGET_VERSION values
+ id: nt
+ shell: pwsh
+ run: |
+ $json = .\Get-NtTargetVersions.ps1 -Newest 4 -AsMatrixJson
+ "versions=$json" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
+ Write-Host "Discovered _NT_TARGET_VERSION matrix: $json"
+
build:
name: build ${{ matrix.nt.tag }} ${{ matrix.configuration }} ${{ matrix.platform }}
+ needs: discover
strategy:
fail-fast: false
matrix:
configuration: [Debug, Release]
platform: [x64, arm64]
- # _NT_TARGET_VERSION = the WDK library version drivers link against (newest first).
- # Each { version, tag } runs as its own parallel job; trim this list to reduce CI load.
- nt:
- - { version: '10.0.28000', tag: '28000' }
- - { version: '10.0.26100', tag: '26100' }
- - { version: '10.0.22621', tag: '22621' }
- - { version: '10.0.22000', tag: '22000' }
+ # _NT_TARGET_VERSION values are auto-discovered by the 'discover' job from the active
+ # WDK, so there is no version list to maintain here.
+ nt: ${{ fromJSON(needs.discover.outputs.versions) }}
runs-on: windows-2025-vs2026
steps:
- name: Check out repository code
diff --git a/Build-Samples.ps1 b/Build-Samples.ps1
index c58164b2..861ec39a 100644
--- a/Build-Samples.ps1
+++ b/Build-Samples.ps1
@@ -27,21 +27,13 @@
.PARAMETER Platforms
Build platforms (e.g. 'x64','arm64'). Defaults to $env:WDS_Platform or ('x64','arm64').
-.PARAMETER TargetVersion
- Target OS version the drivers are built for (the msbuild 'TargetVersion' property).
- Valid values are defined by the WDK DriverGeneral.xml rule and are listed newest-first:
- Windows10 - Windows 10 or higher (default, latest)
- WindowsV6.3 - Windows 8.1
- Windows8 - Windows 8
- Windows7 - Windows 7
- Defaults to $env:WDS_TargetVersion, or 'Windows10' (the latest) when unset.
-
.PARAMETER NtTargetVersion
The _NT_TARGET_VERSION value - the WDK library version the driver links against
- ("OS version of libraries"), which is independent of the Target OS Version. Accepts the
- Windows build-number form (e.g. '10.0.28000'); valid values come from the WDK
- DriverGeneral.xml rule and are listed newest-first. Defaults to $env:WDS_NtTargetVersion,
- or '10.0.28000' (the latest) when unset.
+ ("OS version of libraries"). Accepts the Windows build-number form '10.0.<build>' or the
+ short '<build>' tag (e.g. '10.0.28000' or '28000'). The valid values are auto-discovered
+ from the active WDK's DriverGeneral.xml rule (see Get-NtTargetVersions.ps1), so a new WDK
+ version is picked up with no script change. Defaults to $env:WDS_NtTargetVersion, or the
+ latest discovered version when unset.
.PARAMETER LogFilesDirectory
Directory for build log files. Defaults to _logs in the current directory.
@@ -87,9 +79,9 @@
Forces WDK mode regardless of environment variables.
.EXAMPLE
- .\Build-Samples -TargetVersion Windows7
+ .\Build-Samples -NtTargetVersion 10.0.22000
- Builds all samples targeting Windows 7 instead of the default (latest) Windows10.
+ Builds all samples linking against the 10.0.22000 library set instead of the latest.
#>
#Requires -Version 7.0
@@ -99,13 +91,9 @@ param(
[string[]]$Samples,
[string[]]$Configurations = @(if ([string]::IsNullOrEmpty($env:WDS_Configuration)) { ('Debug', 'Release') } else { $env:WDS_Configuration }),
[string[]]$Platforms = @(if ([string]::IsNullOrEmpty($env:WDS_Platform)) { ('x64', 'arm64') } else { $env:WDS_Platform }),
- # Valid TargetVersion values come from the WDK DriverGeneral.xml rule (newest first).
- [ValidateSet('Windows10', 'WindowsV6.3', 'Windows8', 'Windows7')]
- [string]$TargetVersion = $(if ([string]::IsNullOrEmpty($env:WDS_TargetVersion)) { 'Windows10' } else { $env:WDS_TargetVersion }),
- # _NT_TARGET_VERSION = the WDK library version the driver links against (newest first;
- # values come from the WDK DriverGeneral.xml rule). Default is the latest.
- [ValidateSet('10.0.28000', '10.0.26100', '10.0.22621', '10.0.22000', '10.0.20348', '10.0.19041', '10.0.18362', '10.0.17763', '10.0.17134', '10.0.16299', '10.0.15063', '10.0.14393', '10.0.10586', '10.0.10240')]
- [string]$NtTargetVersion = $(if ([string]::IsNullOrEmpty($env:WDS_NtTargetVersion)) { '10.0.28000' } else { $env:WDS_NtTargetVersion }),
+ # _NT_TARGET_VERSION = the WDK library version the driver links against. Valid values are
+ # auto-discovered from the WDK (Get-NtTargetVersions.ps1); empty = the latest discovered.
+ [string]$NtTargetVersion = $env:WDS_NtTargetVersion,
[string]$LogFilesDirectory = (Join-Path (Get-Location) "_logs"),
[string]$ReportFileName = $(if ([string]::IsNullOrEmpty($env:WDS_ReportFileName)) { "_overview" } else { $env:WDS_ReportFileName }),
[string]$InfOptions,
@@ -131,24 +119,18 @@ function Import-SampleExclusions {
- Reason: human-readable explanation
A row is only returned when ALL of the following match the current build:
- - its [MinBuild, MaxBuild] range includes the given build number,
+ - its [MinBuild, MaxBuild] range includes the given build number, and
- its [MinNtTargetVersion, MaxNtTargetVersion] range includes the current
- _NT_TARGET_VERSION build number (e.g. 22000 parsed from '10.0.22000'), and
- - its TargetVersions list matches the given TargetVersion. TargetVersions is
- blank/'*' for all versions, or a ';'-separated list of -like patterns
- (e.g. 'Windows8', 'Windows7;Windows8', 'Windows*').
- Rows outside any range, or whose TargetVersions does not match, are skipped.
- MinBuild/MaxBuild and MinNtTargetVersion/MaxNtTargetVersion are blank = unbounded.
+ _NT_TARGET_VERSION build number (e.g. 22000 parsed from '10.0.22000').
+ Rows outside either range are skipped; blank range bounds mean unbounded.
.NOTES
- CSV format: Path,Configurations,TargetVersions,MinBuild,MaxBuild,MinNtTargetVersion,MaxNtTargetVersion,Reason
- Example row: network\wlan\wdi,*,,,27100,,,"failure introduced in VS17.14"
- Target-specific: somepath,*|ARM64,Windows8,,,,,"ARM not supported when targeting Windows 8"
- NT-version-specific: somepath,*,,,,,22621,"needs an API newer than the 10.0.22621 library"
+ CSV format: Path,Configurations,MinBuild,MaxBuild,MinNtTargetVersion,MaxNtTargetVersion,Reason
+ Example row: network\wlan\wdi,*,26100,,,,"failure introduced in VS17.14"
+ NT-version-specific: somepath,*,,,,22621,"needs an API newer than the 10.0.22621 library"
#>
param(
[string]$CsvPath,
[int]$BuildNumber,
- [string]$TargetVersion = 'Windows10',
[string]$NtTargetVersion = '10.0.28000'
)
@@ -165,22 +147,15 @@ function Import-SampleExclusions {
Import-Csv $CsvPath | ForEach-Object {
$pattern = $_.Path.Trim('\').Replace('\', '.').ToLower()
$configs = if ([string]::IsNullOrWhiteSpace($_.Configurations)) { '*' } else { $_.Configurations }
- # TargetVersions column is optional; blank or missing means "all target versions".
- $targets = if ([string]::IsNullOrWhiteSpace($_.TargetVersions)) { '*' } else { $_.TargetVersions }
$minBuild = if ([string]::IsNullOrWhiteSpace($_.MinBuild)) { 0 } else { [int]$_.MinBuild }
$maxBuild = if ([string]::IsNullOrWhiteSpace($_.MaxBuild)) { 99999 } else { [int]$_.MaxBuild }
# Min/MaxNtTargetVersion columns are optional; blank or missing means "all NT versions".
$minNt = if ([string]::IsNullOrWhiteSpace($_.MinNtTargetVersion)) { 0 } else { [int]$_.MinNtTargetVersion }
$maxNt = if ([string]::IsNullOrWhiteSpace($_.MaxNtTargetVersion)) { 9999999 } else { [int]$_.MaxNtTargetVersion }
- # TargetVersion and _NT_TARGET_VERSION are constant for the whole run, so (like the
- # build number) filter these rows out here at load time.
- $targetMatches = $targets.Split(';') | Where-Object { $TargetVersion -like $_.Trim() }
-
- if (-not $targetMatches) {
- Write-Verbose "Exclusion skipped: '$pattern' - target '$TargetVersion' not in '$targets'"
- }
- elseif ($ntBuild -lt $minNt -or $ntBuild -gt $maxNt) {
+ # _NT_TARGET_VERSION is constant for the whole run, so (like the build number) filter
+ # these rows out here at load time.
+ if ($ntBuild -lt $minNt -or $ntBuild -gt $maxNt) {
Write-Verbose "Exclusion skipped: '$pattern' - _NT_TARGET_VERSION $ntBuild outside [$minNt, $maxNt]"
}
elseif ($minBuild -le $BuildNumber -and $BuildNumber -le $maxBuild) {
@@ -189,7 +164,7 @@ function Import-SampleExclusions {
Configurations = $configs
Reason = $_.Reason
})
- Write-Verbose "Exclusion applied: '$pattern' configs='$configs' targets='$targets' ntRange=[$minNt,$maxNt] reason='$($_.Reason)'"
+ Write-Verbose "Exclusion applied: '$pattern' configs='$configs' ntRange=[$minNt,$maxNt] reason='$($_.Reason)'"
}
else {
Write-Verbose "Exclusion skipped: '$pattern' - build $BuildNumber outside [$minBuild, $maxBuild]"
@@ -230,7 +205,6 @@ function Build-SingleSample {
[string]$SampleName,
[string]$Configuration = 'Debug',
[string]$Platform = 'x64',
- [string]$TargetVersion = 'Windows10',
[string]$NtTargetVersionCode = '0xA000012',
[string]$InfVerif_AdditionalOptions = '/samples',
[string]$LogFilesDirectory = (Get-Location),
@@ -308,7 +282,7 @@ function Build-SingleSample {
-clp:Verbosity=m -t:rebuild `
-property:Configuration=$Configuration `
-property:Platform=$Platform `
- -p:TargetVersion=$TargetVersion `
+ -p:TargetVersion=Windows10 `
-p:_NT_TARGET_VERSION=$NtTargetVersionCode `
-p:InfVerif_AdditionalOptions="$InfVerif_AdditionalOptions" `
-warnaserror `
@@ -454,26 +428,36 @@ else {
}
# =============================================================================
-# Step 5b - Resolve _NT_TARGET_VERSION code
+# Step 5b - Resolve _NT_TARGET_VERSION
# =============================================================================
#
-# _NT_TARGET_VERSION selects the WDK library version the driver links against
-# (independent of the Target OS Version). The MSBuild property takes the NTDDI hex
-# code, so map the friendly build number to it. Codes come from WDK DriverGeneral.xml.
-$ntTargetVersionCodes = [ordered]@{
- '10.0.28000' = '0xA000012'; '10.0.26100' = '0xA000010'; '10.0.22621' = '0xA00000C'
- '10.0.22000' = '0xA00000B'; '10.0.20348' = '0xA00000A'; '10.0.19041' = '0xA000008'
- '10.0.18362' = '0xA000007'; '10.0.17763' = '0xA000006'; '10.0.17134' = '0xA000005'
- '10.0.16299' = '0xA000004'; '10.0.15063' = '0xA000003'; '10.0.14393' = '0xA000002'
- '10.0.10586' = '0xA000001'; '10.0.10240' = '0x0A00'
+# _NT_TARGET_VERSION selects the WDK library version the driver links against. The valid
+# values (and their NTDDI codes) are auto-discovered from the active WDK by
+# Get-NtTargetVersions.ps1, so nothing here needs updating when a new WDK version ships.
+# msbuild takes the NTDDI code.
+$ntVersions = & (Join-Path $PSScriptRoot 'Get-NtTargetVersions.ps1')
+if (-not $ntVersions) {
+ Write-Error "Could not discover any _NT_TARGET_VERSION values from the active WDK."
+ exit 1
+}
+if ([string]::IsNullOrWhiteSpace($NtTargetVersion) -or $NtTargetVersion -eq 'latest') {
+ $ntSelected = $ntVersions[0] # newest
+}
+else {
+ $ntSelected = $ntVersions | Where-Object { $_.Version -eq $NtTargetVersion -or $_.Tag -eq $NtTargetVersion } | Select-Object -First 1
+ if (-not $ntSelected) {
+ Write-Error "Invalid -NtTargetVersion '$NtTargetVersion'. Valid values: $(($ntVersions.Version) -join ', ')"
+ exit 1
+ }
}
-$ntTargetVersionCode = $ntTargetVersionCodes[$NtTargetVersion]
+$NtTargetVersion = $ntSelected.Version
+$ntTargetVersionCode = $ntSelected.Code
# =============================================================================
# Step 6 - Load Exclusions
# =============================================================================
-$exclusions = Import-SampleExclusions -CsvPath (Join-Path $root 'exclusions.csv') -BuildNumber $buildNumber -TargetVersion $TargetVersion -NtTargetVersion $NtTargetVersion
+$exclusions = Import-SampleExclusions -CsvPath (Join-Path $root 'exclusions.csv') -BuildNumber $buildNumber -NtTargetVersion $NtTargetVersion
# =============================================================================
# Step 7 - Print Build Plan
@@ -494,7 +478,6 @@ Write-Output ""
Write-Output " Samples: $($sampleSet.Count) ($skippedCount skipped)"
Write-Output " Configurations: $($Configurations -join ', ')"
Write-Output " Platforms: $($Platforms -join ', ')"
-Write-Output " Target Version: $TargetVersion"
Write-Output " NT Target Ver: $NtTargetVersion ($ntTargetVersionCode)"
Write-Output " Combinations: $combinationsTotal"
Write-Output " Exclusions: $($exclusions.Count)"
@@ -542,7 +525,6 @@ $sampleSet.GetEnumerator() | ForEach-Object -ThrottleLimit $ThrottleLimit -Paral
$configs = $using:Configurations
$platforms = $using:Platforms
$infOpts = $using:infVerifOptions
- $targetVer = $using:TargetVersion
$ntCode = $using:ntTargetVersionCode
$isVerbose = $using:verbose
$state = $using:buildState
@@ -594,8 +576,7 @@ $sampleSet.GetEnumerator() | ForEach-Object -ThrottleLimit $ThrottleLimit -Paral
$buildResult = Build-SingleSample `
-Directory $directory -SampleName $sampleName `
-LogFilesDirectory $logDir -Configuration $configuration `
- -Platform $platform -TargetVersion $targetVer `
- -NtTargetVersionCode $ntCode `
+ -Platform $platform -NtTargetVersionCode $ntCode `
-InfVerif_AdditionalOptions $infOpts `
-Verbose:$isVerbose
@@ -714,7 +695,6 @@ Write-Output ""
Write-Output " Samples: $($sampleSet.Count)"
Write-Output " Configurations: $($Configurations -join ', ')"
Write-Output " Platforms: $($Platforms -join ', ')"
-Write-Output " Target Version: $TargetVersion"
Write-Output " NT Target Ver: $NtTargetVersion ($ntTargetVersionCode)"
Write-Output " Combinations: $combinationsTotal"
Write-Output ""
@@ -735,7 +715,7 @@ Write-Output "------------------------------------------------------------------
$sortedResults = $buildState.Results | Sort-Object { $_.Sample }
$sortedResults | ConvertTo-Csv | Out-File $reportCsvPath
-$sortedResults | ConvertTo-Html -Title "WDK Sample Build Overview - TargetVersion $TargetVersion, _NT_TARGET_VERSION $NtTargetVersion" | Out-File $reportHtmlPath
+$sortedResults | ConvertTo-Html -Title "WDK Sample Build Overview - _NT_TARGET_VERSION $NtTargetVersion" | Out-File $reportHtmlPath
# Only open the HTML report interactively (not in CI/automation)
if (-not $env:BUILD_BUILDID -and [Environment]::UserInteractive) {
@@ -755,7 +735,7 @@ if ($env:GITHUB_STEP_SUMMARY) {
$md = [System.Text.StringBuilder]::new()
[void]$md.AppendLine("## $icon ``$cfgLabel`` &nbsp;&middot;&nbsp; _NT_TARGET_VERSION ``$NtTargetVersion``")
[void]$md.AppendLine()
- [void]$md.AppendLine("Environment **$($buildEnv.Name)** &middot; WDK build **$buildNumber** &middot; TargetVersion **$TargetVersion** &middot; **$($sampleSet.Count)** samples &middot; $($elapsed.Minutes)m $($elapsed.Seconds)s")
+ [void]$md.AppendLine("Environment **$($buildEnv.Name)** &middot; WDK build **$buildNumber** &middot; **$($sampleSet.Count)** samples &middot; $($elapsed.Minutes)m $($elapsed.Seconds)s")
[void]$md.AppendLine()
[void]$md.AppendLine("| :white_check_mark: Succeeded | :x: Failed | :warning: Sporadic | :heavy_minus_sign: Excluded | :grey_question: Unsupported |")
[void]$md.AppendLine("|---:|---:|---:|---:|---:|")
diff --git a/Building-Locally.md b/Building-Locally.md
index 8c11d012..ebddbfba 100644
--- a/Building-Locally.md
+++ b/Building-Locally.md
@@ -121,36 +121,20 @@ Get-Help .\Build-Samples.ps1 -Detailed
# Build a specific sample for Debug|x64 only:
.\Build-Samples.ps1 -Samples 'tools.sdv.samples.sampledriver' -Configurations 'Debug' -Platforms 'x64'
-# Build every sample targeting an older OS version (default is the latest, Windows10):
-.\Build-Samples.ps1 -TargetVersion Windows7
-
# Build every sample linking against an older WDK library set (default is the latest):
.\Build-Samples.ps1 -NtTargetVersion 10.0.22000
```
-The `-TargetVersion` values come from the WDK `DriverGeneral.xml` rule and are listed
-newest-first. The default is the latest, `Windows10`:
-
-| Value | Target OS |
-| ------------- | ---------------------- |
-| `Windows10` | Windows 10 or higher (default) |
-| `WindowsV6.3` | Windows 8.1 |
-| `Windows8` | Windows 8 |
-| `Windows7` | Windows 7 |
-
-`-TargetVersion` (Target OS Version) selects the driver's *platform model* and is gated to
-Windows 10+ for Universal / Windows Driver samples. To instead vary the **library version the
-driver links against** - the WDK's `_NT_TARGET_VERSION` ("OS version of libraries") - while
-keeping the platform on Windows 10, use `-NtTargetVersion`. It accepts a Windows build number;
-values come from the WDK `DriverGeneral.xml` rule (newest-first), default latest `10.0.28000`:
+`-NtTargetVersion` selects the WDK **`_NT_TARGET_VERSION`** — the OS version of the libraries
+the driver links against. It accepts the Windows build number (`10.0.<build>`) or the short
+`<build>` tag (e.g. `10.0.22000` or `22000`); when omitted it uses the latest. The valid
+values are **auto-discovered from the active WDK** — `Get-NtTargetVersions.ps1` parses the
+WDK's `DriverGeneral.xml` rule — so a new WDK version is picked up automatically with no edits.
+List what's available with:
-| `-NtTargetVersion` | Links against |
-| ------------------ | ----------------- |
-| `10.0.28000` | latest (default) |
-| `10.0.26100` | 24H2 |
-| `10.0.22621` | 22H2 |
-| `10.0.22000` | 21H2 |
-| ... | down to `10.0.10240` |
+```powershell
+.\Get-NtTargetVersions.ps1
+```
---
@@ -159,36 +143,29 @@ values come from the WDK `DriverGeneral.xml` rule (newest-first), default latest
Samples that are known not to build for a given environment are listed in `exclusions.csv`
at the repo root. Each row excludes a path (with wildcards) for specific
configuration/platform combinations, an optional WDK build-number range, and an optional
-set of target versions:
+`_NT_TARGET_VERSION` range:
```
-Path,Configurations,TargetVersions,MinBuild,MaxBuild,MinNtTargetVersion,MaxNtTargetVersion,Reason
+Path,Configurations,MinBuild,MaxBuild,MinNtTargetVersion,MaxNtTargetVersion,Reason
```
| Column | Meaning |
| ---------------- | ---------------------------------------------------------------------------------------- |
| `Path` | Sample path (backslashes); supports `*`/`?` wildcards. |
| `Configurations` | `;`-separated `Config\|Platform` patterns, or `*` for all (e.g. `*\|ARM64`, `Debug\|x64`). |
-| `TargetVersions` | `;`-separated `-like` patterns matched against `-TargetVersion`; blank or `*` = all (e.g. `Windows8`, `Windows7;Windows8`, `Windows*`). |
| `MinBuild`/`MaxBuild` | Inclusive WDK build-number range; blank = unbounded. |
| `MinNtTargetVersion`/`MaxNtTargetVersion` | Inclusive `-NtTargetVersion` build-number range (e.g. `22621` matches `10.0.22621`); blank = unbounded. Use this for samples that fail only when linking against older libraries. |
| `Reason` | Human-readable explanation (keep this column last; quote it if it contains commas). |
A row is applied only when every populated condition matches the current run (path,
-configuration/platform, WDK build-number range, NT target-version range, and target version
-are AND-ed together). Leave a column blank to ignore that dimension (the default for most rows).
-
-For example, to exclude all ARM platforms only when building for Windows 8:
-
-```
-somepath,*|ARM64,Windows8,,,,,"ARM not supported when targeting Windows 8"
-```
+configuration/platform, WDK build-number range, and NT target-version range are AND-ed
+together). Leave a column blank to ignore that dimension (the default for most rows).
-Or to exclude a sample (Debug builds only) when linking against the `10.0.22621` library set
-or older, because it uses a newer API:
+For example, to exclude a sample (Debug builds only) when linking against the `10.0.22621`
+library set or older, because it uses a newer API:
```
-somepath,Debug|*,,,,,22621,uses an API newer than the 10.0.22621 library
+somepath,Debug|*,,,,22621,uses an API newer than the 10.0.22621 library
```
---
diff --git a/Get-NtTargetVersions.ps1 b/Get-NtTargetVersions.ps1
new file mode 100644
index 00000000..68088277
--- /dev/null
+++ b/Get-NtTargetVersions.ps1
@@ -0,0 +1,100 @@
+<#
+.SYNOPSIS
+ Auto-discovers the valid _NT_TARGET_VERSION values from the active WDK.
+
+.DESCRIPTION
+ The _NT_TARGET_VERSION property (the OS version of the libraries a driver links against)
+ is an enumeration defined by the WDK in its 'DriverGeneral.xml' rule file. This script
+ locates that rule file (from the restored NuGet packages, or the installed WDK) and parses
+ the enumeration so that nothing in the build needs a hard-coded version list: when a new
+ WDK adds a new _NT_TARGET_VERSION it is picked up automatically.
+
+ Returns one object per Windows 10/11 entry, newest-first:
+ Version e.g. 10.0.28000 (use with -NtTargetVersion)
+ Tag e.g. 28000 (short, filename/CI-friendly)
+ Code e.g. 0xA000012 (the NTDDI value passed to msbuild)
+ Build e.g. 28000 (numeric, for sorting/ranges)
+
+.PARAMETER XmlPath
+ Optional explicit path to a DriverGeneral.xml. When omitted the newest available rule file
+ is auto-located.
+
+.PARAMETER Newest
+ Return only the newest N versions (0 = all). Useful for bounding the CI build matrix.
+
+.PARAMETER AsMatrixJson
+ Emit a compact JSON array of { version, tag } objects for a GitHub Actions matrix
+ (consumed via fromJSON). Implies a single-line output.
+
+.EXAMPLE
+ .\Get-NtTargetVersions.ps1 # all discovered versions (objects)
+
+.EXAMPLE
+ .\Get-NtTargetVersions.ps1 -Newest 4 -AsMatrixJson
+#>
+[CmdletBinding()]
+param(
+ [string]$XmlPath,
+ [int]$Newest = 0,
+ [switch]$AsMatrixJson
+)
+
+function Find-DriverGeneralXml {
+ # Prefer the restored NuGet WDK package (matches what the build actually uses), then the
+ # installed WDK. Within each source, pick the highest build version.
+ $candidates = @()
+ $candidates += Get-ChildItem -Path (Join-Path $PSScriptRoot 'packages') -Recurse -Filter 'DriverGeneral.xml' -ErrorAction SilentlyContinue
+ foreach ($kitsRoot in @("${env:ProgramFiles(x86)}\Windows Kits\10\build", "${env:ProgramFiles}\Windows Kits\10\build")) {
+ if ($kitsRoot -and (Test-Path $kitsRoot)) {
+ $candidates += Get-ChildItem -Path $kitsRoot -Recurse -Filter 'DriverGeneral.xml' -ErrorAction SilentlyContinue
+ }
+ }
+ # EWDK / arbitrary build environments expose the build tree via these variables.
+ foreach ($envRoot in @($env:WDKContentRoot, $env:WindowsSdkDir)) {
+ if ($envRoot -and (Test-Path $envRoot)) {
+ $buildDir = Join-Path $envRoot 'build'
+ if (Test-Path $buildDir) {
+ $candidates += Get-ChildItem -Path $buildDir -Recurse -Filter 'DriverGeneral.xml' -ErrorAction SilentlyContinue
+ }
+ }
+ }
+ if (-not $candidates) { return $null }
+ # Order by the build version embedded in the path (e.g. ...\10.0.28000.0\...), highest first.
+ return ($candidates | Sort-Object {
+ if ($_.FullName -match '10\.0\.(\d+)\.\d') { [int]$Matches[1] } else { 0 }
+ } -Descending | Select-Object -First 1).FullName
+}
+
+if (-not $XmlPath) { $XmlPath = Find-DriverGeneralXml }
+if (-not $XmlPath -or -not (Test-Path $XmlPath)) {
+ throw "Could not locate DriverGeneral.xml. Restore the WDK NuGet packages or install the WDK, or pass -XmlPath."
+}
+
+[xml]$xml = Get-Content -Path $XmlPath -Raw
+$enum = $xml.ProjectSchemaDefinitions.Rule.EnumProperty | Where-Object { $_.Name -eq '_NT_TARGET_VERSION' }
+if (-not $enum) { throw "No _NT_TARGET_VERSION enumeration found in '$XmlPath'." }
+
+$versions =
+ $enum.EnumValue |
+ ForEach-Object {
+ # DisplayName is e.g. "Windows 10.0.28000"; Name is the NTDDI code e.g. "0xA000012".
+ if ("$($_.DisplayName)" -match 'Windows\s+(?<v>10\.0\.(?<b>\d+))\s*$') {
+ [pscustomobject]@{
+ Version = $Matches.v
+ Tag = $Matches.b
+ Code = $_.Name
+ Build = [int]$Matches.b
+ }
+ }
+ } |
+ Sort-Object Build -Descending
+
+if ($Newest -gt 0) { $versions = $versions | Select-Object -First $Newest }
+
+if ($AsMatrixJson) {
+ # Compact, single-line JSON for a GitHub Actions matrix: [{ "version": "...", "tag": "..." }, ...]
+ $matrix = @($versions | ForEach-Object { [ordered]@{ version = $_.Version; tag = $_.Tag } })
+ return ($matrix | ConvertTo-Json -Compress -Depth 3)
+}
+
+return $versions
diff --git a/exclusions.csv b/exclusions.csv
index 566c685d..0cae0380 100644
--- a/exclusions.csv
+++ b/exclusions.csv
@@ -1,20 +1,20 @@
-Path,Configurations,TargetVersions,MinBuild,MaxBuild,MinNtTargetVersion,MaxNtTargetVersion,Reason
-audio\acx\samples\audiocodec\driver,*,,,22621,,,Only NI: error C1083: Cannot open include file: 'acx.h': No such file or directory
-general\dchu\osrfx2_dchu_extension_loose,*|x64,,,22621,,,Only NI: Only x64: Fails to build
-general\dchu\osrfx2_dchu_extension_tight,*|x64,,,22621,,,Only NI: Only x64: Fails to build
-network\trans\WFPSampler,Debug|ARM64,,,22621,,,Only NI: Only ARM: Fails to build on EWDK 22621 with VS 17.1.5 - CallingConvention=StdCall not supported
-prm,*,,,22621,,,Only NI: Not supported on NI.
-powerlimit\plclient,*,,,22621,,,Only NI: Not supported on NI.
-powerlimit\plpolicy,*,,,22621,,,Only NI: Not supported on NI.
-general\pcidrv,*,,26100,,,,"failure introduced in VS17.14, suppressed until fix"
-serial\serial,*,,26100,,,,"failure introduced in VS17.14, suppressed until fix"
-network\wlan\wdi,*,,26100,,,,"failure introduced in VS17.14, suppressed until fix"
-tools\kasan\samples\kasandemo-wdm,*|x64,,26100,,,,"failure introduced in VS17.14, suppressed until fix"
-audio\sysvad,*,,,,,22000,_NT_TARGET_VERSION: KSJACK_DESCRIPTION3 undeclared; audio jack descriptor v3 was added in 22H2 (10.0.22621)
-network\netadaptercx\netvadapter,*,,,,,22621,_NT_TARGET_VERSION: requests an NDIS/DDI version newer than the linked library (C1189 wrong NDIS or DDI version)
-network\wlan\wificx,*,,,,,22621,_NT_TARGET_VERSION: requests an NDIS/DDI version newer than the linked library (C1189 wrong NDIS or DDI version)
-powerlimit\plclient,*,,,,,22621,_NT_TARGET_VERSION: POWER_LIMIT_ATTRIBUTES not declared in the older library (C2061)
-powerlimit\plpolicy,*,,,,,22621,_NT_TARGET_VERSION: POWER_LIMIT_ATTRIBUTES not declared in the older library (C2061)
-storage\class\classpnp,Debug|*,,,,,22621,_NT_TARGET_VERSION: STOR_ADDRESS_TYPE_NVME undeclared in the older library (C2065); Debug only
-storage\miniports\storahci,Debug|*,,,,,22621,_NT_TARGET_VERSION: STOR_ADDRESS_TYPE_NVME undeclared in the older library (C2065); Debug only
-storage\msdsm,Debug|x64,,,,,22621,_NT_TARGET_VERSION: STOR_ADDRESS_TYPE_NVME undeclared in the older library (C2065); Debug|x64 only
+Path,Configurations,MinBuild,MaxBuild,MinNtTargetVersion,MaxNtTargetVersion,Reason
+audio\acx\samples\audiocodec\driver,*,,22621,,,Only NI: error C1083: Cannot open include file: 'acx.h': No such file or directory
+general\dchu\osrfx2_dchu_extension_loose,*|x64,,22621,,,Only NI: Only x64: Fails to build
+general\dchu\osrfx2_dchu_extension_tight,*|x64,,22621,,,Only NI: Only x64: Fails to build
+network\trans\WFPSampler,Debug|ARM64,,22621,,,Only NI: Only ARM: Fails to build on EWDK 22621 with VS 17.1.5 - CallingConvention=StdCall not supported
+prm,*,,22621,,,Only NI: Not supported on NI.
+powerlimit\plclient,*,,22621,,,Only NI: Not supported on NI.
+powerlimit\plpolicy,*,,22621,,,Only NI: Not supported on NI.
+general\pcidrv,*,26100,,,,"failure introduced in VS17.14, suppressed until fix"
+serial\serial,*,26100,,,,"failure introduced in VS17.14, suppressed until fix"
+network\wlan\wdi,*,26100,,,,"failure introduced in VS17.14, suppressed until fix"
+tools\kasan\samples\kasandemo-wdm,*|x64,26100,,,,"failure introduced in VS17.14, suppressed until fix"
+audio\sysvad,*,,,,22000,_NT_TARGET_VERSION: KSJACK_DESCRIPTION3 undeclared; audio jack descriptor v3 was added in 22H2 (10.0.22621)
+network\netadaptercx\netvadapter,*,,,,22621,_NT_TARGET_VERSION: requests an NDIS/DDI version newer than the linked library (C1189 wrong NDIS or DDI version)
+network\wlan\wificx,*,,,,22621,_NT_TARGET_VERSION: requests an NDIS/DDI version newer than the linked library (C1189 wrong NDIS or DDI version)
+powerlimit\plclient,*,,,,22621,_NT_TARGET_VERSION: POWER_LIMIT_ATTRIBUTES not declared in the older library (C2061)
+powerlimit\plpolicy,*,,,,22621,_NT_TARGET_VERSION: POWER_LIMIT_ATTRIBUTES not declared in the older library (C2061)
+storage\class\classpnp,Debug|*,,,,22621,_NT_TARGET_VERSION: STOR_ADDRESS_TYPE_NVME undeclared in the older library (C2065); Debug only
+storage\miniports\storahci,Debug|*,,,,22621,_NT_TARGET_VERSION: STOR_ADDRESS_TYPE_NVME undeclared in the older library (C2065); Debug only
+storage\msdsm,Debug|x64,,,,22621,_NT_TARGET_VERSION: STOR_ADDRESS_TYPE_NVME undeclared in the older library (C2065); Debug|x64 only