Skip to content

Commit 2af130a

Browse files
authored
Check version; fail if pre-2024.2 (#149)
* Check version; fail if pre-2024.2 In #143, we discovered that upstream OpenVINO had changed the `ov_element_type_e` enum in a backwards-incompatible way. This means that a mismatch between the Rust bindings (based on the C headers) and the shared library will result in tensors being created with the wrong type (e.g., `U64` instead of `U8`). To avoid this situation, this change reads the OpenVINO library version at runtime (e.g., every time a `Core` is created) and fails with an error if the version is older than 2024.2, when the breaking change was introduced. The effect of merging this change would be that newer bindings will fail when used with older libraries, which could be problematic for users. Users could always use an older version of the library (e.g., `v0.7.*`) instead. And the alternative, letting users create tensors of the wrong type, seems like it would open up the door to a slew of reported issues. * Add documentation to helper functions * Update CI versions: library + OS This updates CI to test only the latest three OpenVINO versions, since older versions will no longer be accessible due to the new "breaking change version check." It also updates the OS version of the GitHub runner for good measure. * ci: specify ubuntu-24.04 * ci: roll back OS version OpenVINO has not published packages for `ubuntu-24.04`.
1 parent 61d73c4 commit 2af130a

File tree

5 files changed

+49
-39
lines changed

5 files changed

+49
-39
lines changed

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ jobs:
2121
# found ("dyld: Library not loaded; '@rpath/libopenvino.2310.dylib'"). See
2222
# https://github.com/abrown/openvino-rs/actions/runs/6423141936/job/17441022932#step:7:154
2323
os: [ubuntu-20.04, ubuntu-22.04, windows-latest]
24-
version: [2023.2.0, 2024.1.0, 2024.4.0]
24+
version: [2024.2.0, 2024.3.0, 2024.4.0]
2525
apt: [false]
2626
# We also spot-check that things work when installing from APT by adding to the matrix: see
2727
# https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#expanding-or-adding-matrix-configurations

crates/openvino-sys/src/lib.rs

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,54 @@ pub use generated::*;
4242
pub mod library {
4343
use std::path::PathBuf;
4444

45-
// Include the definition of `load` here. This allows hiding all of the "extra" linking-related
46-
// functions in the same place, without polluting the top-level namespace (which should only
47-
// contain foreign functions and types).
48-
#[doc(inline)]
49-
pub use super::generated::load;
45+
/// When compiled with the `runtime-linking` feature, load the function definitions from a
46+
/// shared library; with the `dynamic-linking` feature, this function does nothing since the
47+
/// library has already been linked.
48+
///
49+
/// # Errors
50+
///
51+
/// When compiled with the `runtime-linking` feature, this may fail if the `openvino-finder`
52+
/// cannot discover the library on the current system. This may also fail if we link to a
53+
/// version of OpenVINO that is too old for these Rust bindings: the upstream library changed
54+
/// the `ov_element_type_e` enum in a backwards-incompatible way in v2024.2, meaning users would
55+
/// unintentionally use the wrong type when creating tensors (see [#143]).
56+
///
57+
/// [#143]: https://github.com/intel/openvino-rs/issues/143
58+
pub fn load() -> Result<(), String> {
59+
super::generated::load()?;
60+
let version = get_version()?;
61+
if is_pre_2024_2_version(&version) {
62+
return Err(format!("OpenVINO version is too old (see https://github.com/intel/openvino-rs/issues/143): {version}"));
63+
}
64+
Ok(())
65+
}
66+
67+
/// Retrieve the OpenVINO library's version string.
68+
fn get_version() -> Result<String, String> {
69+
use super::generated::{
70+
ov_get_openvino_version, ov_status_e, ov_version_free, ov_version_t,
71+
};
72+
let mut ov_version = ov_version_t {
73+
buildNumber: std::ptr::null(),
74+
description: std::ptr::null(),
75+
};
76+
let code = unsafe { ov_get_openvino_version(&mut ov_version) };
77+
if code != ov_status_e::OK {
78+
return Err(format!("failed to get OpenVINO version: {code:?}"));
79+
}
80+
let c_str_version = unsafe { std::ffi::CStr::from_ptr(ov_version.buildNumber) };
81+
let version = c_str_version.to_string_lossy().into_owned();
82+
unsafe { ov_version_free(std::ptr::addr_of_mut!(ov_version)) };
83+
Ok(version)
84+
}
85+
86+
/// Parse the version string and return true if it is older than 2024.2.
87+
fn is_pre_2024_2_version(version: &str) -> bool {
88+
let mut parts = version.split(['.', '-']);
89+
let year: usize = parts.next().unwrap().parse().unwrap();
90+
let minor: usize = parts.next().unwrap().parse().unwrap();
91+
year < 2024 || (year == 2024 && minor < 2)
92+
}
5093

5194
/// Return the location of the shared library `openvino-sys` will link to. If compiled with
5295
/// runtime linking, this will attempt to discover the location of a `openvino_c` shared library

crates/openvino/tests/memory-safety.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,13 @@
33
//! be sure that we do the right thing on this side of the FFI boundary.
44
55
mod fixtures;
6-
mod util;
76

87
use fixtures::mobilenet as fixture;
98
use openvino::{Core, DeviceType, ElementType, Shape, Tensor};
109
use std::fs;
11-
use util::is_version_pre_2024_2;
1210

1311
#[test]
1412
fn memory_safety() -> anyhow::Result<()> {
15-
// OpenVINO 2024.2 changed the order of the `ov_element_type_e` enum, breaking compatibility
16-
// with older versions. Since we are using 2024.2+ bindings here, we skip this test when
17-
// using older libraries.
18-
if is_version_pre_2024_2() {
19-
eprintln!("> skipping test due to pre-2024.2 OpenVINO version");
20-
return Ok(());
21-
}
22-
2313
let mut core = Core::new()?;
2414
let xml = fs::read_to_string(fixture::graph())?;
2515
let weights = fs::read(fixture::weights())?;

crates/openvino/tests/setup.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
//! These tests demonstrate how to setup OpenVINO networks.
22
33
mod fixtures;
4-
mod util;
54

65
use fixtures::alexnet as fixture;
76
use openvino::{Core, ElementType, Shape, Tensor};
87
use std::fs;
9-
use util::is_version_pre_2024_2;
108

119
#[test]
1210
fn read_network() {
@@ -25,14 +23,6 @@ fn read_network() {
2523

2624
#[test]
2725
fn read_network_from_buffers() {
28-
// OpenVINO 2024.2 changed the order of the `ov_element_type_e` enum, breaking compatibility
29-
// with older versions. Since we are using 2024.2+ bindings here, we skip this test when
30-
// using older libraries.
31-
if is_version_pre_2024_2() {
32-
eprintln!("> skipping test due to pre-2024.2 OpenVINO version");
33-
return;
34-
}
35-
3626
let mut core = Core::new().unwrap();
3727
let graph = fs::read(&fixture::graph()).unwrap();
3828
let weights = {

crates/openvino/tests/util.rs

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
1-
#![allow(dead_code)] // Not all functions are used by each test.
2-
31
use core::cmp::Ordering;
42
use float_cmp::{ApproxEq, F32Margin};
5-
use openvino::version;
63

74
/// A structure for holding the `(category, probability)` pair extracted from the output tensor of
85
/// the OpenVINO classification.
@@ -82,13 +79,3 @@ pub const DEFAULT_MARGIN: F32Margin = F32Margin {
8279

8380
/// A helper type for manipulating lists of results.
8481
pub type Predictions = Vec<Prediction>;
85-
86-
/// OpenVINO's v2024.2 release introduced breaking changes to the C headers, upon which this crate
87-
/// relies. This function checks if the running OpenVINO version is pre-2024.2.
88-
pub fn is_version_pre_2024_2() -> bool {
89-
let version = version();
90-
let mut parts = version.parts();
91-
let year: usize = parts.next().unwrap().parse().unwrap();
92-
let minor: usize = parts.next().unwrap().parse().unwrap();
93-
year < 2024 || (year == 2024 && minor < 2)
94-
}

0 commit comments

Comments
 (0)