Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Samples/WindowsML/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ Windows ML enables high-performance, reliable inferencing of machine learning mo
|--------|-------------|--------------|
| [cpp-abi](cpp-abi/) | Direct ABI implementation using raw COM interfaces | Automatic ABI header generation, no projections |

### CMake Samples

| Sample | Description | Key Features |
|--------|-------------|--------------|
| [cmake/WinMLEpCatalog](cmake/WinMLEpCatalog/) | WinMLEpCatalog Native C API with CMake/vcpkg | Native C API, no WinRT dependencies, interactive shell |

### C# Samples

#### Console Applications
Expand Down
49 changes: 49 additions & 0 deletions Samples/WindowsML/cmake/WinMLEpCatalog/.clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Copyright (C) Microsoft Corporation. All rights reserved.
# Clang-format configuration for WinML EP Catalog Sample

BasedOnStyle: Microsoft
IndentWidth: 4
TabWidth: 4
UseTab: Never
ColumnLimit: 120

# Braces
BreakBeforeBraces: Allman
AllowShortBlocksOnASingleLine: Empty
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false

# Indentation
NamespaceIndentation: None
IndentCaseLabels: false

# Alignment
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignOperands: true
AlignTrailingComments: true

# Line breaks
AllowAllParametersOfDeclarationOnNextLine: true
BinPackArguments: false
BinPackParameters: false

# Includes
SortIncludes: true
IncludeBlocks: Preserve

# Pointer alignment
PointerAlignment: Left

# Spaces
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
22 changes: 22 additions & 0 deletions Samples/WindowsML/cmake/WinMLEpCatalog/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Build outputs
out/
build/

# CMake cache
CMakeCache.txt
CMakeFiles/

# Local package overrides (for development/testing)
local_packages/

# IDE files
.vs/
.vscode/
*.user

# Compiled files
*.exe
*.dll
*.pdb
*.obj
*.ilk
98 changes: 98 additions & 0 deletions Samples/WindowsML/cmake/WinMLEpCatalog/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Copyright (C) Microsoft Corporation. All rights reserved.
cmake_minimum_required(VERSION 3.21)

project(WinMLEpCatalogSample
VERSION 1.0.0
DESCRIPTION "Windows ML Execution Provider Catalog Sample with ONNX Runtime Integration"
LANGUAGES CXX
)

# 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"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider extracting somewhere under the CMAKE_CURRENT_BINARY_DIR or CMAKE_BINARY_DIR so that the source tree isn't touched.

CACHE PATH "Directory where the nupkg is extracted")

# Auto-extract the local nupkg (if needed) and wire CMake package discovery.
# Users can still override microsoft.windows.ai.machinelearning_DIR directly.
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}")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

set(_winml_extract_dir "${WINML_LOCAL_PACKAGES_DIR}/${_winml_nupkg_name}")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two could use cmake_Path(APPEND ...) to construct instead of string concatenation.

set(_winml_config_file "${_winml_extract_dir}/build/cmake/microsoft.windows.ai.machinelearning-config.cmake")

if(NOT EXISTS "${_winml_config_file}")
file(MAKE_DIRECTORY "${WINML_LOCAL_PACKAGES_DIR}")
message(STATUS "Extracting ${WINML_NUGET_PACKAGE} -> ${_winml_extract_dir}")
file(ARCHIVE_EXTRACT
INPUT "${WINML_NUGET_PACKAGE}"
DESTINATION "${_winml_extract_dir}")
endif()

set(microsoft.windows.ai.machinelearning_DIR "${_winml_extract_dir}/build/cmake"
CACHE PATH "Path to microsoft.windows.ai.machinelearning CMake config" FORCE)
else()
message(FATAL_ERROR
"Windows ML NuGet package not found: ${WINML_NUGET_PACKAGE}. "
"Place the nupkg at that location or set microsoft.windows.ai.machinelearning_DIR.")
endif()
endif()

# Find the Windows ML package from the extracted NuGet package CMake config.
find_package(microsoft.windows.ai.machinelearning CONFIG REQUIRED)

# C++20 standard for modern features (std::format, etc.)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Create the executable
add_executable(WinMLEpCatalogSample
main.cpp
)

# WindowsML::Api - WinMLEpCatalog* C API for discovering execution providers
# WindowsML::OnnxRuntime - ONNX Runtime C/C++ API (OrtEnv, session creation, etc.)
target_link_libraries(WinMLEpCatalogSample
PRIVATE
WindowsML::Api
WindowsML::OnnxRuntime
)

# Copy runtime DLLs (onnxruntime.dll, Microsoft.Windows.AI.MachineLearning.dll)
# to the executable output directory so the sample can run in-place.
add_custom_command(TARGET WinMLEpCatalogSample POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_RUNTIME_DLLS:WinMLEpCatalogSample> $<TARGET_FILE_DIR:WinMLEpCatalogSample>
COMMAND_EXPAND_LISTS
VERBATIM
)

