Skip to content
Merged
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
36 changes: 35 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ jobs:
run: |
cp target/${{ matrix.target }}/release/libviam_rust_utils.dylib builds/libviam_rust_utils-${{ matrix.platform }}.dylib
cp target/${{ matrix.target }}/release/libviam_rust_utils.a builds/libviam_rust_utils-${{ matrix.platform }}.a
cp viam_rust_utils.h builds/viam_rust_utils-${{ matrix.platform }}.h
Copy link
Member Author

Choose a reason for hiding this comment

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

possibly overly defensive but I opted for unique header files for each architecture in case they differ in includes or otherwise.

Copy link

Choose a reason for hiding this comment

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

maybe cc @acmorrow but I think we're fine just using one header for all of them. i'm not sure the level of control you have over the generated code, but if there are indeed differing includes this is something you'd want to do with a single header file that has #ifdef blocks

Copy link
Member

Choose a reason for hiding this comment

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

Yes, client needs to be able to name one include and get the right things. If there are architecture dependencies, there should be a per-arch header and then they should be unified with a top-level header.

A suggestion if you are worried: generate for each platform, then checksum or diff them. If they compare identical, just ship the first one. If they differ, fail the build.

Then you don't need a wrapper header at all, unless and until a divergence emerges.

Copy link
Member Author

@stuqdog stuqdog Nov 5, 2025

Choose a reason for hiding this comment

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

Hmm unfortunately it's a bit awkward to force in more complicated code blocks to the generated code, not impossible but might be awkward.

I do think though that having multiple headers isn't too bad (at least for the SDK), since we can just enforce that the right one is downloaded in CMakeLists.txt

edit: this comment was made before seeing Drew's reply above!)

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmm, a question on that front just for my own understanding. Are we planning on checking in the header file to the repo? If so, what happens if someone has their own copy of the rust_utils binary that they want to use (a thing we currently support), but it differs in some way from the checked in header? And if we're not checking it in but rather downloading it when we download the rust_utils binary (or expecting a user to provide their own along with their own rust_utils binary) then what's the danger with having that download seek out the architecture-specific header and then save it as to the generic .../rust_utils.h path?

Copy link
Member

Choose a reason for hiding this comment

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

From my perspective, there really shouldn't be any architecture dependent code in this header. It should be identical across all. If architecture variation slipped in, I'd consider that an error.

Shifting the burden to the consumer to select the right header seems somewhat unfair.

Regarding whether we will check this in, my expectation is that no, we wouldn't. I'd instead expect to see the one header published along with the release.

That's why my suggestion was to verify at build time that the header is bit identical on every platform where we generate it. That way, we will notice if they ever diverge, and can publish any one of them as "the header".

