From 00b4505397de45c418780b5dee95c68c433acfc8 Mon Sep 17 00:00:00 2001 From: RM975 Date: Sat, 19 Sep 2026 18:26:45 +0200 Subject: [PATCH] Fix Windows/MSVC build: Handle_X is a distinct class under MSVC On MSVC, OCCT's Standard_Handle.hxx defines `Handle_X` as a non-template subclass of `opencascade::handle` (for C++/CLI export), whereas on other compilers it is a plain typedef. The C++ bridge assumed the typedef everywhere, so opencascade-sys fails to compile with MSVC (error C2440 / C2665) and, once that is fixed, fails to link. Changes: - Construct `Handle_X` directly instead of `opencascade::handle` when wrapping in `std::unique_ptr` (b_rep, gc, geom, geom2d, geom_api, top_tools). Identical on typedef compilers. In GCE2d_MakeSegment_point_point, go through a local `opencascade::handle<...>` first, since Handle_X's own constructors reject the MakeSegment implicit conversion. - cxx binds a function/member pointer directly to some OCCT methods that take `Handle(X)`. A pointer needs an exact type match, so the `Handle_X` parameter no longer matches on MSVC. Route these through small inline wrappers instead: BRepLib_ToolTriangulatedShape::ComputeNormals, BRepOffsetAPI_MakePipeShell::SetLaw, ShapeAnalysis_FreeBounds::ConnectEdgesToWires, and the generic `handle_try_deref` (bound from poly.rs and top_tools.rs). The high-level crate call sites are updated accordingly. - Link advapi32 on Windows: TKernel's OSD_* uses the Win32 security and registry API, and linking any binary otherwise fails with ~23 unresolved externals (SetFileSecurityW, OpenProcessToken, ...). Tested only on Windows 11, MSVC 14.44 (VS 2022 17.14), OCCT 7.8.1 via occt-sys: `cargo build` and a test that builds a box and cylinder, subtracts/unions them, checks the exact volume, and writes STEP all pass. Not tested on Linux or macOS; the changes are meant to be no-ops there. --- crates/opencascade-sys/build.rs | 7 +++++++ crates/opencascade-sys/include/b_rep.hxx | 6 +++--- crates/opencascade-sys/include/b_rep_lib.hxx | 13 +++++++++++++ crates/opencascade-sys/include/b_rep_offset_api.hxx | 12 ++++++++++++ crates/opencascade-sys/include/gc.hxx | 12 ++++++++---- crates/opencascade-sys/include/geom.hxx | 10 +++++----- crates/opencascade-sys/include/geom2d.hxx | 8 ++++---- crates/opencascade-sys/include/geom_api.hxx | 2 +- crates/opencascade-sys/include/poly.hxx | 10 ++++++++++ crates/opencascade-sys/include/shape_analysis.hxx | 10 ++++++++++ crates/opencascade-sys/include/top_tools.hxx | 9 ++++++++- crates/opencascade-sys/src/b_rep_lib.rs | 4 +--- crates/opencascade-sys/src/b_rep_offset_api.rs | 4 ++-- crates/opencascade-sys/src/poly.rs | 2 +- crates/opencascade-sys/src/shape_analysis.rs | 4 +--- crates/opencascade-sys/src/top_tools.rs | 2 +- crates/opencascade/src/make_pipe_shell.rs | 8 +++++++- crates/opencascade/src/mesh.rs | 2 +- crates/opencascade/src/primitives/wire.rs | 2 +- 19 files changed, 96 insertions(+), 31 deletions(-) diff --git a/crates/opencascade-sys/build.rs b/crates/opencascade-sys/build.rs index b65c3137b..4960fd352 100644 --- a/crates/opencascade-sys/build.rs +++ b/crates/opencascade-sys/build.rs @@ -47,6 +47,13 @@ fn main() { if is_windows { println!("cargo:rustc-link-lib=dylib=user32"); + // MSVC only: TKernel's + // OSD_* (file protection, process user name, registry-based debug + // flags) needs the Win32 security/registry API, which isn't pulled in + // by anything else here. Without it, linking any binary against + // opencascade-sys fails with ~23 unresolved externals (SetFileSecurityW, + // OpenProcessToken, GetTokenInformation, RegOpenKeyExW, ...). + println!("cargo:rustc-link-lib=dylib=advapi32"); } // TODO(bschwind) - Iterate over the src/ directory to populate this. diff --git a/crates/opencascade-sys/include/b_rep.hxx b/crates/opencascade-sys/include/b_rep.hxx index 74872521f..60402f4e9 100644 --- a/crates/opencascade-sys/include/b_rep.hxx +++ b/crates/opencascade-sys/include/b_rep.hxx @@ -13,12 +13,12 @@ inline const TopoDS_Builder &BRep_Builder_upcast_to_topods_builder(const BRep_Builder &builder) { return builder; } inline std::unique_ptr BRep_Tool_Surface(const TopoDS_Face &face) { - return std::unique_ptr(new opencascade::handle(BRep_Tool::Surface(face))); + return std::unique_ptr(new Handle_Geom_Surface(BRep_Tool::Surface(face))); } inline std::unique_ptr BRep_Tool_Curve(const TopoDS_Edge &edge, Standard_Real &first, Standard_Real &last) { - return std::unique_ptr(new opencascade::handle(BRep_Tool::Curve(edge, first, last))); + return std::unique_ptr(new Handle_Geom_Curve(BRep_Tool::Curve(edge, first, last))); } inline std::unique_ptr BRep_Tool_Pnt(const TopoDS_Vertex &vertex) { @@ -28,5 +28,5 @@ inline std::unique_ptr BRep_Tool_Pnt(const TopoDS_Vertex &vertex) { inline std::unique_ptr BRep_Tool_Triangulation(const TopoDS_Face &face, TopLoc_Location &location) { return std::unique_ptr( - new opencascade::handle(BRep_Tool::Triangulation(face, location))); + new Handle_Poly_Triangulation(BRep_Tool::Triangulation(face, location))); } diff --git a/crates/opencascade-sys/include/b_rep_lib.hxx b/crates/opencascade-sys/include/b_rep_lib.hxx index 156b7faf2..cd9372368 100644 --- a/crates/opencascade-sys/include/b_rep_lib.hxx +++ b/crates/opencascade-sys/include/b_rep_lib.hxx @@ -2,3 +2,16 @@ #include #include #include + +// MSVC only: `Handle_Poly_Triangulation` is a distinct subclass of +// `opencascade::handle` there (see +// Standard_Handle.hxx), so a function pointer to +// `BRepLib_ToolTriangulatedShape::ComputeNormals` (declared with +// `Handle(Poly_Triangulation)`, i.e. the base type) doesn't exact-match a +// `Handle_Poly_Triangulation` parameter. An inline wrapper sidesteps the +// function-pointer binding entirely; the implicit conversion at the call +// site is fine either way. +inline void BRepLib_ToolTriangulatedShape_ComputeNormals(const TopoDS_Face &face, + const Handle_Poly_Triangulation &triangulation) { + BRepLib_ToolTriangulatedShape::ComputeNormals(face, triangulation); +} diff --git a/crates/opencascade-sys/include/b_rep_offset_api.hxx b/crates/opencascade-sys/include/b_rep_offset_api.hxx index 73d716bf2..aca6f27f0 100644 --- a/crates/opencascade-sys/include/b_rep_offset_api.hxx +++ b/crates/opencascade-sys/include/b_rep_offset_api.hxx @@ -7,3 +7,15 @@ #include #include #include + +// MSVC only: a +// member-function pointer to `BRepOffsetAPI_MakePipeShell::SetLaw` +// doesn't exact-match `Handle_Law_Function` (a distinct subclass of +// `opencascade::handle` under MSVC) against OCCT's own +// `Handle(Law_Function)`-typed parameter. A free-function wrapper +// sidesteps the pointer-type binding. +inline void BRepOffsetAPI_MakePipeShell_SetLaw(BRepOffsetAPI_MakePipeShell &shell, const TopoDS_Shape &profile, + const Handle_Law_Function &law, bool with_contact, + bool with_correction) { + shell.SetLaw(profile, law, with_contact, with_correction); +} diff --git a/crates/opencascade-sys/include/gc.hxx b/crates/opencascade-sys/include/gc.hxx index 25ddc71dd..f05266c71 100644 --- a/crates/opencascade-sys/include/gc.hxx +++ b/crates/opencascade-sys/include/gc.hxx @@ -4,15 +4,19 @@ #include inline std::unique_ptr GC_MakeSegment_Value(const GC_MakeSegment &segment) { - return std::unique_ptr(new opencascade::handle(segment.Value())); + return std::unique_ptr(new Handle_Geom_TrimmedCurve(segment.Value())); } inline std::unique_ptr GCE2d_MakeSegment_point_point(const gp_Pnt2d &p1, const gp_Pnt2d &p2) { - return std::unique_ptr( - new opencascade::handle(GCE2d_MakeSegment(p1, p2))); + // MSVC only: `Handle_Geom2d_TrimmedCurve`'s + // own constructors don't accept `GCE2d_MakeSegment`'s implicit conversion directly (it lands + // on a `const opencascade::handle<...>&&` overload and loses the const qualifier). Converting + // through a plain `opencascade::handle<...>` lvalue first sidesteps that. + opencascade::handle segment_handle = GCE2d_MakeSegment(p1, p2); + return std::unique_ptr(new Handle_Geom2d_TrimmedCurve(segment_handle)); } inline std::unique_ptr GC_MakeArcOfCircle_Value(const GC_MakeArcOfCircle &arc) { - return std::unique_ptr(new opencascade::handle(arc.Value())); + return std::unique_ptr(new Handle_Geom_TrimmedCurve(arc.Value())); } diff --git a/crates/opencascade-sys/include/geom.hxx b/crates/opencascade-sys/include/geom.hxx index b063d9204..9771609eb 100644 --- a/crates/opencascade-sys/include/geom.hxx +++ b/crates/opencascade-sys/include/geom.hxx @@ -9,16 +9,16 @@ inline std::unique_ptr Geom_CylindricalSurface_new(const gp_Ax3 &axis, double radius) { return std::unique_ptr( - new opencascade::handle(new Geom_CylindricalSurface(axis, radius))); + new Handle_Geom_CylindricalSurface(new Geom_CylindricalSurface(axis, radius))); } inline std::unique_ptr cylinder_to_surface(const Handle_Geom_CylindricalSurface &cylinder_handle) { - return std::unique_ptr(new opencascade::handle(cylinder_handle)); + return std::unique_ptr(new Handle_Geom_Surface(cylinder_handle)); } inline std::unique_ptr Geom_BezierSurface_new(const TColgp_Array2OfPnt &poles) { return std::unique_ptr( - new opencascade::handle(new Geom_BezierSurface(poles))); + new Handle_Geom_BezierSurface(new Geom_BezierSurface(poles))); } inline const gp_Pnt &handle_geom_plane_location(const Handle_Geom_Plane &plane) { return plane->Location(); } @@ -29,13 +29,13 @@ Geom_BezierCurve_to_handle(std::unique_ptr bezier_curve) { } inline std::unique_ptr bezier_to_surface(const Handle_Geom_BezierSurface &bezier_handle) { - return std::unique_ptr(new opencascade::handle(bezier_handle)); + return std::unique_ptr(new Handle_Geom_Surface(bezier_handle)); } inline std::unique_ptr new_HandleGeomPlane_from_HandleGeomSurface(const Handle_Geom_Surface &surface) { Handle_Geom_Plane plane_handle = opencascade::handle::DownCast(surface); - return std::unique_ptr(new opencascade::handle(plane_handle)); + return std::unique_ptr(new Handle_Geom_Plane(plane_handle)); } inline std::unique_ptr HandleGeomCurve_Value(const Handle_Geom_Curve &curve, const Standard_Real U) { diff --git a/crates/opencascade-sys/include/geom2d.hxx b/crates/opencascade-sys/include/geom2d.hxx index 938868892..b8534f25e 100644 --- a/crates/opencascade-sys/include/geom2d.hxx +++ b/crates/opencascade-sys/include/geom2d.hxx @@ -5,22 +5,22 @@ inline std::unique_ptr Geom2d_Ellipse_new(const gp_Ax2d &axis, double major_radius, double minor_radius) { return std::unique_ptr( - new opencascade::handle(new Geom2d_Ellipse(axis, major_radius, minor_radius))); + new Handle_Geom2d_Ellipse(new Geom2d_Ellipse(axis, major_radius, minor_radius))); } inline std::unique_ptr ellipse_to_HandleGeom2d_Curve(const Handle_Geom2d_Ellipse &ellipse_handle) { - return std::unique_ptr(new opencascade::handle(ellipse_handle)); + return std::unique_ptr(new Handle_Geom2d_Curve(ellipse_handle)); } inline std::unique_ptr Geom2d_TrimmedCurve_new(const Handle_Geom2d_Curve &curve, double u1, double u2) { return std::unique_ptr( - new opencascade::handle(new Geom2d_TrimmedCurve(curve, u1, u2))); + new Handle_Geom2d_TrimmedCurve(new Geom2d_TrimmedCurve(curve, u1, u2))); } inline std::unique_ptr HandleGeom2d_TrimmedCurve_to_curve(const Handle_Geom2d_TrimmedCurve &trimmed_curve) { - return std::unique_ptr(new opencascade::handle(trimmed_curve)); + return std::unique_ptr(new Handle_Geom2d_Curve(trimmed_curve)); } inline std::unique_ptr ellipse_value(const Handle_Geom2d_Ellipse &ellipse, double u) { diff --git a/crates/opencascade-sys/include/geom_api.hxx b/crates/opencascade-sys/include/geom_api.hxx index 07a104231..fa7c1155e 100644 --- a/crates/opencascade-sys/include/geom_api.hxx +++ b/crates/opencascade-sys/include/geom_api.hxx @@ -4,5 +4,5 @@ #include inline std::unique_ptr GeomAPI_Interpolate_Curve(const GeomAPI_Interpolate &interpolate) { - return std::unique_ptr(new opencascade::handle(interpolate.Curve())); + return std::unique_ptr(new Handle_Geom_BSplineCurve(interpolate.Curve())); } diff --git a/crates/opencascade-sys/include/poly.hxx b/crates/opencascade-sys/include/poly.hxx index 7b35060d4..53f44677a 100644 --- a/crates/opencascade-sys/include/poly.hxx +++ b/crates/opencascade-sys/include/poly.hxx @@ -2,6 +2,16 @@ #include #include +// MSVC only: `handle_try_deref` +// can't be bound directly by function pointer against `Handle_Poly_Triangulation` +// (a distinct subclass of `opencascade::handle` under MSVC). +// A thin, exactly-typed wrapper sidesteps the pointer-type binding; the call to +// the template itself is fine since ordinary calls allow the derived-to-base +// reference conversion that function-pointer binding doesn't. +inline const Poly_Triangulation &Handle_Poly_Triangulation_deref(const Handle_Poly_Triangulation &handle) { + return handle_try_deref(handle); +} + inline std::unique_ptr Handle_Poly_Triangulation_new(std::unique_ptr triangulation) { return std::unique_ptr(new Handle_Poly_Triangulation(triangulation.release())); diff --git a/crates/opencascade-sys/include/shape_analysis.hxx b/crates/opencascade-sys/include/shape_analysis.hxx index eb610c496..f0384918e 100644 --- a/crates/opencascade-sys/include/shape_analysis.hxx +++ b/crates/opencascade-sys/include/shape_analysis.hxx @@ -2,3 +2,13 @@ #include #include #include + +// MSVC only: same reasoning +// as the other wrappers here - a static-method function pointer doesn't +// exact-match `Handle_TopTools_HSequenceOfShape` against OCCT's own +// `Handle(TopTools_HSequenceOfShape)&`-typed parameters. +inline void ShapeAnalysis_FreeBounds_ConnectEdgesToWires(Handle_TopTools_HSequenceOfShape &edges, + Standard_Real tolerance, Standard_Boolean shared, + Handle_TopTools_HSequenceOfShape &wires) { + ShapeAnalysis_FreeBounds::ConnectEdgesToWires(edges, tolerance, shared, wires); +} diff --git a/crates/opencascade-sys/include/top_tools.hxx b/crates/opencascade-sys/include/top_tools.hxx index 68e027a96..a4510a36a 100644 --- a/crates/opencascade-sys/include/top_tools.hxx +++ b/crates/opencascade-sys/include/top_tools.hxx @@ -5,9 +5,16 @@ #include #include +// MSVC only: same reasoning +// as Handle_Poly_Triangulation_deref in poly.hxx. +inline const TopTools_HSequenceOfShape & +Handle_TopTools_HSequenceOfShape_deref(const Handle_TopTools_HSequenceOfShape &handle) { + return handle_try_deref(handle); +} + inline std::unique_ptr new_Handle_TopTools_HSequenceOfShape() { auto sequence = new TopTools_HSequenceOfShape(); - auto handle = new opencascade::handle(sequence); + auto handle = new Handle_TopTools_HSequenceOfShape(sequence); return std::unique_ptr(handle); } diff --git a/crates/opencascade-sys/src/b_rep_lib.rs b/crates/opencascade-sys/src/b_rep_lib.rs index aa44fa315..f48d4a686 100644 --- a/crates/opencascade-sys/src/b_rep_lib.rs +++ b/crates/opencascade-sys/src/b_rep_lib.rs @@ -13,8 +13,6 @@ mod inner { #[Self = "BRepLib"] pub fn BuildCurves3d(shape: &TopoDS_Shape) -> bool; - type BRepLib_ToolTriangulatedShape; - #[Self = "BRepLib_ToolTriangulatedShape"] - pub fn ComputeNormals(face: &TopoDS_Face, triangulation: &Handle_Poly_Triangulation); + pub fn BRepLib_ToolTriangulatedShape_ComputeNormals(face: &TopoDS_Face, triangulation: &Handle_Poly_Triangulation); } } diff --git a/crates/opencascade-sys/src/b_rep_offset_api.rs b/crates/opencascade-sys/src/b_rep_offset_api.rs index 6c560866b..60f651bb5 100644 --- a/crates/opencascade-sys/src/b_rep_offset_api.rs +++ b/crates/opencascade-sys/src/b_rep_offset_api.rs @@ -83,8 +83,8 @@ mod inner { with_contact: bool, with_correction: bool, ); - pub fn SetLaw( - self: Pin<&mut BRepOffsetAPI_MakePipeShell>, + pub fn BRepOffsetAPI_MakePipeShell_SetLaw( + shell: Pin<&mut BRepOffsetAPI_MakePipeShell>, profile: &TopoDS_Shape, law: &Handle_Law_Function, with_contact: bool, diff --git a/crates/opencascade-sys/src/poly.rs b/crates/opencascade-sys/src/poly.rs index 57c02324f..6b2203521 100644 --- a/crates/opencascade-sys/src/poly.rs +++ b/crates/opencascade-sys/src/poly.rs @@ -13,7 +13,7 @@ mod inner { // Handles type Handle_Poly_Triangulation; pub fn IsNull(self: &Handle_Poly_Triangulation) -> bool; - #[cxx_name = "handle_try_deref"] + #[cxx_name = "Handle_Poly_Triangulation_deref"] pub fn Handle_Poly_Triangulation_Get( handle: &Handle_Poly_Triangulation, ) -> Result<&Poly_Triangulation>; diff --git a/crates/opencascade-sys/src/shape_analysis.rs b/crates/opencascade-sys/src/shape_analysis.rs index 0bb9c581e..e6d699b26 100644 --- a/crates/opencascade-sys/src/shape_analysis.rs +++ b/crates/opencascade-sys/src/shape_analysis.rs @@ -8,9 +8,7 @@ mod inner { type TopoDS_Shape = crate::topo_ds::TopoDS_Shape; type Handle_TopTools_HSequenceOfShape = crate::top_tools::Handle_TopTools_HSequenceOfShape; - type ShapeAnalysis_FreeBounds; - #[Self = "ShapeAnalysis_FreeBounds"] - pub fn ConnectEdgesToWires( + pub fn ShapeAnalysis_FreeBounds_ConnectEdgesToWires( edges: Pin<&mut Handle_TopTools_HSequenceOfShape>, tolerance: f64, shared: bool, diff --git a/crates/opencascade-sys/src/top_tools.rs b/crates/opencascade-sys/src/top_tools.rs index 79daf2f08..7d27dc045 100644 --- a/crates/opencascade-sys/src/top_tools.rs +++ b/crates/opencascade-sys/src/top_tools.rs @@ -66,7 +66,7 @@ mod inner { index: i32, ) -> &TopoDS_Shape; - #[cxx_name = "handle_try_deref"] + #[cxx_name = "Handle_TopTools_HSequenceOfShape_deref"] pub fn HandleTopTools_HSequenceOfShape_Get( handle: &Handle_TopTools_HSequenceOfShape, ) -> Result<&TopTools_HSequenceOfShape>; diff --git a/crates/opencascade/src/make_pipe_shell.rs b/crates/opencascade/src/make_pipe_shell.rs index 5e5d53d04..34cf49795 100644 --- a/crates/opencascade/src/make_pipe_shell.rs +++ b/crates/opencascade/src/make_pipe_shell.rs @@ -12,6 +12,12 @@ pub(crate) fn make_pipe_shell_with_law_function( let profile_shape = ffi::topo_ds::cast_wire_to_shape(profile); let with_contact = false; let with_correction = true; - make_pipe_shell.pin_mut().SetLaw(profile_shape, law_function, with_contact, with_correction); + ffi::b_rep_offset_api::BRepOffsetAPI_MakePipeShell_SetLaw( + make_pipe_shell.pin_mut(), + profile_shape, + law_function, + with_contact, + with_correction, + ); make_pipe_shell } diff --git a/crates/opencascade/src/mesh.rs b/crates/opencascade/src/mesh.rs index 177085dd8..668c17114 100644 --- a/crates/opencascade/src/mesh.rs +++ b/crates/opencascade/src/mesh.rs @@ -88,7 +88,7 @@ impl Mesher { // TODO(bschwind) - Use `location` to transform the normals. let normal_array = ffi::t_col_gp::TColgp_Array1OfDir_new(0, face_point_count); - ffi::b_rep_lib::BRepLib_ToolTriangulatedShape::ComputeNormals( + ffi::b_rep_lib::BRepLib_ToolTriangulatedShape_ComputeNormals( &face.inner, &triangulation_handle, ); diff --git a/crates/opencascade/src/primitives/wire.rs b/crates/opencascade/src/primitives/wire.rs index 667a80ba0..bf47a64f2 100644 --- a/crates/opencascade/src/primitives/wire.rs +++ b/crates/opencascade/src/primitives/wire.rs @@ -98,7 +98,7 @@ impl Wire { EdgeConnection::Fuzzy { tolerance } => (tolerance, false), }; - ffi::shape_analysis::ShapeAnalysis_FreeBounds::ConnectEdgesToWires( + ffi::shape_analysis::ShapeAnalysis_FreeBounds_ConnectEdgesToWires( edges.pin_mut(), tolerance, shared,