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}