I am still relatively new to the more fundamental components of VTK. I saw that many other programming languages (such as Python, C#) have bindings which are supported by the community. Since I noticed that nothing in particular exists for Rust, I have started said project.
It took me a while to figure out all the build-system interactions and which tools on the Rust side are suitable in supporting the generation of bindings (namely cxx).
My initial goal is to pick a demo and add bindings for all classes + subclasses which are part of this code. I have started with the sphere source example. Right now I am implementing
If anyone is interested in my project, I would very much appreciate any kind of feedback. I am sure that I can improve in many areas.
As far as I can tell, your wrapping is written manually for each VTK class. VTK has a very large number of classes and no stable public API, so this would be a lot of effort in the long run to wrap all classes and keep it up to date.
Have you looked into vtkWrap* classes and logic that parse headers and perform automatic type and function translation to the target language? That would be a more robust approach to build automatic rust bindings.
Thanks so much for this invaluable tip. I will probably have to revamp my whole setup but this should make it worthwhile. It will probably take me some time to study and understand these tools. There seem to be a lot (looking at Wrapping Tools - VTK documentation).
I strongly recommend taking a look at the WrapVTK repository. It contains the cmake logic for wrapping an installed VTK (this way, people can use it without building VTK themselves).
What WrapVTK does, by default, is generate an xml file for each VTK header file. The XML provides a compact description of the API (documented here). So one can either use the XML as an input for generating new language bindings, or use the vtkWrapXML program as an example of how to access VTK’s vtkWrappingTools library directly (the vtkWrappingTools library is part of the VTK install).
I want to mention that there is now another approach which is possible thanks to the builtin serialization capabilities in VTK that were added last month. This approach uses a “session” to create objects, set/get properties and invoke methods on those objects. You can even observe/unobserve events. The C API is in vtkSession.h. See the functions in VTK: Serialization/Manager/vtkSession.h File Reference
From what I understand, it is easier to wrap C to rust, rather than wrapping C++.
The way it could work is you wrap those C functions to rust, then implement the opaque vtkSessionJson using rust JSON stringify and parse routines. You can use the popular GitHub - serde-rs/json: Strongly typed JSON library for Rust library which provides a serde_json::from_str and a serde_json::Value::to_string(). You can set these function pointers on the vtkSessionDescriptor so that the vtkSession knows how to parse/stringify rust json.
The vtkSession.h header is installed so you can do this in your project outside VTK.
All in all, I expect it to be an easy and interesting project for a rust developer.
We have not benchmarked it but from a surface level, it all boils down to how efficient the json library is. At the end of the day, if not json, some other component has to marshal the arguments passed into the function and the return values between rust/C++.
Btw, the session API uses an optimized approach for function calls. Under the covers, it is a C++ switch-case on tokenized method names that are computed at buildtime. So that is pretty optimized already without using strcmp to find out which method needs to be invoked on a target object.
This code is all autogenerated by WrapSerDes when VTK is configured and built with VTK_WRAP_SERIALIZATION=ON
Thanks very much for the hint. I cloned the repo and will get working and report on my progress. As I feel more familiar in Rust than C, I might use it from this side via ffi bindings. But let’s see …
This sounds really interesting as well. How would I have to set up my project in order to use such a “session”? I suppose that I would need to call this on every object in the code base. Do you propose to integrate this approach into the final bindings or would you use this step as an intermediate result from which we generate Rust-Bindings? This is somewhat unclear to me. If it is “just” a wrapper of a json communication protocol to construct VTK piplines, this would probably not what I was looking for although I can see how such a protocol can be really interesting and effective.
If this involves constant (de)serialization I would prefer not to take this approach. With some setups, we can even achieve link-time optimizations between C++ and Rust libraries which gives us basically 0 cost in communication and thus probably faster than any runtime-calls. However, I still think that it is interesting and might revisit this.
It does involve a controlled (de)serialization when a user makes a function call into the session. That is definitely one downside to this approach. We take some measure to avoid expensive (de)serialization by excluding redundant properties, not traversing objects that were already traversed and so on.
It was honestly engineered to control objects in remote visualization pipelines over a network where the cost of deserialization/serialzation is somewhat acceptable.
I think the remote control aspect is very well justified and thanks for bringing it to my attention. But for low-level bindings I will prefer the approach given by @dgobbi .
Thanks so much. I am getting the following error though:
get_property could not find TARGET VTK::vtkjava.
I did install openjdk8-src to try to fix it but I am not sure how to proceed. My current VTK version is 9.4.2-3 and I am on Archlinux. I use cmake 4.0.2-dirty. Also there are some cmake files related to java:
$ ls /usr/lib/cmake/vtk/*ava*
/usr/lib/cmake/vtk/VTKJava-targets.cmake
/usr/lib/cmake/vtk/VTKJava-targets-release.cmake
/usr/lib/cmake/vtk/vtkModuleWrapJava.cmake
Edit: Full Error
CMake Error at /usr/lib/cmake/vtk/vtkModule.cmake:2172 (get_property):
get_property could not find TARGET VTK::vtkjava. Perhaps it has not yet
been created.
Call Stack (most recent call first):
CMakeLists.txt:18 (_vtk_module_get_module_property)
CMake Error at /usr/lib/cmake/vtk/vtkModule.cmake:2172 (get_property):
get_property could not find TARGET VTK::vtkjava. Perhaps it has not yet
been created.
Call Stack (most recent call first):
CMake/vtkModuleWrapXML.cmake:303 (_vtk_module_get_module_property)
CMakeLists.txt:26 (vtk_module_wrap_xml)
CMake Error at /usr/lib/cmake/vtk/vtkModule.cmake:2172 (get_property):
get_property could not find TARGET VTK::vtkjava. Perhaps it has not yet
been created.
Call Stack (most recent call first):
CMake/vtkModuleWrapXML.cmake:325 (_vtk_module_get_module_property)
CMakeLists.txt:26 (vtk_module_wrap_xml)
CMake Error at /usr/lib/cmake/vtk/vtkModule.cmake:1348 (message):
Failed to determine the real target for the `VTK::vtkjava` module. The
module name is not a CMake target. Is there a typo? Is it missing a
`Package::` prefix? Is a `find_package` missing a required component?
Call Stack (most recent call first):
CMake/vtkModuleWrapXML.cmake:331 (_vtk_module_real_target)
CMakeLists.txt:26 (vtk_module_wrap_xml)
The java errors are because VTK was configured for java, but vtk-java (i.e. the package) was not installed.
There is a simple work-around that can be done in WrapVTK: modify the find_package(VTK) in the main CMakeLists.txt so that it only looks for a specific list of components (i.e. make it like the find_package(VTK) in your vtk-rs repo, but also make sure WrappingTools is one of the components in addition to CommonCore etc).