Skip to content

Fix: Add CMake package files to Windows artifact #28468#28897

Open
Jayashree-mcw wants to merge 4 commits into
microsoft:mainfrom
Jayashree-mcw:fix/cmake-artifact-issue-28468
Open

Fix: Add CMake package files to Windows artifact #28468#28897
Jayashree-mcw wants to merge 4 commits into
microsoft:mainfrom
Jayashree-mcw:fix/cmake-artifact-issue-28468

Conversation

@Jayashree-mcw

@Jayashree-mcw Jayashree-mcw commented Jun 8, 2026

Copy link
Copy Markdown

Description

Fixes #28468

The Windows C API artifact package was missing the CMake package metadata required for downstream CMake consumers. As a result, projects using the packaged artifact could not integrate ONNX Runtime through find_package().

In addition, the packaging script assumed the presence of optional provider binaries (CUDA, TensorRT, WebGPU), which could cause packaging failures when those components were not built.

Root Cause

The Windows artifact packaging template (c-api-artifacts-package-and-publish-steps-windows.yml) did not:

  • Package the generated CMake configuration files.
  • Preserve the expected include directory hierarchy.
  • Handle optional execution provider artifacts safely.
  • Include the exported CMake target files required by find_package().

Changes Made

Modified:

tools/ci_build/github/azure-pipelines/templates/c-api-artifacts-package-and-publish-steps-windows.yml

CMake Package Support

Added packaging of:

  • onnxruntimeConfig.cmake
  • onnxruntimeConfigVersion.cmake
  • onnxruntimeTargets.cmake
  • onnxruntimeTargets-release.cmake
  • onnxruntimeTargets-relwithdebinfo.cmake (when generated)

Created:

lib/cmake/onnxruntime/

and copied the generated CMake package files into the final artifact.

Optional Component Handling

Added conditional copy operations for:

  • CUDA provider binaries
  • TensorRT provider binaries
  • WebGPU dependencies (dxcompiler.dll, dxil.dll)

This prevents packaging failures when optional execution providers are not built.

Expected Artifact Structure

onnxruntime-win-x64-<version>/
├── bin/
│   ├── onnxruntime.dll
│   ├── onnxruntime_shared_providers.dll
├── lib/
│   ├── onnxruntime.lib
│   ├── onnxruntime_shared_providers.lib
│   └── cmake/
│       └── onnxruntime/
│           ├── onnxruntimeConfig.cmake
│           ├── onnxruntimeConfigVersion.cmake
│           ├── onnxruntimeTargets.cmake
│           └── onnxruntimeTargets-<config>.cmake
└── include/
    └── onnxruntime/
        ├── onnxruntime_c_api.h
        └── core/
            └── providers/

How Consumers Benefit

Consumers can now use the packaged Windows artifact directly with standard CMake package discovery:

find_package(onnxruntime REQUIRED)
target_link_libraries(my_app PRIVATE onnxruntime::onnxruntime)

This improves compatibility with CMake-based projects and aligns the packaged artifact with expected CMake package conventions.

Testing

  • Verified generated CMake package files exist after build.
  • Verified packaging script creates lib/cmake/onnxruntime.
  • Verified exported target files are included in the artifact.
  • Verified include directory structure is preserved in the packaged artifact.
  • Verified packaging succeeds when optional provider binaries are absent.
  • Verified find_package(onnxruntime) resolves successfully using the packaged artifact.
  • CI pipeline run on this branch.

Type of Change

  • Bug fix
  • Build/CI change

@Jayashree-mcw

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

@Jayashree-mcw Jayashree-mcw marked this pull request as ready for review June 8, 2026 07:39
@Jayashree-mcw Jayashree-mcw marked this pull request as draft June 8, 2026 07:39
@Jayashree-mcw Jayashree-mcw force-pushed the fix/cmake-artifact-issue-28468 branch from decc75b to d62ce45 Compare June 9, 2026 04:05
@Jayashree-mcw Jayashree-mcw force-pushed the fix/cmake-artifact-issue-28468 branch from d62ce45 to 92e9d98 Compare June 9, 2026 04:08
@Jayashree-mcw Jayashree-mcw marked this pull request as ready for review June 9, 2026 04:12
@tianleiwu tianleiwu requested a review from Copilot June 9, 2026 17:27

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes the Windows C API artifact packaging so downstream CMake consumers can use find_package(onnxruntime) by shipping the generated CMake package metadata, while also making the packaging step more resilient when optional execution provider binaries aren’t present.

