Add WinML EP Catalog CMake sample with NuGet package integration#593
Add WinML EP Catalog CMake sample with NuGet package integration#593nieubank wants to merge 2 commits intorelease/experimentalfrom
Conversation
- Introduced a new sample demonstrating the WinMLEpCatalog Native C API for managing hardware-accelerated execution providers for machine learning inference on Windows. - Added CMake configuration with presets for various architectures and build types. - Created a PowerShell build script to automate the build process, including prerequisite checks and configuration. - Implemented a batch wrapper for the PowerShell script for easier command-line usage. - Included detailed README documentation covering sample usage, project structure, prerequisites, and build instructions. - Established vcpkg configuration and overlay ports for dependency management, including the Microsoft Windows AI Machine Learning SDK. - Implemented the main sample code to demonstrate provider registration and enumeration using the Windows ML API.
Adds a CMake-based C++ sample demonstrating the WinML Execution Provider Catalog C API (WinMLEpCatalog*) for discovering and registering hardware-accelerated ML execution providers with ONNX Runtime. What the sample shows: - Creating an EP catalog and enumerating registered execution providers - Inspecting provider metadata (name, version, certification status) - Preparing certified providers with WinMLEpEnsureReady and registering them with Ort::Env - Consuming the Microsoft.WindowsAppSDK.ML NuGet package from CMake with automatic .nupkg extraction at configure time - Deploying runtime DLLs via TARGET_RUNTIME_DLLS and an explicit WINML_DIRECTML_DLL copy for DirectML (which has no import library) Build setup: - CMake 3.21+ with a single nuget preset; supports both Ninja and Visual Studio generators - build.ps1 helper script handles VS developer environment setup, prerequisite checks, and NuGet package resolution - No vcpkg dependency -- the NuGet package is extracted directly by CMake's file(ARCHIVE_EXTRACT)
|
|
||
| function Write-ErrorMessage { | ||
| param([string]$Message) | ||
| Write-Host "[ERROR] $Message" -ForegroundColor Red |
There was a problem hiding this comment.
| Write-Host "[ERROR] $Message" -ForegroundColor Red | |
| Write-Error $Message |
Send this to the error stream? Maybe get rid of this function and call Write-Error directly.
| # Local NuGet package configuration | ||
| set(WINML_NUGET_PACKAGE "${CMAKE_CURRENT_SOURCE_DIR}/Microsoft.WindowsAppSDK.ML.2.0.246-experimental.nupkg" | ||
| CACHE FILEPATH "Path to Microsoft.WindowsAppSDK.ML nupkg") | ||
| set(WINML_LOCAL_PACKAGES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/local_packages" |
There was a problem hiding this comment.
Consider extracting somewhere under the CMAKE_CURRENT_BINARY_DIR or CMAKE_BINARY_DIR so that the source tree isn't touched.
| if(NOT DEFINED microsoft.windows.ai.machinelearning_DIR) | ||
| if(EXISTS "${WINML_NUGET_PACKAGE}") | ||
| get_filename_component(_winml_nupkg_filename "${WINML_NUGET_PACKAGE}" NAME) | ||
| string(REGEX REPLACE "\\.nupkg$" "" _winml_nupkg_name "${_winml_nupkg_filename}") |
There was a problem hiding this comment.
cmake_path(GET WINML_NUGET_PACKAGE STEM _winml_nupkg_filename) looks like it will handle getting just the filename without the extension. get_filename_component was superseded by the cmake_path() in 3.20 too.
| if(EXISTS "${WINML_NUGET_PACKAGE}") | ||
| get_filename_component(_winml_nupkg_filename "${WINML_NUGET_PACKAGE}" NAME) | ||
| string(REGEX REPLACE "\\.nupkg$" "" _winml_nupkg_name "${_winml_nupkg_filename}") | ||
| set(_winml_extract_dir "${WINML_LOCAL_PACKAGES_DIR}/${_winml_nupkg_name}") |
There was a problem hiding this comment.
These two could use cmake_Path(APPEND ...) to construct instead of string concatenation.
| if (FAILED(hr)) | ||
| { | ||
| std::cout << " Failed to get library path\n\n"; | ||
| return TRUE; | ||
| } | ||
| libraryPathUtf8.resize(used > 0 ? used - 1 : 0); |
There was a problem hiding this comment.
| if (FAILED(hr)) | |
| { | |
| std::cout << " Failed to get library path\n\n"; | |
| return TRUE; | |
| } | |
| libraryPathUtf8.resize(used > 0 ? used - 1 : 0); | |
| if (FAILED(hr) || used == 0) | |
| { | |
| std::cout << " Failed to get library path\n\n"; | |
| return TRUE; | |
| } | |
| libraryPathUtf8.resize(used - 1); |
Minor: symmetry with the error check above and simplifies the resize call
| } | ||
| } | ||
|
|
||
| WinMLEpCatalogRelease(catalog); |
There was a problem hiding this comment.
Can the catalog be released after the enumeration is done?
|
|
||
| std::cout << std::format("\nRegistered {} certified provider(s).\n", ctx.registeredProviders.size()); | ||
|
|
||
| // Unregister providers before env goes out of scope |
There was a problem hiding this comment.
A bit more explanation about why this is needed would be helpful.
env is a C++ object, so I would expect it to automatically clean itself up.
Adds a CMake-based C++ sample demonstrating the WinML Execution Provider Catalog C API (WinMLEpCatalog*) for discovering and registering hardware-accelerated ML execution providers with ONNX Runtime.
What the sample shows:
Build setup: