Skip to content

Fix binding generation bugs, add FreeBSD support, resolve CMake MPI issue#62

Open
elliejs wants to merge 2 commits into
CadQuery:masterfrom
elliejs:freebsd-fixes
Open

Fix binding generation bugs, add FreeBSD support, resolve CMake MPI issue#62
elliejs wants to merge 2 commits into
CadQuery:masterfrom
elliejs:freebsd-fixes

Conversation

@elliejs

@elliejs elliejs commented Jun 25, 2026

Copy link
Copy Markdown

Summary

Two commits:

  1. Fix binding generation bugs and cross-platform CMake issues — fixes several
    bugs that affect all platforms:

    • Fix arg_defualt typo that silently dropped all default parameter values
    • Fix {% if d %} dead conditional that prevented defaults from ever being emitted
    • Fix arg.namearg.arg_name producing empty variable names in by-ref methods
    • Fix nested type qualification (typedefs, enums, POD types inside template classes)
      emitted as bare names instead of fully qualified (NCollection_Array1<T>::value_type)
    • Fix trampoline class dedup comparing by short name, skipping overloaded virtuals
    • Add default_value macro: emit py::none() for null pointer defaults instead of
      invalid static_cast<T*>(0)
    • Fix arg_type_with_template_params for already-parameterized types
    • Add argtypes_for_template for py::init<> dependent-type qualification
    • CMakeLists.j2: enable C language, add find_package(MPI QUIET) (resolves
      fix CMake not finding MPI OCP#179), add fmt::fmt link, bump cmake minimum to 3.17
  2. Add FreeBSD platform support — FreeBSD-specific libclang header handling
    (-nostdinc/-isystem) and symbol manifest (130k symbols from FreeBSD's
    opencascade port).

Test plan

  • Full pywrap generate + ninja compile on FreeBSD 15.0
  • import OCP succeeds
  • Stubs generated
  • FreeBSD CI passes (elliejs/OCP)
  • Linux/Windows/OSX CI passes (elliejs/OCP)

Companion OCP PR: CadQuery/OCP#204

🤖 Generated with Claude Code

elliejs and others added 2 commits June 25, 2026 17:47
Several bugs in the binding generator caused incorrect or missing C++
code in the generated pybind11 bindings. These affect all platforms.

header.py — type resolution (_underlying_type):
  Nested types defined inside template classes (typedefs like
  value_type, enums like BehaviorOnTransform, POD types like
  size_type) were emitted as bare names without their enclosing class
  qualification. In generated static_cast expressions, the compiler
  cannot resolve a bare "value_type" — it needs the fully qualified
  "NCollection_Array1<T>::value_type". Three new blocks handle this:
  non-POD typedefs (134 types), POD typedefs (3 types), and nested
  enums/records (17 types). The non-POD typedef block also fixes a
  corruption pattern where the upstream replace() call could produce
  "X<T>::typename X<T>::Y", and prevents double typename prefixes.

header.py — default values (_default_value):
  Fix a typo in the ArgInfo dataclass field name: "arg_defualt" was
  never matching what Jinja2 templates reference as "arg_default".
  This silently dropped every default parameter value for every
  function on every platform. Also strip "const" from brace-init
  defaults — "const gp_Pnt{ }" is a syntax error (8 parameters).

macros.j2 — default value emission:
  The argnames macro had {% if d %} where d is undefined in Jinja2
  (always falsy), so default values were never emitted even if
  header.py produced them. Fixed to {% if arg.arg_default %}.

  New default_value macro handles null pointer defaults correctly:
  pybind11 expects py::none() for optional pointer arguments, not
  static_cast<T*>(0) which was previously emitted (40 parameters).

  Fix arg.name → arg.arg_name in init_outputs_byref — the ArgInfo
  dataclass field is arg_name. The undefined arg.name produced empty
  variable names in generated C++ for by-reference smart pointer
  methods.

macros.j2 — template type qualification:
  arg_type_with_template_params had a bug where it checked the raw
  input string t instead of ns.t, and only handled types starting
  with the bare class name (ClassName::member). Types where the class
  name already had template params (ClassName<T>::Iterator) were not
  qualified with typename, causing compile failures. Added a second
  branch for this case. Same fix applied to template_return_type.

  New argtypes_for_template macro applies template type qualification
  to py::init<> type lists. Without this, template class constructor
  argument types were emitted without typename qualification, causing
  dependent name lookup failures.

  Removed dead inline type-expansion code in argnames_template that
  computed a namespace variable ns.t which was never used — the
  actual default emission already called arg_type_with_template_params.

macros.j2 — trampoline class deduplication:
  Pure virtual method deduplication compared by short name (m.name),
  so overloaded virtuals like Values(Vec&, Real&, Vec&) and
  Values(Vec&, Real&, Vec&, Mat&) were treated as duplicates. Changed
  to use m.full_name (full signature). Also added the missing
  methods.append call for private virtuals, which allowed parent-class
  loops to re-emit methods already overridden. 20 classes affected.

CMakeLists.j2:
  Bump cmake_minimum_required to 3.17. Enable C language (needed when
  VTK links against MPI::MPI_C). Add find_package(MPI QUIET) so cmake
  can resolve MPI::MPI_C and MPI::MPI_CXX targets on platforms where
  VTK is built with MPI support (resolves CadQuery/OCP#179). Add
  find_package(fmt) and link fmt::fmt — FreeBSD's OCCT port links
  against libfmt externally, while conda builds bundle it statically
  so this is a no-op there. Add status messages for Python lib path
  and VTK version to aid CI debugging.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
FreeBSD's system OCCT (from ports) installs headers and libraries in
different locations than conda, and libclang picks up conflicting
system headers unless explicitly told not to. This commit adds the
platform-specific handling needed to generate OCP bindings on FreeBSD.

translation_unit.py:
  On FreeBSD, libclang's automatic header search adds system include
  paths that conflict with the OCCT headers from the ports tree,
  causing hundreds of type redefinition errors during parsing. To fix
  this, the FreeBSD codepath disables libclang's automatic search
  (-nostdinc, -nostdinc++) and re-adds the platform include paths
  from ocp.toml's [FreeBSD] section as -isystem flags. Duplicate -I
  flags pointing to those same dirs are stripped to keep the arg list
  clean. Without this, the generate phase fails entirely on FreeBSD.
  Also fixes an f-string line break that is valid in Python 3.12+ but
  a syntax error in 3.11 (which FreeBSD uses).

symbols_mangled_freebsd.dat:
  Symbol manifest extracted from FreeBSD's compiled OCCT shared
  libraries via dump_symbols.py. Each platform needs its own manifest
  because name mangling and exported symbol sets differ across
  compilers. 130,310 symbols from FreeBSD's opencascade port.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@elliejs

elliejs commented Jun 26, 2026

Copy link
Copy Markdown
Author

Linux fails due to something already found in upstream, so not related to PR
Windows failed due to not finding a suitable image label found to route agent pool Azure Pipelines. Also unrelated to this PR

This PR has been tested in github actions on my own fork here: https://github.com/elliejs/OCP/actions/workflows/bindings.yml

Requires sister PR commit CadQuery/OCP#204 however.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant