From 57b3c4c23a59d129f2bdfd3cca894b5a78790072 Mon Sep 17 00:00:00 2001 From: Fredrik Orderud Date: Wed, 21 Aug 2024 12:14:15 +0200 Subject: [PATCH 01/20] [simbatt] Remove unused MAX_SUPPORTED_SIMBATT_CHILDREN define This define isn't used anywhere in the driver. Therefore proposing to remove it to clean up. --- simbatt/func/simbattdriverif.h | 1 - 1 file changed, 1 deletion(-) diff --git a/simbatt/func/simbattdriverif.h b/simbatt/func/simbattdriverif.h index 6fb45d8bb..b2157a597 100644 --- a/simbatt/func/simbattdriverif.h +++ b/simbatt/func/simbattdriverif.h @@ -62,7 +62,6 @@ DEFINE_GUID(SIMBATT_DEVINTERFACE_GUID, #define IOCTL_SIMBATT_SET_UNIQUE_ID SIMBATT_IOCTL(0x809) #define IOCTL_SIMBATT_GET_MAXCHARGINGCURRENT SIMBATT_IOCTL(0x810) #define SIMBATT_RATE_CALCULATE 0x7fffffff -#define MAX_SUPPORTED_SIMBATT_CHILDREN 20 //------------------------------------------------------------------- Data Types From 97b9377fe5649c9a745ffc40c43318ae3e4d848e Mon Sep 17 00:00:00 2001 From: Fredrik Orderud Date: Thu, 7 Dec 2023 15:36:38 +0100 Subject: [PATCH 02/20] simbatt: Clear BATTERY_CAPACITY_RELATIVE field Clear BATTERY_INFORMATION::BATTERY_CAPACITY_RELATIVE field to enable per-battery charge display in Windows Settings. --- simbatt/func/miniclass.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/simbatt/func/miniclass.c b/simbatt/func/miniclass.c index 612b4c660..78a13bdf6 100644 --- a/simbatt/func/miniclass.c +++ b/simbatt/func/miniclass.c @@ -239,9 +239,7 @@ Return Value: DevExt->State.BatteryStatus.Capacity = 100; DevExt->State.BatteryStatus.Voltage = BATTERY_UNKNOWN_VOLTAGE; DevExt->State.BatteryStatus.Rate = 0; - DevExt->State.BatteryInfo.Capabilities = BATTERY_SYSTEM_BATTERY | - BATTERY_CAPACITY_RELATIVE; - + DevExt->State.BatteryInfo.Capabilities = BATTERY_SYSTEM_BATTERY; DevExt->State.BatteryInfo.Technology = 1; DevExt->State.BatteryInfo.Chemistry[0] = 'F'; DevExt->State.BatteryInfo.Chemistry[1] = 'a'; From 95ca556121fcf891edcdd162b95b507e8f6c81cb Mon Sep 17 00:00:00 2001 From: Fredrik Orderud Date: Thu, 22 Aug 2024 12:13:48 +0200 Subject: [PATCH 03/20] Remove unreferenced BATTBUS_TYPE_SIMBATT define. --- simbatt/func/simbattdriverif.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/simbatt/func/simbattdriverif.h b/simbatt/func/simbattdriverif.h index b2157a597..ac9fab96c 100644 --- a/simbatt/func/simbattdriverif.h +++ b/simbatt/func/simbattdriverif.h @@ -69,8 +69,6 @@ DEFINE_GUID(SIMBATT_DEVINTERFACE_GUID, // Data structure used in PlugIn and UnPlug ioctls // -#define BATTBUS_TYPE_SIMBATT 0; - typedef struct _BATTBUS_PLUGIN_HARDWARE { // From 673f69a6a755f17a2fb7afd1627cb8890073e4e8 Mon Sep 17 00:00:00 2001 From: Fredrik Orderud Date: Thu, 22 Aug 2024 12:14:53 +0200 Subject: [PATCH 04/20] Remove unreferenced BATTBUS_PLUGIN_HARDWARE struct. --- simbatt/func/simbattdriverif.h | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/simbatt/func/simbattdriverif.h b/simbatt/func/simbattdriverif.h index ac9fab96c..f0ceb0177 100644 --- a/simbatt/func/simbattdriverif.h +++ b/simbatt/func/simbattdriverif.h @@ -69,37 +69,6 @@ DEFINE_GUID(SIMBATT_DEVINTERFACE_GUID, // Data structure used in PlugIn and UnPlug ioctls // -typedef struct _BATTBUS_PLUGIN_HARDWARE -{ - // - // Size of this type. - // - - ULONG Size; - - // - // Unique serial number of the device to be enumerated. - // Enumeration will be failed if another device on the - // bus has the same serial number. - // - - ULONG SerialNo; - - // - // UI number. - // - - ULONG UINumber; - - // - // Type of device being enumerated - // - // Reserved value, set to 0. - // - - ULONG Type; - -} BATTBUS_PLUGIN_HARDWARE, *PBATTBUS_PLUGIN_HARDWARE; typedef struct _BATTBUS_UNPLUG_HARDWARE { From 700a917f0ddd4e8489bbafc18f6326811ae91625 Mon Sep 17 00:00:00 2001 From: Fredrik Orderud Date: Thu, 22 Aug 2024 12:15:38 +0200 Subject: [PATCH 05/20] Remove unreferenced BATTBUS_UNPLUG_HARDWARE struct. --- simbatt/func/simbattdriverif.h | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/simbatt/func/simbattdriverif.h b/simbatt/func/simbattdriverif.h index f0ceb0177..bb617ebee 100644 --- a/simbatt/func/simbattdriverif.h +++ b/simbatt/func/simbattdriverif.h @@ -62,33 +62,3 @@ DEFINE_GUID(SIMBATT_DEVINTERFACE_GUID, #define IOCTL_SIMBATT_SET_UNIQUE_ID SIMBATT_IOCTL(0x809) #define IOCTL_SIMBATT_GET_MAXCHARGINGCURRENT SIMBATT_IOCTL(0x810) #define SIMBATT_RATE_CALCULATE 0x7fffffff - -//------------------------------------------------------------------- Data Types - -// -// Data structure used in PlugIn and UnPlug ioctls -// - - -typedef struct _BATTBUS_UNPLUG_HARDWARE -{ - // - // size of this type - // - - ULONG Size; - - // - // Serial number of the device to be unplugged. - // - - ULONG SerialNo; - - // - // Must not be referenced used. - // - - ULONG Reserved[2]; - -} BATTBUS_UNPLUG_HARDWARE, *PBATTBUS_UNPLUG_HARDWARE; - From c9de4121a19dc08d9a8887d3534b8a86c01160f1 Mon Sep 17 00:00:00 2001 From: Fredrik Orderud Date: Thu, 22 Aug 2024 12:18:33 +0200 Subject: [PATCH 06/20] Remove unreferenced battery bus GUID and IOCTL calls. --- simbatt/func/simbattdriverif.h | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/simbatt/func/simbattdriverif.h b/simbatt/func/simbattdriverif.h index bb617ebee..04549f725 100644 --- a/simbatt/func/simbattdriverif.h +++ b/simbatt/func/simbattdriverif.h @@ -25,20 +25,6 @@ Module Name: //------------------------------------------------------------------ Definitions -// -// Battery bus driver interface -// - -// {780AC894-01FF-4b5e-B4C8-9C00709200EB} -DEFINE_GUID(BATTBUS_DEVINTERFACE_GUID, - 0x780ac894, 0x1ff, 0x4b5e, 0xb4, 0xc8, 0x9c, 0x0, 0x70, 0x92, 0x0, 0xeb); - -#define BATTBUS_IOCTL(_index_) \ - CTL_CODE(FILE_DEVICE_BUS_EXTENDER, _index_, METHOD_BUFFERED, FILE_READ_DATA) - -#define IOCTL_BATTBUS_PLUGIN_HARDWARE BATTBUS_IOCTL(0x0) -#define IOCTL_BATTBUS_UNPLUG_HARDWARE BATTBUS_IOCTL(0x1) - // // Simulated battery ioctl interface // From 239566869e3b25bc381f4f188575da32773abcfd Mon Sep 17 00:00:00 2001 From: Fredrik Orderud Date: Thu, 22 Aug 2024 15:42:07 +0200 Subject: [PATCH 07/20] [simbatt] Delete redundant "batclass_prepublish.h" to simplify The contained BATTERY_MINIPORT_INFO_V1_1 struct and BATTERY_CLASS_MINOR_VERSION_1 define are already defined in , so there shouldn't be a need for duplicating the definitions here. --- simbatt/func/batclass_prepublish.h | 51 ------------------------------ simbatt/func/wdf.c | 2 +- 2 files changed, 1 insertion(+), 52 deletions(-) delete mode 100644 simbatt/func/batclass_prepublish.h diff --git a/simbatt/func/batclass_prepublish.h b/simbatt/func/batclass_prepublish.h deleted file mode 100644 index a952222b3..000000000 --- a/simbatt/func/batclass_prepublish.h +++ /dev/null @@ -1,51 +0,0 @@ -/*++ - -Copyright (c) Microsoft Corporation. All rights reserved. - -Module Name: - - batclass_prepublish.h - -Abstract: - - This module defines pre-publish definations to be made available in DDK/SDK. - - N.B. This file must not be included when batclass.h defines - BATTERY_MINIPORT_INFO_V1_1 type and BATTERY_CLASS_MINOR_VERSION_1. - - N.B. This code is provided "AS IS" without any expressed or implied warranty. - ---*/ - -//---------------------------------------------------------------------- Pragmas - -#pragma once - -//--------------------------------------------------------------------- Includes - -#include - -//-------------------------------------------------- Would be Public Definitions - -#ifndef BATTERY_CLASS_MINOR_VERSION_1 - -typedef struct { - USHORT MajorVersion; - USHORT MinorVersion; - - PVOID Context; // Miniport context - - BCLASS_QUERY_TAG QueryTag; - BCLASS_QUERY_INFORMATION QueryInformation; - BCLASS_SET_INFORMATION SetInformation; - BCLASS_QUERY_STATUS QueryStatus; - BCLASS_SET_STATUS_NOTIFY SetStatusNotify; - BCLASS_DISABLE_STATUS_NOTIFY DisableStatusNotify; - PDEVICE_OBJECT Pdo; - PUNICODE_STRING DeviceName; - PDEVICE_OBJECT Fdo; -} BATTERY_MINIPORT_INFO_V1_1, *PBATTERY_MINIPORT_INFO_V1_1; - -#define BATTERY_CLASS_MINOR_VERSION_1 0x0001 - -#endif // BATTERY_CLASS_MINOR_VERSION_1 diff --git a/simbatt/func/wdf.c b/simbatt/func/wdf.c index de9aee307..3b9e87adf 100644 --- a/simbatt/func/wdf.c +++ b/simbatt/func/wdf.c @@ -19,7 +19,7 @@ Module Name: #include "simbatt.h" #include "simbattdriverif.h" -#include "batclass_prepublish.h" +#include //------------------------------------------------------------------- Prototypes From 77d8f2d6ca1283718626965b53c69477bffb5fa8 Mon Sep 17 00:00:00 2001 From: JakobL-MSFT <110699333+JakobL-MSFT@users.noreply.github.com> Date: Wed, 4 Feb 2026 18:15:21 -0800 Subject: [PATCH 08/20] =?UTF-8?q?removed=20the=20space=20after=20newline?= =?UTF-8?q?=20which=20seems=20to=20be=20bug=20in=20c++=2023=20not=20i?= =?UTF-8?q?=E2=80=A6=20(#1347)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit removed the space after newline which seems to be bug in c++ 23 not in samples Co-authored-by: Prashant Chahar --- .../sys/ClassifyFunctions_AdvancedPacketInjectionCallouts.cpp | 2 +- .../WFPSampler/sys/ClassifyFunctions_BasicActionCallouts.cpp | 2 +- .../sys/ClassifyFunctions_BasicPacketInjectionCallouts.cpp | 2 +- .../sys/ClassifyFunctions_BasicPacketModificationCallouts.cpp | 2 +- .../sys/ClassifyFunctions_BasicStreamInjectionCallouts.cpp | 2 +- .../sys/ClassifyFunctions_FastPacketInjectionCallouts.cpp | 2 +- .../sys/ClassifyFunctions_FastStreamInjectionCallouts.cpp | 2 +- .../sys/ClassifyFunctions_FlowAssociationCallouts.cpp | 2 +- .../sys/ClassifyFunctions_PendAuthorizationCallouts.cpp | 2 +- .../sys/ClassifyFunctions_PendEndpointClosureCallouts.cpp | 2 +- .../trans/WFPSampler/sys/ClassifyFunctions_ProxyCallouts.cpp | 2 +- .../sys/CompletionFunctions_AdvancedPacketInjectionCallouts.cpp | 2 +- .../sys/CompletionFunctions_BasicPacketModificationCallouts.cpp | 2 +- .../sys/CompletionFunctions_PendAuthorizationCallouts.cpp | 2 +- .../trans/WFPSampler/sys/CompletionFunctions_ProxyCallouts.cpp | 2 +- network/trans/WFPSampler/sys/Framework_Events.cpp | 2 +- .../trans/WFPSampler/sys/NotifyFunctions_AdvancedCallouts.cpp | 2 +- network/trans/WFPSampler/sys/NotifyFunctions_BasicCallouts.cpp | 2 +- network/trans/WFPSampler/sys/NotifyFunctions_FastCallouts.cpp | 2 +- network/trans/WFPSampler/sys/NotifyFunctions_FlowDelete.cpp | 2 +- network/trans/WFPSampler/sys/NotifyFunctions_PendCallouts.cpp | 2 +- network/trans/WFPSampler/sys/NotifyFunctions_ProxyCallouts.cpp | 2 +- network/trans/WFPSampler/sys/SubscriptionFunctions_BFEState.cpp | 2 +- network/trans/WFPSampler/syslib/HelperFunctions_FlowContext.cpp | 2 +- network/trans/WFPSampler/syslib/HelperFunctions_FwpObjects.cpp | 2 +- network/trans/WFPSampler/syslib/HelperFunctions_Headers.cpp | 2 +- network/trans/WFPSampler/syslib/HelperFunctions_NetBuffer.cpp | 2 +- network/trans/WFPSampler/syslib/HelperFunctions_PendData.cpp | 2 +- .../trans/WFPSampler/syslib/HelperFunctions_RedirectData.cpp | 2 +- network/trans/WFPSampler/syslib/HelperFunctions_WorkItems.cpp | 2 +- 30 files changed, 30 insertions(+), 30 deletions(-) diff --git a/network/trans/WFPSampler/sys/ClassifyFunctions_AdvancedPacketInjectionCallouts.cpp b/network/trans/WFPSampler/sys/ClassifyFunctions_AdvancedPacketInjectionCallouts.cpp index 1df1f7b5c..b71c77e08 100644 --- a/network/trans/WFPSampler/sys/ClassifyFunctions_AdvancedPacketInjectionCallouts.cpp +++ b/network/trans/WFPSampler/sys/ClassifyFunctions_AdvancedPacketInjectionCallouts.cpp @@ -99,7 +99,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// #include "Framework_WFPSamplerCalloutDriver.h" /// . -#include "ClassifyFunctions_AdvancedPacketInjectionCallouts.tmh" /// $(OBJ_PATH)\$(O)\ +#include "ClassifyFunctions_AdvancedPacketInjectionCallouts.tmh" /// $(OBJ_PATH)\$(O)\ #if DBG diff --git a/network/trans/WFPSampler/sys/ClassifyFunctions_BasicActionCallouts.cpp b/network/trans/WFPSampler/sys/ClassifyFunctions_BasicActionCallouts.cpp index 375dab933..69773e8a7 100644 --- a/network/trans/WFPSampler/sys/ClassifyFunctions_BasicActionCallouts.cpp +++ b/network/trans/WFPSampler/sys/ClassifyFunctions_BasicActionCallouts.cpp @@ -52,7 +52,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// #include "Framework_WFPSamplerCalloutDriver.h" /// . -#include "ClassifyFunctions_BasicActionCallouts.tmh" /// $(OBJ_PATH)\$(O)\ +#include "ClassifyFunctions_BasicActionCallouts.tmh" /// $(OBJ_PATH)\$(O)\ /** @private_function="PerformBasicAction" diff --git a/network/trans/WFPSampler/sys/ClassifyFunctions_BasicPacketInjectionCallouts.cpp b/network/trans/WFPSampler/sys/ClassifyFunctions_BasicPacketInjectionCallouts.cpp index 2409a64da..641cb8beb 100644 --- a/network/trans/WFPSampler/sys/ClassifyFunctions_BasicPacketInjectionCallouts.cpp +++ b/network/trans/WFPSampler/sys/ClassifyFunctions_BasicPacketInjectionCallouts.cpp @@ -103,7 +103,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// #include "Framework_WFPSamplerCalloutDriver.h" /// . -#include "ClassifyFunctions_BasicPacketInjectionCallouts.tmh" /// $(OBJ_PATH)\$(O)\ +#include "ClassifyFunctions_BasicPacketInjectionCallouts.tmh" /// $(OBJ_PATH)\$(O)\ #if DBG diff --git a/network/trans/WFPSampler/sys/ClassifyFunctions_BasicPacketModificationCallouts.cpp b/network/trans/WFPSampler/sys/ClassifyFunctions_BasicPacketModificationCallouts.cpp index d6acb876a..1a31999f2 100644 --- a/network/trans/WFPSampler/sys/ClassifyFunctions_BasicPacketModificationCallouts.cpp +++ b/network/trans/WFPSampler/sys/ClassifyFunctions_BasicPacketModificationCallouts.cpp @@ -106,7 +106,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// #include "Framework_WFPSamplerCalloutDriver.h" /// . -#include "ClassifyFunctions_BasicPacketModificationCallouts.tmh" /// $(OBJ_PATH)\$(O)\ +#include "ClassifyFunctions_BasicPacketModificationCallouts.tmh" /// $(OBJ_PATH)\$(O)\ #if(NTDDI_VERSION >= NTDDI_WIN8) diff --git a/network/trans/WFPSampler/sys/ClassifyFunctions_BasicStreamInjectionCallouts.cpp b/network/trans/WFPSampler/sys/ClassifyFunctions_BasicStreamInjectionCallouts.cpp index 493fdacef..7624c0f65 100644 --- a/network/trans/WFPSampler/sys/ClassifyFunctions_BasicStreamInjectionCallouts.cpp +++ b/network/trans/WFPSampler/sys/ClassifyFunctions_BasicStreamInjectionCallouts.cpp @@ -54,7 +54,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// #include "Framework_WFPSamplerCalloutDriver.h" /// . -#include "ClassifyFunctions_BasicStreamInjectionCallouts.tmh" /// $(OBJ_PATH)\$(O)\ +#include "ClassifyFunctions_BasicStreamInjectionCallouts.tmh" /// $(OBJ_PATH)\$(O)\ /** @private_function="PerformBasicPacketInjectionAtOutboundTransport" diff --git a/network/trans/WFPSampler/sys/ClassifyFunctions_FastPacketInjectionCallouts.cpp b/network/trans/WFPSampler/sys/ClassifyFunctions_FastPacketInjectionCallouts.cpp index b7bf9fc9b..0e99b61e1 100644 --- a/network/trans/WFPSampler/sys/ClassifyFunctions_FastPacketInjectionCallouts.cpp +++ b/network/trans/WFPSampler/sys/ClassifyFunctions_FastPacketInjectionCallouts.cpp @@ -46,7 +46,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// #include "Framework_WFPSamplerCalloutDriver.h" /// . -#include "ClassifyFunctions_FastPacketInjectionCallouts.tmh" /// $(OBJ_PATH)\$(O)\ +#include "ClassifyFunctions_FastPacketInjectionCallouts.tmh" /// $(OBJ_PATH)\$(O)\ #if(NTDDI_VERSION >= NTDDI_WIN7) diff --git a/network/trans/WFPSampler/sys/ClassifyFunctions_FastStreamInjectionCallouts.cpp b/network/trans/WFPSampler/sys/ClassifyFunctions_FastStreamInjectionCallouts.cpp index 07822e88d..a10b0d8a9 100644 --- a/network/trans/WFPSampler/sys/ClassifyFunctions_FastStreamInjectionCallouts.cpp +++ b/network/trans/WFPSampler/sys/ClassifyFunctions_FastStreamInjectionCallouts.cpp @@ -42,7 +42,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// #include "Framework_WFPSamplerCalloutDriver.h" /// . -#include "ClassifyFunctions_FastStreamInjectionCallouts.tmh" /// $(OBJ_PATH)\$(O)\ +#include "ClassifyFunctions_FastStreamInjectionCallouts.tmh" /// $(OBJ_PATH)\$(O)\ #if(NTDDI_VERSION >= NTDDI_WIN7) diff --git a/network/trans/WFPSampler/sys/ClassifyFunctions_FlowAssociationCallouts.cpp b/network/trans/WFPSampler/sys/ClassifyFunctions_FlowAssociationCallouts.cpp index 179a7ac09..f1c7f905e 100644 --- a/network/trans/WFPSampler/sys/ClassifyFunctions_FlowAssociationCallouts.cpp +++ b/network/trans/WFPSampler/sys/ClassifyFunctions_FlowAssociationCallouts.cpp @@ -39,7 +39,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// #include "Framework_WFPSamplerCalloutDriver.h" /// . -#include "ClassifyFunctions_FlowAssociationCallouts.tmh" /// $(OBJ_PATH)\$(O)\ +#include "ClassifyFunctions_FlowAssociationCallouts.tmh" /// $(OBJ_PATH)\$(O)\ NTSTATUS PerformFlowAssociation(_In_ const FWPS_INCOMING_METADATA_VALUES* pMetadata, _In_ const PC_FLOW_ASSOCIATION_DATA* pFlowAssociationData) diff --git a/network/trans/WFPSampler/sys/ClassifyFunctions_PendAuthorizationCallouts.cpp b/network/trans/WFPSampler/sys/ClassifyFunctions_PendAuthorizationCallouts.cpp index f4f23ebaf..b3f3ba156 100644 --- a/network/trans/WFPSampler/sys/ClassifyFunctions_PendAuthorizationCallouts.cpp +++ b/network/trans/WFPSampler/sys/ClassifyFunctions_PendAuthorizationCallouts.cpp @@ -47,7 +47,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// #include "Framework_WFPSamplerCalloutDriver.h" /// . -#include "ClassifyFunctions_PendAuthorizationCallouts.tmh" /// $(OBJ_PATH)\$(O)\ +#include "ClassifyFunctions_PendAuthorizationCallouts.tmh" /// $(OBJ_PATH)\$(O)\ /** @private_function="PrvCloneAuthorizedNBLAndInject" diff --git a/network/trans/WFPSampler/sys/ClassifyFunctions_PendEndpointClosureCallouts.cpp b/network/trans/WFPSampler/sys/ClassifyFunctions_PendEndpointClosureCallouts.cpp index 315dde6c1..d8d88721a 100644 --- a/network/trans/WFPSampler/sys/ClassifyFunctions_PendEndpointClosureCallouts.cpp +++ b/network/trans/WFPSampler/sys/ClassifyFunctions_PendEndpointClosureCallouts.cpp @@ -44,7 +44,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// #include "Framework_WFPSamplerCalloutDriver.h" /// . -#include "ClassifyFunctions_PendEndpointClosureCallouts.tmh" /// $(OBJ_PATH)\$(O)\ +#include "ClassifyFunctions_PendEndpointClosureCallouts.tmh" /// $(OBJ_PATH)\$(O)\ #if(NTDDI_VERSION >= NTDDI_WIN7) diff --git a/network/trans/WFPSampler/sys/ClassifyFunctions_ProxyCallouts.cpp b/network/trans/WFPSampler/sys/ClassifyFunctions_ProxyCallouts.cpp index d6b2b4d4d..f0cc853cd 100644 --- a/network/trans/WFPSampler/sys/ClassifyFunctions_ProxyCallouts.cpp +++ b/network/trans/WFPSampler/sys/ClassifyFunctions_ProxyCallouts.cpp @@ -58,7 +58,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// #include "Framework_WFPSamplerCalloutDriver.h" /// . -#include "ClassifyFunctions_ProxyCallouts.tmh" /// $(OBJ_PATH)\$(O)\ +#include "ClassifyFunctions_ProxyCallouts.tmh" /// $(OBJ_PATH)\$(O)\ /** @private_function="PerformProxyInjectionAtInboundNetwork" diff --git a/network/trans/WFPSampler/sys/CompletionFunctions_AdvancedPacketInjectionCallouts.cpp b/network/trans/WFPSampler/sys/CompletionFunctions_AdvancedPacketInjectionCallouts.cpp index 7348cb8d4..cccaf200a 100644 --- a/network/trans/WFPSampler/sys/CompletionFunctions_AdvancedPacketInjectionCallouts.cpp +++ b/network/trans/WFPSampler/sys/CompletionFunctions_AdvancedPacketInjectionCallouts.cpp @@ -52,7 +52,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// #include "Framework_WFPSamplerCalloutDriver.h" /// . -#include "CompletionFunctions_AdvancedPacketInjectionCallouts.tmh" /// $(OBJ_PATH)\$(O)\ +#include "CompletionFunctions_AdvancedPacketInjectionCallouts.tmh" /// $(OBJ_PATH)\$(O)\ #if DBG diff --git a/network/trans/WFPSampler/sys/CompletionFunctions_BasicPacketModificationCallouts.cpp b/network/trans/WFPSampler/sys/CompletionFunctions_BasicPacketModificationCallouts.cpp index ef51c44b1..cd240d4ec 100644 --- a/network/trans/WFPSampler/sys/CompletionFunctions_BasicPacketModificationCallouts.cpp +++ b/network/trans/WFPSampler/sys/CompletionFunctions_BasicPacketModificationCallouts.cpp @@ -54,7 +54,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// #include "Framework_WFPSamplerCalloutDriver.h" /// . -#include "CompletionFunctions_BasicPacketModificationCallouts.tmh" /// $(OBJ_PATH)\$(O)\ +#include "CompletionFunctions_BasicPacketModificationCallouts.tmh" /// $(OBJ_PATH)\$(O)\ /** @private_function="BasicPacketModificationCompletionDataDestroy" diff --git a/network/trans/WFPSampler/sys/CompletionFunctions_PendAuthorizationCallouts.cpp b/network/trans/WFPSampler/sys/CompletionFunctions_PendAuthorizationCallouts.cpp index e48a9ef81..7dd07b783 100644 --- a/network/trans/WFPSampler/sys/CompletionFunctions_PendAuthorizationCallouts.cpp +++ b/network/trans/WFPSampler/sys/CompletionFunctions_PendAuthorizationCallouts.cpp @@ -53,7 +53,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// #include "Framework_WFPSamplerCalloutDriver.h" /// . -#include "CompletionFunctions_PendAuthorizationCallouts.tmh" /// $(OBJ_PATH)\$(O)\ +#include "CompletionFunctions_PendAuthorizationCallouts.tmh" /// $(OBJ_PATH)\$(O)\ /** @private_function="PendAuthorizationCompletionDataDestroy" diff --git a/network/trans/WFPSampler/sys/CompletionFunctions_ProxyCallouts.cpp b/network/trans/WFPSampler/sys/CompletionFunctions_ProxyCallouts.cpp index ec47380ee..d75279018 100644 --- a/network/trans/WFPSampler/sys/CompletionFunctions_ProxyCallouts.cpp +++ b/network/trans/WFPSampler/sys/CompletionFunctions_ProxyCallouts.cpp @@ -53,7 +53,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// #include "Framework_WFPSamplerCalloutDriver.h" /// . -#include "CompletionFunctions_ProxyCallouts.tmh" /// $(OBJ_PATH)\$(O)\ +#include "CompletionFunctions_ProxyCallouts.tmh" /// $(OBJ_PATH)\$(O)\ /** @private_function="ProxyCompletionDataDestroy" diff --git a/network/trans/WFPSampler/sys/Framework_Events.cpp b/network/trans/WFPSampler/sys/Framework_Events.cpp index baf59cc8d..8f8001cc6 100644 --- a/network/trans/WFPSampler/sys/Framework_Events.cpp +++ b/network/trans/WFPSampler/sys/Framework_Events.cpp @@ -20,7 +20,7 @@ #include "Framework_WFPSamplerCalloutDriver.h" /// . #include "Framework_Include.h" /// . -#include "Framework_Events.tmh" /// $(OBJ_PATH)\$(O)\ +#include "Framework_Events.tmh" /// $(OBJ_PATH)\$(O)\ /** @framework_function="EventDriverUnload" diff --git a/network/trans/WFPSampler/sys/NotifyFunctions_AdvancedCallouts.cpp b/network/trans/WFPSampler/sys/NotifyFunctions_AdvancedCallouts.cpp index 18c938245..badbe8065 100644 --- a/network/trans/WFPSampler/sys/NotifyFunctions_AdvancedCallouts.cpp +++ b/network/trans/WFPSampler/sys/NotifyFunctions_AdvancedCallouts.cpp @@ -32,7 +32,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// #include "Framework_WFPSamplerCalloutDriver.h" /// . -#include "NotifyFunctions_AdvancedCallouts.tmh" /// $(OBJ_PATH)\$(O)\ +#include "NotifyFunctions_AdvancedCallouts.tmh" /// $(OBJ_PATH)\$(O)\ /** @private_function="PrvAdvancedNotificationWorkItemRoutine" diff --git a/network/trans/WFPSampler/sys/NotifyFunctions_BasicCallouts.cpp b/network/trans/WFPSampler/sys/NotifyFunctions_BasicCallouts.cpp index 6b86daaf3..3893d7d11 100644 --- a/network/trans/WFPSampler/sys/NotifyFunctions_BasicCallouts.cpp +++ b/network/trans/WFPSampler/sys/NotifyFunctions_BasicCallouts.cpp @@ -34,7 +34,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// #include "Framework_WFPSamplerCalloutDriver.h" /// . -#include "NotifyFunctions_BasicCallouts.tmh" /// $(OBJ_PATH)\$(O)\ +#include "NotifyFunctions_BasicCallouts.tmh" /// $(OBJ_PATH)\$(O)\ /** @private_function="PrvBasicNotificationWorkItemRoutine" diff --git a/network/trans/WFPSampler/sys/NotifyFunctions_FastCallouts.cpp b/network/trans/WFPSampler/sys/NotifyFunctions_FastCallouts.cpp index 92011dfc3..e7addba74 100644 --- a/network/trans/WFPSampler/sys/NotifyFunctions_FastCallouts.cpp +++ b/network/trans/WFPSampler/sys/NotifyFunctions_FastCallouts.cpp @@ -34,7 +34,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// #include "Framework_WFPSamplerCalloutDriver.h" /// . -#include "NotifyFunctions_FastCallouts.tmh" /// $(OBJ_PATH)\$(O)\ +#include "NotifyFunctions_FastCallouts.tmh" /// $(OBJ_PATH)\$(O)\ /** @private_function="PrvFastNotificationWorkItemRoutine" diff --git a/network/trans/WFPSampler/sys/NotifyFunctions_FlowDelete.cpp b/network/trans/WFPSampler/sys/NotifyFunctions_FlowDelete.cpp index bf1506cec..ab320f622 100644 --- a/network/trans/WFPSampler/sys/NotifyFunctions_FlowDelete.cpp +++ b/network/trans/WFPSampler/sys/NotifyFunctions_FlowDelete.cpp @@ -32,7 +32,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// #include "Framework_WFPSamplerCalloutDriver.h" /// . -#include "NotifyFunctions_FlowDelete.tmh" /// $(OBJ_PATH)\$(O)\ +#include "NotifyFunctions_FlowDelete.tmh" /// $(OBJ_PATH)\$(O)\ _IRQL_requires_min_(PASSIVE_LEVEL) _IRQL_requires_max_(DISPATCH_LEVEL) diff --git a/network/trans/WFPSampler/sys/NotifyFunctions_PendCallouts.cpp b/network/trans/WFPSampler/sys/NotifyFunctions_PendCallouts.cpp index e8b1fd637..1cc2913fb 100644 --- a/network/trans/WFPSampler/sys/NotifyFunctions_PendCallouts.cpp +++ b/network/trans/WFPSampler/sys/NotifyFunctions_PendCallouts.cpp @@ -34,7 +34,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// #include "Framework_WFPSamplerCalloutDriver.h" /// . -#include "NotifyFunctions_PendCallouts.tmh" /// $(OBJ_PATH)\$(O)\ +#include "NotifyFunctions_PendCallouts.tmh" /// $(OBJ_PATH)\$(O)\ /** @private_function="PrvPendNotificationWorkItemRoutine" diff --git a/network/trans/WFPSampler/sys/NotifyFunctions_ProxyCallouts.cpp b/network/trans/WFPSampler/sys/NotifyFunctions_ProxyCallouts.cpp index 5102b78da..b11d8569f 100644 --- a/network/trans/WFPSampler/sys/NotifyFunctions_ProxyCallouts.cpp +++ b/network/trans/WFPSampler/sys/NotifyFunctions_ProxyCallouts.cpp @@ -35,7 +35,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// #include "Framework_WFPSamplerCalloutDriver.h" /// . -#include "NotifyFunctions_ProxyCallouts.tmh" /// $(OBJ_PATH)\$(O)\ +#include "NotifyFunctions_ProxyCallouts.tmh" /// $(OBJ_PATH)\$(O)\ #if(NTDDI_VERSION >= NTDDI_WIN7) diff --git a/network/trans/WFPSampler/sys/SubscriptionFunctions_BFEState.cpp b/network/trans/WFPSampler/sys/SubscriptionFunctions_BFEState.cpp index 8c1416277..52e0b36bc 100644 --- a/network/trans/WFPSampler/sys/SubscriptionFunctions_BFEState.cpp +++ b/network/trans/WFPSampler/sys/SubscriptionFunctions_BFEState.cpp @@ -34,7 +34,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// #include "Framework_WFPSamplerCalloutDriver.h" /// . -#include "SubscriptionFunctions_BFEState.tmh" /// $(OBJ_PATH)\$(O)\ +#include "SubscriptionFunctions_BFEState.tmh" /// $(OBJ_PATH)\$(O)\ /** @notify_function="SubscriptionBFEStateChangeCallback" diff --git a/network/trans/WFPSampler/syslib/HelperFunctions_FlowContext.cpp b/network/trans/WFPSampler/syslib/HelperFunctions_FlowContext.cpp index a21dcf8a9..e53a5e333 100644 --- a/network/trans/WFPSampler/syslib/HelperFunctions_FlowContext.cpp +++ b/network/trans/WFPSampler/syslib/HelperFunctions_FlowContext.cpp @@ -42,7 +42,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// #include "HelperFunctions_Include.h" /// . -#include "HelperFunctions_FlowContext.tmh" /// $(OBJ_PATH)\$(O)\ +#include "HelperFunctions_FlowContext.tmh" /// $(OBJ_PATH)\$(O)\ _IRQL_requires_min_(PASSIVE_LEVEL) _IRQL_requires_max_(DISPATCH_LEVEL) diff --git a/network/trans/WFPSampler/syslib/HelperFunctions_FwpObjects.cpp b/network/trans/WFPSampler/syslib/HelperFunctions_FwpObjects.cpp index 773247850..0b753a574 100644 --- a/network/trans/WFPSampler/syslib/HelperFunctions_FwpObjects.cpp +++ b/network/trans/WFPSampler/syslib/HelperFunctions_FwpObjects.cpp @@ -74,7 +74,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// #include "HelperFunctions_Include.h" /// . -#include "HelperFunctions_FwpObjects.tmh" /// $(OBJ_PATH)\$(O)\ +#include "HelperFunctions_FwpObjects.tmh" /// $(OBJ_PATH)\$(O)\ HANDLE g_EngineHandle = 0; HANDLE g_pIPv4InboundMACInjectionHandles[2] = {0}; diff --git a/network/trans/WFPSampler/syslib/HelperFunctions_Headers.cpp b/network/trans/WFPSampler/syslib/HelperFunctions_Headers.cpp index 3e4008907..f5bb66e36 100644 --- a/network/trans/WFPSampler/syslib/HelperFunctions_Headers.cpp +++ b/network/trans/WFPSampler/syslib/HelperFunctions_Headers.cpp @@ -84,7 +84,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// #include "HelperFunctions_Include.h" /// . -#include "HelperFunctions_Headers.tmh" /// $(OBJ_PATH)\$(O)\ +#include "HelperFunctions_Headers.tmh" /// $(OBJ_PATH)\$(O)\ /** @private_kernel_helper_function="PrvKrnlHlprCopyBufferToMDL" diff --git a/network/trans/WFPSampler/syslib/HelperFunctions_NetBuffer.cpp b/network/trans/WFPSampler/syslib/HelperFunctions_NetBuffer.cpp index 2d6bd3c99..4338d787a 100644 --- a/network/trans/WFPSampler/syslib/HelperFunctions_NetBuffer.cpp +++ b/network/trans/WFPSampler/syslib/HelperFunctions_NetBuffer.cpp @@ -49,7 +49,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// #include "HelperFunctions_Include.h" /// . -#include "HelperFunctions_NetBuffer.tmh" /// $(OBJ_PATH)\$(O)\ +#include "HelperFunctions_NetBuffer.tmh" /// $(OBJ_PATH)\$(O)\ /** diff --git a/network/trans/WFPSampler/syslib/HelperFunctions_PendData.cpp b/network/trans/WFPSampler/syslib/HelperFunctions_PendData.cpp index bc2528a09..d8db09ee3 100644 --- a/network/trans/WFPSampler/syslib/HelperFunctions_PendData.cpp +++ b/network/trans/WFPSampler/syslib/HelperFunctions_PendData.cpp @@ -49,7 +49,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// #include "HelperFunctions_Include.h" /// . -#include "HelperFunctions_PendData.tmh" /// $(OBJ_PATH)\$(O)\ +#include "HelperFunctions_PendData.tmh" /// $(OBJ_PATH)\$(O)\ /** @kernel_helper_function="KrnlHlprPendDataPurge" diff --git a/network/trans/WFPSampler/syslib/HelperFunctions_RedirectData.cpp b/network/trans/WFPSampler/syslib/HelperFunctions_RedirectData.cpp index 22f08c609..92cca4ba1 100644 --- a/network/trans/WFPSampler/syslib/HelperFunctions_RedirectData.cpp +++ b/network/trans/WFPSampler/syslib/HelperFunctions_RedirectData.cpp @@ -48,7 +48,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// #include "HelperFunctions_Include.h" /// . -#include "HelperFunctions_RedirectData.tmh" /// $(OBJ_PATH)\$(O)\ +#include "HelperFunctions_RedirectData.tmh" /// $(OBJ_PATH)\$(O)\ #if(NTDDI_VERSION >= NTDDI_WIN7) diff --git a/network/trans/WFPSampler/syslib/HelperFunctions_WorkItems.cpp b/network/trans/WFPSampler/syslib/HelperFunctions_WorkItems.cpp index 3a5f76966..7e4f8c16d 100644 --- a/network/trans/WFPSampler/syslib/HelperFunctions_WorkItems.cpp +++ b/network/trans/WFPSampler/syslib/HelperFunctions_WorkItems.cpp @@ -54,7 +54,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// #include "HelperFunctions_Include.h" /// . -#include "HelperFunctions_WorkItems.tmh" /// $(OBJ_PATH)\$(O)\ +#include "HelperFunctions_WorkItems.tmh" /// $(OBJ_PATH)\$(O)\ /** @kernel_helper_function="KrnlHlprWorkItemDataPurge" From 1c9d80c06621274f3c3db9315678695de9c4514e Mon Sep 17 00:00:00 2001 From: 5an7y Date: Thu, 19 Mar 2026 15:36:29 -0700 Subject: [PATCH 09/20] Add Build-Samples.ps1, ListAllSamples.ps1, fix Build-Sample retry bug - ListAllSamples.ps1: Enumerates .sln files and writes Samples.txt - Build-Samples.ps1: Unified build script reading Samples.txt with exclusion support, parallel execution, and report generation - Build-Sample.ps1: Fix retry bug where all-fail exits 0 instead of 1 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- Build-Sample.ps1 | 2 +- Build-Samples.ps1 | 407 +++++++++++++++++++++++++++++++++++++++++++++ ListAllSamples.ps1 | 51 ++++++ 3 files changed, 459 insertions(+), 1 deletion(-) create mode 100644 Build-Samples.ps1 create mode 100644 ListAllSamples.ps1 diff --git a/Build-Sample.ps1 b/Build-Sample.ps1 index 093ba1ed9..c09b76948 100644 --- a/Build-Sample.ps1 +++ b/Build-Sample.ps1 @@ -139,7 +139,7 @@ if (-not $configurationIsSupported) Write-Verbose "Building Sample: $SampleName; Configuration: $Configuration; Platform: $Platform {" -$myexit=0 +$myexit=1 # # Let us build up to three times (0th, 1st, and 2nd attempt). diff --git a/Build-Samples.ps1 b/Build-Samples.ps1 new file mode 100644 index 000000000..c8ad72f5d --- /dev/null +++ b/Build-Samples.ps1 @@ -0,0 +1,407 @@ +<# +.SYNOPSIS + Builds driver samples from a sample list file with parallel execution and exclusion support. + +.DESCRIPTION + Reads sample names from Samples.txt (or a specified file), processes exclusions from + exclusions.csv, determines the build environment, and builds all non-excluded samples + in parallel using Build-Sample.ps1. Generates CSV and HTML overview reports. + + Requires PowerShell 7+ (uses ForEach-Object -Parallel and ternary operators). + +.PARAMETER SampleListPath + Path to the file containing sample names (one per line). Defaults to Samples.txt in the + current directory. + +.PARAMETER Samples + Optional array of specific sample names to build. When provided, overrides SampleListPath. + +.PARAMETER Configurations + Build configurations (e.g. 'Debug','Release'). Defaults to $env:WDS_Configuration or + ('Debug','Release'). + +.PARAMETER Platforms + Build platforms (e.g. 'x64','arm64'). Defaults to $env:WDS_Platform or ('x64','arm64'). + +.PARAMETER LogFilesDirectory + Directory for build log files. Defaults to _logs in the current directory. + +.PARAMETER ReportFileName + Base name for the report files (without extension). Defaults to $env:WDS_ReportFileName + or '_overview'. + +.PARAMETER InfOptions + Additional InfVerif options. If not provided, determined automatically based on build number. + +.PARAMETER ThrottleLimit + Maximum parallel build jobs. Defaults to 5 x logical processors. + +.EXAMPLE + .\Build-Samples + +.EXAMPLE + .\Build-Samples -Samples 'audio.acx.samples.audiocodec.driver','usb.kmdf_fx2' -Configurations 'Debug' -Platforms 'x64' + +.EXAMPLE + .\Build-Samples -SampleListPath .\MySamples.txt -ThrottleLimit 8 +#> + +[CmdletBinding()] +param( + [string]$SampleListPath = (Join-Path (Get-Location) "Samples.txt"), + [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 }), + [string]$LogFilesDirectory = (Join-Path (Get-Location) "_logs"), + [string]$ReportFileName = $(if ([string]::IsNullOrEmpty($env:WDS_ReportFileName)) { "_overview" } else { $env:WDS_ReportFileName }), + [string]$InfOptions, + [int]$ThrottleLimit = 0 +) + +$root = (Get-Location).Path + +# Launch developer PowerShell if necessary +if (-not $env:VSCMD_VER) { + Import-Module (Resolve-Path "$env:ProgramFiles\Microsoft Visual Studio\*\*\Common7\Tools\Microsoft.VisualStudio.DevShell.dll") + Enter-VsDevShell -VsInstallPath (Resolve-Path "$env:ProgramFiles\Microsoft Visual Studio\*\*") + Set-Location $root +} + +$ThrottleFactor = 5 +$LogicalProcessors = (Get-CIMInstance -Class 'CIM_Processor' -Verbose:$false).NumberOfLogicalProcessors + +if ($ThrottleLimit -eq 0) { + $ThrottleLimit = $ThrottleFactor * $LogicalProcessors +} + +$Verbose = $false +if ($PSBoundParameters.ContainsKey('Verbose')) { + $Verbose = $PsBoundParameters.Get_Item('Verbose') +} + +# Prepare log directory +Remove-Item -Recurse -Path $LogFilesDirectory 2>&1 | Out-Null +New-Item -ItemType Directory -Force -Path $LogFilesDirectory | Out-Null + +$reportFilePath = Join-Path $LogFilesDirectory "$ReportFileName.htm" +$reportCsvFilePath = Join-Path $LogFilesDirectory "$ReportFileName.csv" + +# Verify msbuild is available +$oldPreference = $ErrorActionPreference +$ErrorActionPreference = "stop" +try { + Get-Command "msbuild" | Out-Null +} +catch { + Write-Host "`u{274C} msbuild cannot be called from current environment. Check that msbuild is set in current path (for example, that it is called from a Visual Studio developer command)." + Write-Error "msbuild cannot be called from current environment." + exit 1 +} +finally { + $ErrorActionPreference = $oldPreference +} + +# +# Load sample list +# +if ($Samples) { + $sampleNames = $Samples +} +else { + if (-not (Test-Path $SampleListPath)) { + Write-Error "Sample list file not found: $SampleListPath. Run .\ListAllSamples.ps1 first to generate Samples.txt." + exit 1 + } + $sampleNames = Get-Content $SampleListPath | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } +} + +# Build the sampleSet hashtable: sampleName -> directory path +$sampleSet = @{} +foreach ($name in $sampleNames) { + $relativePath = $name.Replace('.', '\') + $fullPath = Join-Path $root $relativePath + $sampleSet[$name] = $fullPath +} + +# +# Determine build environment +# +$build_environment = "" +$build_number = 0 +$nuget_package_version = 0 + +if ($env:GITHUB_REPOSITORY) { + $build_environment = "GitHub" + $nuget_package_version = ([regex]'(?<=x64\.)(\d+\.)(\d+\.)(\d+\.)(\d+)').Matches((Get-ChildItem .\packages\*WDK.x64* -Name)).Value + $build_number = $nuget_package_version.split('.')[2] +} +elseif (Test-Path(".\packages\*")) { + $build_environment = "NuGet" + $nuget_package_version = ([regex]'(?<=x64\.)(\d+\.)(\d+\.)(\d+\.)(\d+)').Matches((Get-ChildItem .\packages\*WDK.x64* -Name)).Value + $build_number = $nuget_package_version.split('.')[2] +} +elseif ($env:BuildLab -match '(?[^.]*).(?[^.]*).(?[^.]*)') { + $build_environment = "EWDK." + $Matches.branch + "." + $Matches.build + "." + $Matches.qfe + $build_number = $Matches.build +} +elseif ($env:UCRTVersion -match '10.0.(?.*).0') { + $build_environment = "WDK" + $build_number = $Matches.build +} +else { + Write-Output "Environment variables {" + Get-ChildItem env:* | Sort-Object name + Write-Output "Environment variables }" + Write-Error "Could not determine build environment." + exit 1 +} + +# Determine WDK Visual Studio Component version +if ($build_environment -match '^EWDK') { + $wdk_vs_component_ver = "(WDK Visual Studio Component Version is not included for EWDK builds)" +} +else { + $wdk_vs_component_ver = Get-ChildItem "${env:ProgramData}\Microsoft\VisualStudio\Packages\Microsoft.Windows.DriverKit,version=*" -ErrorAction SilentlyContinue + if (-not $wdk_vs_component_ver) { + Write-Error "WDK Visual Studio Component version not found. Please ensure the WDK Component is installed." + exit 1 + } + $wdk_vs_component_ver = [regex]::Match($wdk_vs_component_ver.Name, '(\d+\.){3}\d+').Value +} + +# +# InfVerif_AdditionalOptions +# +if ($InfOptions) { + $InfVerif_AdditionalOptions = $InfOptions +} +else { + $InfVerif_AdditionalOptions = ($build_number -le 22621 ? "/sw1284 /sw1285 /sw1293 /sw2083 /sw2086" : "/samples") +} + +# +# Load exclusions from exclusions.csv +# +$exclusionConfigurations = @{} +$exclusionReasons = @{} +Import-Csv 'exclusions.csv' | ForEach-Object { + $excluded_driver = $_.Path.Replace($root, '').Trim('\').Replace('\', '.').ToLower() + $excluded_configurations = ($_.configurations -eq '' ? '*' : $_.configurations) + $excluded_minbuild = ($_.MinBuild -eq '' ? 00000 : $_.MinBuild) + $excluded_maxbuild = ($_.MaxBuild -eq '' ? 99999 : $_.MaxBuild) + if (($excluded_minbuild -le $build_number) -and ($build_number -le $excluded_maxbuild)) { + $exclusionConfigurations[$excluded_driver] = $excluded_configurations + $exclusionReasons[$excluded_driver] = $_.Reason + Write-Verbose "Exclusion.csv entry applied for '$excluded_driver' for configuration '$excluded_configurations'." + } + else { + Write-Verbose "Exclusion.csv entry not applied for '$excluded_driver' due to build number." + } +} + +# +# Build all samples +# +$jresult = @{ + SolutionsBuilt = 0 + SolutionsSucceeded = 0 + SolutionsExcluded = 0 + SolutionsUnsupported = 0 + SolutionsFailed = 0 + SolutionsSporadic = 0 + Results = @() + FailSet = @() + SporadicSet = @() + lock = [System.Threading.Mutex]::new($false) +} + +$SolutionsTotal = $sampleSet.Count * $Configurations.Count * $Platforms.Count + +Write-Output "WDK Build Environment: $build_environment" +Write-Output "WDK Build Number: $build_number" +if (($build_environment -eq "GitHub") -or ($build_environment -eq "NuGet")) { + Write-Output "WDK Nuget Version: $nuget_package_version" +} +Write-Output "WDK Visual Studio Component Version: $wdk_vs_component_ver" +Write-Output "Samples: $($sampleSet.Count)" +Write-Output "Configurations: $($Configurations.Count) ($Configurations)" +Write-Output "Platforms: $($Platforms.Count) ($Platforms)" +Write-Output "InfVerif_AdditionalOptions: $InfVerif_AdditionalOptions" +Write-Output "Combinations: $SolutionsTotal" +Write-Output "LogicalProcessors: $LogicalProcessors" +Write-Output "ThrottleFactor: $ThrottleFactor" +Write-Output "ThrottleLimit: $ThrottleLimit" +Write-Output "WDS_WipeOutputs: $env:WDS_WipeOutputs" +Write-Output "Disk Remaining (GB): $(((Get-Volume ((Get-Item ".").PSDrive.Name)).SizeRemaining) / 1GB)" +Write-Output "" +Write-Output "T: Combinations" +Write-Output "B: Built" +Write-Output "R: Build is running currently" +Write-Output "P: Build is pending an available build slot" +Write-Output "" +Write-Output "S: Built and result was 'Succeeded'" +Write-Output "E: Built and result was 'Excluded'" +Write-Output "U: Built and result was 'Unsupported' (Platform and Configuration combination)" +Write-Output "F: Built and result was 'Failed'" +Write-Output "O: Built and result was 'Sporadic'" +Write-Output "" +Write-Output "Building all combinations..." + +$sw = [Diagnostics.Stopwatch]::StartNew() + +$sampleSet.GetEnumerator() | ForEach-Object -ThrottleLimit $ThrottleLimit -Parallel { + $LogFilesDirectory = $using:LogFilesDirectory + $exclusionConfigurations = $using:exclusionConfigurations + $exclusionReasons = $using:exclusionReasons + $Configurations = $using:Configurations + $Platforms = $using:Platforms + $InfVerif_AdditionalOptions = $using:InfVerif_AdditionalOptions + $Verbose = $using:Verbose + + $sampleName = $_.Key + $directory = $_.Value + + $ResultElement = New-Object psobject + Add-Member -InputObject $ResultElement -MemberType NoteProperty -Name Sample -Value "$sampleName" + + foreach ($configuration in $Configurations) { + foreach ($platform in $Platforms) { + $thisunsupported = 0 + $thisfailed = 0 + $thissporadic = 0 + $thisexcluded = 0 + $thissucceeded = 0 + $thisresult = "Not run" + $thisfailset = @() + $thissporadicset = @() + + if ($exclusionConfigurations.ContainsKey($sampleName) -and ($exclusionConfigurations[$sampleName].Split(';') | Where-Object { "$configuration|$platform" -like $_ })) { + Write-Verbose "[$sampleName $configuration|$platform] `u{23E9} Excluded and skipped. Reason: $($exclusionReasons[$sampleName])" + $thisexcluded += 1 + $thisresult = "Excluded" + } + else { + .\Build-Sample -Directory $directory -SampleName $sampleName -LogFilesDirectory $LogFilesDirectory -Configuration $configuration -Platform $platform -InfVerif_AdditionalOptions $InfVerif_AdditionalOptions -Verbose:$Verbose + if ($LASTEXITCODE -eq 0) { + $thissucceeded += 1 + $thisresult = "Succeeded" + } + elseif ($LASTEXITCODE -eq 1) { + $thisfailset += "$sampleName $configuration|$platform" + $thisfailed += 1 + $thisresult = "Failed" + } + elseif ($LASTEXITCODE -eq 2) { + $thissporadicset += "$sampleName $configuration|$platform" + $thissporadic += 1 + $thisresult = "Sporadic" + } + else { + $thisunsupported += 1 + $thisresult = "Unsupported" + } + } + Add-Member -InputObject $ResultElement -MemberType NoteProperty -Name "$configuration|$platform" -Value "$thisresult" + + $null = ($using:jresult).lock.WaitOne() + try { + ($using:jresult).SolutionsBuilt += 1 + ($using:jresult).SolutionsSucceeded += $thissucceeded + ($using:jresult).SolutionsExcluded += $thisexcluded + ($using:jresult).SolutionsUnsupported += $thisunsupported + ($using:jresult).SolutionsFailed += $thisfailed + ($using:jresult).SolutionsSporadic += $thissporadic + ($using:jresult).FailSet += $thisfailset + ($using:jresult).SporadicSet += $thissporadicset + $SolutionsTotal = $using:SolutionsTotal + $ThrottleLimit = $using:ThrottleLimit + $SolutionsBuilt = ($using:jresult).SolutionsBuilt + $SolutionsRemaining = $SolutionsTotal - $SolutionsBuilt + $SolutionsRunning = if ($SolutionsRemaining -ge $ThrottleLimit) { $ThrottleLimit } else { $SolutionsRemaining } + $SolutionsPending = if ($SolutionsRemaining -ge $ThrottleLimit) { ($SolutionsRemaining - $ThrottleLimit) } else { 0 } + $SolutionsBuiltPercent = [Math]::Round(100 * ($SolutionsBuilt / $using:SolutionsTotal)) + $TBRP = "T:" + ($SolutionsTotal) + "; B:" + (($using:jresult).SolutionsBuilt) + "; R:" + ($SolutionsRunning) + "; P:" + ($SolutionsPending) + $rstr = "S:" + (($using:jresult).SolutionsSucceeded) + "; E:" + (($using:jresult).SolutionsExcluded) + "; U:" + (($using:jresult).SolutionsUnsupported) + "; F:" + (($using:jresult).SolutionsFailed) + "; O:" + (($using:jresult).SolutionsSporadic) + Write-Progress -Activity "Building combinations" -Status "$SolutionsBuilt of $using:SolutionsTotal combinations built ($SolutionsBuiltPercent%) | $TBRP | $rstr" -PercentComplete $SolutionsBuiltPercent + } + finally { + ($using:jresult).lock.ReleaseMutex() + } + } + } + $null = ($using:jresult).lock.WaitOne() + try { + ($using:jresult).Results += $ResultElement + } + finally { + ($using:jresult).lock.ReleaseMutex() + } +} + +$sw.Stop() + +Write-Output "" + +if ($jresult.FailSet.Count -gt 0) { + Write-Output "Some combinations were built with errors:" + $jresult.FailSet = $jresult.FailSet | Sort-Object + foreach ($failedSample in $jresult.FailSet) { + $failedSample -match "^(.*) (\w*)\|(\w*)$" | Out-Null + $failName = $Matches[1] + $failConfiguration = $Matches[2] + $failPlatform = $Matches[3] + Write-Output "Build errors in Sample $failName; Configuration: $failConfiguration; Platform: $failPlatform {" + Get-Content "$LogFilesDirectory\$failName.$failConfiguration.$failPlatform.0.err" | Write-Output + Write-Output "} $failedSample" + } + Write-Error "Some combinations were built with errors." + Write-Output "" +} + +if ($jresult.SporadicSet.Count -gt 0) { + Write-Output "Some combinations were built with sporadic error:" + $jresult.SporadicSet = $jresult.SporadicSet | Sort-Object + foreach ($sporadicSample in $jresult.SporadicSet) { + $sporadicSample -match "^(.*) (\w*)\|(\w*)$" | Out-Null + $sporadicName = $Matches[1] + $sporadicConfiguration = $Matches[2] + $sporadicPlatform = $Matches[3] + Write-Output "Build sporadic errors in Sample $sporadicName; Configuration: $sporadicConfiguration; Platform: $sporadicPlatform {" + Get-Content "$LogFilesDirectory\$sporadicName.$sporadicConfiguration.$sporadicPlatform.0.err" | Write-Output + Write-Output "} $sporadicSample" + } + Write-Error "Some combinations were built with sporadic errors." + Write-Output "" +} + +# Display timer statistics +$min = $sw.Elapsed.Minutes +$seconds = $sw.Elapsed.Seconds + +$SolutionsSucceeded = $jresult.SolutionsSucceeded +$SolutionsExcluded = $jresult.SolutionsExcluded +$SolutionsUnsupported = $jresult.SolutionsUnsupported +$SolutionsFailed = $jresult.SolutionsFailed +$SolutionsSporadic = $jresult.SolutionsSporadic +$Results = $jresult.Results + +Write-Output "Built all combinations." +Write-Output "" +Write-Output "Elapsed time: $min minutes, $seconds seconds." +Write-Output ("Disk Remaining (GB): " + (((Get-Volume (Get-Item ".").PSDrive.Name).SizeRemaining / 1GB))) +Write-Output ("Samples: " + $sampleSet.Count) +Write-Output ("Configurations: " + $Configurations.Count + " (" + $Configurations + ")") +Write-Output ("Platforms: " + $Platforms.Count + " (" + $Platforms + ")") +Write-Output "Combinations: $SolutionsTotal" +Write-Output "Succeeded: $SolutionsSucceeded" +Write-Output "Excluded: $SolutionsExcluded" +Write-Output "Unsupported: $SolutionsUnsupported" +Write-Output "Failed: $SolutionsFailed" +Write-Output "Sporadic: $SolutionsSporadic" +Write-Output "Log files directory: $LogFilesDirectory" +Write-Output "Overview report: $reportFilePath" +Write-Output "" + +$Results | Sort-Object { $_.Sample } | ConvertTo-Csv | Out-File $reportCsvFilePath +$Results | Sort-Object { $_.Sample } | ConvertTo-Html -Title "Overview" | Out-File $reportFilePath +Invoke-Item $reportFilePath diff --git a/ListAllSamples.ps1 b/ListAllSamples.ps1 new file mode 100644 index 000000000..2a3876096 --- /dev/null +++ b/ListAllSamples.ps1 @@ -0,0 +1,51 @@ +<# +.SYNOPSIS + Enumerates all available sample solutions in the repository and writes them to Samples.txt. + +.DESCRIPTION + Searches for all .sln files recursively from the repo root, excludes NuGet package directories + (paths starting with 'packages.'), computes a normalized sample name for each, and writes + the sorted list to Samples.txt (one sample name per line). + + The sample name is derived from the relative directory path: backslashes are replaced with dots + and the result is lowercased. + +.EXAMPLE + .\ListAllSamples + + Discovers all samples and writes Samples.txt to the repo root. + +.OUTPUTS + Samples.txt in the current working directory. +#> + +[CmdletBinding()] +param() + +$root = (Get-Location).Path + +# Discover all .sln files +$solutionFiles = Get-ChildItem -Path $root -Recurse -Filter *.sln | Select-Object -ExpandProperty FullName + +$sampleNames = @{} + +foreach ($file in $solutionFiles) { + $dir = (Get-Item $file).DirectoryName + $dirNorm = $dir.Replace($root, '').Trim('\').Replace('\', '.').ToLower() + + if ($dirNorm -match '^packages\.') { + Write-Verbose "Ignored NuGet package directory: $dirNorm" + continue + } + + if (-not $sampleNames.ContainsKey($dirNorm)) { + $sampleNames[$dirNorm] = $true + } +} + +$sortedNames = $sampleNames.Keys | Sort-Object + +$outputPath = Join-Path $root "Samples.txt" +$sortedNames | Out-File -FilePath $outputPath -Encoding utf8 + +Write-Output "Found $($sortedNames.Count) samples. Written to Samples.txt" From 15e6a1f38da2fdcf22ae4a38ab38bd839df72987 Mon Sep 17 00:00:00 2001 From: 5an7y Date: Fri, 20 Mar 2026 14:11:50 -0700 Subject: [PATCH 10/20] Making the maxbuild bigger on exclusions for testint and adding the base samples.txt --- Samples.txt | 137 +++++++++++++++++++++++++++++++++++++++++++++++++ exclusions.csv | 8 +-- 2 files changed, 141 insertions(+), 4 deletions(-) create mode 100644 Samples.txt diff --git a/Samples.txt b/Samples.txt new file mode 100644 index 000000000..e649f7e22 --- /dev/null +++ b/Samples.txt @@ -0,0 +1,137 @@ +audio.acx.samples.audiocodec.driver +audio.simpleaudiosample +audio.soundwire.samples.sdcavad +audio.sysvad +avstream.avscamera +avstream.avshws +avstream.avssamp +avstream.sampledevicemft +avstream.samplemft0 +bluetooth.bthecho +bluetooth.bthecho.packages.microsoft.windows.wdk.x64.10.0.26100.3323.c.tools.10.0.26100.0.x64.acpigenfx.samples +bluetooth.bthecho.packages.microsoft.windows.wdk.x64.10.0.26100.6584-preview.ge-release-svc-prod1.c.tools.10.0.26100.0.x64.acpigenfx.samples +bluetooth.serialhcibus +filesys.cdfs +filesys.fastfat +filesys.minifilter.avscan +filesys.minifilter.cancelsafe +filesys.minifilter.cdo +filesys.minifilter.change +filesys.minifilter.ctx +filesys.minifilter.delete +filesys.minifilter.metadatamanager +filesys.minifilter.minispy +filesys.minifilter.namechanger +filesys.minifilter.nullfilter +filesys.minifilter.passthrough +filesys.minifilter.scanner +filesys.minifilter.simrep +filesys.minifilter.swapbuffers +general.cancel +general.dchu.osrfx2_dchu_base +general.dchu.osrfx2_dchu_extension_loose +general.dchu.osrfx2_dchu_extension_tight +general.echo.kmdf +general.echo.umdf2 +general.event +general.ioctl.kmdf +general.ioctl.wdm +general.obcallback +general.pcidrv +general.perfcounters.kcs +general.plx9x5x +general.registry.regfltr +general.simplemediasource +general.systemdma.wdm +general.toaster.toastdrv +general.toaster.toastpkg +general.toaster.umdf2 +general.tracing.evntdrv +general.tracing.systemtracecontrol +general.tracing.tracedriver +gnss +gpio.samples +hid.firefly +hid.hclient +hid.hidusbfx2 +hid.vhidmini2 +input.kbfiltr +input.layout +input.moufiltr +network.config.bindview +network.modem.fakemodem +network.ndis.extension +network.ndis.filter +network.ndis.mux +network.ndis.ndisprot_kmdf +network.ndis.ndisprot.6x +network.ndis.netvmini.6x +network.radio.radiomanagersample +network.trans.ddproxy +network.trans.inspect +network.trans.msnmntr +network.trans.stmedit +network.trans.wfpsampler +network.wlan.wdi +network.wsk.echosrv +network.wwan.cxwmbclass +nfc.nfccxsample +nfp.net +pofx.pep +pofx.umdf2 +pofx.wdf +pos.drivers.barcodescanner +pos.drivers.magneticstripereader +powerlimit.plclient +powerlimit.plpolicy +prm +sd.miniport.sdhc +security.elam +sensors.activity +sensors.adxl345acc +sensors.customsensors +sensors.fusion +sensors.pedometer +sensors.sensorscombodriver +sensors.simpledeviceorientationsensor +serial.serenum +serial.serenum.packages.microsoft.windows.wdk.x64.10.0.26100.3323.c.tools.10.0.26100.0.x64.acpigenfx.samples +serial.serial +serial.virtualserial2 +setup.devcon +simbatt.func +smartcrd +spb.skeletoni2c +spb.spbtesttool +storage.class.classpnp +storage.class.disk +storage.iscsi +storage.miniports.lsi_u3 +storage.miniports.storahci +storage.msdsm +storage.tools.spti +thermal.simsensor +thermal.thermalclient +tools.dv.samples.dv-faildriver-wdm.driver +tools.kasan.samples.kasandemo-wdm +tools.sdv.samples.sdv-faildriver-kmdf +tools.sdv.samples.sdv-faildriver-ndis +tools.sdv.samples.sdv-faildriver-storport +tools.sdv.samples.sdv-faildriver-wdm +tree +usb.kmdf_enumswitches +usb.kmdf_fx2 +usb.ucmcxucsi +usb.ucmtcpcicxclientsample +usb.ucmucsiacpisample +usb.ufxclientsample +usb.umdf2_fx2 +usb.usbsamp +usb.usbview +usb.wdf_osrfx2_lab +video.archive.pixlib +video.indirectdisplay +video.kmdod +wia +wmi.wmiacpi +wmi.wmisamp diff --git a/exclusions.csv b/exclusions.csv index 63d5e24a9..fbfefa25c 100644 --- a/exclusions.csv +++ b/exclusions.csv @@ -6,8 +6,8 @@ network\trans\WFPSampler,Debug|ARM64,,22621,Only NI: Only ARM: Fails to build on 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" +general\pcidrv,*,,27100,"failure introduced in VS17.14, suppressed until fix" +serial\serial,*,,27100,"failure introduced in VS17.14, suppressed until fix" +network\wlan\wdi,*,,27100,"failure introduced in VS17.14, suppressed until fix" +tools\kasan\samples\kasandemo-wdm,*|x64,,27100,"failure introduced in VS17.14, suppressed until fix" From 8e3b051532deef78849c15f96ce79b5f3b21b911 Mon Sep 17 00:00:00 2001 From: 5an7y Date: Fri, 20 Mar 2026 14:26:54 -0700 Subject: [PATCH 11/20] Remove NuGet packages from samples --- ListAllSamples.ps1 | 2 +- Samples.txt | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/ListAllSamples.ps1 b/ListAllSamples.ps1 index 2a3876096..ed87fc831 100644 --- a/ListAllSamples.ps1 +++ b/ListAllSamples.ps1 @@ -33,7 +33,7 @@ foreach ($file in $solutionFiles) { $dir = (Get-Item $file).DirectoryName $dirNorm = $dir.Replace($root, '').Trim('\').Replace('\', '.').ToLower() - if ($dirNorm -match '^packages\.') { + if ($dirNorm -match '(^|\.|\b)packages(\.|$)') { Write-Verbose "Ignored NuGet package directory: $dirNorm" continue } diff --git a/Samples.txt b/Samples.txt index e649f7e22..7998f3950 100644 --- a/Samples.txt +++ b/Samples.txt @@ -1,4 +1,4 @@ -audio.acx.samples.audiocodec.driver +audio.acx.samples.audiocodec.driver audio.simpleaudiosample audio.soundwire.samples.sdcavad audio.sysvad @@ -8,8 +8,6 @@ avstream.avssamp avstream.sampledevicemft avstream.samplemft0 bluetooth.bthecho -bluetooth.bthecho.packages.microsoft.windows.wdk.x64.10.0.26100.3323.c.tools.10.0.26100.0.x64.acpigenfx.samples -bluetooth.bthecho.packages.microsoft.windows.wdk.x64.10.0.26100.6584-preview.ge-release-svc-prod1.c.tools.10.0.26100.0.x64.acpigenfx.samples bluetooth.serialhcibus filesys.cdfs filesys.fastfat @@ -63,8 +61,8 @@ network.modem.fakemodem network.ndis.extension network.ndis.filter network.ndis.mux -network.ndis.ndisprot_kmdf network.ndis.ndisprot.6x +network.ndis.ndisprot_kmdf network.ndis.netvmini.6x network.radio.radiomanagersample network.trans.ddproxy @@ -95,7 +93,6 @@ sensors.pedometer sensors.sensorscombodriver sensors.simpledeviceorientationsensor serial.serenum -serial.serenum.packages.microsoft.windows.wdk.x64.10.0.26100.3323.c.tools.10.0.26100.0.x64.acpigenfx.samples serial.serial serial.virtualserial2 setup.devcon From 9cd8d031aa48669e9e3cc11886d856ce52d6ce20 Mon Sep 17 00:00:00 2001 From: 5an7y Date: Fri, 20 Mar 2026 15:09:27 -0700 Subject: [PATCH 12/20] Refactor Build-Samples.ps1 and fix ListAllSamples NuGet filter Build-Samples.ps1: - Extract helper functions for readability (Resolve-BuildEnvironment, Import-SampleExclusions, Initialize-DevShell, Assert-MsBuildAvailable, Get-DiskFreeGB) - Add #Requires -Version 7.0 - Fix build_number to explicit [int] cast (was string from regex) - Fix multi-socket CPU handling (sum LogicalProcessors) - Fix NuGet path detection to use absolute repo root path - Support wildcard patterns in exclusion paths (-like vs ContainsKey) - Guard Invoke-Item for CI/automation (skip in non-interactive sessions) - Validate sample directories exist before building - Wrap Get-Volume in try/catch for UNC/network drives - Use Write-Host with carriage return for progress (Write-Progress unreliable in -Parallel runspaces) - Clean up variable names and add section comments - Use switch instead of if/elseif for exit codes ListAllSamples.ps1: - Fix NuGet packages filter regex to catch packages anywhere in path (was only matching paths starting with packages) Samples.txt: - Regenerated with fixed filter, remove BOM Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- Build-Samples.ps1 | 730 ++++++++++++++++++++++++++++----------------- ListAllSamples.ps1 | 2 +- Samples.txt | 4 +- 3 files changed, 461 insertions(+), 275 deletions(-) diff --git a/Build-Samples.ps1 b/Build-Samples.ps1 index c8ad72f5d..6fd86bd37 100644 --- a/Build-Samples.ps1 +++ b/Build-Samples.ps1 @@ -3,15 +3,24 @@ Builds driver samples from a sample list file with parallel execution and exclusion support. .DESCRIPTION - Reads sample names from Samples.txt (or a specified file), processes exclusions from - exclusions.csv, determines the build environment, and builds all non-excluded samples - in parallel using Build-Sample.ps1. Generates CSV and HTML overview reports. + This is the main build orchestrator for driver samples. It performs these steps: - Requires PowerShell 7+ (uses ForEach-Object -Parallel and ternary operators). + 1. Ensures a developer build environment (VS DevShell or EWDK) is active + 2. Reads sample names from Samples.txt (or a specified file/array) + 3. Detects the build environment (GitHub CI, NuGet, EWDK, or WDK) and build number + 4. Loads exclusions from exclusions.csv (supports wildcard paths) + 5. Builds all non-excluded sample/configuration/platform combinations in parallel + 6. Generates CSV and HTML overview reports + + Requires PowerShell 7+ (uses ForEach-Object -Parallel). + + Typical call chain: + Build-AllSamples.ps1 -> ListAllSamples.ps1 -> Build-Samples.ps1 -> Build-Sample.ps1 + (this script) .PARAMETER SampleListPath - Path to the file containing sample names (one per line). Defaults to Samples.txt in the - current directory. + Path to the file containing sample names (one per line, dot-separated). + Defaults to Samples.txt in the current directory. .PARAMETER Samples Optional array of specific sample names to build. When provided, overrides SampleListPath. @@ -31,7 +40,8 @@ or '_overview'. .PARAMETER InfOptions - Additional InfVerif options. If not provided, determined automatically based on build number. + Additional InfVerif options (e.g. '/samples', '/msft'). If not provided, determined + automatically based on the WDK build number. .PARAMETER ThrottleLimit Maximum parallel build jobs. Defaults to 5 x logical processors. @@ -39,13 +49,21 @@ .EXAMPLE .\Build-Samples + Builds all samples from Samples.txt with default settings. + .EXAMPLE .\Build-Samples -Samples 'audio.acx.samples.audiocodec.driver','usb.kmdf_fx2' -Configurations 'Debug' -Platforms 'x64' + Builds specific samples for a single configuration and platform. + .EXAMPLE .\Build-Samples -SampleListPath .\MySamples.txt -ThrottleLimit 8 + + Builds samples from a custom list with limited parallelism. #> +#Requires -Version 7.0 + [CmdletBinding()] param( [string]$SampleListPath = (Join-Path (Get-Location) "Samples.txt"), @@ -58,350 +76,518 @@ param( [int]$ThrottleLimit = 0 ) -$root = (Get-Location).Path +# ============================================================================= +# Helper Functions +# ============================================================================= -# Launch developer PowerShell if necessary -if (-not $env:VSCMD_VER) { - Import-Module (Resolve-Path "$env:ProgramFiles\Microsoft Visual Studio\*\*\Common7\Tools\Microsoft.VisualStudio.DevShell.dll") - Enter-VsDevShell -VsInstallPath (Resolve-Path "$env:ProgramFiles\Microsoft Visual Studio\*\*") - Set-Location $root -} +function Initialize-DevShell { + <# + .SYNOPSIS Imports the Visual Studio Developer PowerShell if not already active. + #> + param([string]$ReturnToDirectory) -$ThrottleFactor = 5 -$LogicalProcessors = (Get-CIMInstance -Class 'CIM_Processor' -Verbose:$false).NumberOfLogicalProcessors + if ($env:VSCMD_VER) { + Write-Verbose "VS Developer Shell already active (VSCMD_VER=$env:VSCMD_VER)." + return + } -if ($ThrottleLimit -eq 0) { - $ThrottleLimit = $ThrottleFactor * $LogicalProcessors + $devShellDll = Resolve-Path "$env:ProgramFiles\Microsoft Visual Studio\*\*\Common7\Tools\Microsoft.VisualStudio.DevShell.dll" ` + -ErrorAction SilentlyContinue | Select-Object -First 1 + if (-not $devShellDll) { + Write-Error "Visual Studio Developer Shell module not found." + exit 1 + } + + Import-Module $devShellDll.Path + $vsInstall = Resolve-Path "$env:ProgramFiles\Microsoft Visual Studio\*\*" | Select-Object -First 1 + Enter-VsDevShell -VsInstallPath $vsInstall.Path + Set-Location $ReturnToDirectory } -$Verbose = $false -if ($PSBoundParameters.ContainsKey('Verbose')) { - $Verbose = $PsBoundParameters.Get_Item('Verbose') +function Assert-MsBuildAvailable { + <# + .SYNOPSIS Verifies msbuild.exe is on PATH. Exits with error if not found. + #> + $savedPref = $ErrorActionPreference + $ErrorActionPreference = 'Stop' + try { + Get-Command 'msbuild' | Out-Null + } + catch { + Write-Error "msbuild cannot be called from current environment. Ensure it is on PATH (run from VS Developer Command Prompt or EWDK)." + exit 1 + } + finally { + $ErrorActionPreference = $savedPref + } } -# Prepare log directory -Remove-Item -Recurse -Path $LogFilesDirectory 2>&1 | Out-Null -New-Item -ItemType Directory -Force -Path $LogFilesDirectory | Out-Null +function Resolve-BuildEnvironment { + <# + .SYNOPSIS + Detects the active build environment and returns metadata. + .DESCRIPTION + Checks (in priority order) for GitHub CI, local NuGet packages, EWDK, or WDK. + Returns a hashtable: Name, BuildNumber (int), NuGetVersion, WdkVsComponentVersion. + #> + param([string]$RepoRoot) + + $result = @{ + Name = '' + BuildNumber = [int]0 + NuGetVersion = '' + WdkVsComponentVersion = '' + } -$reportFilePath = Join-Path $LogFilesDirectory "$ReportFileName.htm" -$reportCsvFilePath = Join-Path $LogFilesDirectory "$ReportFileName.csv" + if ($env:GITHUB_REPOSITORY) { + $result.Name = 'GitHub' + $wdkPackage = Get-ChildItem "$RepoRoot\packages\*WDK.x64*" -Name -ErrorAction SilentlyContinue + $result.NuGetVersion = ([regex]'(?<=x64\.)(\d+\.){3}\d+').Match($wdkPackage).Value + $result.BuildNumber = [int]($result.NuGetVersion.Split('.')[2]) + } + elseif (Test-Path "$RepoRoot\packages\*") { + $result.Name = 'NuGet' + $wdkPackage = Get-ChildItem "$RepoRoot\packages\*WDK.x64*" -Name -ErrorAction SilentlyContinue + $result.NuGetVersion = ([regex]'(?<=x64\.)(\d+\.){3}\d+').Match($wdkPackage).Value + $result.BuildNumber = [int]($result.NuGetVersion.Split('.')[2]) + } + elseif ($env:BuildLab -match '^(?[^.]+)\.(?\d+)\.(?[^.]+)$') { + $result.Name = "EWDK.$($Matches.branch).$($Matches.build).$($Matches.qfe)" + $result.BuildNumber = [int]$Matches.build + } + elseif ($env:UCRTVersion -match '10\.0\.(?\d+)\.0') { + $result.Name = 'WDK' + $result.BuildNumber = [int]$Matches.build + } + else { + Write-Output "Environment variables {" + Get-ChildItem env:* | Sort-Object Name + Write-Output "Environment variables }" + Write-Error "Could not determine build environment. Ensure EWDK, WDK, or NuGet packages are configured." + exit 1 + } -# Verify msbuild is available -$oldPreference = $ErrorActionPreference -$ErrorActionPreference = "stop" -try { - Get-Command "msbuild" | Out-Null + # WDK VS component version (EWDK does not ship this metadata) + if ($result.Name -match '^EWDK') { + $result.WdkVsComponentVersion = '(not available for EWDK builds)' + } + else { + $vsComponent = Get-ChildItem "${env:ProgramData}\Microsoft\VisualStudio\Packages\Microsoft.Windows.DriverKit,version=*" -ErrorAction SilentlyContinue + if (-not $vsComponent) { + Write-Error "WDK Visual Studio Component not found. Ensure the WDK Component is installed." + exit 1 + } + $result.WdkVsComponentVersion = [regex]::Match($vsComponent.Name, '(\d+\.){3}\d+').Value + } + + return $result } -catch { - Write-Host "`u{274C} msbuild cannot be called from current environment. Check that msbuild is set in current path (for example, that it is called from a Visual Studio developer command)." - Write-Error "msbuild cannot be called from current environment." - exit 1 + +function Import-SampleExclusions { + <# + .SYNOPSIS + Loads exclusions.csv and returns exclusion objects applicable to the current build. + .DESCRIPTION + Each returned exclusion has: + - Pattern: dot-separated path (may contain wildcards, e.g. 'general.*') + - 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. + .NOTES + CSV format: Path,Configurations,MinBuild,MaxBuild,Reason + Example row: network\wlan\wdi,*,,27100,"failure introduced in VS17.14" + #> + param( + [string]$CsvPath, + [int]$BuildNumber + ) + + if (-not (Test-Path $CsvPath)) { + Write-Warning "Exclusions file not found: $CsvPath. No exclusions will be applied." + return @() + } + + $exclusions = [System.Collections.ArrayList]::new() + Import-Csv $CsvPath | ForEach-Object { + $pattern = $_.Path.Trim('\').Replace('\', '.').ToLower() + $configs = if ([string]::IsNullOrWhiteSpace($_.Configurations)) { '*' } else { $_.Configurations } + $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) { + [void]$exclusions.Add([PSCustomObject]@{ + Pattern = $pattern + Configurations = $configs + Reason = $_.Reason + }) + Write-Verbose "Exclusion applied: '$pattern' configs='$configs' reason='$($_.Reason)'" + } + else { + Write-Verbose "Exclusion skipped: '$pattern' - build $BuildNumber outside [$minBuild, $maxBuild]" + } + } + + return $exclusions.ToArray() +} + +function Get-DiskFreeGB { + <# + .SYNOPSIS Returns free disk space in GB for the current drive, or 'N/A' on error. + #> + try { + return [math]::Round((Get-Volume (Get-Item '.').PSDrive.Name).SizeRemaining / 1GB, 1) + } + catch { + return 'N/A' + } } -finally { - $ErrorActionPreference = $oldPreference + +# ============================================================================= +# Step 1 - Prepare Build Environment +# ============================================================================= + +$root = (Get-Location).Path + +Initialize-DevShell -ReturnToDirectory $root +Assert-MsBuildAvailable + +# ============================================================================= +# Step 2 - Calculate Parallelism +# ============================================================================= + +$throttleFactor = 5 +# Sum across all CPU sockets (Get-CimInstance returns an array on multi-socket systems) +$logicalProcessors = ((Get-CimInstance -Class CIM_Processor -Verbose:$false).NumberOfLogicalProcessors | Measure-Object -Sum).Sum + +if ($ThrottleLimit -eq 0) { + $ThrottleLimit = $throttleFactor * $logicalProcessors } -# -# Load sample list -# +$verbose = $PSBoundParameters.ContainsKey('Verbose') -and $PSBoundParameters['Verbose'] + +# ============================================================================= +# Step 3 - Prepare Log Directory +# ============================================================================= + +Remove-Item -Recurse -Path $LogFilesDirectory -ErrorAction SilentlyContinue +New-Item -ItemType Directory -Force -Path $LogFilesDirectory | Out-Null + +$reportHtmlPath = Join-Path $LogFilesDirectory "$ReportFileName.htm" +$reportCsvPath = Join-Path $LogFilesDirectory "$ReportFileName.csv" + +# ============================================================================= +# Step 4 - Load Sample List +# ============================================================================= + if ($Samples) { $sampleNames = $Samples } else { if (-not (Test-Path $SampleListPath)) { - Write-Error "Sample list file not found: $SampleListPath. Run .\ListAllSamples.ps1 first to generate Samples.txt." + Write-Error "Sample list not found: $SampleListPath. Run .\ListAllSamples.ps1 first." exit 1 } $sampleNames = Get-Content $SampleListPath | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } } -# Build the sampleSet hashtable: sampleName -> directory path -$sampleSet = @{} +# Map sample names to directory paths, validating each exists +$sampleSet = [ordered]@{} +$skippedCount = 0 foreach ($name in $sampleNames) { - $relativePath = $name.Replace('.', '\') - $fullPath = Join-Path $root $relativePath - $sampleSet[$name] = $fullPath + $fullPath = Join-Path $root ($name.Replace('.', '\')) + if (Test-Path $fullPath -PathType Container) { + $sampleSet[$name] = $fullPath + } + else { + Write-Warning "Sample directory not found, skipping: $name" + $skippedCount++ + } } -# -# Determine build environment -# -$build_environment = "" -$build_number = 0 -$nuget_package_version = 0 - -if ($env:GITHUB_REPOSITORY) { - $build_environment = "GitHub" - $nuget_package_version = ([regex]'(?<=x64\.)(\d+\.)(\d+\.)(\d+\.)(\d+)').Matches((Get-ChildItem .\packages\*WDK.x64* -Name)).Value - $build_number = $nuget_package_version.split('.')[2] -} -elseif (Test-Path(".\packages\*")) { - $build_environment = "NuGet" - $nuget_package_version = ([regex]'(?<=x64\.)(\d+\.)(\d+\.)(\d+\.)(\d+)').Matches((Get-ChildItem .\packages\*WDK.x64* -Name)).Value - $build_number = $nuget_package_version.split('.')[2] -} -elseif ($env:BuildLab -match '(?[^.]*).(?[^.]*).(?[^.]*)') { - $build_environment = "EWDK." + $Matches.branch + "." + $Matches.build + "." + $Matches.qfe - $build_number = $Matches.build -} -elseif ($env:UCRTVersion -match '10.0.(?.*).0') { - $build_environment = "WDK" - $build_number = $Matches.build -} -else { - Write-Output "Environment variables {" - Get-ChildItem env:* | Sort-Object name - Write-Output "Environment variables }" - Write-Error "Could not determine build environment." +if ($sampleSet.Count -eq 0) { + Write-Error "No valid sample directories found. Verify Samples.txt and current directory." exit 1 } -# Determine WDK Visual Studio Component version -if ($build_environment -match '^EWDK') { - $wdk_vs_component_ver = "(WDK Visual Studio Component Version is not included for EWDK builds)" -} -else { - $wdk_vs_component_ver = Get-ChildItem "${env:ProgramData}\Microsoft\VisualStudio\Packages\Microsoft.Windows.DriverKit,version=*" -ErrorAction SilentlyContinue - if (-not $wdk_vs_component_ver) { - Write-Error "WDK Visual Studio Component version not found. Please ensure the WDK Component is installed." - exit 1 - } - $wdk_vs_component_ver = [regex]::Match($wdk_vs_component_ver.Name, '(\d+\.){3}\d+').Value -} +# ============================================================================= +# Step 5 - Detect Build Environment +# ============================================================================= + +$buildEnv = Resolve-BuildEnvironment -RepoRoot $root +$buildNumber = $buildEnv.BuildNumber +# ============================================================================= +# Step 6 - Determine InfVerif Options +# ============================================================================= # -# InfVerif_AdditionalOptions +# Samples must build cleanly, but certain InfVerif warnings are acceptable because +# they flag issues intentionally present in samples (to be fixed when productizing). +# <= 22621: suppress individual warnings /sw1284 /sw1285 /sw1293 /sw2083 /sw2086 +# > 22621: these are grouped under /samples # if ($InfOptions) { - $InfVerif_AdditionalOptions = $InfOptions + $infVerifOptions = $InfOptions } else { - $InfVerif_AdditionalOptions = ($build_number -le 22621 ? "/sw1284 /sw1285 /sw1293 /sw2083 /sw2086" : "/samples") + $infVerifOptions = if ($buildNumber -le 22621) { '/sw1284 /sw1285 /sw1293 /sw2083 /sw2086' } else { '/samples' } } -# -# Load exclusions from exclusions.csv -# -$exclusionConfigurations = @{} -$exclusionReasons = @{} -Import-Csv 'exclusions.csv' | ForEach-Object { - $excluded_driver = $_.Path.Replace($root, '').Trim('\').Replace('\', '.').ToLower() - $excluded_configurations = ($_.configurations -eq '' ? '*' : $_.configurations) - $excluded_minbuild = ($_.MinBuild -eq '' ? 00000 : $_.MinBuild) - $excluded_maxbuild = ($_.MaxBuild -eq '' ? 99999 : $_.MaxBuild) - if (($excluded_minbuild -le $build_number) -and ($build_number -le $excluded_maxbuild)) { - $exclusionConfigurations[$excluded_driver] = $excluded_configurations - $exclusionReasons[$excluded_driver] = $_.Reason - Write-Verbose "Exclusion.csv entry applied for '$excluded_driver' for configuration '$excluded_configurations'." - } - else { - Write-Verbose "Exclusion.csv entry not applied for '$excluded_driver' due to build number." - } -} +# ============================================================================= +# Step 7 - Load Exclusions +# ============================================================================= -# -# Build all samples -# -$jresult = @{ - SolutionsBuilt = 0 - SolutionsSucceeded = 0 - SolutionsExcluded = 0 - SolutionsUnsupported = 0 - SolutionsFailed = 0 - SolutionsSporadic = 0 - Results = @() - FailSet = @() - SporadicSet = @() - lock = [System.Threading.Mutex]::new($false) -} +$exclusions = Import-SampleExclusions -CsvPath (Join-Path $root 'exclusions.csv') -BuildNumber $buildNumber -$SolutionsTotal = $sampleSet.Count * $Configurations.Count * $Platforms.Count +# ============================================================================= +# Step 8 - Print Build Plan +# ============================================================================= -Write-Output "WDK Build Environment: $build_environment" -Write-Output "WDK Build Number: $build_number" -if (($build_environment -eq "GitHub") -or ($build_environment -eq "NuGet")) { - Write-Output "WDK Nuget Version: $nuget_package_version" +$combinationsTotal = $sampleSet.Count * $Configurations.Count * $Platforms.Count + +Write-Output "" +Write-Output "--- WDK Sample Build Plan ------------------------------------------" +Write-Output " Environment: $($buildEnv.Name)" +Write-Output " Build Number: $buildNumber" +if ($buildEnv.NuGetVersion) { + Write-Output " NuGet Version: $($buildEnv.NuGetVersion)" } -Write-Output "WDK Visual Studio Component Version: $wdk_vs_component_ver" -Write-Output "Samples: $($sampleSet.Count)" -Write-Output "Configurations: $($Configurations.Count) ($Configurations)" -Write-Output "Platforms: $($Platforms.Count) ($Platforms)" -Write-Output "InfVerif_AdditionalOptions: $InfVerif_AdditionalOptions" -Write-Output "Combinations: $SolutionsTotal" -Write-Output "LogicalProcessors: $LogicalProcessors" -Write-Output "ThrottleFactor: $ThrottleFactor" -Write-Output "ThrottleLimit: $ThrottleLimit" -Write-Output "WDS_WipeOutputs: $env:WDS_WipeOutputs" -Write-Output "Disk Remaining (GB): $(((Get-Volume ((Get-Item ".").PSDrive.Name)).SizeRemaining) / 1GB)" +Write-Output " WDK VS Component: $($buildEnv.WdkVsComponentVersion)" +Write-Output " InfVerif Options: $infVerifOptions" Write-Output "" -Write-Output "T: Combinations" -Write-Output "B: Built" -Write-Output "R: Build is running currently" -Write-Output "P: Build is pending an available build slot" +Write-Output " Samples: $($sampleSet.Count) ($skippedCount skipped)" +Write-Output " Configurations: $($Configurations -join ', ')" +Write-Output " Platforms: $($Platforms -join ', ')" +Write-Output " Combinations: $combinationsTotal" +Write-Output " Exclusions: $($exclusions.Count)" Write-Output "" -Write-Output "S: Built and result was 'Succeeded'" -Write-Output "E: Built and result was 'Excluded'" -Write-Output "U: Built and result was 'Unsupported' (Platform and Configuration combination)" -Write-Output "F: Built and result was 'Failed'" -Write-Output "O: Built and result was 'Sporadic'" +Write-Output " Parallelism: $ThrottleLimit jobs ($logicalProcessors cores x $throttleFactor)" +Write-Output " Disk Free (GB): $(Get-DiskFreeGB)" +Write-Output " Wipe Outputs: $(-not [string]::IsNullOrEmpty($env:WDS_WipeOutputs))" +Write-Output "--------------------------------------------------------------------" +Write-Output "" +Write-Output "Progress legend:" +Write-Output " T=Total B=Built R=Running P=Pending" +Write-Output " S=Succeeded E=Excluded U=Unsupported F=Failed O=Sporadic" Write-Output "" Write-Output "Building all combinations..." -$sw = [Diagnostics.Stopwatch]::StartNew() +# ============================================================================= +# Step 9 - Execute Parallel Builds +# ============================================================================= + +# Shared mutable state protected by a Mutex. This is required because +# ForEach-Object -Parallel runs each iteration in a separate runspace, +# so standard .NET locks (Monitor/lock) do not work across runspaces. +$buildState = @{ + Built = 0 + Succeeded = 0 + Excluded = 0 + Unsupported = 0 + Failed = 0 + Sporadic = 0 + Results = @() + FailSet = @() + SporadicSet = @() + Lock = [System.Threading.Mutex]::new($false) +} + +$stopwatch = [Diagnostics.Stopwatch]::StartNew() $sampleSet.GetEnumerator() | ForEach-Object -ThrottleLimit $ThrottleLimit -Parallel { - $LogFilesDirectory = $using:LogFilesDirectory - $exclusionConfigurations = $using:exclusionConfigurations - $exclusionReasons = $using:exclusionReasons - $Configurations = $using:Configurations - $Platforms = $using:Platforms - $InfVerif_AdditionalOptions = $using:InfVerif_AdditionalOptions - $Verbose = $using:Verbose + # --- Import shared state from parent scope --- + $logDir = $using:LogFilesDirectory + $exclusions = $using:exclusions + $configs = $using:Configurations + $platforms = $using:Platforms + $infOpts = $using:infVerifOptions + $isVerbose = $using:verbose + $state = $using:buildState + $total = $using:combinationsTotal + $throttle = $using:ThrottleLimit $sampleName = $_.Key - $directory = $_.Value - - $ResultElement = New-Object psobject - Add-Member -InputObject $ResultElement -MemberType NoteProperty -Name Sample -Value "$sampleName" - - foreach ($configuration in $Configurations) { - foreach ($platform in $Platforms) { - $thisunsupported = 0 - $thisfailed = 0 - $thissporadic = 0 - $thisexcluded = 0 - $thissucceeded = 0 - $thisresult = "Not run" - $thisfailset = @() - $thissporadicset = @() - - if ($exclusionConfigurations.ContainsKey($sampleName) -and ($exclusionConfigurations[$sampleName].Split(';') | Where-Object { "$configuration|$platform" -like $_ })) { - Write-Verbose "[$sampleName $configuration|$platform] `u{23E9} Excluded and skipped. Reason: $($exclusionReasons[$sampleName])" - $thisexcluded += 1 - $thisresult = "Excluded" + $directory = $_.Value + + # Build a result row: one column per configuration|platform combination + $resultRow = [PSCustomObject]@{ Sample = $sampleName } + + foreach ($configuration in $configs) { + foreach ($platform in $platforms) { + $result = 'Not run' + $succeededDelta = 0 + $excludedDelta = 0 + $unsupportedDelta = 0 + $failedDelta = 0 + $sporadicDelta = 0 + $failEntry = $null + $sporadicEntry = $null + + # -- Check exclusions (supports wildcard paths like 'general.*') -- + $exclusionReason = $null + foreach ($excl in $exclusions) { + if ($sampleName -like $excl.Pattern) { + $configKey = "$configuration|$platform" + foreach ($cfgPattern in $excl.Configurations.Split(';')) { + if ($configKey -like $cfgPattern) { + $exclusionReason = $excl.Reason + break + } + } + if ($exclusionReason) { break } + } + } + + if ($exclusionReason) { + Write-Verbose "[$sampleName $configuration|$platform] Excluded: $exclusionReason" + $excludedDelta = 1 + $result = 'Excluded' } else { - .\Build-Sample -Directory $directory -SampleName $sampleName -LogFilesDirectory $LogFilesDirectory -Configuration $configuration -Platform $platform -InfVerif_AdditionalOptions $InfVerif_AdditionalOptions -Verbose:$Verbose - if ($LASTEXITCODE -eq 0) { - $thissucceeded += 1 - $thisresult = "Succeeded" - } - elseif ($LASTEXITCODE -eq 1) { - $thisfailset += "$sampleName $configuration|$platform" - $thisfailed += 1 - $thisresult = "Failed" - } - elseif ($LASTEXITCODE -eq 2) { - $thissporadicset += "$sampleName $configuration|$platform" - $thissporadic += 1 - $thisresult = "Sporadic" - } - else { - $thisunsupported += 1 - $thisresult = "Unsupported" + # -- Build the sample -- + .\Build-Sample -Directory $directory -SampleName $sampleName ` + -LogFilesDirectory $logDir -Configuration $configuration ` + -Platform $platform -InfVerif_AdditionalOptions $infOpts ` + -Verbose:$isVerbose + + # Exit codes from Build-Sample.ps1: + # 0 = succeeded on first attempt + # 1 = failed after all retries + # 2 = sporadic (failed first, succeeded on retry) + # 3 = unsupported configuration/platform + switch ($LASTEXITCODE) { + 0 { $succeededDelta = 1; $result = 'Succeeded' } + 1 { $failedDelta = 1; $result = 'Failed'; $failEntry = "$sampleName $configuration|$platform" } + 2 { $sporadicDelta = 1; $result = 'Sporadic'; $sporadicEntry = "$sampleName $configuration|$platform" } + default { $unsupportedDelta = 1; $result = 'Unsupported' } } } - Add-Member -InputObject $ResultElement -MemberType NoteProperty -Name "$configuration|$platform" -Value "$thisresult" - $null = ($using:jresult).lock.WaitOne() + $resultRow | Add-Member -MemberType NoteProperty -Name "$configuration|$platform" -Value $result + + # -- Update shared counters (under lock) -- + $null = $state.Lock.WaitOne() try { - ($using:jresult).SolutionsBuilt += 1 - ($using:jresult).SolutionsSucceeded += $thissucceeded - ($using:jresult).SolutionsExcluded += $thisexcluded - ($using:jresult).SolutionsUnsupported += $thisunsupported - ($using:jresult).SolutionsFailed += $thisfailed - ($using:jresult).SolutionsSporadic += $thissporadic - ($using:jresult).FailSet += $thisfailset - ($using:jresult).SporadicSet += $thissporadicset - $SolutionsTotal = $using:SolutionsTotal - $ThrottleLimit = $using:ThrottleLimit - $SolutionsBuilt = ($using:jresult).SolutionsBuilt - $SolutionsRemaining = $SolutionsTotal - $SolutionsBuilt - $SolutionsRunning = if ($SolutionsRemaining -ge $ThrottleLimit) { $ThrottleLimit } else { $SolutionsRemaining } - $SolutionsPending = if ($SolutionsRemaining -ge $ThrottleLimit) { ($SolutionsRemaining - $ThrottleLimit) } else { 0 } - $SolutionsBuiltPercent = [Math]::Round(100 * ($SolutionsBuilt / $using:SolutionsTotal)) - $TBRP = "T:" + ($SolutionsTotal) + "; B:" + (($using:jresult).SolutionsBuilt) + "; R:" + ($SolutionsRunning) + "; P:" + ($SolutionsPending) - $rstr = "S:" + (($using:jresult).SolutionsSucceeded) + "; E:" + (($using:jresult).SolutionsExcluded) + "; U:" + (($using:jresult).SolutionsUnsupported) + "; F:" + (($using:jresult).SolutionsFailed) + "; O:" + (($using:jresult).SolutionsSporadic) - Write-Progress -Activity "Building combinations" -Status "$SolutionsBuilt of $using:SolutionsTotal combinations built ($SolutionsBuiltPercent%) | $TBRP | $rstr" -PercentComplete $SolutionsBuiltPercent + $state.Built += 1 + $state.Succeeded += $succeededDelta + $state.Excluded += $excludedDelta + $state.Unsupported += $unsupportedDelta + $state.Failed += $failedDelta + $state.Sporadic += $sporadicDelta + if ($failEntry) { $state.FailSet += $failEntry } + if ($sporadicEntry) { $state.SporadicSet += $sporadicEntry } + + # Update progress bar + $built = $state.Built + $remaining = $total - $built + $running = [Math]::Min($remaining, $throttle) + $pending = [Math]::Max($remaining - $throttle, 0) + $pct = [Math]::Round(100 * $built / $total) + + $statusLine = "$built of $total combinations built ($pct%) | " + + "T:$total; B:$built; R:$running; P:$pending | " + + "S:$($state.Succeeded); E:$($state.Excluded); U:$($state.Unsupported); F:$($state.Failed); O:$($state.Sporadic)" + + # Write-Host with carriage return for a single-line progress indicator. + # Write-Progress does not reliably render from -Parallel runspaces. + Write-Host "`rBuilding combinations [$statusLine]" -NoNewline } finally { - ($using:jresult).lock.ReleaseMutex() + $state.Lock.ReleaseMutex() } } } - $null = ($using:jresult).lock.WaitOne() + + # Append the completed result row + $null = $state.Lock.WaitOne() try { - ($using:jresult).Results += $ResultElement + $state.Results += $resultRow } finally { - ($using:jresult).lock.ReleaseMutex() + $state.Lock.ReleaseMutex() } } -$sw.Stop() +$stopwatch.Stop() + +# End the progress line +Write-Host "" + +# ============================================================================= +# Step 10 - Report Failures +# ============================================================================= Write-Output "" -if ($jresult.FailSet.Count -gt 0) { - Write-Output "Some combinations were built with errors:" - $jresult.FailSet = $jresult.FailSet | Sort-Object - foreach ($failedSample in $jresult.FailSet) { - $failedSample -match "^(.*) (\w*)\|(\w*)$" | Out-Null - $failName = $Matches[1] - $failConfiguration = $Matches[2] - $failPlatform = $Matches[3] - Write-Output "Build errors in Sample $failName; Configuration: $failConfiguration; Platform: $failPlatform {" - Get-Content "$LogFilesDirectory\$failName.$failConfiguration.$failPlatform.0.err" | Write-Output - Write-Output "} $failedSample" +if ($buildState.FailSet.Count -gt 0) { + Write-Output "--- Build Failures -------------------------------------------------" + foreach ($entry in ($buildState.FailSet | Sort-Object)) { + if ($entry -match '^(?.*)\s+(?\w+)\|(?\w+)$') { + $errLog = Join-Path $LogFilesDirectory "$($Matches.name).$($Matches.config).$($Matches.platform).0.err" + Write-Output " [FAIL] $($Matches.name) ($($Matches.config)|$($Matches.platform)):" + if (Test-Path $errLog) { + Get-Content $errLog | ForEach-Object { Write-Output " $_" } + } + else { + Write-Output " (error log not found: $errLog)" + } + } } - Write-Error "Some combinations were built with errors." Write-Output "" + Write-Error "Some combinations were built with errors." } -if ($jresult.SporadicSet.Count -gt 0) { - Write-Output "Some combinations were built with sporadic error:" - $jresult.SporadicSet = $jresult.SporadicSet | Sort-Object - foreach ($sporadicSample in $jresult.SporadicSet) { - $sporadicSample -match "^(.*) (\w*)\|(\w*)$" | Out-Null - $sporadicName = $Matches[1] - $sporadicConfiguration = $Matches[2] - $sporadicPlatform = $Matches[3] - Write-Output "Build sporadic errors in Sample $sporadicName; Configuration: $sporadicConfiguration; Platform: $sporadicPlatform {" - Get-Content "$LogFilesDirectory\$sporadicName.$sporadicConfiguration.$sporadicPlatform.0.err" | Write-Output - Write-Output "} $sporadicSample" +if ($buildState.SporadicSet.Count -gt 0) { + Write-Output "--- Sporadic Failures (succeeded on retry) -------------------------" + foreach ($entry in ($buildState.SporadicSet | Sort-Object)) { + if ($entry -match '^(?.*)\s+(?\w+)\|(?\w+)$') { + $errLog = Join-Path $LogFilesDirectory "$($Matches.name).$($Matches.config).$($Matches.platform).0.err" + Write-Output " [SPORADIC] $($Matches.name) ($($Matches.config)|$($Matches.platform)):" + if (Test-Path $errLog) { + Get-Content $errLog | ForEach-Object { Write-Output " $_" } + } + } } - Write-Error "Some combinations were built with sporadic errors." Write-Output "" + Write-Error "Some combinations had sporadic build failures." } -# Display timer statistics -$min = $sw.Elapsed.Minutes -$seconds = $sw.Elapsed.Seconds +# ============================================================================= +# Step 11 - Final Summary +# ============================================================================= -$SolutionsSucceeded = $jresult.SolutionsSucceeded -$SolutionsExcluded = $jresult.SolutionsExcluded -$SolutionsUnsupported = $jresult.SolutionsUnsupported -$SolutionsFailed = $jresult.SolutionsFailed -$SolutionsSporadic = $jresult.SolutionsSporadic -$Results = $jresult.Results +$elapsed = $stopwatch.Elapsed -Write-Output "Built all combinations." +Write-Output "--- Build Complete -------------------------------------------------" +Write-Output " Elapsed: $($elapsed.Minutes)m $($elapsed.Seconds)s" +Write-Output " Disk Free (GB): $(Get-DiskFreeGB)" Write-Output "" -Write-Output "Elapsed time: $min minutes, $seconds seconds." -Write-Output ("Disk Remaining (GB): " + (((Get-Volume (Get-Item ".").PSDrive.Name).SizeRemaining / 1GB))) -Write-Output ("Samples: " + $sampleSet.Count) -Write-Output ("Configurations: " + $Configurations.Count + " (" + $Configurations + ")") -Write-Output ("Platforms: " + $Platforms.Count + " (" + $Platforms + ")") -Write-Output "Combinations: $SolutionsTotal" -Write-Output "Succeeded: $SolutionsSucceeded" -Write-Output "Excluded: $SolutionsExcluded" -Write-Output "Unsupported: $SolutionsUnsupported" -Write-Output "Failed: $SolutionsFailed" -Write-Output "Sporadic: $SolutionsSporadic" -Write-Output "Log files directory: $LogFilesDirectory" -Write-Output "Overview report: $reportFilePath" +Write-Output " Samples: $($sampleSet.Count)" +Write-Output " Configurations: $($Configurations -join ', ')" +Write-Output " Platforms: $($Platforms -join ', ')" +Write-Output " Combinations: $combinationsTotal" Write-Output "" - -$Results | Sort-Object { $_.Sample } | ConvertTo-Csv | Out-File $reportCsvFilePath -$Results | Sort-Object { $_.Sample } | ConvertTo-Html -Title "Overview" | Out-File $reportFilePath -Invoke-Item $reportFilePath +Write-Output " Succeeded: $($buildState.Succeeded)" +Write-Output " Excluded: $($buildState.Excluded)" +Write-Output " Unsupported: $($buildState.Unsupported)" +Write-Output " Failed: $($buildState.Failed)" +Write-Output " Sporadic: $($buildState.Sporadic)" +Write-Output "" +Write-Output " Log directory: $LogFilesDirectory" +Write-Output " CSV report: $reportCsvPath" +Write-Output " HTML report: $reportHtmlPath" +Write-Output "--------------------------------------------------------------------" + +# ============================================================================= +# Step 12 - Generate Reports +# ============================================================================= + +$sortedResults = $buildState.Results | Sort-Object { $_.Sample } +$sortedResults | ConvertTo-Csv | Out-File $reportCsvPath +$sortedResults | ConvertTo-Html -Title "WDK Sample Build Overview" | Out-File $reportHtmlPath + +# Only open the HTML report interactively (not in CI/automation) +if (-not $env:GITHUB_REPOSITORY -and -not $env:BUILD_BUILDID -and [Environment]::UserInteractive) { + Invoke-Item $reportHtmlPath +} diff --git a/ListAllSamples.ps1 b/ListAllSamples.ps1 index ed87fc831..f533c0802 100644 --- a/ListAllSamples.ps1 +++ b/ListAllSamples.ps1 @@ -4,7 +4,7 @@ .DESCRIPTION Searches for all .sln files recursively from the repo root, excludes NuGet package directories - (paths starting with 'packages.'), computes a normalized sample name for each, and writes + (paths containing 'packages' as a segment), computes a normalized sample name for each, and writes the sorted list to Samples.txt (one sample name per line). The sample name is derived from the relative directory path: backslashes are replaced with dots diff --git a/Samples.txt b/Samples.txt index 7998f3950..571b6b4cc 100644 --- a/Samples.txt +++ b/Samples.txt @@ -1,4 +1,4 @@ -audio.acx.samples.audiocodec.driver +audio.acx.samples.audiocodec.driver audio.simpleaudiosample audio.soundwire.samples.sdcavad audio.sysvad @@ -61,8 +61,8 @@ network.modem.fakemodem network.ndis.extension network.ndis.filter network.ndis.mux -network.ndis.ndisprot.6x network.ndis.ndisprot_kmdf +network.ndis.ndisprot.6x network.ndis.netvmini.6x network.radio.radiomanagersample network.trans.ddproxy From 05b65dac08c551a94e1d7fc282e35c546e00472e Mon Sep 17 00:00:00 2001 From: "Junyan Liu (Centific Technologies Inc)" Date: Thu, 26 Mar 2026 00:10:49 -0700 Subject: [PATCH 13/20] removing unused workflow --- .github/workflows/StaleIssues.yml | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 .github/workflows/StaleIssues.yml diff --git a/.github/workflows/StaleIssues.yml b/.github/workflows/StaleIssues.yml deleted file mode 100644 index d3a3776a3..000000000 --- a/.github/workflows/StaleIssues.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: Close inactive issues -on: - workflow_dispatch: -jobs: - close-issues: - runs-on: ubuntu-latest - permissions: - issues: write - steps: - - uses: actions/stale@v10 - with: - days-before-issue-stale: 365 - stale-issue-label: "stale" - stale-issue-message: "This issue has been inactive for a year. It will be closed in 31 days if no further activity occurs. If you believe this issue is still relevant, please comment to keep it open." - operations-per-run: 400 - repo-token: ${{ secrets.GITHUB_TOKEN }} From 302d18984142a22d5195105fe0347eb5b145d859 Mon Sep 17 00:00:00 2001 From: 5an7y Date: Fri, 27 Mar 2026 16:04:47 -0700 Subject: [PATCH 14/20] Remove Samples.txt: discover samples dynamically via ListAllSamples - ListAllSamples.ps1: output sorted sample names to stdout instead of writing Samples.txt. The file output is replaced with Write-Output so callers can capture results via pipeline or command substitution. - Build-Samples.ps1: remove SampleListPath parameter. Default discovery now calls ListAllSamples.ps1 at runtime and consumes its stdout. Explicit -Samples array still works and is sorted alphabetically. Both paths guarantee a consistent alphabetical sample ordering. - Samples.txt: deleted. No longer needed as a pre-generated artifact. WDS_TestPass.cs is unaffected - it only passes -LogFilesDirectory and -InfOptions, neither of which changed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- Build-Samples.ps1 | 33 +++++------ ListAllSamples.ps1 | 14 ++--- Samples.txt | 134 --------------------------------------------- 3 files changed, 21 insertions(+), 160 deletions(-) delete mode 100644 Samples.txt diff --git a/Build-Samples.ps1 b/Build-Samples.ps1 index 6fd86bd37..aad2d3e53 100644 --- a/Build-Samples.ps1 +++ b/Build-Samples.ps1 @@ -6,7 +6,7 @@ This is the main build orchestrator for driver samples. It performs these steps: 1. Ensures a developer build environment (VS DevShell or EWDK) is active - 2. Reads sample names from Samples.txt (or a specified file/array) + 2. Discovers samples via ListAllSamples.ps1 (or uses the -Samples parameter if provided) 3. Detects the build environment (GitHub CI, NuGet, EWDK, or WDK) and build number 4. Loads exclusions from exclusions.csv (supports wildcard paths) 5. Builds all non-excluded sample/configuration/platform combinations in parallel @@ -15,15 +15,12 @@ Requires PowerShell 7+ (uses ForEach-Object -Parallel). Typical call chain: - Build-AllSamples.ps1 -> ListAllSamples.ps1 -> Build-Samples.ps1 -> Build-Sample.ps1 - (this script) + Build-AllSamples.ps1 -> Build-Samples.ps1 -> ListAllSamples.ps1 (for discovery) + (this script) -> Build-Sample.ps1 (per sample) -.PARAMETER SampleListPath - Path to the file containing sample names (one per line, dot-separated). - Defaults to Samples.txt in the current directory. .PARAMETER Samples - Optional array of specific sample names to build. When provided, overrides SampleListPath. + Optional array of specific sample names to build. When omitted, all samples are discovered dynamically via ListAllSamples.ps1. .PARAMETER Configurations Build configurations (e.g. 'Debug','Release'). Defaults to $env:WDS_Configuration or @@ -49,7 +46,7 @@ .EXAMPLE .\Build-Samples - Builds all samples from Samples.txt with default settings. + Discovers all samples via ListAllSamples.ps1 and builds them with default settings. .EXAMPLE .\Build-Samples -Samples 'audio.acx.samples.audiocodec.driver','usb.kmdf_fx2' -Configurations 'Debug' -Platforms 'x64' @@ -57,16 +54,15 @@ Builds specific samples for a single configuration and platform. .EXAMPLE - .\Build-Samples -SampleListPath .\MySamples.txt -ThrottleLimit 8 + .\Build-Samples -ThrottleLimit 8 - Builds samples from a custom list with limited parallelism. + Discovers all samples and builds them with limited parallelism. #> #Requires -Version 7.0 [CmdletBinding()] param( - [string]$SampleListPath = (Join-Path (Get-Location) "Samples.txt"), [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 }), @@ -282,14 +278,15 @@ $reportCsvPath = Join-Path $LogFilesDirectory "$ReportFileName.csv" # ============================================================================= if ($Samples) { - $sampleNames = $Samples + # Explicit list passed by the caller — use as-is, sorted alphabetically. + $sampleNames = $Samples | Sort-Object } else { - if (-not (Test-Path $SampleListPath)) { - Write-Error "Sample list not found: $SampleListPath. Run .\ListAllSamples.ps1 first." - exit 1 - } - $sampleNames = Get-Content $SampleListPath | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } + # Default: discover samples dynamically via ListAllSamples.ps1. + # ListAllSamples outputs one alphabetically-sorted sample name per line to stdout. + Write-Verbose "No -Samples provided. Discovering samples via ListAllSamples.ps1..." + $sampleNames = & (Join-Path $PSScriptRoot 'ListAllSamples.ps1') -Verbose:$verbose | + Where-Object { -not [string]::IsNullOrWhiteSpace($_) } } # Map sample names to directory paths, validating each exists @@ -307,7 +304,7 @@ foreach ($name in $sampleNames) { } if ($sampleSet.Count -eq 0) { - Write-Error "No valid sample directories found. Verify Samples.txt and current directory." + Write-Error "No valid sample directories found. Ensure ListAllSamples.ps1 is available in the repo root." exit 1 } diff --git a/ListAllSamples.ps1 b/ListAllSamples.ps1 index f533c0802..1a1a4a784 100644 --- a/ListAllSamples.ps1 +++ b/ListAllSamples.ps1 @@ -1,11 +1,11 @@ <# .SYNOPSIS - Enumerates all available sample solutions in the repository and writes them to Samples.txt. + Enumerates all available sample solutions in the repository and writes them to the console. .DESCRIPTION Searches for all .sln files recursively from the repo root, excludes NuGet package directories (paths containing 'packages' as a segment), computes a normalized sample name for each, and writes - the sorted list to Samples.txt (one sample name per line). + the sorted list to stdout (one sample name per line). The sample name is derived from the relative directory path: backslashes are replaced with dots and the result is lowercased. @@ -13,10 +13,10 @@ .EXAMPLE .\ListAllSamples - Discovers all samples and writes Samples.txt to the repo root. + Discovers all samples and writes the sorted names to the console. .OUTPUTS - Samples.txt in the current working directory. + Sorted sample names written to stdout, one per line. #> [CmdletBinding()] @@ -45,7 +45,5 @@ foreach ($file in $solutionFiles) { $sortedNames = $sampleNames.Keys | Sort-Object -$outputPath = Join-Path $root "Samples.txt" -$sortedNames | Out-File -FilePath $outputPath -Encoding utf8 - -Write-Output "Found $($sortedNames.Count) samples. Written to Samples.txt" +Write-Verbose "Found $($sortedNames.Count) samples." +$sortedNames | Write-Output diff --git a/Samples.txt b/Samples.txt deleted file mode 100644 index 571b6b4cc..000000000 --- a/Samples.txt +++ /dev/null @@ -1,134 +0,0 @@ -audio.acx.samples.audiocodec.driver -audio.simpleaudiosample -audio.soundwire.samples.sdcavad -audio.sysvad -avstream.avscamera -avstream.avshws -avstream.avssamp -avstream.sampledevicemft -avstream.samplemft0 -bluetooth.bthecho -bluetooth.serialhcibus -filesys.cdfs -filesys.fastfat -filesys.minifilter.avscan -filesys.minifilter.cancelsafe -filesys.minifilter.cdo -filesys.minifilter.change -filesys.minifilter.ctx -filesys.minifilter.delete -filesys.minifilter.metadatamanager -filesys.minifilter.minispy -filesys.minifilter.namechanger -filesys.minifilter.nullfilter -filesys.minifilter.passthrough -filesys.minifilter.scanner -filesys.minifilter.simrep -filesys.minifilter.swapbuffers -general.cancel -general.dchu.osrfx2_dchu_base -general.dchu.osrfx2_dchu_extension_loose -general.dchu.osrfx2_dchu_extension_tight -general.echo.kmdf -general.echo.umdf2 -general.event -general.ioctl.kmdf -general.ioctl.wdm -general.obcallback -general.pcidrv -general.perfcounters.kcs -general.plx9x5x -general.registry.regfltr -general.simplemediasource -general.systemdma.wdm -general.toaster.toastdrv -general.toaster.toastpkg -general.toaster.umdf2 -general.tracing.evntdrv -general.tracing.systemtracecontrol -general.tracing.tracedriver -gnss -gpio.samples -hid.firefly -hid.hclient -hid.hidusbfx2 -hid.vhidmini2 -input.kbfiltr -input.layout -input.moufiltr -network.config.bindview -network.modem.fakemodem -network.ndis.extension -network.ndis.filter -network.ndis.mux -network.ndis.ndisprot_kmdf -network.ndis.ndisprot.6x -network.ndis.netvmini.6x -network.radio.radiomanagersample -network.trans.ddproxy -network.trans.inspect -network.trans.msnmntr -network.trans.stmedit -network.trans.wfpsampler -network.wlan.wdi -network.wsk.echosrv -network.wwan.cxwmbclass -nfc.nfccxsample -nfp.net -pofx.pep -pofx.umdf2 -pofx.wdf -pos.drivers.barcodescanner -pos.drivers.magneticstripereader -powerlimit.plclient -powerlimit.plpolicy -prm -sd.miniport.sdhc -security.elam -sensors.activity -sensors.adxl345acc -sensors.customsensors -sensors.fusion -sensors.pedometer -sensors.sensorscombodriver -sensors.simpledeviceorientationsensor -serial.serenum -serial.serial -serial.virtualserial2 -setup.devcon -simbatt.func -smartcrd -spb.skeletoni2c -spb.spbtesttool -storage.class.classpnp -storage.class.disk -storage.iscsi -storage.miniports.lsi_u3 -storage.miniports.storahci -storage.msdsm -storage.tools.spti -thermal.simsensor -thermal.thermalclient -tools.dv.samples.dv-faildriver-wdm.driver -tools.kasan.samples.kasandemo-wdm -tools.sdv.samples.sdv-faildriver-kmdf -tools.sdv.samples.sdv-faildriver-ndis -tools.sdv.samples.sdv-faildriver-storport -tools.sdv.samples.sdv-faildriver-wdm -tree -usb.kmdf_enumswitches -usb.kmdf_fx2 -usb.ucmcxucsi -usb.ucmtcpcicxclientsample -usb.ucmucsiacpisample -usb.ufxclientsample -usb.umdf2_fx2 -usb.usbsamp -usb.usbview -usb.wdf_osrfx2_lab -video.archive.pixlib -video.indirectdisplay -video.kmdod -wia -wmi.wmiacpi -wmi.wmisamp From 4d94b8bf0d05c294b61087b395843a868789d911 Mon Sep 17 00:00:00 2001 From: 5an7y Date: Mon, 30 Mar 2026 12:00:47 -0700 Subject: [PATCH 15/20] Revert exclusions.csv to match main --- exclusions.csv | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/exclusions.csv b/exclusions.csv index fbfefa25c..63d5e24a9 100644 --- a/exclusions.csv +++ b/exclusions.csv @@ -6,8 +6,8 @@ network\trans\WFPSampler,Debug|ARM64,,22621,Only NI: Only ARM: Fails to build on 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,*,,27100,"failure introduced in VS17.14, suppressed until fix" -serial\serial,*,,27100,"failure introduced in VS17.14, suppressed until fix" -network\wlan\wdi,*,,27100,"failure introduced in VS17.14, suppressed until fix" -tools\kasan\samples\kasandemo-wdm,*|x64,,27100,"failure introduced in VS17.14, suppressed until fix" +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 d92950792737971182298c34d7efa445fbb23728 Mon Sep 17 00:00:00 2001 From: 5an7y Date: Mon, 30 Mar 2026 15:26:00 -0700 Subject: [PATCH 16/20] Remove Build-AllSamples.ps1 and Build-SampleSet.ps1 in favor of Build-Samples.ps1 - Delete Build-AllSamples.ps1 and Build-SampleSet.ps1 (replaced by Build-Samples.ps1) - Update ci.yml workflow to call Build-Samples.ps1 - Update Build-ChangedSamples.ps1 to call Build-Samples.ps1 - Rewrite Building-Locally.md Step 6 with new script usage and output format - Update Step 7 NuGet notes to reference Build-Samples.ps1 --- .github/scripts/Build-ChangedSamples.ps1 | 7 +- .github/workflows/ci.yml | 2 +- Build-AllSamples.ps1 | 71 ----- Build-SampleSet.ps1 | 375 ----------------------- Building-Locally.md | 104 ++++--- 5 files changed, 58 insertions(+), 501 deletions(-) delete mode 100644 Build-AllSamples.ps1 delete mode 100644 Build-SampleSet.ps1 diff --git a/.github/scripts/Build-ChangedSamples.ps1 b/.github/scripts/Build-ChangedSamples.ps1 index bdaee943c..29f990612 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-AllSamples.ps1" -or $filename -eq "Build-Sample.ps1" -or $filename -eq "Build-SampleSet.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 "Build-Sample.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\*") { @@ -52,9 +52,10 @@ foreach ($file in $ChangedFiles) { } if ($buildAll) { - .\Build-AllSamples -Verbose:$Verbose -LogFilesDirectory (Join-Path $root "_logs") + .\Build-Samples -Verbose:$Verbose -LogFilesDirectory (Join-Path $root "_logs") } else { - .\Build-SampleSet -SampleSet $sampleSet -Verbose:$Verbose -LogFilesDirectory (Join-Path $root "_logs") + $sampleNames = $sampleSet.Keys | Sort-Object + .\Build-Samples -Samples $sampleNames -Verbose:$Verbose -LogFilesDirectory (Join-Path $root "_logs") } diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1f3d76930..0e847b35c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,7 +29,7 @@ jobs: run: nuget restore .\packages.config -PackagesDirectory .\packages\ - name: Retrieve and build all available solutions - run: .\Build-AllSamples.ps1 -Verbose + run: .\Build-Samples.ps1 -Verbose env: WDS_Configuration: ${{ matrix.configuration }} WDS_Platform: ${{ matrix.platform }} diff --git a/Build-AllSamples.ps1 b/Build-AllSamples.ps1 deleted file mode 100644 index 6b3a19765..000000000 --- a/Build-AllSamples.ps1 +++ /dev/null @@ -1,71 +0,0 @@ -<# -.SYNOPSIS -Builds all available sample solutions in the repository (excluding specific solutions). - -.DESCRIPTION -This script searches for all available Visual Studio Solutions (.sln files) and attempts to run MSBuild to build them for the specified configurations and platforms. - -.PARAMETER Samples -A regular expression matching the samples to be built. Default is '' that matches all samples. Examples include '^tools.' or '.dchu'. - -.PARAMETER Configurations -A list of configurations to build samples under. Values available are 'Debug' and 'Release'. By default, $env:WDS_Configuration will be used as the sole configuration to build for. If this environment variable is not set the default is 'Debug' and 'Release'. - -.PARAMETER Platforms -A list of platforms to build samples under (e.g. 'x64', 'arm64'). By default, $env:WDS_Platform will be used as the sole platform to build for. If this environment variable is not set the default is 'x64' and'arm64'. - -.PARAMETER LogFilesDirectory -Path to a directory where the log files will be written to. If not provided, outputs will be logged to the '_logs' directory within the current working directory. - -.PARAMETER ThrottleLimit -An integer indicating how many combinations to build in parallel. If 0 or not provided this defaults to 5 x number of logical processors. - -.INPUTS -None. - -.OUTPUTS -None. - -.EXAMPLE -.\Build-AllSamples - -.EXAMPLE -.\Build-AllSamples -Samples '^tools.' -Configurations 'Debug','Release' -Platforms 'x64','arm64' - -#> - -[CmdletBinding()] -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 }), - [string]$LogFilesDirectory = (Join-Path (Get-Location) "_logs"), - [int]$ThrottleLimit -) - -$Verbose = $false -if ($PSBoundParameters.ContainsKey('Verbose')) { - $Verbose = $PsBoundParameters.Get_Item('Verbose') -} - -$root = Get-Location -$solutionFiles = Get-ChildItem -Path $root -Recurse -Filter *.sln | Select-Object -ExpandProperty FullName - -# To include in CI gate -$sampleSet = @{} -foreach ($file in $solutionFiles) { - $dir = (Get-Item $file).DirectoryName - $dir_norm = $dir.Replace($root, '').Trim('\').Replace('\', '.').ToLower() - if ($dir_norm -match ("^packages.")) { - Write-Verbose "`u{1F50E} Found and ignored non-sample [$dir_norm] at $dir" - } - elseif ($dir_norm -match ($Samples)) { - Write-Verbose "`u{1F50E} Found and filtered in sample [$dir_norm] at $dir" - $sampleSet[$dir_norm] = $dir - } - else { - Write-Verbose "`u{1F50E} Found and filtered out sample [$dir_norm] at $dir" - } -} - -.\Build-SampleSet -SampleSet $sampleSet -Configurations $Configurations -Platform $Platforms -LogFilesDirectory $LogFilesDirectory -Verbose:$Verbose -ThrottleLimit $ThrottleLimit diff --git a/Build-SampleSet.ps1 b/Build-SampleSet.ps1 deleted file mode 100644 index da016f05c..000000000 --- a/Build-SampleSet.ps1 +++ /dev/null @@ -1,375 +0,0 @@ -[CmdletBinding()] -param( - [hashtable]$SampleSet, - [string[]]$Configurations = @(if ([string]::IsNullOrEmpty($env:WDS_Configuration)) { "Debug" } else { $env:WDS_Configuration }), - [string[]]$Platforms = @(if ([string]::IsNullOrEmpty($env:WDS_Platform)) { "x64" } else { $env:WDS_Platform }), - $LogFilesDirectory = (Get-Location), - [string]$ReportFileName = $(if ([string]::IsNullOrEmpty($env:WDS_ReportFileName)) { "_overview" } else { $env:WDS_ReportFileName }), - [int]$ThrottleLimit = 0 -) - -$root = Get-Location - -# launch developer powershell (if necessary to prevent multiple developer sessions) -if (-not $env:VSCMD_VER) { - Import-Module (Resolve-Path "$env:ProgramFiles\Microsoft Visual Studio\*\*\Common7\Tools\Microsoft.VisualStudio.DevShell.dll") - Enter-VsDevShell -VsInstallPath (Resolve-Path "$env:ProgramFiles\Microsoft Visual Studio\*\*") - Set-Location $root -} - -$ThrottleFactor = 5 -$LogicalProcessors = (Get-CIMInstance -Class 'CIM_Processor' -Verbose:$false).NumberOfLogicalProcessors - -if ($ThrottleLimit -eq 0) { - $ThrottleLimit = $ThrottleFactor * $LogicalProcessors -} - -$Verbose = $false -if ($PSBoundParameters.ContainsKey('Verbose')) { - $Verbose = $PsBoundParameters.Get_Item('Verbose') -} - -New-Item -ItemType Directory -Force -Path $LogFilesDirectory | Out-Null -$reportFilePath = Join-Path $LogFilesDirectory "$ReportFileName.htm" -$reportCsvFilePath = Join-Path $LogFilesDirectory "$ReportFileName.csv" - - -Remove-Item -Recurse -Path $LogFilesDirectory 2>&1 | Out-Null -New-Item -ItemType Directory -Force -Path $LogFilesDirectory | Out-Null - -$oldPreference = $ErrorActionPreference -$ErrorActionPreference = "stop" -try { - # Check that msbuild can be called before trying anything. - Get-Command "msbuild" | Out-Null -} -catch { - Write-Host "`u{274C} msbuild cannot be called from current environment. Check that msbuild is set in current path (for example, that it is called from a Visual Studio developer command)." - Write-Error "msbuild cannot be called from current environment." - exit 1 -} -finally { - $ErrorActionPreference = $oldPreference -} - -# -# Determine build environment: 'GitHub', 'NuGet', 'EWDK', or 'WDK'. -# Determine build number (used for exclusions based on build number). Five digits. Say, '22621'. -# Determine NuGet package version (if applicable). -# -$build_environment="" -$build_number=0 -$nuget_package_version=0 -# -# In Github we build using NuGet. -# -if ($env:GITHUB_REPOSITORY) { - $build_environment="GitHub" - $nuget_package_version=([regex]'(?<=x64\.)(\d+\.)(\d+\.)(\d+\.)(\d+)').Matches((Get-Childitem .\packages\*WDK.x64* -Name)).Value - $build_number=$nuget_package_version.split('.')[2] -} -# -# WDK NuGet will require presence of a folder 'packages'. The version is sourced from repo .\Env-Vars.ps1. -# -# Hack: If user has hydrated nuget packages, then use those. That will be indicated by presence of a folder named '.\packages'. -# Further, we need to test that the directory has been hydrated using '.\packages\*'. -# -elseif(Test-Path(".\packages\*")) { - $build_environment=("NuGet") - $nuget_package_version=([regex]'(?<=x64\.)(\d+\.)(\d+\.)(\d+\.)(\d+)').Matches((Get-Childitem .\packages\*WDK.x64* -Name)).Value - $build_number=$nuget_package_version.split('.')[2] -} -# -# EWDK sets environment variable BuildLab. For example 'ni_release_svc_prod1.22621.2428'. -# -elseif($env:BuildLab -match '(?[^.]*).(?[^.]*).(?[^.]*)') { - $build_environment=("EWDK."+$Matches.branch+"."+$Matches.build+"."+$Matches.qfe) - $build_number=$Matches.build -} -# -# WDK sets environment variable UCRTVersion. For example '10.0.22621.0'. -# -elseif ($env:UCRTVersion -match '10.0.(?.*).0') { - $build_environment="WDK" - $build_number=$Matches.build -} -else { - - # Dump all environment variables so as to help debug error: - Write-Output "Environment variables {" - Get-ChildItem env:* | Sort-Object name - Write-Output "Environment variables }" - - Write-Error "Could not determine build environment." - exit 1 -} - -# Determine WDK Visual Studio Component version -# -# Be lenient with EWDK builds that do not include the component information -if ($build_environment -match '^EWDK') { - $wdk_vs_component_ver = "(WDK Visual Studio Component Version is not included for EWDK builds)" -} else { - # Get the WDK extension version from installed packages - $wdk_vs_component_ver = Get-ChildItem "${env:ProgramData}\Microsoft\VisualStudio\Packages\Microsoft.Windows.DriverKit,version=*" -ErrorAction SilentlyContinue - if (-not $wdk_vs_component_ver) { - Write-Error "WDK Visual Studio Component version not found. Please ensure the WDK Component is installed." - exit 1 - } - $wdk_vs_component_ver = [regex]::Match($wdk_vs_component_ver.Name, '(\d+\.){3}\d+').Value -} - -# -# -# InfVerif_AdditionalOptions -# -# Samples must build cleanly and even without warnings. -# -# An exception is for infverif where specific warnings are acceptable. Those -# specific warnings indicates issues intentially present in the samples, that -# anyone that clones the samples must fix as part of productizing a driver. -# -# In 22621 those warnings are: /sw1284 /sw1285 /sw1293 /sw2083 /sw2086 -# -# After 22621 those warnings are put under a common flag: /samples -# -$InfVerif_AdditionalOptions=($build_number -le 22621 ? "/sw1284 /sw1285 /sw1293 /sw2083 /sw2086" : "/samples") - -# -# Determine exclusions. -# -# Exclusions are loaded from .\exclusions.csv. -# Each line has form: -# Path,Configurations,MinBuild,MaxBuild,Reason -# Where: -# Path: Is the path to folder containing solution(s) using backslashes. For example: 'audio\acx\samples\audiocodec\driver' . -# Configurations: Are the configurations to exclude. For example: '*|arm64' . -# MinBuild: Is the minimum WDK/EWDK build number the exclusion is applicable for. For example: '22621' . -# MaxBuild: Is the maximum WDK/EWDK build number the exclusion is applicable for. For example: '26031' . -# Reason: Is plain text documenting the reason for the exclusion. For example: 'error C1083: Cannot open include file: 'acx.h': No such file or directory' . -# -$exclusionConfigurations = @{} -$exclusionReasons = @{} -Import-Csv 'exclusions.csv' | ForEach-Object { - $excluded_driver=$_.Path.Replace($root, '').Trim('\').Replace('\', '.').ToLower() - $excluded_configurations=($_.configurations -eq '' ? '*' : $_.configurations) - $excluded_minbuild=($_.MinBuild -eq '' ? 00000 : $_.MinBuild) - $excluded_maxbuild=($_.MaxBuild -eq '' ? 99999 : $_.MaxBuild) - if (($excluded_minbuild -le $build_number) -and ($build_number -le $excluded_maxbuild) ) - { - $exclusionConfigurations[$excluded_driver] = $excluded_configurations - $exclusionReasons[$excluded_driver] = $_.Reason - Write-Verbose "Exclusion.csv entry applied for '$excluded_driver' for configuration '$excluded_configurations'." - } - else - { - Write-Verbose "Exclusion.csv entry not applied for '$excluded_driver' due to build number." - } -} - -$jresult = @{ - SolutionsBuilt = 0 - SolutionsSucceeded = 0 - SolutionsExcluded = 0 - SolutionsUnsupported = 0 - SolutionsFailed = 0 - SolutionsSporadic = 0 - Results = @() - FailSet = @() - lock = [System.Threading.Mutex]::new($false) -} - -$SolutionsTotal = $sampleSet.Count * $Configurations.Count * $Platforms.Count - -Write-Output "WDK Build Environment: $build_environment" -Write-Output "WDK Build Number: $build_number" -if (($build_environment -eq "GitHub") -or ($build_environment -eq "NuGet")) { -Write-Output "WDK Nuget Version: $nuget_package_version" -} -Write-Output "WDK Visual Studio Component Version: $wdk_vs_component_ver" -Write-Output "Samples: $($sampleSet.Count)" -Write-Output "Configurations: $($Configurations.Count) ($Configurations)" -Write-Output "Platforms: $($Platforms.Count) ($Platforms)" -Write-Output "InfVerif_AdditionalOptions: $InfVerif_AdditionalOptions" -Write-Output "Combinations: $SolutionsTotal" -Write-Output "LogicalProcessors: $LogicalProcessors" -Write-Output "ThrottleFactor: $ThrottleFactor" -Write-Output "ThrottleLimit: $ThrottleLimit" -Write-Output "WDS_WipeOutputs: $env:WDS_WipeOutputs" -Write-Output "Disk Remaining (GB): $(((Get-Volume ((Get-Item ".").PSDrive.Name)).SizeRemaining) / 1GB)" -Write-Output "" -Write-Output "T: Combinations" -Write-Output "B: Built" -Write-Output "R: Build is running currently" -Write-Output "P: Build is pending an available build slot" -Write-Output "" -Write-Output "S: Built and result was 'Succeeded'" -Write-Output "E: Built and result was 'Excluded'" -Write-Output "U: Built and result was 'Unsupported' (Platform and Configuration combination)" -Write-Output "F: Built and result was 'Failed'" -Write-Output "O: Built and result was 'Sporadic'" -Write-Output "" -Write-Output "Building all combinations..." - -$Results = @() - -$sw = [Diagnostics.Stopwatch]::StartNew() - -$SampleSet.GetEnumerator() | ForEach-Object -ThrottleLimit $ThrottleLimit -Parallel { - $LogFilesDirectory = $using:LogFilesDirectory - $exclusionConfigurations = $using:exclusionConfigurations - $exclusionReasons = $using:exclusionReasons - $Configurations = $using:Configurations - $Platforms = $using:Platforms - $InfVerif_AdditionalOptions = $using:InfVerif_AdditionalOptions - $Verbose = $using:Verbose - - $sampleName = $_.Key - $directory = $_.Value - - $ResultElement = new-object psobject - Add-Member -InputObject $ResultElement -MemberType NoteProperty -Name Sample -Value "$sampleName" - - foreach ($configuration in $Configurations) { - foreach ($platform in $Platforms) { - $thisunsupported = 0 - $thisfailed = 0 - $thissporadic = 0 - $thisexcluded = 0 - $thissucceeded = 0 - $thisresult = "Not run" - $thisfailset = @() - $thissporadicset = @() - - if ($exclusionConfigurations.ContainsKey($sampleName) -and ($exclusionConfigurations[$sampleName].Split(';') | Where-Object { "$configuration|$platform" -like $_ })) { - # Verbose - Write-Verbose "[$sampleName $configuration|$platform] `u{23E9} Excluded and skipped. Reason: $($exclusionReasons[$sampleName])" - $thisexcluded += 1 - $thisresult = "Excluded" - } - else { - .\Build-Sample -Directory $directory -SampleName $sampleName -LogFilesDirectory $LogFilesDirectory -Configuration $configuration -Platform $platform -InfVerif_AdditionalOptions $InfVerif_AdditionalOptions -Verbose:$Verbose - if ($LASTEXITCODE -eq 0) { - $thissucceeded += 1 - $thisresult = "Succeeded" - } - elseif ($LASTEXITCODE -eq 1) { - $thisfailset += "$sampleName $configuration|$platform" - $thisfailed += 1 - $thisresult = "Failed" - } - elseif ($LASTEXITCODE -eq 2) { - $thissporadicset += "$sampleName $configuration|$platform" - $thissporadic += 1 - $thisresult = "Sporadic" - } - else { - # ($LASTEXITCODE -eq 3) - $thisunsupported += 1 - $thisresult = "Unsupported" - } - } - Add-Member -InputObject $ResultElement -MemberType NoteProperty -Name "$configuration|$platform" -Value "$thisresult" - - $null = ($using:jresult).lock.WaitOne() - try { - ($using:jresult).SolutionsBuilt += 1 - ($using:jresult).SolutionsSucceeded += $thissucceeded - ($using:jresult).SolutionsExcluded += $thisexcluded - ($using:jresult).SolutionsUnsupported += $thisunsupported - ($using:jresult).SolutionsFailed += $thisfailed - ($using:jresult).SolutionsSporadic += $thissporadic - ($using:jresult).FailSet += $thisfailset - ($using:jresult).SporadicSet += $thissporadicset - $SolutionsTotal = $using:SolutionsTotal - $ThrottleLimit = $using:ThrottleLimit - $SolutionsBuilt = ($using:jresult).SolutionsBuilt - $SolutionsRemaining = $SolutionsTotal - $SolutionsBuilt - $SolutionsRunning = if ($SolutionsRemaining -ge $ThrottleLimit) { $ThrottleLimit } else { $SolutionsRemaining } - $SolutionsPending = if ($SolutionsRemaining -ge $ThrottleLimit) { ($SolutionsRemaining - $ThrottleLimit) } else { 0 } - $SolutionsBuiltPercent = [Math]::Round(100 * ($SolutionsBuilt / $using:SolutionsTotal)) - $TBRP = "T:" + ($SolutionsTotal) + "; B:" + (($using:jresult).SolutionsBuilt) + "; R:" + ($SolutionsRunning) + "; P:" + ($SolutionsPending) - $rstr = "S:" + (($using:jresult).SolutionsSucceeded) + "; E:" + (($using:jresult).SolutionsExcluded) + "; U:" + (($using:jresult).SolutionsUnsupported) + "; F:" + (($using:jresult).SolutionsFailed) + "; O:" + (($using:jresult).SolutionsSporadic) - Write-Progress -Activity "Building combinations" -Status "$SolutionsBuilt of $using:SolutionsTotal combinations built ($SolutionsBuiltPercent%) | $TBRP | $rstr" -PercentComplete $SolutionsBuiltPercent - } - finally { - ($using:jresult).lock.ReleaseMutex() - } - } - } - $null = ($using:jresult).lock.WaitOne() - try { - ($using:jresult).Results += $ResultElement - } - finally { - ($using:jresult).lock.ReleaseMutex() - } -} - -$sw.Stop() - -Write-Output "" - -if ($jresult.FailSet.Count -gt 0) { - Write-Output "Some combinations were built with errors:" - $jresult.FailSet = $jresult.FailSet | Sort-Object - foreach ($failedSample in $jresult.FailSet) { - $failedSample -match "^(.*) (\w*)\|(\w*)$" | Out-Null - $failName = $Matches[1] - $failConfiguration = $Matches[2] - $failPlatform = $Matches[3] - Write-Output "Build errors in Sample $failName; Configuration: $failConfiguration; Platform: $failPlatform {" - Get-Content "$LogFilesDirectory\$failName.$failConfiguration.$failPlatform.0.err" | Write-Output - Write-Output "} $failedSample" - } - Write-Error "Some combinations were built with errors." - Write-Output "" -} - -if ($jresult.SporadicSet.Count -gt 0) { - Write-Output "Some combinations were built with sporadic error:" - $jresult.SporadicSet = $jresult.SporadicSet | Sort-Object - foreach ($sporadicSample in $jresult.SporadicSet) { - $sporadicSample -match "^(.*) (\w*)\|(\w*)$" | Out-Null - $sporadicName = $Matches[1] - $sporadicConfiguration = $Matches[2] - $sporadicPlatform = $Matches[3] - Write-Output "Build sporadic errors in Sample $sporadicName; Configuration: $sporadicConfiguration; Platform: $sporadicPlatform {" - Get-Content "$LogFilesDirectory\$sporadicName.$sporadicConfiguration.$sporadicPlatform.0.err" | Write-Output - Write-Output "} $sporadicSample" - } - Write-Error "Some combinations were built with sporadic errors." - Write-Output "" -} - -# Display timer statistics to host -$min = $sw.Elapsed.Minutes -$seconds = $sw.Elapsed.Seconds - -$SolutionsSucceeded = $jresult.SolutionsSucceeded -$SolutionsExcluded = $jresult.SolutionsExcluded -$SolutionsUnsupported = $jresult.SolutionsUnsupported -$SolutionsFailed = $jresult.SolutionsFailed -$SolutionsSporadic = $jresult.SolutionsSporadic -$Results = $jresult.Results - -Write-Output "Built all combinations." -Write-Output "" -Write-Output "Elapsed time: $min minutes, $seconds seconds." -Write-Output ("Disk Remaining (GB): " + (((Get-Volume (Get-Item ".").PSDrive.Name).SizeRemaining / 1GB))) -Write-Output ("Samples: " + $sampleSet.Count) -Write-Output ("Configurations: " + $Configurations.Count + " (" + $Configurations + ")") -Write-Output ("Platforms: " + $Platforms.Count + " (" + $Platforms + ")") -Write-Output "Combinations: $SolutionsTotal" -Write-Output "Succeeded: $SolutionsSucceeded" -Write-Output "Excluded: $SolutionsExcluded" -Write-Output "Unsupported: $SolutionsUnsupported" -Write-Output "Failed: $SolutionsFailed" -Write-Output "Sporadic: $SolutionsSporadic" -Write-Output "Log files directory: $LogFilesDirectory" -Write-Output "Overview report: $reportFilePath" -Write-Output "" - -$Results | Sort-Object { $_.Sample } | ConvertTo-Csv | Out-File $reportCsvFilePath -$Results | Sort-Object { $_.Sample } | ConvertTo-Html -Title "Overview" | Out-File $reportFilePath -Invoke-Item $reportFilePath diff --git a/Building-Locally.md b/Building-Locally.md index 312c59674..d988a330e 100644 --- a/Building-Locally.md +++ b/Building-Locally.md @@ -129,80 +129,82 @@ Microsoft.Windows.WDK.arm64.10.0.26000.1 --- -## Step 6: Check all samples builds with expected results for all flavors +## Step 6: Build all samples ```powershell pwsh -.\Build-AllSamples +.\Build-Samples ``` -Above builds all samples for all configurations and platforms. +Above builds all samples for all configurations and platforms. -You can refine what exact samples to build, what configurations, and platforms to build. build Here are a few examples: +You can refine what exact samples to build, what configurations, and platforms to build. Here are a few examples: ```powershell # Get Help: -Get-Help .\Build-AllSamples +Get-Help .\Build-Samples # Build all solutions for all flavors with builds running in parallel: -.\Build-AllSamples +.\Build-Samples # Build with Verbose output (print start and finish of each sample): -.\Build-AllSamples -Verbose +.\Build-Samples -Verbose -# Build without massive parallism (slow, but good debugging): -.\Build-AllSamples -ThrottleLimit 1 +# Build without massive parallelism (slow, but good for debugging): +.\Build-Samples -ThrottleLimit 1 -# Build the solutions in the tools folder for all flavors: -.\Build-AllSamples -Samples '^tools.' -Configurations 'Debug','Release' -Platforms 'x64','arm64' +# Build specific samples for all flavors: +.\Build-Samples -Samples 'tools.sdv.samples.sampledriver','usb.kmdf_fx2' -# Build the solutions in the tools folder for only 'Debug|x64': -.\Build-AllSamples -Samples '^tools.' -Configurations 'Debug' -Platforms 'x64' +# Build specific samples for only 'Debug|x64': +.\Build-Samples -Samples 'tools.sdv.samples.sampledriver' -Configurations 'Debug' -Platforms 'x64' ``` Example of expected output: ``` -Build Environment: NuGet -Build Number: 26100 -Samples: 132 -Configurations: 2 (Debug Release) -Platforms: 2 (x64 arm64) -InfVerif_AdditionalOptions: /samples -Combinations: 528 -LogicalProcessors: 12 -ThrottleFactor: 5 -ThrottleLimit: 60 -WDS_WipeOutputs: -Disk Remaining (GB): ... - -T: Combinations -B: Built -R: Build is running currently -P: Build is pending an available build slot - -S: Built and result was 'Succeeded' -E: Built and result was 'Excluded' -U: Built and result was 'Unsupported' (Platform and Configuration combination) -F: Built and result was 'Failed' -O: Built and result was 'Sporadic' +--- WDK Sample Build Plan ------------------------------------------ + Environment: NuGet + Build Number: 26100 + NuGet Version: 10.0.26100.1 + WDK VS Component: 10.0.26100.1882 + InfVerif Options: /samples + + Samples: 132 (0 skipped) + Configurations: Debug, Release + Platforms: x64, arm64 + Combinations: 528 + Exclusions: 4 + + Parallelism: 60 jobs (12 cores x 5) + Disk Free (GB): ... + Wipe Outputs: False +-------------------------------------------------------------------- + +Progress legend: + T=Total B=Built R=Running P=Pending + S=Succeeded E=Excluded U=Unsupported F=Failed O=Sporadic Building all combinations... -Built all combinations. +--- Build Complete ------------------------------------------------- + Elapsed: 12m 42s + Disk Free (GB): ... + + Samples: 132 + Configurations: Debug, Release + Platforms: x64, arm64 + Combinations: 528 + + Succeeded: 526 + Excluded: 0 + Unsupported: 2 + Failed: 0 + Sporadic: 0 -Elapsed time: 12 minutes, 42 seconds. -Disk Remaining (GB): ... -Samples: 132 -Configurations: 2 (Debug Release) -Platforms: 2 (x64 arm64) -Combinations: 528 -Succeeded: 526 -Excluded: 0 -Unsupported: 2 -Failed: 0 -Sporadic: 0 -Log files directory: .\_logs -Overview report: .\_overview.htm + Log directory: .\_logs + CSV report: .\_logs\_overview.csv + HTML report: .\_logs\_overview.htm +-------------------------------------------------------------------- ``` --- @@ -214,7 +216,7 @@ To restore a specific version of our WDK NuGet packages: Follow these steps before running "nuget restore" command: * Open the .\packages.config file and update the full version (including the branch if required) in all three entries. * Open the .\Directory.build.props file and update the version and build of the package with the same values as in previous step. -* Open .\Build-SampleSet and change the NuGet build number (used by .\exclusions.csv and for determining infverif flags) +* Open .\Build-Samples.ps1 and check the NuGet build number logic (used by .\exclusions.csv and for determining infverif flags) * Now you can run "nuget restore" A few examples of how to interact with nuget: From bc6b2708d9d762dde716a2af7c8fa08534c1afcc Mon Sep 17 00:00:00 2001 From: 5an7y Date: Mon, 30 Mar 2026 15:32:35 -0700 Subject: [PATCH 17/20] Merge Build-Sample.ps1 into Build-Samples.ps1 as internal function - Inline Build-Sample.ps1 logic as Build-SingleSample function in Build-Samples.ps1 - Pass function definition into parallel runspaces via $using: pattern - Replace exit codes with return values for in-process execution - Delete Build-Sample.ps1 (no longer needed as a separate script) - Update Build-ChangedSamples.ps1 trigger file list --- .github/scripts/Build-ChangedSamples.ps1 | 2 +- Build-Sample.ps1 | 211 ----------------------- Build-Samples.ps1 | 152 +++++++++++++++- 3 files changed, 146 insertions(+), 219 deletions(-) delete mode 100644 Build-Sample.ps1 diff --git a/.github/scripts/Build-ChangedSamples.ps1 b/.github/scripts/Build-ChangedSamples.ps1 index 29f990612..3e91eb883 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 "Build-Sample.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 "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/Build-Sample.ps1 b/Build-Sample.ps1 deleted file mode 100644 index c09b76948..000000000 --- a/Build-Sample.ps1 +++ /dev/null @@ -1,211 +0,0 @@ -<# -.SYNOPSIS -Builds an specific directory containing a sample solution. - -.DESCRIPTION -This script attempts to build a directory containing a driver sample Solution for the specified configurations and platforms. - -.PARAMETER Directory -Path to a directory containing a valid Visual Studio Solution (.sln file). This is the solution that will be built. - -.PARAMETER SampleName -A friendly name to refer to the sample. Is unspecified, a name will be automatically generated one from the sample path. - -.PARAMETER Configuration -Configuration name that will be used to build the solution. Common available values are "Debug" and "Release". - -.PARAMETER Platform -Platform to build the solution for (e.g. "x64", "arm64"). - -.PARAMETER InfVerif_AdditionalOptions -Additional options for infverif (e.g. "/samples"). - -.PARAMETER LogFilesDirectoy -Path to a directory where the log files will be written to. If not provided, outputs will be logged to the current working directory. - -.INPUTS -None. - -.OUTPUTS -Verbose output about the execution of this script will be provided only if -Verbose is provided. Otherwise, no output will be generated. - -.EXAMPLE -.\Build-Sample -Directory .\usb\kmdf_fx2 - -.EXAMPLE -.\Build-Sample -Directory .\usb\kmdf_fx2 -Configuration 'Release' -Platform 'x64' -Verbose -LogFilesDirectory .\_logs - -#> - -[CmdletBinding()] -param( - [Parameter(Mandatory = $true, - HelpMessage = 'Enter one directory path', - Position = 0)] - [string]$Directory, - [string]$SampleName, - [string]$Configuration = "Debug", - [string]$Platform = "x64", - [string]$InfVerif_AdditionalOptions = "/samples", - $LogFilesDirectory = (Get-Location) -) - -$Verbose = $false -if ($PSBoundParameters.ContainsKey('Verbose')) { - $Verbose = $PsBoundParameters.Get_Item('Verbose') -} - -$oldPreference = $ErrorActionPreference -$ErrorActionPreference = "stop" -try -{ - # Check that msbuild can be called before trying anything. - Get-Command "msbuild" | Out-Null -} -catch -{ - Write-Verbose "`u{274C} msbuild cannot be called from current environment. Check that msbuild is set in current path (for example, that it is called from a Visual Studio developer command)." - Write-Error "msbuild cannot be called from current environment." - exit 1 -} -finally -{ - $ErrorActionPreference = $oldPreference -} - -if (-not (Test-Path -Path $Directory -PathType Container)) -{ - Write-Warning "`u{274C} A valid directory could not be found under $Directory" - exit 1 -} - -New-Item -ItemType Directory -Force -Path $LogFilesDirectory | Out-Null - -if (-not (Test-Path -Path $LogFilesDirectory -PathType Container)) -{ - Write-Warning "`u{274C} A valid directory for storing log files could not be created under $LogFilesDirectory" - # No exit here: process will continue but logs won't be available. -} - -if ([string]::IsNullOrWhitespace($SampleName)) -{ - $SampleName = (Resolve-Path $Directory).Path.Replace((Get-Location), '').Replace('\', '.').Trim('.').ToLower() -} - -$solutionFile = Get-ChildItem -Path $Directory -Filter *.sln | Select-Object -ExpandProperty FullName -First 1 - -if ($null -eq $solutionFile) -{ - Write-Warning "`u{274C} A solution could not be found under $Directory" - exit 1 -} - -$configurationIsSupported = $false -$inSolutionConfigurationPlatformsSection = $false -foreach ($line in Get-Content -Path $solutionFile) -{ - if (-not $inSolutionConfigurationPlatformsSection -and $line -match "\s*GlobalSection\(SolutionConfigurationPlatforms\).*") - { - $inSolutionConfigurationPlatformsSection = $true; - continue; - } - elseif ($line -match "\s*EndGlobalSection.*") - { - $inSolutionConfigurationPlatformsSection = $false; - continue; - } - - if ($inSolutionConfigurationPlatformsSection) - { - [regex]$regex = ".*=\s*(?(?.*)\|(?.*))\s*" - $match = $regex.Match($line) - if ([string]::IsNullOrWhiteSpace($match.Groups["ConfigString"].Value) -or [string]::IsNullOrWhiteSpace($match.Groups["Platform"].Value)) - { - Write-Warning "Could not parse configuration entry $line from file $solutionFile." - continue; - } - if ($match.Groups["Configuration"].Value.Trim() -eq $Configuration -and $match.Groups["Platform"].Value.Trim() -eq $Platform) - { - $configurationIsSupported = $true; - } - } -} - -if (-not $configurationIsSupported) -{ - Write-Verbose "[$SampleName] `u{23E9} Skipped. Configuration $Configuration|$Platform not supported." - exit 3 -} - -Write-Verbose "Building Sample: $SampleName; Configuration: $Configuration; Platform: $Platform {" - -$myexit=1 - -# -# Let us build up to three times (0th, 1st, and 2nd attempt). -# If we succeed at first, then it is a success. -# If we fail at first, but succeed at either of next two attempts, then it is a sporadic failure. -# If we even at third attempt fail, then it is a true failure. -# -for ($i = 0; $i -lt 3; $i++) -{ - $binLogFilePath = "$LogFilesDirectory\$SampleName.$Configuration.$Platform.$i.binlog" - $errorLogFilePath = "$LogFilesDirectory\$SampleName.$Configuration.$Platform.$i.err" - $warnLogFilePath = "$LogFilesDirectory\$SampleName.$Configuration.$Platform.$i.wrn" - $OutLogFilePath = "$LogFilesDirectory\$SampleName.$Configuration.$Platform.$i.out" - - msbuild $solutionFile -clp:Verbosity=m -t:rebuild -property:Configuration=$Configuration -property:Platform=$Platform -p:TargetVersion=Windows10 -p:InfVerif_AdditionalOptions="$InfVerif_AdditionalOptions" -warnaserror -binaryLogger:LogFile=$binLogFilePath`;ProjectImports=None -flp1:errorsonly`;logfile=$errorLogFilePath -flp2:WarningsOnly`;logfile=$warnLogFilePath -noLogo > $OutLogFilePath - if ($null -ne $env:WDS_WipeOutputs) - { - Write-Verbose ("WipeOutputs: " + $Directory + " " + (((Get-Volume (Get-Item ".").PSDrive.Name).SizeRemaining / 1GB))) - Get-ChildItem -path $Directory -Recurse -Include x64 | Remove-Item -Recurse - Get-ChildItem -path $Directory -Recurse -Include arm64 | Remove-Item -Recurse - } - if ($LASTEXITCODE -eq 0) - { - # We succeeded building. - # If it was at a later attempt, let the caller know with a different exit code. - if ($i -eq 0) - { - $myexit = 0 - } - else - { - $myexit = 2 - } - # Remove binlog on success to save space; keep otherwise to diagnose issues. - Remove-Item $binLogFilePath - break; - } - else - { - # We failed building. - # Let us sleep for a bit. - # Then let the while loop do its thing and re-run. - Start-Sleep 1 - if ($Verbose) - { - Write-Warning "`u{274C} Build failed. Retrying to see if sporadic..." - } - } -} - -if ($myexit -eq 1) -{ - if ($Verbose) - { - Write-Warning "`u{274C} Build failed. Log available at $errorLogFilePath" - } - exit 1 -} - -if ($myexit -eq 2) -{ - if ($Verbose) - { - Write-Warning "`u{274C} Build sporadically failed. Log available at $errorLogFilePath" - } - exit 2 -} - -Write-Verbose "Building Sample: $SampleName; Configuration: $Configuration; Platform: $Platform }" diff --git a/Build-Samples.ps1 b/Build-Samples.ps1 index aad2d3e53..4242d428f 100644 --- a/Build-Samples.ps1 +++ b/Build-Samples.ps1 @@ -14,10 +14,6 @@ Requires PowerShell 7+ (uses ForEach-Object -Parallel). - Typical call chain: - Build-AllSamples.ps1 -> Build-Samples.ps1 -> ListAllSamples.ps1 (for discovery) - (this script) -> Build-Sample.ps1 (per sample) - .PARAMETER Samples Optional array of specific sample names to build. When omitted, all samples are discovered dynamically via ListAllSamples.ps1. @@ -240,6 +236,141 @@ function Get-DiskFreeGB { } } +function Build-SingleSample { + <# + .SYNOPSIS + Builds a single sample directory for one configuration/platform combination. + .DESCRIPTION + Locates the .sln in the given directory, verifies the configuration|platform is + supported, then invokes msbuild with up to 3 attempts (to detect sporadic failures). + .OUTPUTS + Returns an integer exit code: + 0 = succeeded on first attempt + 1 = failed after all retries + 2 = sporadic (failed first, succeeded on retry) + 3 = unsupported configuration/platform + #> + param( + [string]$Directory, + [string]$SampleName, + [string]$Configuration = 'Debug', + [string]$Platform = 'x64', + [string]$InfVerif_AdditionalOptions = '/samples', + [string]$LogFilesDirectory = (Get-Location), + [bool]$Verbose = $false + ) + + if (-not (Test-Path -Path $Directory -PathType Container)) { + Write-Warning "`u{274C} A valid directory could not be found under $Directory" + return 1 + } + + New-Item -ItemType Directory -Force -Path $LogFilesDirectory | Out-Null + + if ([string]::IsNullOrWhiteSpace($SampleName)) { + $SampleName = (Resolve-Path $Directory).Path.Replace((Get-Location), '').Replace('\', '.').Trim('.').ToLower() + } + + $solutionFile = Get-ChildItem -Path $Directory -Filter *.sln | + Select-Object -ExpandProperty FullName -First 1 + + if ($null -eq $solutionFile) { + Write-Warning "`u{274C} A solution could not be found under $Directory" + return 1 + } + + # --- Check whether the solution supports the requested configuration|platform --- + $configurationIsSupported = $false + $inSolutionConfigurationPlatformsSection = $false + foreach ($line in Get-Content -Path $solutionFile) { + if (-not $inSolutionConfigurationPlatformsSection -and + $line -match '\s*GlobalSection\(SolutionConfigurationPlatforms\).*') { + $inSolutionConfigurationPlatformsSection = $true + continue + } + elseif ($line -match '\s*EndGlobalSection.*') { + $inSolutionConfigurationPlatformsSection = $false + continue + } + + if ($inSolutionConfigurationPlatformsSection) { + [regex]$regex = '.*=\s*(?(?.*)\|(?.*))\s*' + $match = $regex.Match($line) + if ([string]::IsNullOrWhiteSpace($match.Groups['ConfigString'].Value) -or + [string]::IsNullOrWhiteSpace($match.Groups['Platform'].Value)) { + Write-Warning "Could not parse configuration entry $line from file $solutionFile." + continue + } + if ($match.Groups['Configuration'].Value.Trim() -eq $Configuration -and + $match.Groups['Platform'].Value.Trim() -eq $Platform) { + $configurationIsSupported = $true + } + } + } + + if (-not $configurationIsSupported) { + Write-Verbose "[$SampleName] `u{23E9} Skipped. Configuration $Configuration|$Platform not supported." + return 3 + } + + Write-Verbose "Building Sample: $SampleName; Configuration: $Configuration; Platform: $Platform {" + + $myexit = 1 + + # Build up to three times (0th, 1st, and 2nd attempt). + # Succeed on 1st -> success (0) + # Fail 1st, succeed on retry -> sporadic (2) + # Fail all three -> failure (1) + for ($i = 0; $i -lt 3; $i++) { + $binLogFilePath = "$LogFilesDirectory\$SampleName.$Configuration.$Platform.$i.binlog" + $errorLogFilePath = "$LogFilesDirectory\$SampleName.$Configuration.$Platform.$i.err" + $warnLogFilePath = "$LogFilesDirectory\$SampleName.$Configuration.$Platform.$i.wrn" + $outLogFilePath = "$LogFilesDirectory\$SampleName.$Configuration.$Platform.$i.out" + + msbuild $solutionFile ` + -clp:Verbosity=m -t:rebuild ` + -property:Configuration=$Configuration ` + -property:Platform=$Platform ` + -p:TargetVersion=Windows10 ` + -p:InfVerif_AdditionalOptions="$InfVerif_AdditionalOptions" ` + -warnaserror ` + -binaryLogger:LogFile=$binLogFilePath`;ProjectImports=None ` + -flp1:errorsonly`;logfile=$errorLogFilePath ` + -flp2:WarningsOnly`;logfile=$warnLogFilePath ` + -noLogo > $outLogFilePath + + if ($null -ne $env:WDS_WipeOutputs) { + Write-Verbose ("WipeOutputs: $Directory " + (((Get-Volume (Get-Item '.').PSDrive.Name).SizeRemaining / 1GB))) + Get-ChildItem -Path $Directory -Recurse -Include x64 | Remove-Item -Recurse + Get-ChildItem -Path $Directory -Recurse -Include arm64 | Remove-Item -Recurse + } + + if ($LASTEXITCODE -eq 0) { + $myexit = if ($i -eq 0) { 0 } else { 2 } + # Remove binlog on success to save space; keep otherwise to diagnose issues. + Remove-Item $binLogFilePath + break + } + else { + Start-Sleep 1 + if ($Verbose) { + Write-Warning "`u{274C} Build failed. Retrying to see if sporadic..." + } + } + } + + if ($myexit -eq 1 -and $Verbose) { + Write-Warning "`u{274C} Build failed. Log available at $errorLogFilePath" + } + if ($myexit -eq 2 -and $Verbose) { + Write-Warning "`u{274C} Build sporadically failed. Log available at $errorLogFilePath" + } + + Write-Verbose "Building Sample: $SampleName; Configuration: $Configuration; Platform: $Platform }" + + return $myexit +} + # ============================================================================= # Step 1 - Prepare Build Environment # ============================================================================= @@ -392,6 +523,9 @@ $buildState = @{ $stopwatch = [Diagnostics.Stopwatch]::StartNew() +# Capture function definition so it can be reconstructed inside each parallel runspace. +$buildSingleSampleDef = ${function:Build-SingleSample}.ToString() + $sampleSet.GetEnumerator() | ForEach-Object -ThrottleLimit $ThrottleLimit -Parallel { # --- Import shared state from parent scope --- $logDir = $using:LogFilesDirectory @@ -404,6 +538,9 @@ $sampleSet.GetEnumerator() | ForEach-Object -ThrottleLimit $ThrottleLimit -Paral $total = $using:combinationsTotal $throttle = $using:ThrottleLimit + # Reconstruct the function inside this parallel runspace + ${function:Build-SingleSample} = $using:buildSingleSampleDef + $sampleName = $_.Key $directory = $_.Value @@ -443,17 +580,18 @@ $sampleSet.GetEnumerator() | ForEach-Object -ThrottleLimit $ThrottleLimit -Paral } else { # -- Build the sample -- - .\Build-Sample -Directory $directory -SampleName $sampleName ` + $buildResult = Build-SingleSample ` + -Directory $directory -SampleName $sampleName ` -LogFilesDirectory $logDir -Configuration $configuration ` -Platform $platform -InfVerif_AdditionalOptions $infOpts ` -Verbose:$isVerbose - # Exit codes from Build-Sample.ps1: + # Return codes from Build-SingleSample: # 0 = succeeded on first attempt # 1 = failed after all retries # 2 = sporadic (failed first, succeeded on retry) # 3 = unsupported configuration/platform - switch ($LASTEXITCODE) { + switch ($buildResult) { 0 { $succeededDelta = 1; $result = 'Succeeded' } 1 { $failedDelta = 1; $result = 'Failed'; $failEntry = "$sampleName $configuration|$platform" } 2 { $sporadicDelta = 1; $result = 'Sporadic'; $sporadicEntry = "$sampleName $configuration|$platform" } From 83cfa72cc265ab052100563cfc2e8c9d9b6020ba Mon Sep 17 00:00:00 2001 From: 5an7y Date: Mon, 30 Mar 2026 15:43:16 -0700 Subject: [PATCH 18/20] Support wildcard patterns in -Samples parameter - When -Samples contains wildcards (* or ?), discover all samples first then filter with -like (same pattern style as exclusions.csv) - Exact sample names still work as before without discovery overhead - Update parameter docs, examples, and Building-Locally.md --- Build-Samples.ps1 | 43 +++++++++++++++++++++++++++++++++++-------- Building-Locally.md | 3 +++ 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/Build-Samples.ps1 b/Build-Samples.ps1 index 4242d428f..7eafb54d4 100644 --- a/Build-Samples.ps1 +++ b/Build-Samples.ps1 @@ -16,7 +16,9 @@ .PARAMETER Samples - Optional array of specific sample names to build. When omitted, all samples are discovered dynamically via ListAllSamples.ps1. + Optional array of specific sample names or wildcard patterns to build. Supports + wildcards (e.g. 'tools.*', 'audio.*') which are matched against all discovered + samples. When omitted, all samples are discovered dynamically via ListAllSamples.ps1. .PARAMETER Configurations Build configurations (e.g. 'Debug','Release'). Defaults to $env:WDS_Configuration or @@ -49,6 +51,11 @@ Builds specific samples for a single configuration and platform. +.EXAMPLE + .\Build-Samples -Samples 'tools.*' + + Builds all samples whose name matches the wildcard pattern 'tools.*'. + .EXAMPLE .\Build-Samples -ThrottleLimit 8 @@ -408,17 +415,37 @@ $reportCsvPath = Join-Path $LogFilesDirectory "$ReportFileName.csv" # Step 4 - Load Sample List # ============================================================================= -if ($Samples) { - # Explicit list passed by the caller — use as-is, sorted alphabetically. - $sampleNames = $Samples | Sort-Object -} -else { - # Default: discover samples dynamically via ListAllSamples.ps1. - # ListAllSamples outputs one alphabetically-sorted sample name per line to stdout. +# Always discover the full sample list when patterns contain wildcards, +# or when no -Samples were provided at all. +$hasWildcards = $Samples | Where-Object { $_ -match '[*?]' } + +if (-not $Samples) { + # No filter: discover and build everything. Write-Verbose "No -Samples provided. Discovering samples via ListAllSamples.ps1..." $sampleNames = & (Join-Path $PSScriptRoot 'ListAllSamples.ps1') -Verbose:$verbose | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } } +elseif ($hasWildcards) { + # One or more entries contain wildcards — discover all, then filter with -like. + Write-Verbose "Wildcard detected in -Samples. Discovering all samples to match patterns..." + $allSamples = & (Join-Path $PSScriptRoot 'ListAllSamples.ps1') -Verbose:$verbose | + Where-Object { -not [string]::IsNullOrWhiteSpace($_) } + $sampleNames = @() + foreach ($pattern in $Samples) { + $matched = $allSamples | Where-Object { $_ -like $pattern } + if ($matched) { + $sampleNames += $matched + } + else { + Write-Warning "Pattern '$pattern' did not match any samples." + } + } + $sampleNames = $sampleNames | Sort-Object -Unique +} +else { + # Exact list passed by the caller — use as-is, sorted alphabetically. + $sampleNames = $Samples | Sort-Object +} # Map sample names to directory paths, validating each exists $sampleSet = [ordered]@{} diff --git a/Building-Locally.md b/Building-Locally.md index d988a330e..451100986 100644 --- a/Building-Locally.md +++ b/Building-Locally.md @@ -155,6 +155,9 @@ Get-Help .\Build-Samples # Build specific samples for all flavors: .\Build-Samples -Samples 'tools.sdv.samples.sampledriver','usb.kmdf_fx2' +# Build all samples inside the 'tools' folder using wildcards: +.\Build-Samples -Samples 'tools.*' + # Build specific samples for only 'Debug|x64': .\Build-Samples -Samples 'tools.sdv.samples.sampledriver' -Configurations 'Debug' -Platforms 'x64' ``` From 8056a2723c732809b4ca684666ac08385f6e835f Mon Sep 17 00:00:00 2001 From: 5an7y Date: Mon, 30 Mar 2026 15:45:36 -0700 Subject: [PATCH 19/20] Remove redundant specific-samples example from Building-Locally.md --- Building-Locally.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/Building-Locally.md b/Building-Locally.md index 451100986..645e9a615 100644 --- a/Building-Locally.md +++ b/Building-Locally.md @@ -152,9 +152,6 @@ Get-Help .\Build-Samples # Build without massive parallelism (slow, but good for debugging): .\Build-Samples -ThrottleLimit 1 -# Build specific samples for all flavors: -.\Build-Samples -Samples 'tools.sdv.samples.sampledriver','usb.kmdf_fx2' - # Build all samples inside the 'tools' folder using wildcards: .\Build-Samples -Samples 'tools.*' From 78a9b6fd1ae57346a854cd1456e1d2a6de3d5fc3 Mon Sep 17 00:00:00 2001 From: 5an7y Date: Tue, 31 Mar 2026 10:34:40 -0700 Subject: [PATCH 20/20] ci: update Code-Scanning workflow to use Build-Samples.ps1 Build-AllSamples.ps1 was removed in favor of Build-Samples.ps1. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/Code-Scanning.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Code-Scanning.yml b/.github/workflows/Code-Scanning.yml index 63e155c9c..232545ada 100644 --- a/.github/workflows/Code-Scanning.yml +++ b/.github/workflows/Code-Scanning.yml @@ -66,7 +66,7 @@ jobs: WDS_Platform: x64 WDS_WipeOutputs: ${{ true }} - if: github.event_name == 'push' - run: .\Build-AllSamples.ps1 -Verbose -ThrottleLimit 1 + run: .\Build-Samples.ps1 -Verbose -ThrottleLimit 1 env: WDS_Configuration: Debug WDS_Platform: x64