Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions iceoryx2-cxx/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ add_library(iceoryx2-cxx-object-lib OBJECT
src/static_config_request_response.cpp
src/subscriber_details.cpp
src/unique_port_id.cpp
src/version.cpp
src/waitset.cpp
src/writer_details.cpp
)
Expand Down
40 changes: 40 additions & 0 deletions iceoryx2-cxx/include/iox2/version.hpp

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Food for thought. In iceoryx classic, we generated a C header from the version set in cmake. See also -> https://github.com/eclipse-iceoryx/iceoryx/blob/main/iceoryx_platform/cmake/iceoryx_versions.h.in

This gave us the option to use the version info for deprecation macros like this -> https://github.com/eclipse-iceoryx/iceoryx/blob/main/iceoryx_hoofs/legacy/include/iceoryx_hoofs/cxx/optional.hpp#L22

It's on my todo list to also introduce this macros for iceoryx2 once we reached 1.0, in order to provide a smoother migration path if we deprecate an API call. So, having an analogous C header would help.

Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) 2026 Contributors to the Eclipse Foundation

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please rename the file to package_version.hpp. Currently, the file name and the class name correspond - nearly everywhere. I would try to keep it consistent. Same goes for package_version.cpp

//
// See the NOTICE file(s) distributed with this work for additional
// information regarding copyright ownership.
//
// This program and the accompanying materials are made available under the
// terms of the Apache Software License 2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
// which is available at https://opensource.org/licenses/MIT.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT

#ifndef IOX2_VERSION_HPP
#define IOX2_VERSION_HPP

#include "iox2/internal/iceoryx2.hpp"

#include <cstdint>
#include <iosfwd>

namespace iox2 {

/// Version number.
struct PackageVersion {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to provide a little background on the package version. It is currently stored in the first 8 bytes of any shared memory object iceoryx2 creates. When a user wants to connect to anything within iceoryx2, the package version is verified first, and only if it matches does the connection proceed.

The only construct lacking this is static service details (based on the static storage concept).

The question is, if we ever change the layout/implementation of the rust package version and if a C++/C/Python user might want to acquire the package version of a running iceoryx2 instance. If so, it would make sense to create a "classical" C binding for it and have just one implementation as the source of truth.

If this is a non-existing use case, this approach is fine. We can always provide CLI tooling to perform this task.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For testing we can add a c++ header file called testing.hpp with a testing name space and add a friend function that is able to instantiate different package versions to test the operators.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why make it a struct with public accessible members?

I think this shouldn't be a generic building block that the user can use in their project to define their package version, but it is more the current package version of the iceoryx2 crate and in this case, the user should never change the version.

So I would turn it into a class and add 3 getter methods major(), minor() and patch(). This also reduces the API surface a bit.

std::uint16_t major;
std::uint16_t minor;
std::uint16_t patch;
};

/// Returns the crates version acquired through the internal environment variables set by cargo,
/// ("CARGO_PKG_VERSION_{MAJOR|MINOR|PATCH}").
PackageVersion package_version();

auto operator<<(std::ostream& stream, const PackageVersion& version) -> std::ostream&;
auto operator==(const PackageVersion& lhs, const PackageVersion& rhs) -> bool;
auto operator<(const PackageVersion& lhs, const PackageVersion& rhs) -> bool;

} // namespace iox2

#endif
42 changes: 42 additions & 0 deletions iceoryx2-cxx/src/version.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright (c) 2026 Contributors to the Eclipse Foundation
//
// See the NOTICE file(s) distributed with this work for additional
// information regarding copyright ownership.
//
// This program and the accompanying materials are made available under the
// terms of the Apache Software License 2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
// which is available at https://opensource.org/licenses/MIT.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT

#include "iox2/version.hpp"

#include <ostream>

namespace iox2 {

PackageVersion package_version() {
iox2_package_version_t const v = iox2_package_version();
return PackageVersion { v.major, v.minor, v.patch };
}

auto operator<<(std::ostream& stream, const PackageVersion& version) -> std::ostream& {
return stream << version.major << '.' << version.minor << '.' << version.patch;
}

auto operator==(const PackageVersion& lhs, const PackageVersion& rhs) -> bool {
return lhs.major == rhs.major && lhs.minor == rhs.minor && lhs.patch == rhs.patch;
}

auto operator<(const PackageVersion& lhs, const PackageVersion& rhs) -> bool {
if (lhs.major != rhs.major) {
return lhs.major < rhs.major;
} else if (lhs.minor != rhs.minor) {
return lhs.minor < rhs.minor;
} else {
return lhs.patch < rhs.patch;
}
}

} // namespace iox2
143 changes: 143 additions & 0 deletions iceoryx2-cxx/tests/src/version_tests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
// Copyright (c) 2026 Contributors to the Eclipse Foundation
//
// See the NOTICE file(s) distributed with this work for additional
// information regarding copyright ownership.
//
// This program and the accompanying materials are made available under the
// terms of the Apache Software License 2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
// which is available at https://opensource.org/licenses/MIT.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT

#include "iox2/version.hpp"
#include "test.hpp"

#include <sstream>

