openvino_sys/lib.rs
1//! This crate provides low-level, unsafe, Rust bindings to OpenVINO™ using its [C API]. If you are
2//! looking to use OpenVINO™ from Rust, you likely should look at the ergonomic, safe bindings in
3//! [openvino], which depends on this crate. See the repository [README] for more information,
4//! including build instructions.
5//!
6//! [C API]: https://docs.openvinotoolkit.org/2020.1/ie_c_api/groups.html
7//! [openvino-sys]: https://crates.io/crates/openvino-sys
8//! [openvino]: https://crates.io/crates/openvino
9//! [README]: https://github.com/intel/openvino-rs/tree/main/crates/openvino-sys
10//!
11//! An example interaction with raw [openvino-sys]:
12//! ```
13//! # use std::ffi::CStr;
14//! openvino_sys::library::load().expect("to have an OpenVINO library available");
15//! let mut ov_version = openvino_sys::ov_version_t {
16//! // Initialize the fields to default values
17//! description: std::ptr::null(),
18//! buildNumber: std::ptr::null(),
19//! };
20//! let code = unsafe { openvino_sys::ov_get_openvino_version(&mut ov_version) };
21//! assert_eq!(code, openvino_sys::ov_status_e::OK);
22//! let version_ptr = { ov_version }.buildNumber;
23//! let string_version = unsafe { CStr::from_ptr(version_ptr) }.to_string_lossy().into_owned();
24//! unsafe { openvino_sys::ov_version_free(std::ptr::addr_of_mut!(ov_version)) };
25//! assert!(string_version.starts_with("2"));
26//! ```
27
28#![allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]
29#![allow(unused, dead_code)]
30#![deny(clippy::all)]
31#![warn(clippy::pedantic)]
32#![warn(clippy::cargo)]
33#![allow(
34 clippy::must_use_candidate,
35 clippy::suspicious_doc_comments,
36 clippy::wildcard_imports
37)]
38
39mod linking;
40
41mod generated;
42pub use generated::*;
43
44/// Contains extra utilities for finding and loading the OpenVINO shared libraries.
45pub mod library {
46 use std::path::PathBuf;
47
48 /// When compiled with the `runtime-linking` feature, load the function definitions from a
49 /// shared library; with the `dynamic-linking` feature, this function does nothing since the
50 /// library has already been linked.
51 ///
52 /// # Errors
53 ///
54 /// When compiled with the `runtime-linking` feature, this may fail if the `openvino-finder`
55 /// cannot discover the library on the current system. This may also fail if we link to a
56 /// version of OpenVINO that is too old for these Rust bindings: the upstream library changed
57 /// the `ov_element_type_e` enum in a backwards-incompatible way in v2025.1, meaning users would
58 /// unintentionally use the wrong type when creating tensors (see [#167]).
59 ///
60 /// [#167]: https://github.com/intel/openvino-rs/issues/167
61 pub fn load() -> Result<(), String> {
62 super::generated::load()?;
63 let version = get_version()?;
64 if is_pre_2025_1_version(&version) {
65 return Err(format!("OpenVINO version is too old (see https://github.com/intel/openvino-rs/issues/167): {version}"));
66 }
67 Ok(())
68 }
69
70 /// Retrieve the OpenVINO library's version string.
71 fn get_version() -> Result<String, String> {
72 use super::generated::{
73 ov_get_openvino_version, ov_status_e, ov_version_free, ov_version_t,
74 };
75 let mut ov_version = ov_version_t {
76 buildNumber: std::ptr::null(),
77 description: std::ptr::null(),
78 };
79 let code = unsafe { ov_get_openvino_version(&mut ov_version) };
80 if code != ov_status_e::OK {
81 return Err(format!("failed to get OpenVINO version: {code:?}"));
82 }
83 let c_str_version = unsafe { std::ffi::CStr::from_ptr(ov_version.buildNumber) };
84 let version = c_str_version.to_string_lossy().into_owned();
85 unsafe { ov_version_free(std::ptr::addr_of_mut!(ov_version)) };
86 Ok(version)
87 }
88
89 /// Parse the version string and return true if it is older than 2025.1.
90 fn is_pre_2025_1_version(version: &str) -> bool {
91 let mut parts = version.split(['.', '-']);
92 let year: usize = parts.next().unwrap().parse().unwrap();
93 let minor: usize = parts.next().unwrap().parse().unwrap();
94 year < 2025 || (year == 2025 && minor < 1)
95 }
96
97 /// Return the location of the shared library `openvino-sys` will link to. If compiled with
98 /// runtime linking, this will attempt to discover the location of a `openvino_c` shared library
99 /// on the system. Otherwise (with dynamic linking or compilation from source), this relies on a
100 /// static path discovered at build time.
101 ///
102 /// Knowing the location of the OpenVINO libraries is critical to avoid errors, unfortunately.
103 /// OpenVINO loads target-specific libraries on demand for performing inference. To do so, it
104 /// relies on a `plugins.xml` file that maps targets (e.g. CPU) to the target-specific
105 /// implementation library. At runtime, users must pass the path to this file so that OpenVINO
106 /// can inspect it and load the required libraries to satisfy the user's specified targets. By
107 /// default, the `plugins.xml` file is found in the same directory as the libraries, e.g.
108 /// `find().unwrap().parent()`.
109 pub fn find() -> Option<PathBuf> {
110 if cfg!(feature = "runtime-linking") {
111 openvino_finder::find("openvino_c", openvino_finder::Linking::Dynamic)
112 } else {
113 Some(PathBuf::from(env!("OPENVINO_LIB_PATH")))
114 }
115 }
116}