- name: Correct install path
run: |
install_name_tool -id "@rpath/libviam_rust_utils.dylib" builds/libviam_rust_utils-${{ matrix.platform }}.dylib
Expand Down Expand Up @@ -195,6 +196,7 @@ jobs:
run: |
cp target/${{ matrix.target }}/release/libviam_rust_utils.so builds/libviam_rust_utils-${{ matrix.platform }}.so
cp target/${{ matrix.target }}/release/libviam_rust_utils.a builds/libviam_rust_utils-${{ matrix.platform }}.a
cp viam_rust_utils.h builds/viam_rust_utils-${{ matrix.platform }}.h
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
Expand Down Expand Up @@ -228,15 +230,47 @@ jobs:
run: |
cp target/release/viam_rust_utils.dll builds/libviam_rust_utils-${{ matrix.platform }}.dll
cp target/release/viam_rust_utils.lib builds/viam_rust_utils-${{ matrix.platform }}.lib
cp viam_rust_utils.h builds/viam_rust_utils-${{ matrix.platform }}.h
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: builds-${{ matrix.platform }}
path: builds/*

merge:
create_canonical_header:
needs: [build_macos, build_linux, build_windows]
runs-on: ubuntu-latest
steps:
# pick one arbitrarily as the canonical header file
- name: create canonical header
run: mv builds/viam_rust_utils-macosx_arm64.h builds/viam_rust_utils.h

compare_headers:
needs: [create_canonical_header]
runs-on: ubuntu-latest
strategy:
fail-fast: true
matrix:
include:
- platform: macosx_x86_64
- platform: linux_aarch64
- platform: linux_x86_64
- platform: musllinux_x86_64
- platform: musllinux_aarch64
- platform: linux_armv6l
- platform: musllinux_armv6l
- platform: musllinux_armv7l
- platform: musllinux_x86
- platform: windows_x86_64
steps:
- name: compare files
run: cmp builds/viam_rust_utils.h builds/viam_rust_utils-${{ matrix.platform }}.h
- name: remove duplicate header
run: rm builds/viam_rust_utils-${{ matrix.platform }}.h

merge:
needs: [build_macos, build_linux, build_windows, compare_headers]
runs-on: ubuntu-latest
steps:
- name: Merge artifacts
uses: actions/upload-artifact/merge@v4
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ bin/

# goutils
tests/goutils/

viam_rust_utils.h
108 changes: 96 additions & 12 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,4 @@ env_logger = "0.9.0"

[build-dependencies]
tonic-build = {version = "0.9.2",features = ["prost"]}
cbindgen = "0.29.2"
88 changes: 88 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
extern crate cbindgen;

use std::{collections::HashMap, env};

use cbindgen::{Config, ExportConfig, FunctionConfig, ParseConfig, RenameRule, StructConfig};

fn main() {
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();

// mangled nalgebra type outputs, mapped to a prefixed snake case variant
let nalgebra_types = vec![
("ArrayStorage_f64__3__1", "nalgebra_array_storage_f64__3__1"),
(
"Matrix_f64__U3__U1__ArrayStorage_f64__3__1",
"nalgebra_matrix_f64_3_1",
),
("Vector3_f64", "nalgebra_vector3_f64"),
("ArrayStorage_f64__4__1", "nalgebra_array_storage_f64__4__1"),
(
"Matrix_f64__U4__U1__ArrayStorage_f64__4__1",
"nalgebra_matrix_f64_4_1",
),
("Vector4_f64", "nalgebra_vector4_f64"),
("Quaternion_f64", "nalgebra_quaternion_f64"),
(
"Unit_Matrix_f64__U3__U1__ArrayStorage_f64__3__1",
"nalgebra_unit_matrix_f64_3_1",
),
("UnitVector3_f64", "nalgebra_unit_vector3_f64"),
("Rotation_f64__3", "nalgebra_rotation_f64_3"),
(
"Matrix_f64__Const_3_____Const_3_____ArrayStorage_f64__3__3",
"nalgebra_matrix_f64_3_3",
),
("ArrayStorage_f64__3__3", "nalgebra_array_storage_f64__3__3"),
("SMatrix_f64__3__3", "nalgebra_smatrix_f64_3_3"),
("Rotation_f64__3", "nalgebra_rotation_f64_3"),
("Rotation3_f64", "nalgebra_rotation3_f64"),
];

// mangled viam type outputs, mapped to a prefixed snake case variant
let viam_types = vec![
("DialFfi", "viam_dial_ffi"),
("AxisAngle", "viam_axis_angle"),
("EulerAngles", "viam_euler_angles"),
("OrientationVector", "viam_orientation_vector"),
];

let rename = vec![nalgebra_types, viam_types]
.into_iter()
.flatten()
.map(|(a, b)| (a.to_string(), b.to_string()))
.collect::<HashMap<String, String>>();

cbindgen::Builder::new()
.with_crate(crate_dir)
.with_config(Config {
parse: ParseConfig {
parse_deps: true,
include: Some(vec!["nalgebra".to_string()]),
..Default::default()
},
export: ExportConfig {
rename,
..Default::default()
},
structure: StructConfig {
rename_associated_constant: RenameRule::SnakeCase,
rename_fields: RenameRule::SnakeCase,
..Default::default()
},
function: FunctionConfig {
deprecated: Some(
"/// @deprecated please use `viam_`-prefixed function instead".to_string(),
),
..Default::default()
},
..Default::default()
})
.with_cpp_compat(true)
.with_language(cbindgen::Language::C)
.with_autogen_warning(
"/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */",
)
.generate()
.expect("Unable to generate bindings")
.write_to_file("viam_rust_utils.h"); // Output to target directory
}
6 changes: 6 additions & 0 deletions doc/dependency_decisions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,9 @@
:why:
:versions: []
:when: 2025-04-14 14:25:17.811988000 Z
- - :permit
Copy link
Member Author

Choose a reason for hiding this comment

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

(flyby) license finder was failing because of a BSD-zero-clause license. since it's an extremely permissive license, it seemed fine to include here.

- BSD-zero-clause
- :who:
:why:
:versions: []
:when: 2025-11-04 16:20:20.790232000 Z
Loading
Loading