From 167a11ba7b1fd981755921f604106b6dbce6ec99 Mon Sep 17 00:00:00 2001 From: 5an7y Date: Mon, 22 Jun 2026 12:38:36 -0700 Subject: [PATCH 1/7] Expose TargetVersion parameter in Build-Samples.ps1 Add a validated -TargetVersion parameter (also settable via the WDS_TargetVersion environment variable) so samples can be built for older target OS versions. Valid values come from the WDK DriverGeneral.xml rule and default to the latest, Windows10: Windows10 (Windows 10 or higher), WindowsV6.3 (Windows 8.1), Windows8 (Windows 8), Windows7 (Windows 7). The value is threaded through Build-SingleSample into the msbuild invocation (replacing the hard-coded TargetVersion=Windows10) and across the parallel runspace, and is surfaced in the build plan, final summary, and HTML report title. Document the new parameter in the script help and Building-Locally.md. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- Build-Samples.ps1 | 28 +++++++++++++++++++++++++--- Building-Locally.md | 13 +++++++++++++ 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/Build-Samples.ps1 b/Build-Samples.ps1 index a73a2afa1..c63d4d55b 100644 --- a/Build-Samples.ps1 +++ b/Build-Samples.ps1 @@ -27,6 +27,15 @@ .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 LogFilesDirectory Directory for build log files. Defaults to _logs in the current directory. @@ -69,6 +78,11 @@ .\Build-Samples -RunMode WDK Forces WDK mode regardless of environment variables. + +.EXAMPLE + .\Build-Samples -TargetVersion Windows7 + + Builds all samples targeting Windows 7 instead of the default (latest) Windows10. #> #Requires -Version 7.0 @@ -78,6 +92,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 }), [string]$LogFilesDirectory = (Join-Path (Get-Location) "_logs"), [string]$ReportFileName = $(if ([string]::IsNullOrEmpty($env:WDS_ReportFileName)) { "_overview" } else { $env:WDS_ReportFileName }), [string]$InfOptions, @@ -172,6 +189,7 @@ function Build-SingleSample { [string]$SampleName, [string]$Configuration = 'Debug', [string]$Platform = 'x64', + [string]$TargetVersion = 'Windows10', [string]$InfVerif_AdditionalOptions = '/samples', [string]$LogFilesDirectory = (Get-Location), [bool]$Verbose = $false @@ -248,7 +266,7 @@ function Build-SingleSample { -clp:Verbosity=m -t:rebuild ` -property:Configuration=$Configuration ` -property:Platform=$Platform ` - -p:TargetVersion=Windows10 ` + -p:TargetVersion=$TargetVersion ` -p:InfVerif_AdditionalOptions="$InfVerif_AdditionalOptions" ` -warnaserror ` -binaryLogger:LogFile=$binLogFilePath`;ProjectImports=None ` @@ -417,6 +435,7 @@ 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 " Combinations: $combinationsTotal" Write-Output " Exclusions: $($exclusions.Count)" Write-Output "" @@ -463,6 +482,7 @@ $sampleSet.GetEnumerator() | ForEach-Object -ThrottleLimit $ThrottleLimit -Paral $configs = $using:Configurations $platforms = $using:Platforms $infOpts = $using:infVerifOptions + $targetVer = $using:TargetVersion $isVerbose = $using:verbose $state = $using:buildState $total = $using:combinationsTotal @@ -513,7 +533,8 @@ $sampleSet.GetEnumerator() | ForEach-Object -ThrottleLimit $ThrottleLimit -Paral $buildResult = Build-SingleSample ` -Directory $directory -SampleName $sampleName ` -LogFilesDirectory $logDir -Configuration $configuration ` - -Platform $platform -InfVerif_AdditionalOptions $infOpts ` + -Platform $platform -TargetVersion $targetVer ` + -InfVerif_AdditionalOptions $infOpts ` -Verbose:$isVerbose # Return codes from Build-SingleSample: @@ -631,6 +652,7 @@ Write-Output "" Write-Output " Samples: $($sampleSet.Count)" Write-Output " Configurations: $($Configurations -join ', ')" Write-Output " Platforms: $($Platforms -join ', ')" +Write-Output " Target Version: $TargetVersion" Write-Output " Combinations: $combinationsTotal" Write-Output "" Write-Output " Succeeded: $($buildState.Succeeded)" @@ -650,7 +672,7 @@ Write-Output "------------------------------------------------------------------ $sortedResults = $buildState.Results | Sort-Object { $_.Sample } $sortedResults | ConvertTo-Csv | Out-File $reportCsvPath -$sortedResults | ConvertTo-Html -Title "WDK Sample Build Overview" | Out-File $reportHtmlPath +$sortedResults | ConvertTo-Html -Title "WDK Sample Build Overview - TargetVersion $TargetVersion" | Out-File $reportHtmlPath # Only open the HTML report interactively (not in CI/automation) if (-not $env:BUILD_BUILDID -and [Environment]::UserInteractive) { diff --git a/Building-Locally.md b/Building-Locally.md index 9d683a86a..a4db07475 100644 --- a/Building-Locally.md +++ b/Building-Locally.md @@ -120,8 +120,21 @@ 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 ``` +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 | + --- ## Additional Notes From a659bfc6b48a908a0b244d32de575bcf30033e7b Mon Sep 17 00:00:00 2001 From: 5an7y Date: Mon, 22 Jun 2026 13:54:56 -0700 Subject: [PATCH 2/7] Support TargetVersion-scoped rules in exclusions.csv Add an optional TargetVersions column to exclusions.csv so an exclusion can be limited to specific target OS versions (e.g. exclude ARM only when building Windows8). The column holds a ';'-separated list of -like patterns matched against -TargetVersion; blank or '*' means all versions, so every existing row stays applicable to all targets. Import-SampleExclusions now takes -TargetVersion and filters rows by it at load time (alongside the existing MinBuild/MaxBuild range); a missing column is treated as '*' for backward compatibility. Document the new column and an example in Building-Locally.md. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- Build-Samples.ps1 | 30 ++++++++++++++++++++++-------- Building-Locally.md | 31 +++++++++++++++++++++++++++++++ exclusions.csv | 24 ++++++++++++------------ 3 files changed, 65 insertions(+), 20 deletions(-) diff --git a/Build-Samples.ps1 b/Build-Samples.ps1 index c63d4d55b..bb250a2f7 100644 --- a/Build-Samples.ps1 +++ b/Build-Samples.ps1 @@ -119,15 +119,21 @@ function Import-SampleExclusions { - Configurations: semicolon-separated config|platform patterns (or '*' for all) - Reason: human-readable explanation - Only exclusions whose [MinBuild, MaxBuild] range includes the given build number - are returned. Exclusions outside the range are silently skipped. + A row is only returned when BOTH of the following match the current build: + - its [MinBuild, MaxBuild] range includes the given build number, 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 the build range, or whose TargetVersions does not match, are skipped. .NOTES - CSV format: Path,Configurations,MinBuild,MaxBuild,Reason - Example row: network\wlan\wdi,*,,27100,"failure introduced in VS17.14" + CSV format: Path,Configurations,TargetVersions,MinBuild,MaxBuild,Reason + Example row: network\wlan\wdi,*,,,27100,"failure introduced in VS17.14" + Target-specific: somepath,*|ARM64,Windows8,,,"ARM not supported when targeting Windows 8" #> param( [string]$CsvPath, - [int]$BuildNumber + [int]$BuildNumber, + [string]$TargetVersion = 'Windows10' ) if (-not (Test-Path $CsvPath)) { @@ -139,16 +145,24 @@ 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 } - if ($minBuild -le $BuildNumber -and $BuildNumber -le $maxBuild) { + # TargetVersion is constant for the whole run, so (like the build number) filter here. + $targetMatches = $targets.Split(';') | Where-Object { $TargetVersion -like $_.Trim() } + + if (-not $targetMatches) { + Write-Verbose "Exclusion skipped: '$pattern' - target '$TargetVersion' not in '$targets'" + } + elseif ($minBuild -le $BuildNumber -and $BuildNumber -le $maxBuild) { [void]$exclusions.Add([PSCustomObject]@{ Pattern = $pattern Configurations = $configs Reason = $_.Reason }) - Write-Verbose "Exclusion applied: '$pattern' configs='$configs' reason='$($_.Reason)'" + Write-Verbose "Exclusion applied: '$pattern' configs='$configs' targets='$targets' reason='$($_.Reason)'" } else { Write-Verbose "Exclusion skipped: '$pattern' - build $BuildNumber outside [$minBuild, $maxBuild]" @@ -414,7 +428,7 @@ else { # Step 6 - Load Exclusions # ============================================================================= -$exclusions = Import-SampleExclusions -CsvPath (Join-Path $root 'exclusions.csv') -BuildNumber $buildNumber +$exclusions = Import-SampleExclusions -CsvPath (Join-Path $root 'exclusions.csv') -BuildNumber $buildNumber -TargetVersion $TargetVersion # ============================================================================= # Step 7 - Print Build Plan diff --git a/Building-Locally.md b/Building-Locally.md index a4db07475..5b746a640 100644 --- a/Building-Locally.md +++ b/Building-Locally.md @@ -137,6 +137,37 @@ newest-first. The default is the latest, `Windows10`: --- +## Excluding samples from the build + +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: + +``` +Path,Configurations,TargetVersions,MinBuild,MaxBuild,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. | +| `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, build-number range, and target version are AND-ed together). Leave +`TargetVersions` blank to exclude regardless of target version (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" +``` + +--- + ## Additional Notes ### Pre-release WDK: disable strong name validation diff --git a/exclusions.csv b/exclusions.csv index df12335dc..b3d8a50aa 100644 --- a/exclusions.csv +++ b/exclusions.csv @@ -1,12 +1,12 @@ -Path,Configurations,MinBuild,MaxBuild,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" +Path,Configurations,TargetVersions,MinBuild,MaxBuild,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" From 6c6c308f1fe6ec1ce2ce7d0d7b3b455305a4a346 Mon Sep 17 00:00:00 2001 From: 5an7y Date: Mon, 22 Jun 2026 15:52:55 -0700 Subject: [PATCH 3/7] Add -NtTargetVersion to build samples against older WDK library sets Expose the WDK '_NT_TARGET_VERSION' property (the OS version of the libraries the driver links against) as -NtTargetVersion / WDS_NtTargetVersion. Unlike -TargetVersion (Target OS Version), this does not change the platform model, so Universal/Windows Driver samples keep building on Windows 10 while linking against an older library set. The parameter accepts the Windows build number (e.g. 10.0.22000), maps it to the NTDDI code from the WDK DriverGeneral.xml rule, and passes -p:_NT_TARGET_VERSION to msbuild (threaded through Build-SingleSample and the parallel runspace). It defaults to the latest (10.0.28000) and is surfaced in the build plan, summary, and HTML report title. Documented in Building-Locally.md. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- Build-Samples.ps1 | 35 ++++++++++++++++++++++++++++++++++- Building-Locally.md | 17 +++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/Build-Samples.ps1 b/Build-Samples.ps1 index bb250a2f7..063947b62 100644 --- a/Build-Samples.ps1 +++ b/Build-Samples.ps1 @@ -36,6 +36,13 @@ 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. + .PARAMETER LogFilesDirectory Directory for build log files. Defaults to _logs in the current directory. @@ -95,6 +102,10 @@ param( # 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 }), [string]$LogFilesDirectory = (Join-Path (Get-Location) "_logs"), [string]$ReportFileName = $(if ([string]::IsNullOrEmpty($env:WDS_ReportFileName)) { "_overview" } else { $env:WDS_ReportFileName }), [string]$InfOptions, @@ -204,6 +215,7 @@ function Build-SingleSample { [string]$Configuration = 'Debug', [string]$Platform = 'x64', [string]$TargetVersion = 'Windows10', + [string]$NtTargetVersionCode = '0xA000012', [string]$InfVerif_AdditionalOptions = '/samples', [string]$LogFilesDirectory = (Get-Location), [bool]$Verbose = $false @@ -281,6 +293,7 @@ function Build-SingleSample { -property:Configuration=$Configuration ` -property:Platform=$Platform ` -p:TargetVersion=$TargetVersion ` + -p:_NT_TARGET_VERSION=$NtTargetVersionCode ` -p:InfVerif_AdditionalOptions="$InfVerif_AdditionalOptions" ` -warnaserror ` -binaryLogger:LogFile=$binLogFilePath`;ProjectImports=None ` @@ -424,6 +437,22 @@ else { $infVerifOptions = if ($buildNumber -le 22621) { '/sw1284 /sw1285 /sw1293 /sw2083 /sw2086' } else { '/samples' } } +# ============================================================================= +# Step 5b - Resolve _NT_TARGET_VERSION code +# ============================================================================= +# +# _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' +} +$ntTargetVersionCode = $ntTargetVersionCodes[$NtTargetVersion] + # ============================================================================= # Step 6 - Load Exclusions # ============================================================================= @@ -450,6 +479,7 @@ 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)" Write-Output "" @@ -497,6 +527,7 @@ $sampleSet.GetEnumerator() | ForEach-Object -ThrottleLimit $ThrottleLimit -Paral $platforms = $using:Platforms $infOpts = $using:infVerifOptions $targetVer = $using:TargetVersion + $ntCode = $using:ntTargetVersionCode $isVerbose = $using:verbose $state = $using:buildState $total = $using:combinationsTotal @@ -548,6 +579,7 @@ $sampleSet.GetEnumerator() | ForEach-Object -ThrottleLimit $ThrottleLimit -Paral -Directory $directory -SampleName $sampleName ` -LogFilesDirectory $logDir -Configuration $configuration ` -Platform $platform -TargetVersion $targetVer ` + -NtTargetVersionCode $ntCode ` -InfVerif_AdditionalOptions $infOpts ` -Verbose:$isVerbose @@ -667,6 +699,7 @@ 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 "" Write-Output " Succeeded: $($buildState.Succeeded)" @@ -686,7 +719,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" | Out-File $reportHtmlPath +$sortedResults | ConvertTo-Html -Title "WDK Sample Build Overview - TargetVersion $TargetVersion, _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) { diff --git a/Building-Locally.md b/Building-Locally.md index 5b746a640..6619c3fe0 100644 --- a/Building-Locally.md +++ b/Building-Locally.md @@ -123,6 +123,9 @@ Get-Help .\Build-Samples.ps1 -Detailed # 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 @@ -135,6 +138,20 @@ newest-first. The default is the latest, `Windows10`: | `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` | Links against | +| ------------------ | ----------------- | +| `10.0.28000` | latest (default) | +| `10.0.26100` | 24H2 | +| `10.0.22621` | 22H2 | +| `10.0.22000` | 21H2 | +| ... | down to `10.0.10240` | + --- ## Excluding samples from the build From be91bbd2dc4478a57a4007fc32fe320da79f85e1 Mon Sep 17 00:00:00 2001 From: 5an7y Date: Mon, 22 Jun 2026 17:31:47 -0700 Subject: [PATCH 4/7] Add NT-version-scoped exclusions and a parallel multi-version CI matrix Exclusions: - Add MinNtTargetVersion/MaxNtTargetVersion columns to exclusions.csv so a row can apply only within an _NT_TARGET_VERSION build-number range (parsed from -NtTargetVersion, e.g. 22000 from 10.0.22000). Import-SampleExclusions filters this range at load time alongside the existing build-number range; blank = unbounded. - Exclude the samples that fail only when linking against older library sets, with the reason taken from the build logs: audio.sysvad (<=22000, KSJACK_DESCRIPTION3); network.netadaptercx.netvadapter and network.wlan.wificx (<=22621, NDIS/DDI version); powerlimit.plclient/plpolicy (<=22621, POWER_LIMIT_ATTRIBUTES); storage classpnp/storahci (<=22621, STOR_ADDRESS_TYPE_NVME, Debug-only) and storage.msdsm (Debug|x64). usb.usbview is intentionally NOT excluded: it fails on every version for a known host reason (missing .NET 4.7.2/4.8.1 targeting packs). CI: - ci.yml and ci-pr.yml: add _NT_TARGET_VERSION as a manual matrix axis (4 newest versions, latest-first) so each version x configuration x platform runs on its own parallel runner. - Build-Samples.ps1 and Join-CsvReports.ps1 now write an easy-to-scan Markdown summary to GITHUB_STEP_SUMMARY: each build job shows counts and a failures table with the first error; the report job shows per-version totals and a consolidated failures list, plus the colour-coded sample x version HTML/CSV overview. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/scripts/Join-CsvReports.ps1 | 228 ++++++++++++++++++++++++---- .github/workflows/ci-pr.yml | 14 +- .github/workflows/ci.yml | 14 +- Build-Samples.ps1 | 88 +++++++++-- Building-Locally.md | 16 +- exclusions.csv | 32 ++-- 6 files changed, 333 insertions(+), 59 deletions(-) diff --git a/.github/scripts/Join-CsvReports.ps1 b/.github/scripts/Join-CsvReports.ps1 index 32cd9d63e..b3e6cd4f1 100644 --- a/.github/scripts/Join-CsvReports.ps1 +++ b/.github/scripts/Join-CsvReports.ps1 @@ -1,35 +1,209 @@ -$logsPath = Join-Path (Get-Location).Path "_logs" +<# +.SYNOPSIS + Joins the per-job Build-Samples CSV reports (one per _NT_TARGET_VERSION x configuration x + platform) into a single overview, and writes an easy-to-scan summary to the GitHub Actions + run page ($GITHUB_STEP_SUMMARY). + +.DESCRIPTION + Each build job uploads a "_logs" folder containing a report named + _overview....csv + with columns: Sample, (one combination per file). This script: + * parses the _NT_TARGET_VERSION tag and combination from every report, + * collapses each sample's combinations into one status per version, + * writes _overview.all.csv / _overview.all.htm (a colour-coded sample x version matrix), and + * appends a Markdown summary (per-version totals + a failures table) to $GITHUB_STEP_SUMMARY + so failures are obvious from the run page without opening any logs. + + The older 2-part name (_overview...csv, no version) is still + understood and bucketed under the "latest" column. +#> + +$logsPath = Join-Path (Get-Location).Path "_logs" $reportFileName = '_overview.all' -$idProperty = 'Sample' -$results = $null -Get-ChildItem -Path $logsPath -Filter '*.csv' | ForEach-Object { - $csv = Import-Csv -Path $_ - if ($results -eq $null) { - $results = $csv +if (-not (Test-Path $logsPath)) { + Write-Warning "No _logs directory found at $logsPath - nothing to report." + return +} + +# --- Friendly labels for the known _NT_TARGET_VERSION build tags -------------- +$ntLabel = @{ + '28000' = 'latest'; '26100' = '24H2'; '22621' = '22H2'; '22000' = '21H2' + '20348' = 'Server 2022'; '19041' = '2004'; '18362' = '1903'; '17763' = '1809' +} + +# --- Load every per-job CSV --------------------------------------------------- +# data[sample][tag][combo] = status +$data = @{} +$allSamples = [System.Collections.Generic.SortedSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase) +$tagSet = [System.Collections.Generic.HashSet[string]]::new() + +Get-ChildItem -Path $logsPath -Filter '_overview.*.csv' | + Where-Object { $_.Name -notlike '_overview.all.*' } | + ForEach-Object { + # _overview... -> drop _overview; last two are config/platform. + $parts = [IO.Path]::GetFileNameWithoutExtension($_.Name).Split('.') + $parts = $parts[1..($parts.Count - 1)] # drop the leading "_overview" + if ($parts.Count -ge 3) { $tag = ($parts[0..($parts.Count - 3)] -join '.') } + else { $tag = 'latest' } + [void]$tagSet.Add($tag) + + Import-Csv -Path $_.FullName | ForEach-Object { + $sample = $_.Sample + if (-not $sample) { return } + [void]$allSamples.Add($sample) + if (-not $data.ContainsKey($sample)) { $data[$sample] = @{} } + if (-not $data[$sample].ContainsKey($tag)) { $data[$sample][$tag] = @{} } + foreach ($col in ($_.PSObject.Properties.Name | Where-Object { $_ -ne 'Sample' })) { + $data[$sample][$tag][$col] = "$($_.$col)".Trim() + } + } } - else { - $results = $csv | ForEach-Object { - $id = $_.$idProperty - $match = $results | Where-Object { $_.$idProperty -eq $id } - if ($match) { - $properties = $_ | Get-Member -MemberType NoteProperty | Where-Object { $_.Name -ne $idProperty } | Select-Object -ExpandProperty Name - $newObject = New-Object PSObject - # Add ID property separately to ensure it appears first - $newObject | Add-Member -MemberType NoteProperty -Name $idProperty -Value $_.$idProperty - foreach ($property in $properties) { - $newObject | Add-Member -MemberType NoteProperty -Name $property -Value $_.$property - } - foreach ($property in ($match | Get-Member -MemberType NoteProperty | Where-Object { $_.Name -ne $idProperty } | Select-Object -ExpandProperty Name)) { - if ($properties -notcontains $property) { - $newObject | Add-Member -MemberType NoteProperty -Name $property -Value $match.$property - } - } - $newObject + +if ($tagSet.Count -eq 0) { + Write-Warning "No per-job '_overview.*.csv' reports were found in $logsPath." + return +} + +# Order versions newest-first (numeric tags descending; non-numeric last) +$tags = $tagSet | Sort-Object @{ Expression = { if ($_ -match '^\d+$') { [int]$_ } else { 0 } }; Descending = $true }, @{ Expression = { $_ } } + +function Get-Status { + # Collapse one sample/version's combinations into a single status object. + param([hashtable]$Combos) + $c = @{ Succeeded = 0; Failed = 0; Sporadic = 0; Unsupported = 0; Excluded = 0 } + $details = @() + if ($Combos) { + foreach ($k in ($Combos.Keys | Sort-Object)) { + switch ($Combos[$k]) { + 'Succeeded' { $c.Succeeded++ } 'Failed' { $c.Failed++ } 'Sporadic' { $c.Sporadic++ } + 'Unsupported' { $c.Unsupported++ } 'Excluded' { $c.Excluded++ } + } + $details += "$k = $($Combos[$k])" + } + } + $buildable = $c.Succeeded + $c.Failed + $c.Sporadic + if (-not $Combos -or $Combos.Count -eq 0) { $label = 'n/a'; $klass = 'na' } + elseif ($buildable -eq 0) { $label = '--'; $klass = 'na' } + elseif ($c.Failed -eq 0 -and $c.Sporadic -eq 0) { $label = "PASS ($($c.Succeeded)/$buildable)"; $klass = 'pass' } + elseif ($c.Failed -eq 0) { $label = "PASS* ($($c.Succeeded + $c.Sporadic)/$buildable)"; $klass = 'flaky' } + elseif ($c.Failed -eq $buildable) { $label = "FAIL ($($c.Failed)/$buildable)"; $klass = 'fail' } + else { $label = "PARTIAL ($($c.Failed) failed / $buildable)"; $klass = 'partial' } + [pscustomobject]@{ Label = $label; Class = $klass; Tooltip = ($details -join ' | '); Counts = $c; Buildable = $buildable } +} + +# --- Build per-version totals + the matrix ------------------------------------ +$totals = @{}; foreach ($t in $tags) { $totals[$t] = [pscustomobject]@{ S = 0; F = 0; O = 0; U = 0; E = 0; pass = 0; flaky = 0; partial = 0; fail = 0; na = 0 } } +$failuresList = [System.Collections.ArrayList]::new() +$csvRows = @() +$bodyRows = New-Object System.Text.StringBuilder + +foreach ($sample in $allSamples) { + $csvRow = [ordered]@{ Sample = $sample } + $cells = '' + foreach ($t in $tags) { + $combos = $null + if ($data[$sample].ContainsKey($t)) { $combos = $data[$sample][$t] } + $st = Get-Status -Combos $combos + $tt = $totals[$t] + $tt.S += $st.Counts.Succeeded; $tt.F += $st.Counts.Failed; $tt.O += $st.Counts.Sporadic + $tt.U += $st.Counts.Unsupported; $tt.E += $st.Counts.Excluded + switch ($st.Class) { 'pass' { $tt.pass++ } 'flaky' { $tt.flaky++ } 'partial' { $tt.partial++ } 'fail' { $tt.fail++ } 'na' { $tt.na++ } } + $csvRow["$t"] = $st.Label + $tip = [System.Web.HttpUtility]::HtmlEncode($st.Tooltip) + $cells += "$($st.Label)" + if ($combos) { + foreach ($k in ($combos.Keys | Sort-Object)) { + if ($combos[$k] -eq 'Failed') { [void]$failuresList.Add([pscustomobject]@{ Sample = $sample; Version = $t; Combo = $k }) } } } } + $csvRows += [pscustomobject]$csvRow + $enc = [System.Web.HttpUtility]::HtmlEncode($sample) + [void]$bodyRows.Append("$enc$cells`n") } -$results | ConvertTo-Csv | Out-File (Join-Path $logsPath "$reportFileName.csv") -$results | ConvertTo-Html -Title "Overview" | Out-File (Join-Path $logsPath "$reportFileName.htm") +Add-Type -AssemblyName System.Web -ErrorAction SilentlyContinue + +# --- CSV ---------------------------------------------------------------------- +$csvRows | Export-Csv -Path (Join-Path $logsPath "$reportFileName.csv") -NoTypeInformation + +# --- HTML (colour-coded sample x version matrix) ------------------------------ +$generated = Get-Date -Format 'yyyy-MM-dd HH:mm:ss' +$sumHead = "_NT_TARGET_VERSIONReleasePassFlakyPartialFailn/aCombos OKSporadicFailedExcludedPass rate" +$sumRows = '' +foreach ($t in $tags) { + $x = $totals[$t]; $tot = $x.pass + $x.flaky + $x.partial + $x.fail + $x.na; $elig = $tot - $x.na + $rate = if ($elig -gt 0) { '{0:N0}%' -f (100.0 * ($x.pass + $x.flaky) / $elig) } else { 'n/a' } + $rel = $ntLabel[$t]; if (-not $rel) { $rel = '' } + $sumRows += "$t$rel$($x.pass)$($x.flaky)$($x.partial)$($x.fail)$($x.na)$($x.S)$($x.O)$($x.F)$($x.E)$rate`n" +} +$matHead = "Sample" +foreach ($t in $tags) { $rel = $ntLabel[$t]; if (-not $rel) { $rel = '' }; $matHead += "$t
$rel" } +$matHead += "" + +$html = @" + +WDK Driver Samples - Build Overview + +

