From 1892962dfa78e98c5689b723e7d333a8b9c1ec8a Mon Sep 17 00:00:00 2001 From: n1harika Date: Thu, 11 Jun 2026 05:53:06 -0700 Subject: [PATCH 1/3] Add sxs manifest support for openvino.dll --- cmake/onnxruntime_providers_openvino.cmake | 151 ++++++++++++++++++ cmake/onnxruntime_unittests.cmake | 3 + cmake/sxs/assembly.manifest.in | 12 ++ cmake/sxs/dep.manifest.in | 18 +++ cmake/sxs/embed_manifests.cmake | 117 ++++++++++++++ .../openvino_ep_sxs_isolation_test.cc | 141 ++++++++++++++++ 6 files changed, 442 insertions(+) create mode 100644 cmake/sxs/assembly.manifest.in create mode 100644 cmake/sxs/dep.manifest.in create mode 100644 cmake/sxs/embed_manifests.cmake create mode 100644 onnxruntime/test/providers/openvino/openvino_ep_sxs_isolation_test.cc diff --git a/cmake/onnxruntime_providers_openvino.cmake b/cmake/onnxruntime_providers_openvino.cmake index 1584d9f703575..287842b1019d5 100644 --- a/cmake/onnxruntime_providers_openvino.cmake +++ b/cmake/onnxruntime_providers_openvino.cmake @@ -98,3 +98,154 @@ set_target_properties(onnxruntime_providers_openvino PROPERTIES MAP_IMPORTED_CONFIG_RELEASE RelWithDebInfo MAP_IMPORTED_CONFIG_DEBUG RelWithDebInfo ) + +# --------------------------------------------------------------------------- +# Windows SxS (Side-by-Side) loading support +# +# Embeds private-assembly manifests into OV/TBB DLLs and the provider DLL so +# that Windows loads them from the EP's own directory, avoiding DLL collisions +# when another application in the same process also uses OpenVINO. +# --------------------------------------------------------------------------- +if(WIN32) + # Require mt.exe for manifest embedding + if(NOT CMAKE_MT) + message(FATAL_ERROR + "mt.exe not found — SxS manifest embedding is required on Windows.\n" + "Set -DCMAKE_MT= or ensure the Windows SDK is on PATH.") + endif() + + # --- Enumerate OV and TBB DLL filenames for the SxS assembly manifest --- + # Glob patterns selecting the OV binaries needed by the EP. + set(_ORT_OV_PATTERNS + "cache.json" + "*openvino.*" + "*openvinod.*" + "*openvino*plugin*" + "*openvino*compiler*" + "*openvino_ir_frontend*" + "*openvino_onnx_frontend*") + + function(_ort_glob_ov _out_var _dir) + set(_result "") + foreach(_pat IN LISTS _ORT_OV_PATTERNS) + file(GLOB _tmp "${_dir}/${_pat}") + list(APPEND _result ${_tmp}) + endforeach() + set(${_out_var} "${_result}" PARENT_SCOPE) + endfunction() + + if(DEFINED ENV{INTEL_OPENVINO_DIR}) + file(TO_CMAKE_PATH "$ENV{INTEL_OPENVINO_DIR}" _ORT_OV_ROOT) + set(_ov_bin "${_ORT_OV_ROOT}/runtime/bin/intel64") + set(_tbb_bin "${_ORT_OV_ROOT}/runtime/3rdparty/tbb/bin") + + # TBB: split into non-debug (Release/RelWithDebInfo) and debug subsets + file(GLOB _all_tbb "${_tbb_bin}/tbb*.dll") + set(_tbb_release "") + set(_tbb_debug "") + foreach(_f IN LISTS _all_tbb) + get_filename_component(_lname "${_f}" NAME) + string(TOLOWER "${_lname}" _lname_lower) + if(_lname_lower MATCHES "debug") + list(APPEND _tbb_debug "${_f}") + else() + list(APPEND _tbb_release "${_f}") + endif() + endforeach() + + if(EXISTS "${_ov_bin}/Release") + _ort_glob_ov(_ov_release "${_ov_bin}/Release") + set(ORT_OV_INSTALL_FILES_Release ${_ov_release} ${_tbb_release}) + endif() + if(EXISTS "${_ov_bin}/Debug") + _ort_glob_ov(_ov_debug "${_ov_bin}/Debug") + set(ORT_OV_INSTALL_FILES_Debug ${_ov_debug} ${_tbb_debug}) + endif() + if(EXISTS "${_ov_bin}/RelWithDebInfo") + _ort_glob_ov(_ov_rwdi "${_ov_bin}/RelWithDebInfo") + set(ORT_OV_INSTALL_FILES_RelWithDebInfo ${_ov_rwdi} ${_tbb_release}) + elseif(DEFINED ORT_OV_INSTALL_FILES_Release) + set(ORT_OV_INSTALL_FILES_RelWithDebInfo ${ORT_OV_INSTALL_FILES_Release}) + endif() + else() + # Python wheel layout — all binaries flat in /openvino/libs/ + set(Python3_FIND_VIRTUALENV FIRST) + find_package(Python3 QUIET COMPONENTS Interpreter) + if(Python3_FOUND) + execute_process( + COMMAND "${Python3_EXECUTABLE}" -c + "import openvino, pathlib; print(pathlib.Path(openvino.__file__).parent)" + OUTPUT_VARIABLE _ORT_OV_WHEEL_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE _ORT_OV_WHEEL_RESULT) + endif() + if(Python3_FOUND AND _ORT_OV_WHEEL_RESULT EQUAL 0 AND _ORT_OV_WHEEL_DIR) + file(TO_CMAKE_PATH "${_ORT_OV_WHEEL_DIR}" _ORT_OV_ROOT) + set(_libs "${_ORT_OV_ROOT}/libs") + if(EXISTS "${_libs}") + _ort_glob_ov(_ov_wheel "${_libs}") + file(GLOB _tbb_wheel "${_libs}/tbb*.dll") + set(ORT_OV_INSTALL_FILES_wheel ${_ov_wheel} ${_tbb_wheel}) + endif() + endif() + endif() + + # Collect unique DLL filenames for SxS dep manifest embedding + set(_all_files + ${ORT_OV_INSTALL_FILES_Release} + ${ORT_OV_INSTALL_FILES_Debug} + ${ORT_OV_INSTALL_FILES_RelWithDebInfo} + ${ORT_OV_INSTALL_FILES_wheel}) + set(ORT_OV_TBB_DLL_NAMES "") + foreach(_f IN LISTS _all_files) + get_filename_component(_ext "${_f}" EXT) + get_filename_component(_name "${_f}" NAME) + if(_ext STREQUAL ".dll") + list(APPEND ORT_OV_TBB_DLL_NAMES "${_name}") + endif() + endforeach() + list(REMOVE_DUPLICATES ORT_OV_TBB_DLL_NAMES) + + if(ORT_OV_TBB_DLL_NAMES) + message(STATUS "OpenVINO SxS: DLLs for manifest: ${ORT_OV_TBB_DLL_NAMES}") + + # --- Generate assembly manifest --- + set(ORT_SXS_VERSION "${ORT_VERSION}") + set(_file_entries "") + foreach(_dll IN LISTS ORT_OV_TBB_DLL_NAMES) + string(APPEND _file_entries " \n") + endforeach() + set(ORT_SXS_ASSEMBLY_FILE_ENTRIES "${_file_entries}") + + configure_file( + "${CMAKE_CURRENT_LIST_DIR}/sxs/assembly.manifest.in" + "${CMAKE_BINARY_DIR}/cmake/sxs/openvino_runtime.manifest" + @ONLY) + install(FILES "${CMAKE_BINARY_DIR}/cmake/sxs/openvino_runtime.manifest" + DESTINATION ${CMAKE_INSTALL_BINDIR}) + + # --- Install OV+TBB binaries alongside the provider DLL --- + if(DEFINED ORT_OV_INSTALL_FILES_wheel) + install(FILES ${ORT_OV_INSTALL_FILES_wheel} DESTINATION ${CMAKE_INSTALL_BINDIR}) + else() + foreach(_config IN ITEMS Release Debug RelWithDebInfo) + if(ORT_OV_INSTALL_FILES_${_config}) + install(FILES ${ORT_OV_INSTALL_FILES_${_config}} + DESTINATION ${CMAKE_INSTALL_BINDIR} + CONFIGURATIONS ${_config}) + endif() + endforeach() + endif() + + # --- Embed SxS manifests at install time --- + install(CODE "set(CMAKE_MT \"${CMAKE_MT}\")") + install(CODE "set(SXS_SOURCE_DIR \"${CMAKE_CURRENT_LIST_DIR}/sxs\")") + install(CODE "set(EP_FILE_VERSION \"${ORT_VERSION}.0\")") + install(CODE "set(OV_TBB_DLL_NAMES \"${ORT_OV_TBB_DLL_NAMES}\")") + install(CODE "set(ORT_SXS_BIN_DIR \"\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}\")") + install(SCRIPT "${CMAKE_CURRENT_LIST_DIR}/sxs/embed_manifests.cmake") + else() + message(WARNING "OpenVINO SxS: No OV/TBB DLLs found — SxS manifest embedding skipped.\n" + "Ensure INTEL_OPENVINO_DIR is set (setupvars.bat) or the openvino wheel is installed.") + endif() +endif() diff --git a/cmake/onnxruntime_unittests.cmake b/cmake/onnxruntime_unittests.cmake index 4b1ef26fc29d5..8b5ae555d80db 100644 --- a/cmake/onnxruntime_unittests.cmake +++ b/cmake/onnxruntime_unittests.cmake @@ -1186,6 +1186,9 @@ endif() if (onnxruntime_ENABLE_TRAINING_TORCH_INTEROP) target_link_libraries(onnxruntime_test_all PRIVATE Python::Python) endif() +if (WIN32 AND onnxruntime_USE_OPENVINO) + target_link_libraries(onnxruntime_test_all PRIVATE psapi) +endif() onnxruntime_apply_emscripten_test_link_settings(onnxruntime_test_all) if (onnxruntime_ENABLE_ATEN) diff --git a/cmake/sxs/assembly.manifest.in b/cmake/sxs/assembly.manifest.in new file mode 100644 index 0000000000000..bf67fac66ab14 --- /dev/null +++ b/cmake/sxs/assembly.manifest.in @@ -0,0 +1,12 @@ + + + + +@ORT_SXS_ASSEMBLY_FILE_ENTRIES@ diff --git a/cmake/sxs/dep.manifest.in b/cmake/sxs/dep.manifest.in new file mode 100644 index 0000000000000..ba01ae08bb93b --- /dev/null +++ b/cmake/sxs/dep.manifest.in @@ -0,0 +1,18 @@ + + + + + + + + + + diff --git a/cmake/sxs/embed_manifests.cmake b/cmake/sxs/embed_manifests.cmake new file mode 100644 index 0000000000000..6abb9f3fb5483 --- /dev/null +++ b/cmake/sxs/embed_manifests.cmake @@ -0,0 +1,117 @@ +# Copyright (C) Intel Corporation +# Licensed under the MIT License +# +# Install-time CMake script: embeds SxS manifests into OV+TBB DLLs and +# onnxruntime_providers_openvino.dll. +# Run via install(SCRIPT ...) after OV/TBB binaries are installed. +# +# Variables injected by install(CODE) in onnxruntime_providers_openvino.cmake: +# CMAKE_MT — absolute path to mt.exe +# SXS_SOURCE_DIR — cmake/sxs/ source directory +# EP_FILE_VERSION — EP version in A.B.C.D form (e.g. 1.28.0.0) +# OV_TBB_DLL_NAMES — semicolon-separated list of OV+TBB DLL filenames + +cmake_minimum_required(VERSION 3.28) + +set(PROVIDER_DLL_NAME "onnxruntime_providers_openvino") + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + +# Embed a manifest into a DLL as RT_MANIFEST resource ID 2. +# If the DLL already has a resource ID 2 manifest it is extracted and merged first. +# Temporary files are written next to the DLL and deleted on completion. +function(ort_sxs_embed_manifest DLL_PATH MANIFEST_PATH) + get_filename_component(_dll_dir "${DLL_PATH}" DIRECTORY) + get_filename_component(_dll_name_we "${DLL_PATH}" NAME_WE) + set(_existing "${_dll_dir}/existing_${_dll_name_we}.manifest") + + # Try to extract any existing RT_MANIFEST resource ID 2. + execute_process( + COMMAND "${CMAKE_MT}" -nologo + "-inputresource:${DLL_PATH};2" + "-out:${_existing}" + RESULT_VARIABLE _rc + OUTPUT_QUIET ERROR_QUIET) + + if(_rc EQUAL 0 AND EXISTS "${_existing}") + # Merge existing + new dep manifest, then re-embed. + execute_process( + COMMAND "${CMAKE_MT}" -nologo + "-manifest" "${_existing}" "${MANIFEST_PATH}" + "-outputresource:${DLL_PATH};2" + RESULT_VARIABLE _rc2) + file(REMOVE "${_existing}") + if(NOT _rc2 EQUAL 0) + message(FATAL_ERROR + "SxS manifest embedding: mt.exe merge failed for '${DLL_PATH}' (exit ${_rc2}).") + endif() + else() + # No existing manifest — embed the new one directly. + execute_process( + COMMAND "${CMAKE_MT}" -nologo + "-manifest" "${MANIFEST_PATH}" + "-outputresource:${DLL_PATH};2" + RESULT_VARIABLE _rc2) + if(NOT _rc2 EQUAL 0) + message(FATAL_ERROR + "SxS manifest embedding: mt.exe embed failed for '${DLL_PATH}' (exit ${_rc2}).") + endif() + endif() +endfunction() + +# --------------------------------------------------------------------------- +# Resolve install directory +# --------------------------------------------------------------------------- + +if(DEFINED ORT_SXS_BIN_DIR AND NOT ORT_SXS_BIN_DIR STREQUAL "") + set(BIN_DIR "${ORT_SXS_BIN_DIR}") +else() + set(BIN_DIR "${CMAKE_INSTALL_PREFIX}/bin") +endif() +message(STATUS "SxS manifest embedding: processing '${BIN_DIR}'") + +# --------------------------------------------------------------------------- +# Step 1: Embed dep manifests into each OV+TBB DLL +# --------------------------------------------------------------------------- + +foreach(_name IN LISTS OV_TBB_DLL_NAMES) + set(_dll "${BIN_DIR}/${_name}") + if(NOT EXISTS "${_dll}") + continue() # DLL absent for this config (e.g. debug-only DLL in a Release build) + endif() + get_filename_component(_name_we "${_name}" NAME_WE) + set(DLL_BASE_NAME "${_name_we}") + set(_dep_manifest "${BIN_DIR}/${_name_we}.dep.manifest") + configure_file("${SXS_SOURCE_DIR}/dep.manifest.in" "${_dep_manifest}") + ort_sxs_embed_manifest("${_dll}" "${_dep_manifest}") + file(REMOVE "${_dep_manifest}") + message(STATUS "SxS manifest embedding: embedded dep manifest in ${_name_we}.dll") +endforeach() + +# --------------------------------------------------------------------------- +# Step 2: Embed dep manifest into onnxruntime_providers_openvino.dll +# --------------------------------------------------------------------------- + +# The provider DLL may be installed to bin/ or lib/ depending on whether it's +# a SHARED or MODULE library. Check both locations. +set(_provider_dll "${BIN_DIR}/${PROVIDER_DLL_NAME}.dll") +if(NOT EXISTS "${_provider_dll}") + # Try the lib/ sibling directory (MODULE libraries install to LIBRARY dest) + get_filename_component(_prefix "${BIN_DIR}" DIRECTORY) + set(_provider_dll "${_prefix}/lib/${PROVIDER_DLL_NAME}.dll") +endif() +if(NOT EXISTS "${_provider_dll}") + message(FATAL_ERROR + "SxS manifest embedding: '${PROVIDER_DLL_NAME}.dll' not found in '${BIN_DIR}' or '${_prefix}/lib'.") +endif() + +set(DLL_BASE_NAME "${PROVIDER_DLL_NAME}") +set(_dep_manifest "${BIN_DIR}/${PROVIDER_DLL_NAME}.dep.manifest") +configure_file("${SXS_SOURCE_DIR}/dep.manifest.in" "${_dep_manifest}") +ort_sxs_embed_manifest("${_provider_dll}" "${_dep_manifest}") +file(REMOVE "${_dep_manifest}") +message(STATUS "SxS manifest embedding: embedded dep manifest in ${PROVIDER_DLL_NAME}.dll") + +message(STATUS "SxS manifest embedding: done") diff --git a/onnxruntime/test/providers/openvino/openvino_ep_sxs_isolation_test.cc b/onnxruntime/test/providers/openvino/openvino_ep_sxs_isolation_test.cc new file mode 100644 index 0000000000000..b9a5955923635 --- /dev/null +++ b/onnxruntime/test/providers/openvino/openvino_ep_sxs_isolation_test.cc @@ -0,0 +1,141 @@ +// Copyright (C) Intel Corporation +// Licensed under the MIT License +// +// Windows-only test for SxS (Side-by-Side) DLL isolation. +// Verifies that OpenVINO EP loads its own private copy of openvino.dll even +// when another copy is already loaded in the process. + +#ifdef _WIN32 + +#define WIN32_LEAN_AND_MEAN +#include +#include + +#include +#include +#include +#include + +#include "core/session/onnxruntime_cxx_api.h" +#include "gtest/gtest.h" + +namespace fs = std::filesystem; + +extern std::unique_ptr ort_env; + +namespace { + +static fs::path GetExeDir() { + wchar_t exe_path[MAX_PATH] = {}; + GetModuleFileNameW(nullptr, exe_path, MAX_PATH); + return fs::path(exe_path).parent_path(); +} + +// Returns full paths of all loaded DLLs whose name contains the given fragment. +static std::vector FindLoadedModules(std::wstring_view name_fragment_lower) { + std::vector result; + std::vector modules(4096); + DWORD cbNeeded = 0; + if (!EnumProcessModulesEx(GetCurrentProcess(), modules.data(), + static_cast(modules.size() * sizeof(HMODULE)), + &cbNeeded, LIST_MODULES_ALL)) { + return result; + } + DWORD count = cbNeeded / sizeof(HMODULE); + for (DWORD i = 0; i < count; ++i) { + wchar_t path[MAX_PATH] = {}; + GetModuleFileNameExW(GetCurrentProcess(), modules[i], path, MAX_PATH); + std::wstring wpath(path); + std::wstring lower = wpath; + for (auto& c : lower) c = towlower(c); + if (lower.find(name_fragment_lower) != std::wstring::npos) { + result.push_back(wpath); + } + } + return result; +} + +} // namespace + +// --------------------------------------------------------------------------- +struct SxsIsolationFixture : public ::testing::Test { + fs::path bin_dir_; + fs::path temp_dir_; + fs::path preloaded_ov_; + HMODULE h_preloaded_ov_ = nullptr; + + void SetUp() override { + bin_dir_ = GetExeDir(); + + if (!fs::exists(bin_dir_ / L"openvino.dll")) { + GTEST_SKIP() << "openvino.dll not found — run from installed directory"; + } + + // Skip if manifests haven't been embedded (cmake --install) + if (!fs::exists(bin_dir_ / L"openvino_runtime.manifest")) { + GTEST_SKIP() << "openvino_runtime.manifest not found — run cmake --install first"; + } + + // Copy openvino.dll to a temp folder and pre-load it. + // This simulates another app having already loaded + // its own openvino.dll into this process. + temp_dir_ = bin_dir_ / L"sxs_test_temp"; + fs::create_directories(temp_dir_); + + preloaded_ov_ = temp_dir_ / L"openvino.dll"; + fs::copy_file(bin_dir_ / L"openvino.dll", preloaded_ov_, + fs::copy_options::overwrite_existing); + + // Load into module list without actually initializing the DLL + h_preloaded_ov_ = LoadLibraryExW(preloaded_ov_.wstring().c_str(), nullptr, + DONT_RESOLVE_DLL_REFERENCES); + ASSERT_NE(h_preloaded_ov_, nullptr) + << "Pre-load of openvino.dll failed (error " << GetLastError() << ")"; + } + + void TearDown() override { + if (h_preloaded_ov_) { + FreeLibrary(h_preloaded_ov_); + h_preloaded_ov_ = nullptr; + } + std::error_code ec; + fs::remove_all(temp_dir_, ec); + } +}; + +// --------------------------------------------------------------------------- +TEST_F(SxsIsolationFixture, SxsLoadsPrivateAssemblyCopy) { + // At this point we have 1 openvino.dll loaded (the fake pre-loaded one) + auto ov_mods_before = FindLoadedModules(L"openvino.dll"); + ASSERT_GE(ov_mods_before.size(), 1u); + + // Trigger OpenVINO EP load — SxS should cause a SECOND openvino.dll to + // load from the bin directory, ignoring the already-loaded copy. + Ort::SessionOptions session_opts; + std::unordered_map ov_options; + ov_options["device_type"] = "CPU"; + session_opts.AppendExecutionProvider_OpenVINO_V2(ov_options); + + // If SxS works, we should now have 2 distinct openvino.dll modules + auto ov_mods_after = FindLoadedModules(L"openvino.dll"); + + ASSERT_GE(ov_mods_after.size(), 2u) + << "SxS isolation failed: expected >=2 openvino.dll instances, got " + << ov_mods_after.size(); + + // Confirm both paths are present + auto iequals = [](const std::wstring& a, const std::wstring& b) { + return _wcsicmp(a.c_str(), b.c_str()) == 0; + }; + auto contains = [&](const std::wstring& path) { + return std::any_of(ov_mods_after.begin(), ov_mods_after.end(), + [&](const auto& p) { return iequals(p, path); }); + }; + + EXPECT_TRUE(contains(preloaded_ov_.wstring())) + << "Pre-loaded openvino.dll not found in module list"; + EXPECT_TRUE(contains((bin_dir_ / L"openvino.dll").wstring())) + << "SxS bin-dir openvino.dll not found in module list"; +} + +#endif // _WIN32 From 27231a7d8b7b8c2db179e49d49b32cf7d1a42b2b Mon Sep 17 00:00:00 2001 From: n1harika Date: Wed, 24 Jun 2026 22:57:34 -0700 Subject: [PATCH 2/3] Remove signatures before embedding manifests --- cmake/external/onnx | 2 +- cmake/onnxruntime_providers_openvino.cmake | 206 +++++++++++++++++---- cmake/sxs/dep.manifest.in | 2 +- cmake/sxs/embed_manifest.cmake | 24 +++ cmake/sxs/embed_manifests.cmake | 117 ------------ cmake/sxs/remove_signature.cmake | 35 ++++ 6 files changed, 227 insertions(+), 159 deletions(-) create mode 100644 cmake/sxs/embed_manifest.cmake delete mode 100644 cmake/sxs/embed_manifests.cmake create mode 100644 cmake/sxs/remove_signature.cmake diff --git a/cmake/external/onnx b/cmake/external/onnx index 2bb50465112fe..be2b5fde82d9c 160000 --- a/cmake/external/onnx +++ b/cmake/external/onnx @@ -1 +1 @@ -Subproject commit 2bb50465112feca9003e1ed654d77f01ff1415ca +Subproject commit be2b5fde82d9c8874f3d19328bdfe3b6962dc67b diff --git a/cmake/onnxruntime_providers_openvino.cmake b/cmake/onnxruntime_providers_openvino.cmake index 287842b1019d5..60575c3b9b931 100644 --- a/cmake/onnxruntime_providers_openvino.cmake +++ b/cmake/onnxruntime_providers_openvino.cmake @@ -105,14 +105,38 @@ set_target_properties(onnxruntime_providers_openvino PROPERTIES # Embeds private-assembly manifests into OV/TBB DLLs and the provider DLL so # that Windows loads them from the EP's own directory, avoiding DLL collisions # when another application in the same process also uses OpenVINO. +# +# Build-time approach: OV/TBB DLLs are staged into /sxs_staging//, +# Authenticode signatures are stripped, and SxS dep manifests are embedded. +# The provider DLL gets its dep manifest via a POST_BUILD step. # --------------------------------------------------------------------------- if(WIN32) - # Require mt.exe for manifest embedding - if(NOT CMAKE_MT) - message(FATAL_ERROR - "mt.exe not found — SxS manifest embedding is required on Windows.\n" - "Set -DCMAKE_MT= or ensure the Windows SDK is on PATH.") - endif() + # --- Locate Windows SDK tools --- + # Locate a tool in the newest available Windows SDK x64 bin directory. + function(ort_find_winsdk_tool out_var exe_name) + if(${out_var}) + return() + endif() + set(_hints "") + if(DEFINED ENV{WDKBinRoot}) + list(APPEND _hints "$ENV{WDKBinRoot}/x64") + endif() + file(GLOB _glob_hints + "C:/Program Files (x86)/Windows Kits/10/bin/10.*/x64" + "C:/Program Files/Windows Kits/10/bin/10.*/x64") + list(SORT _glob_hints COMPARE NATURAL ORDER DESCENDING) + list(APPEND _hints ${_glob_hints}) + find_program(${out_var} "${exe_name}" HINTS ${_hints} NO_DEFAULT_PATH) + if(NOT ${out_var}) + message(FATAL_ERROR + "${exe_name}.exe not found in known Windows SDK paths.\n" + "Set -D${out_var}= to override.") + endif() + message(STATUS "Found ${exe_name}.exe: ${${out_var}}") + endfunction() + + ort_find_winsdk_tool(CMAKE_MT mt) + ort_find_winsdk_tool(ORT_SIGNTOOL_EXE signtool) # --- Enumerate OV and TBB DLL filenames for the SxS assembly manifest --- # Glob patterns selecting the OV binaries needed by the EP. @@ -155,17 +179,17 @@ if(WIN32) if(EXISTS "${_ov_bin}/Release") _ort_glob_ov(_ov_release "${_ov_bin}/Release") - set(ORT_OV_INSTALL_FILES_Release ${_ov_release} ${_tbb_release}) + set(ORT_OV_TBB_INSTALL_FILES_Release ${_ov_release} ${_tbb_release}) endif() if(EXISTS "${_ov_bin}/Debug") _ort_glob_ov(_ov_debug "${_ov_bin}/Debug") - set(ORT_OV_INSTALL_FILES_Debug ${_ov_debug} ${_tbb_debug}) + set(ORT_OV_TBB_INSTALL_FILES_Debug ${_ov_debug} ${_tbb_debug}) endif() if(EXISTS "${_ov_bin}/RelWithDebInfo") _ort_glob_ov(_ov_rwdi "${_ov_bin}/RelWithDebInfo") - set(ORT_OV_INSTALL_FILES_RelWithDebInfo ${_ov_rwdi} ${_tbb_release}) - elseif(DEFINED ORT_OV_INSTALL_FILES_Release) - set(ORT_OV_INSTALL_FILES_RelWithDebInfo ${ORT_OV_INSTALL_FILES_Release}) + set(ORT_OV_TBB_INSTALL_FILES_RelWithDebInfo ${_ov_rwdi} ${_tbb_release}) + elseif(DEFINED ORT_OV_TBB_INSTALL_FILES_Release) + set(ORT_OV_TBB_INSTALL_FILES_RelWithDebInfo ${ORT_OV_TBB_INSTALL_FILES_Release}) endif() else() # Python wheel layout — all binaries flat in /openvino/libs/ @@ -185,17 +209,17 @@ if(WIN32) if(EXISTS "${_libs}") _ort_glob_ov(_ov_wheel "${_libs}") file(GLOB _tbb_wheel "${_libs}/tbb*.dll") - set(ORT_OV_INSTALL_FILES_wheel ${_ov_wheel} ${_tbb_wheel}) + set(ORT_OV_TBB_INSTALL_FILES_wheel ${_ov_wheel} ${_tbb_wheel}) endif() endif() endif() # Collect unique DLL filenames for SxS dep manifest embedding set(_all_files - ${ORT_OV_INSTALL_FILES_Release} - ${ORT_OV_INSTALL_FILES_Debug} - ${ORT_OV_INSTALL_FILES_RelWithDebInfo} - ${ORT_OV_INSTALL_FILES_wheel}) + ${ORT_OV_TBB_INSTALL_FILES_Release} + ${ORT_OV_TBB_INSTALL_FILES_Debug} + ${ORT_OV_TBB_INSTALL_FILES_RelWithDebInfo} + ${ORT_OV_TBB_INSTALL_FILES_wheel}) set(ORT_OV_TBB_DLL_NAMES "") foreach(_f IN LISTS _all_files) get_filename_component(_ext "${_f}" EXT) @@ -209,41 +233,143 @@ if(WIN32) if(ORT_OV_TBB_DLL_NAMES) message(STATUS "OpenVINO SxS: DLLs for manifest: ${ORT_OV_TBB_DLL_NAMES}") - # --- Generate assembly manifest --- + # --- Pre-generate SxS manifests at configure time --- + set(_sxs_manifest_dir "${CMAKE_BINARY_DIR}/sxs_manifests") + file(MAKE_DIRECTORY "${_sxs_manifest_dir}") + set(_ep_file_version "${ORT_VERSION}.0") + + # Per-DLL dep manifests (dep.manifest.in uses ${DLL_BASE_NAME} and ${EP_FILE_VERSION}) + foreach(_dll_name IN LISTS ORT_OV_TBB_DLL_NAMES) + get_filename_component(_dll_we "${_dll_name}" NAME_WE) + set(DLL_BASE_NAME "${_dll_we}") + set(EP_FILE_VERSION "${_ep_file_version}") + configure_file( + "${CMAKE_CURRENT_LIST_DIR}/sxs/dep.manifest.in" + "${_sxs_manifest_dir}/${_dll_we}.dep.manifest" + ) + endforeach() + + # Per-config assembly manifests (only list DLLs that belong to each config) set(ORT_SXS_VERSION "${ORT_VERSION}") - set(_file_entries "") - foreach(_dll IN LISTS ORT_OV_TBB_DLL_NAMES) - string(APPEND _file_entries " \n") + set(_asm_configs Release Debug RelWithDebInfo) + if(DEFINED ORT_OV_TBB_INSTALL_FILES_wheel) + set(_asm_configs wheel) + endif() + + foreach(_cfg IN LISTS _asm_configs) + set(ORT_SXS_ASSEMBLY_FILE_ENTRIES "") + foreach(_f IN LISTS ORT_OV_TBB_INSTALL_FILES_${_cfg}) + get_filename_component(_ext "${_f}" EXT) + get_filename_component(_name "${_f}" NAME) + if(_ext STREQUAL ".dll") + string(APPEND ORT_SXS_ASSEMBLY_FILE_ENTRIES " \n") + endif() + endforeach() + configure_file( + "${CMAKE_CURRENT_LIST_DIR}/sxs/assembly.manifest.in" + "${_sxs_manifest_dir}/openvino_runtime_${_cfg}.manifest" + @ONLY) + set(ORT_SXS_ASSEMBLY_MANIFEST_${_cfg} "${_sxs_manifest_dir}/openvino_runtime_${_cfg}.manifest") endforeach() - set(ORT_SXS_ASSEMBLY_FILE_ENTRIES "${_file_entries}") + # --- Build-time staging: copy, strip signatures, embed dep manifests --- + set(_sxs_staging_root "${CMAKE_BINARY_DIR}/sxs_staging") + + function(_ort_sxs_stage_file _out_dst _cfg _src) + get_filename_component(_name "${_src}" NAME) + get_filename_component(_ext "${_src}" EXT) + set(_dst "${_sxs_staging_root}/${_cfg}/${_name}") + + if(_ext STREQUAL ".dll") + get_filename_component(_name_we "${_src}" NAME_WE) + add_custom_command( + OUTPUT "${_dst}" + COMMAND "${CMAKE_COMMAND}" -E make_directory "${_sxs_staging_root}/${_cfg}" + COMMAND "${CMAKE_COMMAND}" -E copy "${_src}" "${_dst}" + COMMAND "${CMAKE_COMMAND}" + "-DSIGNTOOL=${ORT_SIGNTOOL_EXE}" + "-DDLL_PATH=${_dst}" + -P "${CMAKE_CURRENT_LIST_DIR}/sxs/remove_signature.cmake" + COMMAND "${CMAKE_COMMAND}" + "-DCMAKE_MT=${CMAKE_MT}" + "-DDLL_PATH=${_dst}" + "-DMANIFEST_PATH=${_sxs_manifest_dir}/${_name_we}.dep.manifest" + -P "${CMAKE_CURRENT_LIST_DIR}/sxs/embed_manifest.cmake" + DEPENDS "${_src}" "${_sxs_manifest_dir}/${_name_we}.dep.manifest" + COMMENT "SxS ${_cfg}/${_name}: remove signature + embed manifest" + VERBATIM + ) + else() + add_custom_command( + OUTPUT "${_dst}" + COMMAND "${CMAKE_COMMAND}" -E make_directory "${_sxs_staging_root}/${_cfg}" + COMMAND "${CMAKE_COMMAND}" -E copy "${_src}" "${_dst}" + DEPENDS "${_src}" + COMMENT "SxS ${_cfg}/${_name}: copy" + VERBATIM + ) + endif() + set(${_out_dst} "${_dst}" PARENT_SCOPE) + endfunction() + + if(DEFINED ORT_OV_TBB_INSTALL_FILES_wheel) + set(_staged_wheel "") + foreach(_src IN LISTS ORT_OV_TBB_INSTALL_FILES_wheel) + _ort_sxs_stage_file(_dst "$" "${_src}") + list(APPEND _staged_wheel "${_dst}") + endforeach() + set(ORT_OV_TBB_STAGED_FILES_wheel "${_staged_wheel}") + add_custom_target(ort_embed_ov_tbb_manifests ALL DEPENDS ${ORT_OV_TBB_STAGED_FILES_wheel}) + else() + set(_all_staged "") + foreach(_cfg IN ITEMS Release Debug RelWithDebInfo) + foreach(_src IN LISTS ORT_OV_TBB_INSTALL_FILES_${_cfg}) + _ort_sxs_stage_file(_dst "${_cfg}" "${_src}") + list(APPEND _all_staged "${_dst}") + list(APPEND ORT_OV_TBB_STAGED_FILES_${_cfg} "${_dst}") + endforeach() + endforeach() + add_custom_target(ort_embed_ov_tbb_manifests ALL DEPENDS ${_all_staged}) + endif() + + # --- Post-build: embed dep manifest into onnxruntime_providers_openvino.dll --- + set(DLL_BASE_NAME "onnxruntime_providers_openvino") + set(EP_FILE_VERSION "${_ep_file_version}") configure_file( - "${CMAKE_CURRENT_LIST_DIR}/sxs/assembly.manifest.in" - "${CMAKE_BINARY_DIR}/cmake/sxs/openvino_runtime.manifest" - @ONLY) - install(FILES "${CMAKE_BINARY_DIR}/cmake/sxs/openvino_runtime.manifest" - DESTINATION ${CMAKE_INSTALL_BINDIR}) - - # --- Install OV+TBB binaries alongside the provider DLL --- - if(DEFINED ORT_OV_INSTALL_FILES_wheel) - install(FILES ${ORT_OV_INSTALL_FILES_wheel} DESTINATION ${CMAKE_INSTALL_BINDIR}) + "${CMAKE_CURRENT_LIST_DIR}/sxs/dep.manifest.in" + "${_sxs_manifest_dir}/onnxruntime_providers_openvino.dep.manifest" + ) + add_custom_command(TARGET onnxruntime_providers_openvino POST_BUILD + COMMAND "${CMAKE_COMMAND}" + "-DCMAKE_MT=${CMAKE_MT}" + "-DDLL_PATH=$" + "-DMANIFEST_PATH=${_sxs_manifest_dir}/onnxruntime_providers_openvino.dep.manifest" + -P "${CMAKE_CURRENT_LIST_DIR}/sxs/embed_manifest.cmake" + COMMENT "SxS: embedding dep manifest into onnxruntime_providers_openvino.dll" + VERBATIM + ) + + # --- Install staged OV+TBB binaries and assembly manifest --- + if(DEFINED ORT_OV_TBB_STAGED_FILES_wheel) + install(FILES ${ORT_OV_TBB_STAGED_FILES_wheel} DESTINATION ${CMAKE_INSTALL_BINDIR}) + install(FILES "${ORT_SXS_ASSEMBLY_MANIFEST_wheel}" + RENAME "openvino_runtime.manifest" + DESTINATION ${CMAKE_INSTALL_BINDIR}) else() foreach(_config IN ITEMS Release Debug RelWithDebInfo) - if(ORT_OV_INSTALL_FILES_${_config}) - install(FILES ${ORT_OV_INSTALL_FILES_${_config}} + if(ORT_OV_TBB_STAGED_FILES_${_config}) + install(FILES ${ORT_OV_TBB_STAGED_FILES_${_config}} + DESTINATION ${CMAKE_INSTALL_BINDIR} + CONFIGURATIONS ${_config}) + endif() + if(ORT_SXS_ASSEMBLY_MANIFEST_${_config}) + install(FILES "${ORT_SXS_ASSEMBLY_MANIFEST_${_config}}" + RENAME "openvino_runtime.manifest" DESTINATION ${CMAKE_INSTALL_BINDIR} CONFIGURATIONS ${_config}) endif() endforeach() endif() - - # --- Embed SxS manifests at install time --- - install(CODE "set(CMAKE_MT \"${CMAKE_MT}\")") - install(CODE "set(SXS_SOURCE_DIR \"${CMAKE_CURRENT_LIST_DIR}/sxs\")") - install(CODE "set(EP_FILE_VERSION \"${ORT_VERSION}.0\")") - install(CODE "set(OV_TBB_DLL_NAMES \"${ORT_OV_TBB_DLL_NAMES}\")") - install(CODE "set(ORT_SXS_BIN_DIR \"\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}\")") - install(SCRIPT "${CMAKE_CURRENT_LIST_DIR}/sxs/embed_manifests.cmake") else() message(WARNING "OpenVINO SxS: No OV/TBB DLLs found — SxS manifest embedding skipped.\n" "Ensure INTEL_OPENVINO_DIR is set (setupvars.bat) or the openvino wheel is installed.") diff --git a/cmake/sxs/dep.manifest.in b/cmake/sxs/dep.manifest.in index ba01ae08bb93b..8d6c180fd37cc 100644 --- a/cmake/sxs/dep.manifest.in +++ b/cmake/sxs/dep.manifest.in @@ -4,7 +4,7 @@ onnxruntime_providers_openvino.dll. Declares a dependency on the openvino_runtime private assembly at the EP version, matching the version in assembly.manifest.in. - Generated by cmake/sxs/embed_manifests.cmake — do not edit by hand. + Generated by cmake/sxs/embed_manifest.cmake — do not edit by hand. --> Date: Wed, 24 Jun 2026 23:07:52 -0700 Subject: [PATCH 3/3] copilot review --- .../openvino_ep_sxs_isolation_test.cc | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/onnxruntime/test/providers/openvino/openvino_ep_sxs_isolation_test.cc b/onnxruntime/test/providers/openvino/openvino_ep_sxs_isolation_test.cc index b9a5955923635..83a4d6a1c8691 100644 --- a/onnxruntime/test/providers/openvino/openvino_ep_sxs_isolation_test.cc +++ b/onnxruntime/test/providers/openvino/openvino_ep_sxs_isolation_test.cc @@ -12,8 +12,10 @@ #include #include +#include #include #include +#include #include #include "core/session/onnxruntime_cxx_api.h" @@ -34,20 +36,30 @@ static fs::path GetExeDir() { // Returns full paths of all loaded DLLs whose name contains the given fragment. static std::vector FindLoadedModules(std::wstring_view name_fragment_lower) { std::vector result; - std::vector modules(4096); + std::vector modules(1024); DWORD cbNeeded = 0; - if (!EnumProcessModulesEx(GetCurrentProcess(), modules.data(), - static_cast(modules.size() * sizeof(HMODULE)), - &cbNeeded, LIST_MODULES_ALL)) { - return result; + + // Retry with a larger buffer if the initial allocation is too small. + for (int attempt = 0; attempt < 3; ++attempt) { + if (!EnumProcessModulesEx(GetCurrentProcess(), modules.data(), + static_cast(modules.size() * sizeof(HMODULE)), + &cbNeeded, LIST_MODULES_ALL)) { + return result; + } + if (cbNeeded <= modules.size() * sizeof(HMODULE)) break; + modules.resize(cbNeeded / sizeof(HMODULE) + 64); } - DWORD count = cbNeeded / sizeof(HMODULE); + + DWORD count = std::min(cbNeeded / sizeof(HMODULE), + static_cast(modules.size())); for (DWORD i = 0; i < count; ++i) { wchar_t path[MAX_PATH] = {}; - GetModuleFileNameExW(GetCurrentProcess(), modules[i], path, MAX_PATH); + if (!GetModuleFileNameExW(GetCurrentProcess(), modules[i], path, MAX_PATH)) { + continue; + } std::wstring wpath(path); std::wstring lower = wpath; - for (auto& c : lower) c = towlower(c); + for (auto& c : lower) c = static_cast(std::towlower(c)); if (lower.find(name_fragment_lower) != std::wstring::npos) { result.push_back(wpath); } @@ -79,7 +91,8 @@ struct SxsIsolationFixture : public ::testing::Test { // Copy openvino.dll to a temp folder and pre-load it. // This simulates another app having already loaded // its own openvino.dll into this process. - temp_dir_ = bin_dir_ / L"sxs_test_temp"; + temp_dir_ = fs::temp_directory_path() / + (std::wstring(L"ort_openvino_sxs_test_") + std::to_wstring(GetCurrentProcessId())); fs::create_directories(temp_dir_); preloaded_ov_ = temp_dir_ / L"openvino.dll";