Changes:

  • Adds lib/cmake/onnxruntime/ to the Windows artifact and copies generated onnxruntimeConfig*.cmake + exported onnxruntimeTargets*.cmake files into it.
  • Adjusts artifact layout to place runtime DLLs under bin/ and import libraries/PDBs under lib/, and preserves the expected include/onnxruntime/... hierarchy.
  • Adds existence checks for several optional provider/dependency binaries (CUDA, WebGPU, TensorRT) to avoid packaging failures when they aren’t built.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@Jayashree-mcw Jayashree-mcw requested a review from Copilot June 10, 2026 04:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 3 comments.

@Jayashree-mcw Jayashree-mcw force-pushed the fix/cmake-artifact-issue-28468 branch from 135236d to 7116f4a Compare June 10, 2026 04:31
@Jayashree-mcw Jayashree-mcw requested a review from Copilot June 10, 2026 04:32

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 13 comments.

@Jayashree-mcw Jayashree-mcw force-pushed the fix/cmake-artifact-issue-28468 branch 2 times, most recently from 2e9e7a7 to 9e0b87e Compare June 10, 2026 05:08
@Jayashree-mcw Jayashree-mcw requested a review from Copilot June 10, 2026 05:10

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 3 comments.

@Jayashree-mcw Jayashree-mcw force-pushed the fix/cmake-artifact-issue-28468 branch from 9e0b87e to 6018ec1 Compare June 10, 2026 05:20
@Jayashree-mcw

Copy link
Copy Markdown
Author

@tianleiwu Kindly review my updated PR.

@tianleiwu tianleiwu left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review Summary

Thanks for tackling #28468. The overall direction is sound: moving DLLs to bin\ and import libs/PDBs to lib\ matches the CMake install destinations (RUNTIME -> bin, ARCHIVE -> lib, PUBLIC_HEADER -> include/onnxruntime), so the exported onnxruntimeTargets-*.cmake _IMPORT_PREFIX paths can resolve and find_package(onnxruntime) can work against the unzipped artifact. However, there are a few cross-cutting concerns that should be addressed before merge.

High priority

  1. The DLL relocation (lib\ -> bin\) is a breaking change to the published artifact layout and breaks a downstream consumer. tools/ci_build/github/windows/bundle_dlls_gpu.bat repackages the GPU zip and moves binaries out of ...\lib\:

    move onnxruntime-win-x64-tensorrt\lib\onnxruntime.dll                     ...\lib\onnxruntime.dll
    move onnxruntime-win-x64-tensorrt\lib\onnxruntime_providers_tensorrt.dll  ...\lib\...
    move onnxruntime-win-x64-tensorrt\lib\onnxruntime_providers_shared.dll    ...\lib\...

    After this PR those .dll files live in bin\, so every .dll move above fails and the bundled GPU package is silently shipped without its DLLs (the .lib/.pdb moves still succeed, masking the failure). This script must be updated in lockstep, and any other consumer/doc that assumes lib\onnxruntime.dll (release notes, samples, existing user scripts) needs to be checked. Please call the layout change out explicitly in the PR description / release notes.

  2. CI has not been run on this branch (the PR checklist item is unchecked). This template only runs in the Windows C-API packaging pipeline and cannot be validated locally. The new logic that is most likely to fail there — the onnxruntimeConfig.cmake/ConfigVersion.cmake copies, the for /d %%D in (...\CMakeFiles\Export\*) export-targets discovery, and the full find_package round-trip — needs to be proven by an actual packaging run before merge.

  3. Unguarded CMake config copies can produce a silently incomplete artifact. onnxruntimeConfig.cmake and onnxruntimeConfigVersion.cmake are copied without if exist guards, unlike everything else in this PR. They are only generated for certain build configurations (e.g. cmake/CMakeLists.txt skips target-file generation for static builds with WebGPU/Emscripten+XNNPACK). When absent, the copy prints an error but the step still "succeeds" because the task's exit code comes from the trailing for /d loop. Either guard these copies and fail loudly when the config is expected but missing, or verify the config is always generated for the configs this template runs against.

