Skip to content

Commit f23eaf3

Browse files
committed
Build and ship the OpenVINO backend in the Windows wheels
The OpenVINO delegate lets ExecuTorch run models on Intel CPUs, GPUs and NPUs. Until now the prebuilt delegate shipped only in the Linux wheels. The Windows wheels left it out, even though Intel publishes an OpenVINO runtime for Windows x86-64, so Windows users had to build ExecuTorch from source. This change builds the delegate into the Windows wheels, CPU and CUDA, the same way the Linux wheels carry it. setup.py enables EXECUTORCH_BUILD_OPENVINO on Windows and packages the delegate's import library (.lib) beside the other Windows DLLs. The build file passes /EHsc and /GR when CMake reports an MSVC style compiler, which includes the clang-cl the wheels use, and -frtti and -fexceptions otherwise. The delegate loads the OpenVINO C library at run time, so the build needs no OpenVINO SDK. That loader used dlopen, with libopenvino_c.so as the default name. It is now split by platform. On Windows it reads OPENVINO_LIB_PATH with GetEnvironmentVariableW and loads with LoadLibraryExW, so a path outside the active code page still works, and it reports load errors as the system's message text. A bare name such as openvino_c.dll is searched with LOAD_LIBRARY_SEARCH_DEFAULT_DIRS, which covers the program's own folder, System32 and folders added with AddDllDirectory, but not the current folder or PATH. So an openvino_c.dll planted in the current folder is not loaded. A path is made absolute and also searches its own folder, so the runtime's dependencies, openvino.dll and tbb12.dll, load from beside it. The Python package already finds the pip installed runtime and passes its full path; it now looks for openvino_c.dll on Windows. The delegate is a global, so on Windows its destructor keeps the runtime loaded rather than calling FreeLibrary inside DllMain. On Linux the load error now also names the path it tried. pip install "executorch[openvino]" now installs the runtime on Windows x86-64 too. The OpenVINO versions the extra allows publish no build for Python 3.15, or for Linux aarch64 on Python 3.14, so there the extra now installs nothing. Before, the command failed on those Linux setups. The docs say so. The Windows wheel smoke tests, CPU and CUDA, check that the delegate registers. They then install the openvino extra and the quantizer the partitioner needs. The extra is pinned to the installed version, so pip cannot swap the wheel under test. In a new process, they require that the delegate loads the runtime and that a model it runs matches eager. From a folder holding a copy of the runtime, they also check that the delegate loads the copy by its full path but not by its bare name. On Python 3.15 they only check that the extra installs without a runtime. The shared model check now asserts that the program is really delegated, and loads it from memory, because Windows does not delete a file the loaded program keeps open. The shared library check requires the delegate on Linux and Windows wheels, and finds it by its is_available member rather than its class name, because the reader of Windows exports matches decorated names, which spell a member and never a class alone. The docs, the README and the PyPI description list Windows. The backend README explains where Windows looks for the runtime's dependencies, and its Linux OPENVINO_LIB_PATH example now finds the versioned library the pip package ships. Test plan: - Built the loader for Windows with a MinGW cross compiler and ran it under Wine with the OpenVINO 2025.4.1 Windows DLLs. Full, forward slash, relative and non-ASCII paths load the runtime and find the CPU device, and so does a path set with SetEnvironmentVariableW after startup, or changed while it is read. A bare name does not load a copy planted in the current folder. Errors read as text with their code. Unloading the delegate's DLL leaves the runtime loaded. - Ran the bare name check against that build under Wine. It passes with the real DLLs. It fails when the copied runtime cannot load, and when the loader searches the current folder. - On Python 3.15 with pip, the extra installs without a runtime, and the check fails if the python_version bound is removed, also when an older release is available to pip. A resolver run shows the extra resolves on Linux aarch64 with Python 3.14 only with the new bound. - On Linux, built the delegate against the wheel's C++ SDK and ran the Windows OpenVINO check with OpenVINO 2025.4.1 and nncf 3.1.0. The runtime loads and the model matches eager exactly, and the check fails when the runtime cannot load. - Ran the repository's linters (black, usort, flake8, clang-format and others) on the changed files. - On native Windows, the CPU and CUDA wheel jobs (Python 3.11) run the new checks. The Python 3.15 branch first runs in the nightly build.
1 parent e0692c7 commit f23eaf3