namespace {
using namespace iox2;

TEST(VersionTest, version_obtains_version_number) {
ASSERT_EQ(package_version().major, 0);
ASSERT_EQ(package_version().minor, 8);
ASSERT_EQ(package_version().patch, 999);
}

TEST(VersionTest, version_numbers_compare_equal_if_all_components_are_equal) {
PackageVersion sut1;
sut1.major = 1;
sut1.minor = 2;
sut1.patch = 3;
PackageVersion sut2;
sut2.major = 1;
sut2.minor = 2;
sut2.patch = 3;
EXPECT_EQ(sut1, sut1);
EXPECT_EQ(sut1, sut2);
EXPECT_EQ(sut2, sut1);
sut1.major = 25;
sut1.minor = 22;
sut1.patch = 0;
sut2.major = 25;
sut2.minor = 22;
sut2.patch = 0;
EXPECT_EQ(sut1, sut1);
EXPECT_EQ(sut1, sut2);
EXPECT_EQ(sut2, sut1);
}

TEST(VersionTest, version_numbers_do_not_compare_equal_if_major_version_differs) {
PackageVersion sut1;
sut1.major = 1;
sut1.minor = 2;
sut1.patch = 3;
PackageVersion sut2;
sut2.major = 0;
sut2.minor = 2;
sut2.patch = 3;
EXPECT_FALSE(sut1 == sut2);
EXPECT_FALSE(sut2 == sut1);
sut1.major = 99;
sut2.major = 6;
EXPECT_FALSE(sut1 == sut2);
EXPECT_FALSE(sut2 == sut1);
}

TEST(VersionTest, version_numbers_do_not_compare_equal_if_minor_version_differs) {
PackageVersion sut1;
sut1.major = 1;
sut1.minor = 2;
sut1.patch = 3;
PackageVersion sut2;
sut2.major = 1;
sut2.minor = 0;
sut2.patch = 3;
EXPECT_FALSE(sut1 == sut2);
EXPECT_FALSE(sut2 == sut1);
sut1.minor = 99;
sut2.minor = 6;
EXPECT_FALSE(sut1 == sut2);
EXPECT_FALSE(sut2 == sut1);
}

TEST(VersionTest, version_numbers_do_not_compare_equal_if_patch_version_differs) {
PackageVersion sut1;
sut1.major = 1;
sut1.minor = 2;
sut1.patch = 3;
PackageVersion sut2;
sut2.major = 1;
sut2.minor = 2;
sut2.patch = 0;
EXPECT_FALSE(sut1 == sut2);
EXPECT_FALSE(sut2 == sut1);
sut1.patch = 99;
sut2.patch = 6;
EXPECT_FALSE(sut1 == sut2);
EXPECT_FALSE(sut2 == sut1);
}

TEST(VersionTest, version_numbers_less_compares_lexicographically) {
PackageVersion sut1;
sut1.major = 1;
sut1.minor = 2;
sut1.patch = 3;
PackageVersion sut2;
sut2.major = 2;
sut2.minor = 2;
sut2.patch = 3;
EXPECT_LT(sut1, sut2);
EXPECT_FALSE(sut2 < sut1);
sut2.major = sut1.major;
sut2.minor = 3;
EXPECT_LT(sut1, sut2);
EXPECT_FALSE(sut2 < sut1);
sut2.minor = sut1.minor;
sut2.patch = 4;
EXPECT_LT(sut1, sut2);
EXPECT_FALSE(sut2 < sut1);
sut2.patch = sut1.patch;
EXPECT_FALSE(sut1 < sut2);
EXPECT_FALSE(sut2 < sut1);
}

TEST(VersionTest, version_numbers_ostream_insertion_produces_version_string) {
std::stringstream sstr;
PackageVersion sut;
sut.major = 0;
sut.minor = 0;
sut.patch = 0;
sstr << sut;
ASSERT_FALSE(sstr.fail());
EXPECT_STREQ(sstr.str().c_str(), "0.0.0");
sstr = std::stringstream {};
sut.major = 22;
sut.minor = 4;
sut.patch = 102;
sstr << sut;
ASSERT_FALSE(sstr.fail());
EXPECT_STREQ(sstr.str().c_str(), "22.4.102");
}

} // namespace
20 changes: 20 additions & 0 deletions iceoryx2-ffi/c/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,3 +295,23 @@ pub unsafe extern "C" fn iox2_semantic_string_error_string(
) -> *const c_char {
error.as_const_cstr().as_ptr() as *const c_char
}

/// Version number.
#[repr(C)]
pub struct iox2_package_version_t {
major: u16,
minor: u16,
patch: u16,
}

/// Returns the crates version acquired through the internal environment variables set by cargo,
/// ("CARGO_PKG_VERSION_{MAJOR|MINOR|PATCH}").
#[no_mangle]
pub unsafe extern "C" fn iox2_package_version() -> iox2_package_version_t {
let package_version = PackageVersion::get();
iox2_package_version_t {
major: package_version.major(),
minor: package_version.minor(),
patch: package_version.patch(),
}
}
1 change: 1 addition & 0 deletions iceoryx2/src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pub use iceoryx2_bb_container::semantic_string::SemanticStringError;
pub use iceoryx2_bb_derive_macros::PlacementDefault;
pub use iceoryx2_bb_derive_macros::ZeroCopySend;
pub use iceoryx2_bb_elementary::alignment::Alignment;
pub use iceoryx2_bb_elementary::package_version::PackageVersion;
pub use iceoryx2_bb_elementary::CallbackProgression;
pub use iceoryx2_bb_elementary_traits::placement_default::PlacementDefault;
pub use iceoryx2_bb_elementary_traits::zero_copy_send::ZeroCopySend;
Expand Down