# DirectML.dll has no import library, so it is not included in TARGET_RUNTIME_DLLS.
# Copy it explicitly if your application uses the DirectML execution provider.
add_custom_command(TARGET WinMLEpCatalogSample POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${WINML_DIRECTML_DLL}" $<TARGET_FILE_DIR:WinMLEpCatalogSample>
)

# Set Windows-specific compiler options
if(MSVC)
target_compile_options(WinMLEpCatalogSample PRIVATE
/W4 # Warning level 4
/permissive- # Strict C++ conformance
/Zc:__cplusplus # Report correct __cplusplus value
/EHsc # Enable C++ exception handling
)

# Use static runtime for easier deployment (no MSVC runtime dependency)
set_property(TARGET WinMLEpCatalogSample PROPERTY
MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>"
)
endif()

# Set subsystem to console (not Windows GUI)
if(WIN32)
set_target_properties(WinMLEpCatalogSample PROPERTIES
WIN32_EXECUTABLE FALSE
)
endif()
28 changes: 28 additions & 0 deletions Samples/WindowsML/cmake/WinMLEpCatalog/CMakePresets.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"version": 6,
"cmakeMinimumRequired": {
"major": 3,
"minor": 21,
"patch": 0
},
"configurePresets": [
{
"name": "nuget",
"displayName": "NuGet (Direct)",
"description": "Configure using local .nupkg extraction and direct CMake package files",
"generator": "Ninja",
"binaryDir": "${sourceDir}/out/build/${presetName}",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
}
}
],
"buildPresets": [
{
"name": "nuget",
"configurePreset": "nuget"
}
]
}
91 changes: 91 additions & 0 deletions Samples/WindowsML/cmake/WinMLEpCatalog/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Windows ML EP Catalog Sample (CMake/WinML C API)

This sample demonstrates the **WinMLEpCatalog WinML C API** for discovering and managing hardware-accelerated execution providers (EPs) for machine learning inference on Windows.

The CMake project is configured to use the Windows ML NuGet package directly and auto-extract it during configure.

## Overview

This sample showcases:

- Creating an ONNX Runtime environment (`Ort::Env`)
- Creating and releasing a catalog handle
- Enumerating registered execution providers
- Inspecting provider metadata (name, version, state, certification)
- Preparing providers with `EnsureReady`
- Registering prepared providers with ONNX Runtime

## Prerequisites

- **Visual Studio 2022** with C++ workload
- **CMake** 3.21 or later
- **Ninja** (optional; only needed when using Ninja generator)
- `Microsoft.WindowsAppSDK.ML.2.0.246-experimental.nupkg` in this folder

Example install commands:

```powershell
winget install --exact --id Kitware.CMake
winget install --exact --id Ninja-build.Ninja
```

## Build (Recommended)

Use the helper script:

```powershell
# RelWithDebInfo for host architecture
.\build.ps1

# Debug with Visual Studio generator
.\build.ps1 -Generator VisualStudio -Configuration Debug

# Release for ARM64
.\build.ps1 -Configuration Release -Platform arm64

# Clean and rebuild
.\build.ps1 -Clean
```

During configure, CMake automatically:

1. Finds the local `.nupkg`
2. Extracts it to `local_packages/<nupkg-name>/` (if not already extracted)
3. Sets `microsoft.windows.ai.machinelearning_DIR` to the extracted `build/cmake` folder

## Manual Build

```powershell
# Configure (auto-extracts nupkg if needed)
cmake --preset nuget

# Build
cmake --build out/build/nuget --config RelWithDebInfo

# Run
.\out\build\nuget\WinMLEpCatalogSample.exe
```

## Package Version Override

To use a different package file:

```powershell
cmake --preset nuget -DWINML_NUGET_PACKAGE=.\Microsoft.WindowsAppSDK.ML.<new-version>.nupkg
```

For a full refresh, delete `local_packages/` and `out/` and configure again.

## Troubleshooting

### "Windows ML NuGet package not found"

Ensure the package exists in this directory, or pass `-DWINML_NUGET_PACKAGE=<path-to-nupkg>`.

### "Failed to create EP catalog"

Check that runtime DLLs were copied to the executable output directory and the target OS is supported.

## License

Copyright (C) Microsoft Corporation. All rights reserved.
20 changes: 20 additions & 0 deletions Samples/WindowsML/cmake/WinMLEpCatalog/build.cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
@echo off
REM Copyright (C) Microsoft Corporation. All rights reserved.
REM
REM Simple batch wrapper for build.ps1
REM Usage: build.cmd [Debug|Release|RelWithDebInfo|MinSizeRel] [x64|arm64] [Ninja|VisualStudio]
REM

setlocal

set CONFIG=%1
set PLATFORM=%2
set GENERATOR=%3

if "%CONFIG%"=="" set CONFIG=Debug

if "%GENERATOR%"=="" (
powershell -ExecutionPolicy Bypass -File "%~dp0build.ps1" -Configuration %CONFIG% -Platform %PLATFORM%
) else (
powershell -ExecutionPolicy Bypass -File "%~dp0build.ps1" -Configuration %CONFIG% -Platform %PLATFORM% -Generator %GENERATOR%
)
Loading