17 files changed

Lines changed: 401 additions & 69 deletions

‎.ci/scripts/wheel/test_base.py‎

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,8 @@
88
import os
99
import subprocess
1010
import sys
11-
import tempfile
1211
from dataclasses import dataclass
1312
from functools import cache
14-
from pathlib import Path
1513
from typing import List
1614

1715

@@ -43,7 +41,7 @@ class ModelTest:
4341
backend: Backend
4442

4543

46-
def test_a_model_runs_through_the_openvino_delegate() -> None:
44+
def test_a_model_runs_through_the_openvino_delegate(required: bool = False) -> None:
4745
"""Export a model to the OpenVINO delegate and run it, comparing against eager.
4846
4947
The checks elsewhere prove the delegate library ships, owns its symbols and registers
@@ -53,7 +51,8 @@ def test_a_model_runs_through_the_openvino_delegate() -> None:
5351
The OpenVINO runtime is not part of the wheel. It comes from the openvino extra, so a
5452
default install cannot run this and says so rather than passing quietly. Where the runtime
5553
is present the export and the comparison are the point of the check, and a failure there
56-
is a real one.
54+
is a real one. A caller that installed the export stack passes required=True, so a missing
55+
piece fails instead of skipping.
5756
"""
5857
import torch
5958
from executorch.exir import to_edge_transform_and_lower
@@ -67,6 +66,8 @@ def test_a_model_runs_through_the_openvino_delegate() -> None:
6766
try:
6867
from executorch.backends.openvino.partitioner import OpenvinoPartitioner
6968
except ImportError as error:
69+
if required:
70+
raise
7071
print(
7172
f"SKIP: the OpenVINO export stack is not installed, so the delegate cannot "
7273
f"execute here ({error}). The wheel ships the adapter only; the runtime and the "
@@ -88,13 +89,16 @@ def forward(self, x, y):
8889
partitioner=[OpenvinoPartitioner([CompileSpec("device", b"CPU")])],
8990
)
9091
program = lowered.to_executorch()
92+
delegates = [d.id for d in program.executorch_program.execution_plan[0].delegates]
93+
assert "OpenvinoBackend" in delegates, (
94+
f"the partitioner did not hand the model to OpenVINO (delegates: {delegates}), so "
95+
f"running it would test the portable kernels instead of the delegate"
96+
)
9197

92-
with tempfile.TemporaryDirectory() as work_dir:
93-
pte = Path(work_dir) / "add_openvino.pte"
94-
pte.write_bytes(program.buffer)
95-
96-
method = Runtime.get().load_program(pte).load_method("forward")
97-
actual = method.execute(list(example))[0]
98+
# From memory rather than a temporary file, which the loaded program keeps open and
99+
# Windows then refuses to delete.
100+
method = Runtime.get().load_program(program.buffer).load_method("forward")
101+
actual = method.execute(list(example))[0]
98102