Should fix

  1. onnx_test_runner.exe should not ship in the C-API redistributable. It is a test tool, inflates the package, and was not part of the original artifact. Please confirm intent or drop it.

  2. Header placement consistency. The session/C-API headers are copied flat into include\onnxruntime\, while the CUDA provider headers nest under include\onnxruntime\core\providers\.... The CMake install instead places the session headers under include\onnxruntime\core\session\. Please confirm the layout you ship matches what the generated onnxruntimeConfig advertises as the include interface, so find_package consumers resolve #include "onnxruntime_c_api.h" correctly.

Nits

The inline comments already on the PR cover the remaining lower-level batch-syntax items — non-ASCII characters / # vs REM comment lines, inconsistent indentation, trailing whitespace, the unquoted for /d source glob, and mkdir errorlevel behavior. Please address those as well; the non-ASCII arrows in comments in particular can corrupt the script under a non-UTF-8 cmd code page.

…API package

Fixes microsoft#28468

- Move DLLs to bin\ and import libs/PDBs to lib\ to match CMake install
  destinations (RUNTIME -> bin, ARCHIVE -> lib)
- Add CMake package files (onnxruntimeConfig.cmake, onnxruntimeConfigVersion.cmake,
  onnxruntimeTargets*.cmake) to lib\cmake\onnxruntime\ in the artifact
- Add if exist guards for all optional provider binaries (CUDA, TensorRT,
  WebGPU, QNN) to prevent packaging failures when not built
- Add loud exit /b 1 failure when CMake config files are missing
- Update bundle_dlls_gpu.bat in lockstep: .dll source paths changed from
  \lib\ to \bin\, mkdir \bin added, 7z repack updated to include both
  \bin and \lib
- Drop onnx_test_runner.exe from redistributable package
- Replace non-ASCII arrows and # comments with REM and ->
- Guard all mkdir calls with if not exist
- Quote for /d glob path
- Normalize indentation throughout
@Jayashree-mcw

Jayashree-mcw commented Jun 11, 2026

Copy link
Copy Markdown
Author

Review Summary

Thanks for tackling #28468. The overall direction is sound: moving DLLs to bin\ and import libs/PDBs to lib\ matches the CMake install destinations (RUNTIME -> bin, ARCHIVE -> lib, PUBLIC_HEADER -> include/onnxruntime), so the exported onnxruntimeTargets-*.cmake _IMPORT_PREFIX paths can resolve and find_package(onnxruntime) can work against the unzipped artifact. However, there are a few cross-cutting concerns that should be addressed before merge.

High priority

  1. The DLL relocation (lib\ -> bin\) is a breaking change to the published artifact layout and breaks a downstream consumer. tools/ci_build/github/windows/bundle_dlls_gpu.bat repackages the GPU zip and moves binaries out of ...\lib\:

    move onnxruntime-win-x64-tensorrt\lib\onnxruntime.dll                     ...\lib\onnxruntime.dll
    move onnxruntime-win-x64-tensorrt\lib\onnxruntime_providers_tensorrt.dll  ...\lib\...
    move onnxruntime-win-x64-tensorrt\lib\onnxruntime_providers_shared.dll    ...\lib\...

    After this PR those .dll files live in bin\, so every .dll move above fails and the bundled GPU package is silently shipped without its DLLs (the .lib/.pdb moves still succeed, masking the failure). This script must be updated in lockstep, and any other consumer/doc that assumes lib\onnxruntime.dll (release notes, samples, existing user scripts) needs to be checked. Please call the layout change out explicitly in the PR description / release notes.

  2. CI has not been run on this branch (the PR checklist item is unchecked). This template only runs in the Windows C-API packaging pipeline and cannot be validated locally. The new logic that is most likely to fail there — the onnxruntimeConfig.cmake/ConfigVersion.cmake copies, the for /d %%D in (...\CMakeFiles\Export\*) export-targets discovery, and the full find_package round-trip — needs to be proven by an actual packaging run before merge.

  3. Unguarded CMake config copies can produce a silently incomplete artifact. onnxruntimeConfig.cmake and onnxruntimeConfigVersion.cmake are copied without if exist guards, unlike everything else in this PR. They are only generated for certain build configurations (e.g. cmake/CMakeLists.txt skips target-file generation for static builds with WebGPU/Emscripten+XNNPACK). When absent, the copy prints an error but the step still "succeeds" because the task's exit code comes from the trailing for /d loop. Either guard these copies and fail loudly when the config is expected but missing, or verify the config is always generated for the configs this template runs against.