WDK Driver Samples — Build Overview

+
Generated: $generated  |  columns are _NT_TARGET_VERSION (library link version); hover a cell for the per-combination breakdown.
+
PASSPASS* (retry)PARTIALFAIL-- n/a
+

Summary by _NT_TARGET_VERSION

+$sumHead +$sumRows
+

Sample × _NT_TARGET_VERSION

+$matHead +$($bodyRows.ToString())
+ +"@ +$html | Out-File -FilePath (Join-Path $logsPath "$reportFileName.htm") -Encoding UTF8 + +# --- GitHub Actions run summary (Markdown) ------------------------------------ +if ($env:GITHUB_STEP_SUMMARY) { + $totalFailed = ($totals.Values | Measure-Object -Property fail -Sum).Sum + ($totals.Values | Measure-Object -Property partial -Sum).Sum + $icon = if ($failuresList.Count -gt 0) { ':x:' } else { ':white_check_mark:' } + + $md = [System.Text.StringBuilder]::new() + [void]$md.AppendLine("# $icon WDK Driver Samples — Build Overview") + [void]$md.AppendLine() + [void]$md.AppendLine("Columns are **_NT_TARGET_VERSION** (the WDK library version drivers link against). Each version was built for Debug/Release x x64/arm64.") + [void]$md.AppendLine() + [void]$md.AppendLine("## Summary by _NT_TARGET_VERSION") + [void]$md.AppendLine("| _NT_TARGET_VERSION | Release | :white_check_mark: Pass | :warning: Flaky | :large_orange_diamond: Partial | :x: Fail | :heavy_minus_sign: n/a | Pass rate |") + [void]$md.AppendLine("|---|---|---:|---:|---:|---:|---:|---:|") + foreach ($t in $tags) { + $x = $totals[$t]; $tot = $x.pass + $x.flaky + $x.partial + $x.fail + $x.na; $elig = $tot - $x.na + $rate = if ($elig -gt 0) { '{0:N0}%' -f (100.0 * ($x.pass + $x.flaky) / $elig) } else { 'n/a' } + $rel = $ntLabel[$t]; if (-not $rel) { $rel = '' } + [void]$md.AppendLine("| ``$t`` | $rel | $($x.pass) | $($x.flaky) | $($x.partial) | $($x.fail) | $($x.na) | **$rate** |") + } + [void]$md.AppendLine() + + if ($failuresList.Count -gt 0) { + [void]$md.AppendLine("## :x: Failures ($($failuresList.Count))") + [void]$md.AppendLine("| Sample | _NT_TARGET_VERSION | Config/Platform |") + [void]$md.AppendLine("|---|---|---|") + foreach ($f in ($failuresList | Sort-Object Sample, Version, Combo)) { + [void]$md.AppendLine("| ``$($f.Sample)`` | $($f.Version) | $($f.Combo.Replace('|','/')) |") + } + [void]$md.AppendLine() + [void]$md.AppendLine("> Open the matching **build** job's summary (or the ``logs-*`` artifact) for the exact compiler error.") + } + else { + [void]$md.AppendLine(":tada: **All combinations built successfully.**") + } + + $md.ToString() | Out-File -FilePath $env:GITHUB_STEP_SUMMARY -Append -Encoding utf8 +} diff --git a/.github/workflows/ci-pr.yml b/.github/workflows/ci-pr.yml index 6719270e7..7983c8dd5 100644 --- a/.github/workflows/ci-pr.yml +++ b/.github/workflows/ci-pr.yml @@ -9,12 +9,19 @@ on: - 'LICENSE' jobs: build: - name: Build driver samples + name: build ${{ matrix.nt.tag }} ${{ matrix.configuration }} ${{ matrix.platform }} 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' } runs-on: windows-2025-vs2026 steps: - name: Check out repository code @@ -38,13 +45,14 @@ jobs: env: WDS_Configuration: ${{ matrix.configuration }} WDS_Platform: ${{ matrix.platform }} - WDS_ReportFileName: _overview.${{ matrix.configuration }}.${{ matrix.platform }} + WDS_NtTargetVersion: ${{ matrix.nt.version }} + WDS_ReportFileName: _overview.${{ matrix.nt.tag }}.${{ matrix.configuration }}.${{ matrix.platform }} - name: Archive build logs and overview build reports uses: actions/upload-artifact@v4 if: always() with: - name: logs-${{ matrix.configuration }}-${{ matrix.platform }} + name: logs-${{ matrix.nt.tag }}-${{ matrix.configuration }}-${{ matrix.platform }} path: _logs report: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ca2696d89..022ae4f68 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,12 +12,19 @@ on: - cron: '0 8 * * 6' jobs: build: - name: Build driver samples + name: build ${{ matrix.nt.tag }} ${{ matrix.configuration }} ${{ matrix.platform }} 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' } runs-on: windows-2025-vs2026 steps: - name: Check out repository code @@ -33,13 +40,14 @@ jobs: env: WDS_Configuration: ${{ matrix.configuration }} WDS_Platform: ${{ matrix.platform }} - WDS_ReportFileName: _overview.${{ matrix.configuration }}.${{ matrix.platform }} + WDS_NtTargetVersion: ${{ matrix.nt.version }} + WDS_ReportFileName: _overview.${{ matrix.nt.tag }}.${{ matrix.configuration }}.${{ matrix.platform }} - name: Archive build logs and overview build reports uses: actions/upload-artifact@v4 if: always() with: - name: logs-${{ matrix.configuration }}-${{ matrix.platform }} + name: logs-${{ matrix.nt.tag }}-${{ matrix.configuration }}-${{ matrix.platform }} path: _logs report: diff --git a/Build-Samples.ps1 b/Build-Samples.ps1 index 063947b62..c58164b27 100644 --- a/Build-Samples.ps1 +++ b/Build-Samples.ps1 @@ -130,21 +130,26 @@ function Import-SampleExclusions { - Configurations: semicolon-separated config|platform patterns (or '*' for all) - Reason: human-readable explanation - A row is only returned when BOTH of the following match the current build: - - its [MinBuild, MaxBuild] range includes the given build number, and + A row is only returned when ALL of the following match the current build: + - its [MinBuild, MaxBuild] range includes the given build number, + - 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 the build range, or whose TargetVersions does not match, are skipped. + Rows outside any range, or whose TargetVersions does not match, are skipped. + MinBuild/MaxBuild and MinNtTargetVersion/MaxNtTargetVersion are blank = unbounded. .NOTES - CSV format: Path,Configurations,TargetVersions,MinBuild,MaxBuild,Reason - Example row: network\wlan\wdi,*,,,27100,"failure introduced in VS17.14" - Target-specific: somepath,*|ARM64,Windows8,,,"ARM not supported when targeting Windows 8" + 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" #> param( [string]$CsvPath, [int]$BuildNumber, - [string]$TargetVersion = 'Windows10' + [string]$TargetVersion = 'Windows10', + [string]$NtTargetVersion = '10.0.28000' ) if (-not (Test-Path $CsvPath)) { @@ -152,6 +157,10 @@ function Import-SampleExclusions { return @() } + # The _NT_TARGET_VERSION param is the friendly build-number form (e.g. '10.0.22000'); + # take its last dotted component for numeric range comparisons. + $ntBuild = [int]($NtTargetVersion -replace '.*\.', '') + $exclusions = [System.Collections.ArrayList]::new() Import-Csv $CsvPath | ForEach-Object { $pattern = $_.Path.Trim('\').Replace('\', '.').ToLower() @@ -160,20 +169,27 @@ function Import-SampleExclusions { $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 is constant for the whole run, so (like the build number) filter here. + # 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) { + Write-Verbose "Exclusion skipped: '$pattern' - _NT_TARGET_VERSION $ntBuild outside [$minNt, $maxNt]" + } elseif ($minBuild -le $BuildNumber -and $BuildNumber -le $maxBuild) { [void]$exclusions.Add([PSCustomObject]@{ Pattern = $pattern Configurations = $configs Reason = $_.Reason }) - Write-Verbose "Exclusion applied: '$pattern' configs='$configs' targets='$targets' reason='$($_.Reason)'" + Write-Verbose "Exclusion applied: '$pattern' configs='$configs' targets='$targets' ntRange=[$minNt,$maxNt] reason='$($_.Reason)'" } else { Write-Verbose "Exclusion skipped: '$pattern' - build $BuildNumber outside [$minBuild, $maxBuild]" @@ -457,7 +473,7 @@ $ntTargetVersionCode = $ntTargetVersionCodes[$NtTargetVersion] # Step 6 - Load Exclusions # ============================================================================= -$exclusions = Import-SampleExclusions -CsvPath (Join-Path $root 'exclusions.csv') -BuildNumber $buildNumber -TargetVersion $TargetVersion +$exclusions = Import-SampleExclusions -CsvPath (Join-Path $root 'exclusions.csv') -BuildNumber $buildNumber -TargetVersion $TargetVersion -NtTargetVersion $NtTargetVersion # ============================================================================= # Step 7 - Print Build Plan @@ -725,3 +741,55 @@ $sortedResults | ConvertTo-Html -Title "WDK Sample Build Overview - TargetVersio if (-not $env:BUILD_BUILDID -and [Environment]::UserInteractive) { Invoke-Item $reportHtmlPath } + +# ============================================================================= +# Step 12 - GitHub Actions job summary (CI only; no-op when run locally) +# ============================================================================= +# When $GITHUB_STEP_SUMMARY is set, emit an easy-to-scan markdown summary for the run +# page: a status header, a counts table, and (if any) a table of failures with the first +# compiler/linker error so problems are obvious without opening the logs. +if ($env:GITHUB_STEP_SUMMARY) { + $icon = if ($buildState.Failed -gt 0) { ':x:' } elseif ($buildState.Sporadic -gt 0) { ':warning:' } else { ':white_check_mark:' } + $cfgLabel = "$($Configurations -join ',')|$($Platforms -join ',')" + + $md = [System.Text.StringBuilder]::new() + [void]$md.AppendLine("## $icon ``$cfgLabel``  ·  _NT_TARGET_VERSION ``$NtTargetVersion``") + [void]$md.AppendLine() + [void]$md.AppendLine("Environment **$($buildEnv.Name)** · WDK build **$buildNumber** · TargetVersion **$TargetVersion** · **$($sampleSet.Count)** samples · $($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("|---:|---:|---:|---:|---:|") + [void]$md.AppendLine("| $($buildState.Succeeded) | $($buildState.Failed) | $($buildState.Sporadic) | $($buildState.Excluded) | $($buildState.Unsupported) |") + [void]$md.AppendLine() + + if ($buildState.FailSet.Count -gt 0) { + [void]$md.AppendLine("
:x: $($buildState.FailSet.Count) failed") + [void]$md.AppendLine() + [void]$md.AppendLine("| Sample | Config/Platform | First error |") + [void]$md.AppendLine("|---|---|---|") + foreach ($entry in ($buildState.FailSet | Sort-Object)) { + if ($entry -match '^(?.*)\s+(?\w+)\|(?\w+)$') { + $fName = $Matches.name; $fConfig = $Matches.config; $fPlatform = $Matches.platform + $errLog = Join-Path $LogFilesDirectory "$fName.$fConfig.$fPlatform.0.err" + $msg = '' + if (Test-Path $errLog) { + $line = Get-Content $errLog | Where-Object { $_ -match ': (error|fatal error) ' } | Select-Object -First 1 + if ($line -match ':\s*((?:fatal )?error\s.+?)\s*\[[^\[]*\]\s*$') { $msg = $Matches[1] } else { $msg = $line } + } + $msg = ("$msg" -replace '\|', '\|').Trim() + if ($msg.Length -gt 180) { $msg = $msg.Substring(0, 177) + '...' } + [void]$md.AppendLine("| ``$fName`` | $fConfig/$fPlatform | $msg |") + } + } + [void]$md.AppendLine("
") + [void]$md.AppendLine() + } + + if ($buildState.SporadicSet.Count -gt 0) { + $sp = ($buildState.SporadicSet | Sort-Object | ForEach-Object { "``$_``" }) -join ', ' + [void]$md.AppendLine(":warning: **Sporadic** (passed on retry): $sp") + [void]$md.AppendLine() + } + + $md.ToString() | Out-File -FilePath $env:GITHUB_STEP_SUMMARY -Append -Encoding utf8 +} diff --git a/Building-Locally.md b/Building-Locally.md index 6619c3fe0..8c11d0123 100644 --- a/Building-Locally.md +++ b/Building-Locally.md @@ -162,7 +162,7 @@ configuration/platform combinations, an optional WDK build-number range, and an set of target versions: ``` -Path,Configurations,TargetVersions,MinBuild,MaxBuild,Reason +Path,Configurations,TargetVersions,MinBuild,MaxBuild,MinNtTargetVersion,MaxNtTargetVersion,Reason ``` | Column | Meaning | @@ -171,16 +171,24 @@ Path,Configurations,TargetVersions,MinBuild,MaxBuild,Reason | `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, build-number range, and target version are AND-ed together). Leave -`TargetVersions` blank to exclude regardless of target version (the default for most rows). +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" +somepath,*|ARM64,Windows8,,,,,"ARM not supported when targeting Windows 8" +``` + +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: + +``` +somepath,Debug|*,,,,,22621,uses an API newer than the 10.0.22621 library ``` --- diff --git a/exclusions.csv b/exclusions.csv index b3d8a50aa..566c685d2 100644 --- a/exclusions.csv +++ b/exclusions.csv @@ -1,12 +1,20 @@ -Path,Configurations,TargetVersions,MinBuild,MaxBuild,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" +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 From ceceab78412feefd2f343a0e3bc07f1262665b62 Mon Sep 17 00:00:00 2001 From: 5an7y Date: Tue, 23 Jun 2026 10:38:40 -0700 Subject: [PATCH 5/7] 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.' or the short '' 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 <223556219+Copilot@users.noreply.github.com> --- .github/scripts/Build-ChangedSamples.ps1 | 2 +- .github/workflows/ci-pr.yml | 33 +++++-- .github/workflows/ci.yml | 33 +++++-- Build-Samples.ps1 | 112 ++++++++++------------- Building-Locally.md | 55 ++++------- Get-NtTargetVersions.ps1 | 100 ++++++++++++++++++++ exclusions.csv | 40 ++++---- 7 files changed, 235 insertions(+), 140 deletions(-) create mode 100644 Get-NtTargetVersions.ps1 diff --git a/.github/scripts/Build-ChangedSamples.ps1 b/.github/scripts/Build-ChangedSamples.ps1 index 3e91eb883..f03f93f3b 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 7983c8dd5..8119c94c4 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 022ae4f68..de856d556 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 c58164b27..861ec39af 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.' or the + short '' 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``  ·  _NT_TARGET_VERSION ``$NtTargetVersion``") [void]$md.AppendLine() - [void]$md.AppendLine("Environment **$($buildEnv.Name)** · WDK build **$buildNumber** · TargetVersion **$TargetVersion** · **$($sampleSet.Count)** samples · $($elapsed.Minutes)m $($elapsed.Seconds)s") + [void]$md.AppendLine("Environment **$($buildEnv.Name)** · WDK build **$buildNumber** · **$($sampleSet.Count)** samples · $($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 8c11d0123..ebddbfbad 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.`) or the short +`` 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 000000000..680882777 --- /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+(?10\.0\.(?\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 566c685d2..0cae0380f 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 From 8745e5b82f0a0183e779dcdcc8164ad926fdcf8c Mon Sep 17 00:00:00 2001 From: 5an7y Date: Tue, 23 Jun 2026 11:05:03 -0700 Subject: [PATCH 6/7] Drop hardcoded version defaults and the un-discoverable label map - Remove the hand-maintained _NT_TARGET_VERSION -> friendly-name map (latest/24H2/...) from Join-CsvReports.ps1, along with its "Release" column in the HTML and step-summary tables; those labels cannot be auto-discovered. - Stop hardcoding a version in the helper defaults: Import-SampleExclusions' -NtTargetVersion now defaults to empty (treated as the latest, so no NT-scoped row applies), and Build-SingleSample's -NtTargetVersionCode has no hardcoded code (the resolved value is always passed in). Blank MaxNtTargetVersion now uses [int]::MaxValue so 'latest'/empty matches the newest version's exclusion set. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/scripts/Join-CsvReports.ps1 | 20 ++++++-------------- Build-Samples.ps1 | 16 +++++++++++----- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/.github/scripts/Join-CsvReports.ps1 b/.github/scripts/Join-CsvReports.ps1 index b3e6cd4f1..43e0c826b 100644 --- a/.github/scripts/Join-CsvReports.ps1 +++ b/.github/scripts/Join-CsvReports.ps1 @@ -26,12 +26,6 @@ if (-not (Test-Path $logsPath)) { return } -# --- Friendly labels for the known _NT_TARGET_VERSION build tags -------------- -$ntLabel = @{ - '28000' = 'latest'; '26100' = '24H2'; '22621' = '22H2'; '22000' = '21H2' - '20348' = 'Server 2022'; '19041' = '2004'; '18362' = '1903'; '17763' = '1809' -} - # --- Load every per-job CSV --------------------------------------------------- # data[sample][tag][combo] = status $data = @{} @@ -130,16 +124,15 @@ $csvRows | Export-Csv -Path (Join-Path $logsPath "$reportFileName.csv") -NoTypeI # --- HTML (colour-coded sample x version matrix) ------------------------------ $generated = Get-Date -Format 'yyyy-MM-dd HH:mm:ss' -$sumHead = "_NT_TARGET_VERSIONReleasePassFlakyPartialFailn/aCombos OKSporadicFailedExcludedPass rate" +$sumHead = "_NT_TARGET_VERSIONPassFlakyPartialFailn/aCombos OKSporadicFailedExcludedPass rate" $sumRows = '' foreach ($t in $tags) { $x = $totals[$t]; $tot = $x.pass + $x.flaky + $x.partial + $x.fail + $x.na; $elig = $tot - $x.na $rate = if ($elig -gt 0) { '{0:N0}%' -f (100.0 * ($x.pass + $x.flaky) / $elig) } else { 'n/a' } - $rel = $ntLabel[$t]; if (-not $rel) { $rel = '' } - $sumRows += "$t$rel$($x.pass)$($x.flaky)$($x.partial)$($x.fail)$($x.na)$($x.S)$($x.O)$($x.F)$($x.E)$rate`n" + $sumRows += "$t$($x.pass)$($x.flaky)$($x.partial)$($x.fail)$($x.na)$($x.S)$($x.O)$($x.F)$($x.E)$rate`n" } $matHead = "Sample" -foreach ($t in $tags) { $rel = $ntLabel[$t]; if (-not $rel) { $rel = '' }; $matHead += "$t
$rel" } +foreach ($t in $tags) { $matHead += "$t" } $matHead += "" $html = @" @@ -181,13 +174,12 @@ if ($env:GITHUB_STEP_SUMMARY) { [void]$md.AppendLine("Columns are **_NT_TARGET_VERSION** (the WDK library version drivers link against). Each version was built for Debug/Release x x64/arm64.") [void]$md.AppendLine() [void]$md.AppendLine("## Summary by _NT_TARGET_VERSION") - [void]$md.AppendLine("| _NT_TARGET_VERSION | Release | :white_check_mark: Pass | :warning: Flaky | :large_orange_diamond: Partial | :x: Fail | :heavy_minus_sign: n/a | Pass rate |") - [void]$md.AppendLine("|---|---|---:|---:|---:|---:|---:|---:|") + [void]$md.AppendLine("| _NT_TARGET_VERSION | :white_check_mark: Pass | :warning: Flaky | :large_orange_diamond: Partial | :x: Fail | :heavy_minus_sign: n/a | Pass rate |") + [void]$md.AppendLine("|---|---:|---:|---:|---:|---:|---:|") foreach ($t in $tags) { $x = $totals[$t]; $tot = $x.pass + $x.flaky + $x.partial + $x.fail + $x.na; $elig = $tot - $x.na $rate = if ($elig -gt 0) { '{0:N0}%' -f (100.0 * ($x.pass + $x.flaky) / $elig) } else { 'n/a' } - $rel = $ntLabel[$t]; if (-not $rel) { $rel = '' } - [void]$md.AppendLine("| ``$t`` | $rel | $($x.pass) | $($x.flaky) | $($x.partial) | $($x.fail) | $($x.na) | **$rate** |") + [void]$md.AppendLine("| ``$t`` | $($x.pass) | $($x.flaky) | $($x.partial) | $($x.fail) | $($x.na) | **$rate** |") } [void]$md.AppendLine() diff --git a/Build-Samples.ps1 b/Build-Samples.ps1 index 861ec39af..e0b1a6b35 100644 --- a/Build-Samples.ps1 +++ b/Build-Samples.ps1 @@ -131,7 +131,7 @@ function Import-SampleExclusions { param( [string]$CsvPath, [int]$BuildNumber, - [string]$NtTargetVersion = '10.0.28000' + [string]$NtTargetVersion ) if (-not (Test-Path $CsvPath)) { @@ -140,8 +140,14 @@ function Import-SampleExclusions { } # The _NT_TARGET_VERSION param is the friendly build-number form (e.g. '10.0.22000'); - # take its last dotted component for numeric range comparisons. - $ntBuild = [int]($NtTargetVersion -replace '.*\.', '') + # take its last dotted component for numeric range comparisons. An empty value (or + # 'latest') means the newest libraries, so no NT-version-scoped row applies. + $ntBuild = if ([string]::IsNullOrWhiteSpace($NtTargetVersion) -or $NtTargetVersion -eq 'latest') { + [int]::MaxValue + } + else { + [int]($NtTargetVersion -replace '.*\.', '') + } $exclusions = [System.Collections.ArrayList]::new() Import-Csv $CsvPath | ForEach-Object { @@ -151,7 +157,7 @@ function Import-SampleExclusions { $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 } + $maxNt = if ([string]::IsNullOrWhiteSpace($_.MaxNtTargetVersion)) { [int]::MaxValue } else { [int]$_.MaxNtTargetVersion } # _NT_TARGET_VERSION is constant for the whole run, so (like the build number) filter # these rows out here at load time. @@ -205,7 +211,7 @@ function Build-SingleSample { [string]$SampleName, [string]$Configuration = 'Debug', [string]$Platform = 'x64', - [string]$NtTargetVersionCode = '0xA000012', + [string]$NtTargetVersionCode, [string]$InfVerif_AdditionalOptions = '/samples', [string]$LogFilesDirectory = (Get-Location), [bool]$Verbose = $false From d157348f0566d3da5bf00a3f1e414f95443b3a59 Mon Sep 17 00:00:00 2001 From: 5an7y Date: Tue, 23 Jun 2026 12:23:47 -0700 Subject: [PATCH 7/7] Allow manual runs of the build-all workflow (workflow_dispatch) Add a workflow_dispatch trigger so "Build all driver samples" can be started on demand from the Actions tab. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index de856d556..4b263a826 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,5 +1,7 @@ name: Build all driver samples on: + # Allows the workflow to be triggered manually from the Actions tab ("Run workflow"). + workflow_dispatch: push: branches: - main