99103
difference = (actual - eager).abs().max().item()
100104
assert difference == 0.0, (

‎.ci/scripts/wheel/test_cuda_windows.py‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,15 @@ def export(destination: str) -> None:
640640
with tempfile.TemporaryDirectory() as work_dir:
641641
test_cpp_sdk.run_tests(Path(work_dir))
642642
import test_base
643+
from executorch.extension.pybindings.portable_lib import (
644+
_get_registered_backend_names,
645+
)
646+
647+
registered = _get_registered_backend_names()
648+
assert (
649+
"OpenvinoBackend" in registered
650+
), f"OpenvinoBackend not found in registered backends: {registered}"
651+
print("✓ OpenvinoBackend is registered")
643652

644653
test_base.test_cmsis_nn_install()
645654
# The same model run the CPU row ends with, through the Python bindings.
@@ -650,3 +659,6 @@ def export(destination: str) -> None:
650659
test_windows.run_tests(
651660
model_tests=[ModelTest(model=Model.Mv3, backend=Backend.Xnnpack)]
652661
)
662+
663+
# Last, because it installs packages the wheel does not declare.
664+
test_windows.test_the_openvino_delegate_runs()

‎.ci/scripts/wheel/test_shared_libraries.py‎

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,11 @@
149149
# The delegate's own entry points. A second definer means the delegate is compiled
150150
# into the Python extension as well, which would register it twice in one process.
151151
_QNN_BACKEND_SYMBOLS = ("QnnExecuTorchBackendRegister",)
152-
_OPENVINO_BACKEND_SYMBOLS = ("executorch::backends::openvino::OpenvinoBackend",)
152+
# A member rather than the bare class name, because the PE reader matches MSVC decorated
153+
# names, which spell a member as ?is_available@OpenvinoBackend@... and never the class alone.
154+
_OPENVINO_BACKEND_SYMBOLS = (
155+
"executorch::backends::openvino::OpenvinoBackend::is_available",
156+
)
153157

154158
_BUNDLED_XNNPACK_SYMBOLS = ("xnn_create_runtime_v4",)
155159

@@ -1097,31 +1101,32 @@ def _wheel_cuda_train() -> str:
10971101
# wheel is inspected, and a row cannot call that at import time.
10981102
_REQUIRED_ON_A_CUDA_WHEEL = "cuda-wheel-only"
10991103

1100-
# Marker for a row whose owner every Linux wheel carries and no macOS wheel does.
1101-
_REQUIRED_ON_LINUX = "linux-only"
1104+
# Marker for a row whose owner every Linux and Windows wheel carries and no macOS wheel
1105+
# does.
1106+
_REQUIRED_ON_LINUX_AND_WINDOWS = "linux-and-windows-only"
11021107
# Marker for a row whose owner every macOS wheel carries and no other wheel does.
11031108
# The Core ML delegate is built on every macOS wheel, so its presence is decidable
11041109
# from the installed wheel and a macOS wheel that dropped it should fail rather than
11051110
# quietly regress to folding it into the Python extension.
11061111
_REQUIRED_ON_MACOS = "macos-only"
1107-
# Narrower than the marker above on purpose. The Qualcomm SDK the delegate builds
1108-
# against is published for Linux x86_64 only, so the aarch64 Linux wheels ship no such
1109-
# library and demanding it there would fail a wheel that is correct. Reusing the
1110-
# Linux-wide marker would do exactly that.
1112+
# Narrower than the Linux and Windows marker on purpose. The Qualcomm SDK the delegate
1113+
# builds against is published for Linux x86_64 only, so the aarch64 Linux wheels ship no
1114+
# such library and demanding it there would fail a wheel that is correct. Reusing that
1115+
# marker would do exactly that.
11111116
_REQUIRED_ON_LINUX_X86 = "linux-x86-only"
11121117
# Marker for a row whose owner every aarch64 wheel carries, macOS and Linux alike. The
11131118
# TorchAO kernels are selected by the processor rather than the operating system, so
1114-
# neither the macOS nor the Linux marker describes them and a fixed False would let a
1115-
# wheel that silently dropped the library pass.
1119+
# neither the macOS nor the Linux and Windows marker describes them and a fixed False
1120+
# would let a wheel that silently dropped the library pass.
11161121
_REQUIRED_ON_AARCH64 = "aarch64-only"
11171122

11181123

11191124
def _resolve_required(required):
11201125
"""Turn a row's requirement marker into the answer for the installed wheel."""
11211126
if required == _REQUIRED_ON_A_CUDA_WHEEL:
11221127
return bool(_wheel_cuda_train())
1123-
if required == _REQUIRED_ON_LINUX:
1124-
return sys.platform == "linux"
1128+
if required == _REQUIRED_ON_LINUX_AND_WINDOWS:
1129+
return sys.platform in ("linux", "win32")
11251130
if required == _REQUIRED_ON_MACOS:
11261131
return sys.platform == "darwin"
11271132
if required == _REQUIRED_ON_LINUX_X86:
@@ -1279,15 +1284,15 @@ def _resolve_required(required):
12791284
_library_file_name("libexecutorch_backend_mlx"),
12801285
False,
12811286
),
1282-
# Required on Linux, where packaging turns the backend on for every non-minimal
1283-
# build. A fixed False passed a wheel that had compiled the delegate back into the
1284-
# extension: no library ships, so the row skips, and one definer inside the
1287+
# Required on Linux and Windows, where packaging turns the backend on for every
1288+
# non-minimal build. A fixed False passed a wheel that had compiled the delegate back
1289+
# into the extension: no library ships, so the row skips, and one definer inside the
12851290
# extension is exactly the monolithic layout a definer count cannot distinguish.
12861291
(
12871292
"OpenVINO delegate",
12881293
_OPENVINO_BACKEND_SYMBOLS,
12891294
_library_file_name("libexecutorch_backend_openvino"),
1290-
_REQUIRED_ON_LINUX,
1295+
_REQUIRED_ON_LINUX_AND_WINDOWS,
12911296
),
12921297
# Required on Linux x86_64 only, where the Qualcomm SDK the delegate builds against
12931298
# is published. A fixed False would pass a wheel that compiled the delegate back