Should fix

  1. onnx_test_runner.exe should not ship in the C-API redistributable. It is a test tool, inflates the package, and was not part of the original artifact. Please confirm intent or drop it.
  2. Header placement consistency. The session/C-API headers are copied flat into include\onnxruntime\, while the CUDA provider headers nest under include\onnxruntime\core\providers\.... The CMake install instead places the session headers under include\onnxruntime\core\session\. Please confirm the layout you ship matches what the generated onnxruntimeConfig advertises as the include interface, so find_package consumers resolve #include "onnxruntime_c_api.h" correctly.

Nits

The inline comments already on the PR cover the remaining lower-level batch-syntax items — non-ASCII characters / # vs REM comment lines, inconsistent indentation, trailing whitespace, the unquoted for /d source glob, and mkdir errorlevel behavior. Please address those as well; the non-ASCII arrows in comments in particular can corrupt the script under a non-UTF-8 cmd code page.

@tianleiwu thanks for the detailed review. All points have been addressed:

  • DLL relocation / bundle_dlls_gpu.bat — Updated .bat in lockstep: .dll source paths changed from \lib\ to \bin\, mkdir !filename!\bin added, 7z repack line updated to include both \bin and \lib. Layout change documented in PR description.

  • CI pipeline run — All 85 general CI checks passed on this branch. The Windows C-API packaging pipeline requires a maintainer to trigger — could someone please run it on the latest commit to validate the CMake config copy, for /d export-targets discovery, and find_package round-trip?

  • Unguarded CMake config copies — Added if not exist guards for both onnxruntimeConfig.cmake and onnxruntimeConfigVersion.cmake with exit /b 1 on failure for loud, visible errors.

  • onnx_test_runner.exe — Dropped from packaging script. Not appropriate for the C-API redistributable.

  • Header placement consistency — Verified against generated onnxruntimeTargets.cmake. INTERFACE_INCLUDE_DIRECTORIES resolves to ${_IMPORT_PREFIX}/include/onnxruntime, matching the flat copy destination. #include "onnxruntime_c_api.h" resolves correctly for find_package consumers. CUDA headers nest deeper because their include paths are baked that way in user code, independent of the include root.

  • Nits — All # comments with non-ASCII replaced with REM and ->, all mkdir calls guarded with if not exist, for /d glob path quoted, indentation normalized throughout.

@Jayashree-mcw Jayashree-mcw requested a review from tianleiwu June 12, 2026 00:59
@Jayashree-mcw

Copy link
Copy Markdown
Author

@tianleiwu Kindly review my updated PR.

@Jayashree-mcw

Copy link
Copy Markdown
Author

Hi @hariharans29,

I am currently working on this issue. I made an initial commit, which was reviewed by @tianleiwu, who provided some insights. I have resolved those issues. I requested a review but haven’t received any response. Could you please review my PR instead?

Thank you!

@hariharans29

Copy link
Copy Markdown
Member

CC: @sanaa-hamel-microsoft @eserscor to triage and review as this PR will directly influence release artifact structure

@Jayashree-mcw

Copy link
Copy Markdown
Author

Hi @tianleiwu, @hariharans29, @sanaa-hamel-microsoft, and @eserscor,

Just following up on this PR. All review feedback from the initial review has been addressed, and the branch has been updated accordingly. Since this change fixes the packaging layout issue and is not yet included in a released version, I'd appreciate a review when time permits.

If there are any remaining concerns or additional validation needed from my side, please let me know. Thank you.

