Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
3da97a0
add notes how to build WrapVTK and xml file with WrapVTK
yungselm Mar 8, 2026
2a76bdb
set up bash script
yungselm Mar 8, 2026
f996d9a
working set up to add functions to current vtk-rs-9.1 (had to update …
yungselm Mar 9, 2026
1021478
address several problems in automated pipeline
yungselm May 29, 2026
c8ad22c
small fix
yungselm May 29, 2026
d41e5ff
working setup_vtk.sh
yungselm May 29, 2026
d91c139
add vtk_name field to IRMethod and short_name() helper
yungselm May 29, 2026
1791c97
update gitignore to exlude notes, small typo fix
yungselm May 29, 2026
1391bf6
write tests for intermediate representaiton
yungselm May 29, 2026
d795421
prepare a CHANGELOG.md
yungselm May 29, 2026
6d426b0
add tests to inheritance_hierarchy
yungselm May 29, 2026
464ed77
initial draft, that resolves all the errors especially for types and…
yungselm May 29, 2026
9497686
fix to work with full ancestor chain
yungselm May 29, 2026
27f9ee1
update newly generated vtk v9.1.0
yungselm May 29, 2026
d9cf067
fix all pointer issues with claude using an iterative approach
yungselm May 29, 2026
df6ec6d
update CHANGELOG.md
yungselm May 29, 2026
dd075f8
fix C++ codegen: use raw T* instead of vtkNew<T> in extern "C" wrappers
yungselm May 29, 2026
3ff98ee
fix correct c_longlong mapping
yungselm May 29, 2026
be976c3
fix test to work with T* instead of vtkNew<T>
yungselm May 29, 2026
4e6f99a
fix generated create/drop test and new() for T*
yungselm May 29, 2026
fa021a8
fix avoid panic in get_exposable_methods when no parent class
yungselm May 29, 2026
a21d105
refactor remove dead code in ToTokens for IRModule
yungselm May 29, 2026
a2e2102
fix remove dead StarStar special-case
yungselm May 29, 2026
f0a065b
update stale vtkNew comment in is_constructable
yungselm May 29, 2026
7f74564
update CHANGELOG
yungselm May 29, 2026
adb59d3
include updated vtk-rs-9.1
yungselm May 29, 2026
74e4ccb
remove the version bound example (unnecessary)
yungselm May 29, 2026
4f3214c
cleanup CHANGELOG and README
yungselm May 29, 2026
6f2a48e
refactor remove now unsued get_ptr C++ binding and get_ptr_binding_name
yungselm May 29, 2026
ed060e5
add the updated vtk-rs-9.1
yungselm May 29, 2026
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/target
vtk-rs/libvtkrs/build
Cargo.lock
LEARNINGS.md
WORKFLOW.md
49 changes: 49 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
## [0.3.0] - 2026-05-29
This change will introduce the new feature of automatically creating the hierarchy. Additionally, tests were added for all the core functionalities of `vtk-gen` (not complete for possible edge cases, focused on straight forward functionality assessment). Most other changes are a result of getting everything to build without errors (e.g. handling rust keywords, handling different cpp pointers, ...).

Detailed summary:

### Added
- `vtkFiltersSources` module is now generated and linked, adding `SphereSource` and 20+ other source classes.
- Re-export all constructable VTK classes at the crate root with the `vtk` prefix stripped (e.g. `vtk_rs::SphereSource`, `vtk_rs::NamedColors`).
- `pub mod prelude` in the generated `lib.rs` that re-exports all module contents via glob, enabling `use vtk_rs::prelude::*` for ergonomic trait method access without explicit trait imports.
- `sphere_source` example in `examples/` (workspace root), runnable via `cargo run --example sphere_source`.
- `has_ancestor(class_name, target) -> bool` on `ClassHierarchy` -> iterative DFS to walk the full ancestor chain (not just direct parents). Used to correctly detect `vtkObjectBase` ancestry across deep inheritance hierarchies.
- `IRStruct::has_vtk_object_base_ancestor: bool` field, computed via `has_ancestor` rather than checking direct parents only, fixing `is_constructable()` for deeply inherited classes.
- `IRMethod::vtk_name: String` field (PascalCase VTK method name) and `short_name()` helper for generating clean Rust method names.
- `c_signed_char` IR type to distinguish VTK's explicitly-typed `signed char` (used in typed data arrays such as `vtkSignedCharArray`) from plain `char` (used for C strings). `CppType::PlainChar` added to the C++ parser for the same reason.
- Overload deduplication via `.scan()` in `IRModule::new()`: C does not support overloading, so only the first VTK overload seen for each binding name is kept.
- `StarStarConst` (`**const`) and `StarStarStar` (`***`) pointer variants added to the `Pointer` enum in `parse_wrap_vtk_xml`.
- `pointer: Option<Pointer>` field added to `Parameter` in `parse_wrap_vtk_xml` so parameter pointer qualifiers are no longer silently dropped.
- C-style array parameter filter in `get_exposable_methods`: methods whose signature contains `[` are skipped because array extents are not encoded in the WrapVTK XML.
- Comprehensive test suites: `#[cfg(test)] mod inheritance_tests` (5 tests), `mod gen_rust_tests` (20 tests), `mod gen_cpp_tests` (8 tests), `mod tests` in `intermediate_representation` (5 tests). Total: 52 vtk-gen unit tests.

### Changed
- `is_constructable()` now requires `has_vtk_object_base_ancestor` (full ancestor chain) instead of checking only direct parents for `vtkObjectBase`.
- `method_to_cpp` / `method_to_cpp_header` emit `extern "C"` bindings using `method.vtk_name` for the C++ call site and `method.name` for the symbol name.
- The glob processed by vtk-gen now includes `vtkFiltersSources` in addition to `vtkCommon*`.
- `write_build_rs` in `vtk-gen/src/main.rs` no longer hardcodes `vtktoken` in the link list (VTK 9.1 system packages do not ship `libvtktoken`).

### Fixed
- **`vtkNew<T>` ABI mismatch in generated C++ wrappers**: `vtkNew<T>` has a non-trivial destructor, so passing or returning it by value in `extern "C"` functions violates the x86-64 SysV ABI and causes the wrapped VTK object to be destroyed on every method call. Constructor, destructor, get-ptr, and all method wrappers now use raw `T*` (`T::New()` / `sself->Delete()` / `return sself`) instead of `vtkNew<T>`.
- **`std::string` return types** (`IRType::String`): bridging `std::string` as `const char*` is illegal (dangling pointer). These methods are now skipped on both the Rust and C++ sides.
- **`const char*` vs `const char* const*`**: `StarStarConst` and `StarStar` now always bail instead of incorrectly reducing to a single pointer.
- **Mutable `char**` output parameters**: `StarStar` always bails -> VTK_FILEPATH uses `pointer="*"` in the actual XML, never `pointer="**"`. The previous special-case for `Const(SignedChar)**` was unreachable dead code and has been removed.
- **Mutable `char*` vs `signed char*`**: `Pointer(c_char)` (without `Const`) is now rejected on both Rust and C++ sides — VTK typed-data-array methods use `signed char*`, which is not implicitly convertible from `char*` in C++.
- **`signed char*` data array methods**: Separated `CppType::PlainChar` (`"char"`) from `CppType::SignedChar` (`"signed char"`) so typed-data-array parameters (`const signed char*`) generate the correct C++ type and are rejected at the Rust FFI boundary (not safely bridgeable without element-count information).
- **`Path` types by value/reference** (e.g. `const vtkStdString&`, `vtkColor3ub`): rejected in `ir_type_is_supported`; VTK object types are only bridgeable as opaque pointers.
- **Heap collection types** (`Vec`, `LinkedList`, `Map`): rejected in `ir_type_is_supported` — these types cannot cross the `extern "C"` boundary safely.
- **Cross-module supertrait bounds**: removed from generated trait definitions. Generating `trait VtkFoo: VtkBar` across module boundaries requires the concrete struct to implement all ancestor traits, which the generator does not yet support.
- **`vtktoken` linker error**: removed from the hardcoded link list in `write_build_rs`; `libvtktoken` is a VTK 9.2+ library not present in VTK 9.1 system packages.
- **`c_longlong` Rust type mapping**: was incorrectly emitting `core::ffi::c_uchar` (copy-paste error); now correctly emits `core::ffi::c_longlong`.
- **Generated `test_vtkXxx_create_drop` was broken**: after the `vtkNew<T>` → `T*` switch, `get_ptr` returns the pointer itself so the post-drop null assertion was wrong and the test accessed freed memory (UB). Simplified to verify creation gives a non-null pointer and `drop` does not panic.
- **Panic in `get_exposable_methods`**: indexing `self.classes[parent]` would panic if a parent class named in an XML `<inheritance>` entry had no corresponding XML file scanned. Changed to a silent skip via `.filter_map(|n| self.classes.get(&n))`.
- **`new()` in generated bindings**: `Self(unsafe { &mut *constructor() })` created a spurious `&mut c_void` reference before coercing back to `*mut c_void`. Simplified to `Self(unsafe { constructor() })`.

## [0.2.0] - 2025-06-03

## [0.1.3] - 2025-05-25

## [0.1.2] - 2025-05-24

## [0.1.1] - 2025-04-01
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[workspace]
resolver = "3"
members = [
"vtk-gen",
"vtk-rs-9.1",
Expand Down
68 changes: 68 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,74 @@ However, we do not use `cxx` to compile the code but rather let `cmake` handle t
To implement the desired class methods, we use Rust
[macros](https://doc.rust-lang.org/reference/macros-by-example.html).

## Contributing / Development Setup

This section is for contributors who want to regenerate bindings for a new VTK version.
If you only want to *use* the existing `vtk-rs-9.1` bindings, skip this section since a system VTK install and `cargo build` is sufficient.

### Prerequisites

Before following the steps below, ensure you have the following tools installed:

| Tool | Required | Purpose |
| --- | --- | --- |
| `cmake` (≥ 3.12) | Yes | Build VTK from source and build WrapVTK |
| `git` | Yes | Clone the VTK source repository |
| C++ compiler (`gcc` or `clang`) | Yes | Compile VTK and WrapVTK |
| Python dev headers | Yes | Required by VTK's Python wrapping layer, which WrapVTK depends on to generate XML |
| `libarchive` dev headers | Optional | Enables the `vtkCommonArchive` module; skipped gracefully if absent |
| ~10 GB free disk space | Yes | VTK source clone + build artifacts |

Install on Ubuntu 22 / 24:
```bash
# Required
sudo apt install cmake build-essential python3-dev
# Optional (for vtkCommonArchive)
sudo apt install libarchive-dev
```
Install on Arch Linux:
```bash
sudo pacman -S cmake gcc python libarchive
```
Install on macOS:
```bash
brew install cmake python libarchive
```

### 1. Run the setup script

`libvtk9-dev` (the system package) does **not** install the internal wrapping tool headers (e.g. `vtkParseAttributes.h`) that WrapVTK needs.
Use the provided `setup_vtk.sh` script to clone VTK from source, build it, initialise the `WrapVTK` submodule if needed, build WrapVTK against it, and verify the XML output all in one step:

```bash
./setup_vtk.sh 9.2.0
```

The version argument is optional and defaults to `9.2.0`. This takes roughly 15–30 minutes depending on your machine.

The script will:
1. Wipe any existing `~/VTK` clone and `WrapVTK/build` directory
2. Clone VTK at the exact tag (e.g. `v9.2.0`) into `~/VTK`
3. Build VTK with static libs, Python wrapping enabled (required by WrapVTK), and the non-Common groups disabled (Rendering, Imaging, Qt, Web, Views, MPI — not needed for XML generation, and some contain version-specific compile bugs)
4. Initialise the `WrapVTK` git submodule automatically if not already done
5. Build WrapVTK against the fresh VTK build
6. Verify that XML files were generated under `WrapVTK/build/xml/`

### 2. Regenerate bindings with vtk-gen

```bash
cargo run -p vtk-gen -- \
--opath vtk-rs-9.2 \
--wrap-vtk WrapVTK
```
or one-line
```bash
cargo run -p vtk-gen -- --opath vtk-rs-9.2 --wrap-vtk WrapVTK
```

This regenerates all files in `vtk-rs-9.2/` from the WrapVTK XML output.
To target a different VTK version, run `./setup_vtk.sh <version>` first, then repeat this step with a matching output path (e.g. `--opath vtk-rs-9.1` as included in the repository).

## Roadmap
1. [x] Stabilize Build system
2. [x] Automate system library detection and generate linker flags
Expand Down
7 changes: 5 additions & 2 deletions examples/sphere_source.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
use vtk_rs as vtk;
use vtk_rs::prelude::*;

fn main() {
let colors = vtk::NamedColors::new();
let _colors = vtk::NamedColors::new();

// Create a sphere
let mut sphere_source = vtk::SphereSource::new();
sphere_source.set_center([0.; 3]);
sphere_source.set_center(0., 0., 0.);
sphere_source.set_radius(5.0);

// Make the surface smooth
sphere_source.set_phi_resolution(100);
sphere_source.set_theta_resolution(100);

println!("sphere source: {sphere_source:?}")

/* let mut mapper = vtk::PolyDataMapper::new();
mapper.set_input_connection(sphere_source.get_output_port());
let mut mapper = vtkPolyDataMapper::New();
Expand Down
177 changes: 177 additions & 0 deletions setup_vtk.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
#!/usr/bin/env bash
# setup_vtk.sh — Download VTK from source, build WrapVTK, and generate XML files.
#
# Usage:
# ./setup_vtk.sh [VTK_VERSION]
#
# Example:
# ./setup_vtk.sh 9.2.0 (default)
# ./setup_vtk.sh 9.3.0
#
# What this script does:
# 1. Wipes any existing ~/VTK clone and WrapVTK/build directory.
# 2. Clones VTK at the exact tag v<VTK_VERSION> into ~/VTK.
# 3. Builds VTK (static libs, no Python/Java/testing).
# 4. Builds WrapVTK against the fresh VTK build.
# 5. Verifies that XML files were generated.

set -euo pipefail

# ---------------------------------------------------------------------------
# Configuration
# ---------------------------------------------------------------------------
VTK_VERSION="${1:-9.2.0}"
VTK_TAG="v${VTK_VERSION}"
VTK_SRC="${HOME}/VTK"
VTK_BUILD="${VTK_SRC}/build"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
WRAP_VTK_DIR="${SCRIPT_DIR}/WrapVTK"
WRAP_BUILD="${WRAP_VTK_DIR}/build"
JOBS="$(nproc)"

echo "=========================================="
echo " VTK setup script"
echo " VTK version : ${VTK_TAG}"
echo " VTK source : ${VTK_SRC}"
echo " WrapVTK dir : ${WRAP_VTK_DIR}"
echo " Parallel jobs: ${JOBS}"
echo "=========================================="

# ---------------------------------------------------------------------------
# Step 0: Wipe existing builds
# ---------------------------------------------------------------------------
echo ""
echo "[0/4] Wiping existing builds..."

if [ -d "${VTK_SRC}" ]; then
echo " Removing ${VTK_SRC} ..."
rm -rf "${VTK_SRC}"
fi

if [ -d "${WRAP_BUILD}" ]; then
echo " Removing ${WRAP_BUILD} ..."
rm -rf "${WRAP_BUILD}"
fi

echo " Done."

# ---------------------------------------------------------------------------
# Step 1: Clone VTK at the exact version tag
# ---------------------------------------------------------------------------
echo ""
echo "[1/4] Cloning VTK ${VTK_TAG} into ${VTK_SRC} ..."

git clone \
https://github.com/Kitware/VTK.git \
--branch "${VTK_TAG}" \
--depth 1 \
"${VTK_SRC}"

echo " Clone complete."

# ---------------------------------------------------------------------------
# Step 2: Build VTK from source
# ---------------------------------------------------------------------------
echo ""
echo "[2/4] Building VTK (this takes 15-30 minutes) ..."

mkdir -p "${VTK_BUILD}"

# Module disable notes:
# - VTK_WRAP_PYTHON=ON is required for the wrapping tools (vtkWrapHierarchy etc.)
# that WrapVTK depends on to generate XML, but it also enables Python wrapper
# compilation for every built module — so we disable all module groups we don't
# need to avoid compiling broken or unnecessary code.
# - IOImage and IOImage are in the StandAlone group alongside Common modules,
# so they cannot be excluded via group flags. DONT_WANT is overridden by the
# group DEFAULT, so NO is required — it is unconditional and ignores group
# membership. vtkSEPReader.cxx in IOImage fails to compile on GCC with
# VTK <= 9.1 (out-of-sync header/impl: missing EndiannessType, DataFormat
# members and std::int32_t). Safe to hard-disable: vtk-gen only reads
# vtkCommon* XML.
# - libproj (ThirdParty): bundled PROJ library uses std::int64_t without
# including <cstdint>; fails on GCC >= 13. Pulled in by IO/GeoJSON and
# similar StandAlone modules we don't need.
cmake -S "${VTK_SRC}" -B "${VTK_BUILD}" \
-DVTK_WRAP_PYTHON=ON \
-DVTK_WRAP_JAVA=OFF \
-DBUILD_TESTING=OFF \
-DBUILD_SHARED_LIBS=OFF \
-DCMAKE_BUILD_TYPE=Release \
-DVTK_MODULE_ENABLE_VTK_CommonArchive=DONT_WANT \
-DVTK_MODULE_ENABLE_VTK_CommonPython=DONT_WANT \
-DVTK_MODULE_ENABLE_VTK_IOImage=NO \
-DVTK_MODULE_ENABLE_VTK_libproj=NO \
-DVTK_GROUP_ENABLE_Rendering=DONT_WANT \
-DVTK_GROUP_ENABLE_Qt=DONT_WANT \
-DVTK_GROUP_ENABLE_Web=DONT_WANT \
-DVTK_GROUP_ENABLE_Views=DONT_WANT \
-DVTK_GROUP_ENABLE_MPI=DONT_WANT \
-DVTK_GROUP_ENABLE_Imaging=DONT_WANT

cmake --build "${VTK_BUILD}" -j"${JOBS}"

echo " VTK build complete."

# Sanity check: ensure wrapping headers are present
if [ ! -f "${VTK_BUILD}/Wrapping/Tools/vtkParseAttributes.h" ] && \
[ ! -f "${VTK_SRC}/Wrapping/Tools/vtkParseAttributes.h" ]; then
echo ""
echo "WARNING: vtkParseAttributes.h not found."
echo " WrapVTK may fail if wrapping headers are missing."
fi

# ---------------------------------------------------------------------------
# Step 3: Build WrapVTK
# ---------------------------------------------------------------------------
echo ""
echo "[3/4] Building WrapVTK ..."

# Initialise the submodule if it hasn't been cloned yet
if [ ! -f "${WRAP_VTK_DIR}/CMakeLists.txt" ]; then
echo " WrapVTK submodule not initialised — running git submodule update ..."
git -C "${SCRIPT_DIR}" submodule update --init --recursive
fi

mkdir -p "${WRAP_BUILD}"
cmake -S "${WRAP_VTK_DIR}" -B "${WRAP_BUILD}" \
-DVTK_DIR="${VTK_BUILD}"

cmake --build "${WRAP_BUILD}" -j"${JOBS}"

echo " WrapVTK build complete."

# ---------------------------------------------------------------------------
# Step 4: Verify XML output
# ---------------------------------------------------------------------------
echo ""
echo "[4/4] Verifying XML output ..."

XML_DIR="${WRAP_BUILD}/xml"

if [ ! -d "${XML_DIR}" ]; then
echo "ERROR: XML directory not found at ${XML_DIR}"
echo " Something went wrong during the WrapVTK build."
exit 1
fi

XML_COUNT="$(ls -1 "${XML_DIR}" | wc -l)"
echo " Found ${XML_COUNT} XML module directories in ${XML_DIR}."

if [ "${XML_COUNT}" -eq 0 ]; then
echo "ERROR: No XML files were generated. Check the WrapVTK build output."
exit 1
fi

echo ""
echo "=========================================="
echo " Setup complete for VTK ${VTK_TAG}!"
echo ""
echo " VTK build : ${VTK_BUILD}"
echo " XML output: ${XML_DIR}"
echo ""
echo " Next step — regenerate Rust bindings:"
echo " cargo run -p vtk-gen -- \\"
echo " --opath vtk-rs-${VTK_VERSION%.*} \\"
echo " --wrap-vtk WrapVTK"
echo "=========================================="
4 changes: 2 additions & 2 deletions vtk-gen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ include = ["src/*.rs", "/Default/*"]
anyhow = "1.0.98"
cargo_toml = "0.22.3"
clap = { version = "4.5.54", features = ["derive"] }
convert_case = "0.10.0"
convert_case = "0.11.0"
glob = "0.3.2"
log = "0.4.27"
pretty_env_logger = "0.5.0"
Expand All @@ -23,4 +23,4 @@ regex = "1.11.1"
serde = { version = "1.0.219", features = ["derive"] }
serde-xml-rs = "0.8.1"
syn = "2.0.101"
toml = "0.9.11"
toml = "1.1.2"
Loading