‎.ci/scripts/wheel/test_windows.py‎

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,13 @@
66
# This source code is licensed under the BSD-style license found in the
77
# LICENSE file in the root directory of this source tree.
88

9+
import importlib.metadata
10+
import importlib.util
11+
import os
912
import platform
13+
import shutil
14+
import subprocess
15+
import sys
1016
import tempfile
1117
from pathlib import Path
1218
from typing import List
@@ -24,6 +30,7 @@
2430
from executorch.exir import EdgeCompileConfig, to_edge_transform_and_lower
2531
from executorch.extension.pybindings.portable_lib import (
2632
_get_registered_backend_names,
33+
_is_available,
2734
_load_for_executorch_from_buffer,
2835
)
2936
from test_base import ModelTest
@@ -71,14 +78,116 @@ def run_tests(model_tests: List[ModelTest]) -> None:
7178
raise RuntimeError(f"Unsupported backend {model_test.backend}.")
7279

7380

81+
def test_the_openvino_delegate_runs() -> None:
82+
"""Install the OpenVINO runtime the way a user does, then run a model through it.
83+
84+
The wheel ships the delegate but not the runtime, and registering the delegate does not
85+
load the runtime, so nothing else here proves the delegate can open openvino_c.dll and
86+
compute. The check runs in a new process because the package looks for the runtime when
87+
it is imported, which in this process happened before the install.
88+
"""
89+
# Pinned, so pip cannot swap the wheel under test for another release.
90+
install = [
91+
sys.executable,
92+
"-m",
93+
"pip",
94+
"install",
95+
f"executorch[openvino]=={importlib.metadata.version('executorch')}",
96+
]
97+
# The same bound as the python_version marker on the openvino extra.
98+
if sys.version_info >= (3, 15):
99+
subprocess.run(install, check=True)
100+
importlib.invalidate_caches()
101+
assert (
102+
importlib.util.find_spec("openvino") is None
103+
), "the openvino extra installed a runtime on a Python its marker leaves out"
104+
print(
105+
"SKIP: OpenVINO publishes no build for this Python, so the openvino extra "
106+
"installs no runtime and the delegate cannot load here."
107+
)
108+
return
109+
subprocess.run(
110+
install
111+
+ [
112+
"-r",
113+
str(
114+
Path(test_base._repository_root_dir())
115+
/ "backends/openvino/requirements.txt"
116+
),
117+
],
118+
check=True,
119+
)
120+
subprocess.run(
121+
[sys.executable, str(Path(__file__).resolve()), "--openvino"], check=True
122+
)
123+
importlib.invalidate_caches()
124+
openvino = importlib.util.find_spec("openvino")
125+
test_a_bare_name_does_not_load_from_the_current_folder(
126+
Path(openvino.submodule_search_locations[0]) / "libs"
127+
)
128+
129+
130+
def test_a_bare_name_does_not_load_from_the_current_folder(libs: Path) -> None:
131+
"""Run from a folder holding the real runtime and ask for it by bare name.
132+
133+
The standard Windows search order includes the current folder, where a planted
134+
openvino_c.dll would run, so the delegate has to refuse the copy found there. The
135+
same copy asked for by its full path has to load, so the refusal comes from the
136+
search order and not from a copy that cannot load at all.
137+
"""
138+
with tempfile.TemporaryDirectory() as work_dir:
139+
for library in libs.glob("*.dll"):
140+
shutil.copy2(library, work_dir)
141+
for lib_path, expected in (
142+
(str(Path(work_dir) / "openvino_c.dll"), "True"),
143+
("openvino_c.dll", "False"),
144+
):
145+
probe = subprocess.run(
146+
[
147+
sys.executable,
148+
"-c",
149+
"from executorch.extension.pybindings.portable_lib import "
150+
"_is_available; print(_is_available('OpenvinoBackend'))",
151+
],
152+
cwd=work_dir,
153+
env={**os.environ, "OPENVINO_LIB_PATH": lib_path},
154+
capture_output=True,
155+
text=True,
156+
check=False,
157+
)
158+
assert probe.returncode == 0 and probe.stdout.split()[-1:] == [expected], (
159+
f"OPENVINO_LIB_PATH={lib_path}, run from a folder holding the runtime, "
160+
f"should make _is_available return {expected}: the full path has to "
161+
"load the copy there and the bare name must not, since a planted copy "
162+
f"would run:\n{probe.stdout}{probe.stderr}"
163+
)
164+
print(
165+
"✓ a bare openvino_c.dll name does not load from the current folder, while "
166+
"its full path does"
167+
)
168+
169+
74170
if __name__ == "__main__":
171+
if sys.argv[1:] == ["--openvino"]:
172+
assert _is_available(
173+
"OpenvinoBackend"
174+
), "OpenvinoBackend is registered but cannot load the OpenVINO runtime"
175+
print("✓ OpenvinoBackend loads the OpenVINO runtime")
176+
test_base.test_a_model_runs_through_the_openvino_delegate(required=True)
177+
sys.exit(0)
178+
75179
# Before anything else, because this is the check that fails the way a user
76180
# fails: with only the dependencies the wheel declares.
77181
with tempfile.TemporaryDirectory() as work_dir:
78182
test_clean_install.run_tests(Path(work_dir))
79183