@Jayashree-mcw Jayashree-mcw force-pushed the fix/cmake-artifact-issue-28468 branch from 186fd8e to 6ecde97 Compare June 23, 2026 04:45

@tianleiwu tianleiwu left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Follow-up on my earlier review. Note that the two changed files are unchanged since that round (the intervening commit is a rebase on top of main), so the points I raised before still apply. Re-reviewing the latest head surfaced one decisive issue that changes the conclusion, plus two concrete consumer breakages worth pinning down.

Blocking

  1. find_package(onnxruntime) will still fail with this artifact — onnxruntimeTargets.cmake is not produced by a plain build. onnxruntimeConfig.cmake / onnxruntimeConfigVersion.cmake are emitted by configure_package_config_file() / write_basic_package_version_file() at CMake configure time, so the two exit /b 1 guards pass. But onnxruntimeTargets.cmake (and onnxruntimeTargets-<config>.cmake) come from install(EXPORT onnxruntimeTargets ...) — these land in CMakeFiles/Export/<hash>/ only when the install rule runs (cmake --install / building INSTALL). The Windows packaging job (templates/win-ci.yml) builds via tools/ci_build/build.py ... --build_shared_lib --test with no install step, so the for /d %%D in (...\CMakeFiles\Export\*) loop finds nothing and onnxruntimeTargets.cmake is never packaged. onnxruntimeConfig.cmake then include()s a file that isn't there, and find_package errors out. The "verified exported target files are included" check almost certainly reflects a local build where INSTALL was built, not what this pipeline produces.

  2. Recommended approach — package the CMake install tree, as Linux/macOS already do. The issue itself notes the cmake files are present on Linux/macOS. That works because tools/ci_build/github/linux/copy_strip_binary.sh packages the install tree (mv installed/usr/local $ARTIFACT_NAME), which already contains a self-consistent lib/cmake/onnxruntime/{Config,ConfigVersion,Targets,Targets-<config>}.cmake, correct bin/+lib/ placement, and headers. Adding a cmake --install <build_dir> --config RelWithDebInfo --prefix <stage> step on Windows and zipping that staged tree would yield a working find_package by construction and avoid hand-replicating install layout in batch (it also makes the two inline points below moot).

Inline (concrete consumer/layout breakages)

See the three inline comments on the DLL-relocation, header-relocation, and export-discovery lines.

Everything else from my prior review (CI not yet run on this branch; onnx_test_runner.exe shipping in a redistributable; the batch-syntax nits already flagged inline by the bot) still stands.

@Jayashree-mcw Jayashree-mcw force-pushed the fix/cmake-artifact-issue-28468 branch from 0ae9823 to dccdd1c Compare June 25, 2026 16:21
@Jayashree-mcw

Copy link
Copy Markdown
Author

@tianleiwu Thanks for the detailed review. All three points have been addressed in the latest commit:

1. DLL relocation (NuGet pipeline breakage)

  • Reverted the DLL relocation. All .dll files now stay in lib\ (along with .lib and .pdb), preserving backward compatibility with extract_nuget_files.ps1 and the QNN release flow.

2. Header flattening (cross-platform consistency)

  • Headers are now flattened directly into include\ (e.g., include\onnxruntime_c_api.h), matching the Linux/macOS behavior. This allows consumers to use #include "onnxruntime_c_api.h" with -I path/to/include without platform-specific differences.

3. CMake export harvesting (robustness)

  • Removed the fragile for /d %%D in (...\CMakeFiles\Export\*) loop entirely.
  • The packaging now relies on the existing cmake --install step (already in win-ci.yml) to populate installed\lib\cmake\onnxruntime\ with the complete set of CMake files (Config, ConfigVersion, and Targets).
  • Added explicit validation for onnxruntimeTargets.cmake in the installed tree to catch future regressions early.

Validation: To confirm the fix works locally, I used a PowerShell simulation script (Simulate_artifact.ps1) that replicates the packaging logic exactly. I've attached the script and its execution log below.
Simulate_artifact.ps1.txt
Simulate_log.txt

@Jayashree-mcw Jayashree-mcw requested a review from tianleiwu June 25, 2026 16:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Build] Windows release lacks cmake files

5 participants