80184
if platform.system() == "Windows":
81185
registered = _get_registered_backend_names()
186+
assert (
187+
"OpenvinoBackend" in registered
188+
), f"OpenvinoBackend not found in registered backends: {registered}"
189+
print("✓ OpenvinoBackend is registered")
190+
82191
# Vulkan backend is optional: only present when the wheel was built with
83192
# EXECUTORCH_BUILD_VULKAN=1 and the Vulkan SDK (glslc) was available.
84193
if "VulkanBackend" in registered:
@@ -108,3 +217,7 @@ def run_tests(model_tests: List[ModelTest]) -> None:
108217
),
109218
]
110219
)
220+
221+
# Last, because it installs packages the wheel does not declare.
222+
if platform.system() == "Windows":
223+
test_the_openvino_delegate_runs()

‎README-wheel.md‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,11 @@ to run ExecuTorch `.pte` files, with some restrictions:
3434
* \[macOS only] [Core ML](docs/source/backends/coreml/coreml-overview.md) and MLX backends are
3535
also linked into the prebuilt module.
3636
* \[Linux x86_64] [QNN](docs/source/backends-qualcomm.md) backend is linked into the prebuilt module.
37-
* \[Linux] [OpenVINO](docs/source/build-run-openvino.md) backend is also linked into the
37+
* \[Linux and Windows] [OpenVINO](docs/source/build-run-openvino.md) backend is also linked into the
3838
prebuilt module. OpenVINO requires the runtime to be installed separately:
39-
`pip install executorch[openvino]`
39+
`pip install executorch[openvino]`. For now the extra installs no runtime on Python 3.15,
40+
or on Linux aarch64 with Python 3.14, because the OpenVINO versions it supports publish no
41+
build there.
4042

4143
On Linux, macOS and Windows the runtime, kernels and backends also ship as shared libraries
4244
with headers and a CMake package, so a C++ application can link them without building

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ is authoritative. See also the [Desktop guide](desktop/README.md).
200200
| iOS / iPadOS | [XNNPACK](https://docs.pytorch.org/executorch/main/backends/xnnpack/xnnpack-overview.html) CPU; [Core ML](https://docs.pytorch.org/executorch/main/backends/coreml/coreml-overview.html); [MLX](https://docs.pytorch.org/executorch/main/backends/mlx/mlx-overview.html) on physical devices *(experimental)* |
201201
| macOS | [XNNPACK](https://docs.pytorch.org/executorch/main/backends/xnnpack/xnnpack-overview.html); [Core ML](https://docs.pytorch.org/executorch/main/backends/coreml/coreml-overview.html); experimental [MLX](https://docs.pytorch.org/executorch/main/backends/mlx/mlx-overview.html), [Metal/AOTInductor](backends/apple/metal/README.md), and [WebGPU](https://docs.pytorch.org/executorch/main/backends/webgpu/webgpu-overview.html) paths |
202202
| Linux | [XNNPACK](https://docs.pytorch.org/executorch/main/backends/xnnpack/xnnpack-overview.html); [OpenVINO](https://docs.pytorch.org/executorch/main/build-run-openvino.html); experimental [CUDA/AOTInductor](https://docs.pytorch.org/executorch/main/backends/cuda/cuda-overview.html), [Vulkan](https://docs.pytorch.org/executorch/main/backends/vulkan/vulkan-overview.html), and [WebGPU](https://docs.pytorch.org/executorch/main/backends/webgpu/webgpu-overview.html) desktop paths |
203-
| Windows | [XNNPACK](https://docs.pytorch.org/executorch/main/backends/xnnpack/xnnpack-overview.html); experimental [CUDA/AOTInductor](https://docs.pytorch.org/executorch/main/backends/cuda/cuda-overview.html) and [Vulkan](https://docs.pytorch.org/executorch/main/backends/vulkan/vulkan-overview.html) desktop paths |
203+
| Windows | [XNNPACK](https://docs.pytorch.org/executorch/main/backends/xnnpack/xnnpack-overview.html); [OpenVINO](https://docs.pytorch.org/executorch/main/build-run-openvino.html); experimental [CUDA/AOTInductor](https://docs.pytorch.org/executorch/main/backends/cuda/cuda-overview.html) and [Vulkan](https://docs.pytorch.org/executorch/main/backends/vulkan/vulkan-overview.html) desktop paths |
204204
| Browser / WebAssembly | [Portable WebAssembly runtime](extension/wasm/README.md) and [WebGPU](https://docs.pytorch.org/executorch/main/backends/webgpu/webgpu-overview.html) *(both experimental)* |
205205
| Embedded / MCU | [Arm Cortex-M with CMSIS-NN](https://docs.pytorch.org/executorch/main/backends/arm-cortex-m/arm-cortex-m-overview.html) *(beta)*; [Arm Ethos-U](https://docs.pytorch.org/executorch/main/backends/arm-ethos-u/arm-ethos-u-overview.html); [NXP eIQ Neutron](https://docs.pytorch.org/executorch/main/backends/nxp/nxp-overview.html); [Cadence DSP](https://docs.pytorch.org/executorch/main/backends-cadence.html); [Zephyr](zephyr/README.md) and [Arduino](examples/arduino/README.md) integrations |
206206

‎backends/openvino/CMakeLists.txt‎

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ set(COMMON_INCLUDE_DIRS ${EXECUTORCH_ROOT}/..)
2828
# Include utility CMake scripts from ExecuteTorch
2929
include(${EXECUTORCH_ROOT}/tools/cmake/Utils.cmake)
3030

31-
# The backend resolves OpenVINO C API symbols via dlopen/dlsym at runtime, so
32-
# there is no build-time dependency on the OpenVINO SDK.
31+
# The backend resolves OpenVINO C API symbols at runtime (dlopen on Linux,
32+
# LoadLibrary on Windows), so there is no build-time dependency on the OpenVINO
33+
# SDK.
3334

3435
# Shared when the wheel build asks for it, static otherwise.
3536
if(EXECUTORCH_BUILD_SHARED)
@@ -39,8 +40,13 @@ else()
3940
endif()
4041
add_library(openvino_backend ${_openvino_backend_library_type})
4142

42-
# Enable exceptions and RTTI for OpenVINO backend
43-
target_compile_options(openvino_backend PRIVATE -frtti -fexceptions)
43+
# Enable exceptions and RTTI for OpenVINO backend. MSVC is also set for
44+
# clang-cl, which takes the cl spellings.
45+
if(MSVC)
46+
target_compile_options(openvino_backend PRIVATE /EHsc /GR)
47+
else()
48+
target_compile_options(openvino_backend PRIVATE -frtti -fexceptions)
49+
endif()
4450

4551
# Add source files for OpenVINO backend
4652
target_sources(

0 commit comments

Comments
 (0)