ci: verify meshlib.mrmeshpy import before Unit Tests#6069
Merged
Conversation
When the Python bindings are built but `mrmeshpy.pyd` / `.so` can't be
loaded — DLL load failure, missing PyInit_*, libpython ABI mismatch,
binding-generation regression that drops a referenced class — MRTest's
embedded-python smoke test surfaces the problem only as CPython's
opaque
ImportError: initialization failed
…with no traceback and a single `<string>(N): <module>` location.
Diagnosing requires reproducing the import out-of-process to get a
real traceback.
Add a small Python script (`scripts/ci/verify_meshlib_import.py`) that
runs `import meshlib` and `import meshlib.mrmeshpy` with PYTHONPATH
pointing at the build's bin dir, exits non-zero with a real Python
traceback on failure, and a composite action
(`.github/actions/verify-meshlib-python-import`) that invokes it with
the right shell on Windows (pwsh + py -3) vs Unix (bash + python3).
Wire the action into all eight build pipelines that run
`MRTest`/`MRTest.exe`, immediately before the Unit Tests step:
* build-test-windows.yml (Windows main matrix)
* build-test-linux-vcpkg.yml (Linux vcpkg)
* build-test-macos.yml (macOS)
* build-test-ubuntu-x64.yml (Ubuntu x64)
* build-test-ubuntu-arm64.yml (Ubuntu arm64)
* pip-build.yml (manylinux + windows + macos
pip-wheel jobs)
Each invocation respects the same `if:` gate the workflow already uses
to decide whether bindings were built (`inputs.mrbind` for the build-test
matrices, the iterator-debug exclusion on Windows, unconditional for
the pip-wheel jobs which always build bindings).
Previous version probed for one shim and used the matching Python. That works for build-test-* (one shim per build), but pip-build's wheel jobs (FOR_WHEEL=1) build a shim per Python in scripts/mrbind-pybind11/python_versions.txt — currently 3.8 .. 3.14. Verify against all of them. For each pybind11nonlimitedapi_meshlib_<X.Y>.<ext> in <build-bin-dir>/meshlib/: * if `pythonX.Y` (Unix) or `py -X.Y` (Windows) is on the runner, invoke it on scripts/ci/verify_meshlib_import.py and tally pass/fail. * if not on the runner, log "SKIP: pythonX.Y not on PATH" so the step's output is honest about coverage instead of silently hiding gaps. Step exits non-zero if any *attempted* import failed, prints a summary line of shims/attempted/failed/skipped at the end. The single-shim build-test-* case still works — the loop runs once with the one matching Python.
The existing single-import check `import meshlib.mrmeshpy` is too narrow:
`test_python/helper/__init__.py` does both `import meshlib.mrmeshpy as
mrmesh` AND `import meshlib.mrmeshnumpy as mrmeshnumpy` at module
load. If pytest collects a test file that pulls in `helper`, both of
those imports run during collection. A crash in mrmeshnumpy (or any
other shipped submodule) takes pytest's collector down silently —
exactly what we're seeing on Daniil's macOS runner.
Iterate over every native-extension file in `<build>/meshlib/`
(`*.{so,dylib,pyd}`), strip ABI tags like `.cpython-310-darwin`, skip
`libpybind11nonlimitedapi*` shims, and import each with traceback on
failure. Print a per-module OK/FAIL line and a tally summary at the
end. Same exit-code semantics as before (non-zero on any failure).
…very
A run on the new code (Ubuntu Debug) imported all 4 native submodules
in meshlib/ and exposed an unrelated pre-existing bug: importing
`meshlib.mrviewerpy` and letting Python shut down trips a C++ debug
assertion in MRViewer/MRCommandLoop.cpp (CommandLoop destructor
expecting a drained queue), aborting the process despite all 4
imports having succeeded:
OK: meshlib.mrmeshpy ...
OK: meshlib.mrmeshnumpy ...
OK: meshlib.mrviewerpy ...
Summary: 4/4 submodules imported OK
python3.10: source/MRViewer/MRCommandLoop.cpp:13:
MR::CommandLoop::~CommandLoop(): Assertion `commands_.empty()' failed.
Aborted (core dumped)
That's a real but separate bug from what this script is gating
against (binding load failures pre-pytest), and it makes the verify
step false-positive on Debug builds.
Drop auto-discovery; hardcode the list to exactly what
test_python/helper/__init__.py imports — `mrmeshpy` and `mrmeshnumpy`
— since `helper` is what pytest collection pulls in transitively
through every test file. That's the meaningful set for catching
collection-time silent crashes (the original Daniil failure mode).
Comment links the list to the helper file so the next person knows
to keep it in sync.
…pip-build env Last run on pip-build's manylinux x86_64 job hit: FAIL: import meshlib.mrmeshnumpy ModuleNotFoundError: No module named 'numpy' ImportError: initialization failed That container's bare system Python has no numpy — the actual Python Tests step uses `uv run --with-requirements requirements/python.txt` to spawn each interpreter with numpy installed, but the verify step runs against the bare system Python without that, so mrmeshnumpy's module-init `import numpy` fails. False positive for the verify step. Drop mrmeshnumpy from the import list. Keep mrmeshpy: it's the one whose silent load failure was the original motivation, and it has no external runtime deps. mrmeshnumpy load failures (in env where numpy is actually present) still surface downstream in pytest collection.
Two follow-ups for the verify-meshlib-python-import step: 1) Add `timeout-minutes: 3` to each of the 8 callsites. The step is cheap (one or a few `import meshlib.mrmeshpy` calls), so 3 minutes is plenty even on slow runners; without it the step could in theory hang on a runner-side issue and inherit the surrounding job's much longer timeout (60–100 min). 2) Pass `-u` to python at the action invocation, same trick as #6071. Lets us drop the half-applied `flush=True` on individual prints in `scripts/ci/verify_meshlib_import.py` — `-u` flushes stdout/stderr unbuffered, so the script's own output stays in chronological order with the wrapping shell's `echo` lines (the per-shim `===== verify with pythonX.Y =====` headers, the final `Summary:` line, etc.) in the GitHub Actions log.
Grantim
approved these changes
May 8, 2026
Contributor
Grantim
left a comment
There was a problem hiding this comment.
please make comment shorter
Drop the long-winded background paragraphs from the script docstring and the action comments; keep just enough to explain the per-shim loop. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Fedr
added a commit
that referenced
this pull request
May 8, 2026
The pre-Unit-Tests "Verify meshlib.mrmeshpy import" step (added in #6069) now surfaces the import failure with a real traceback before MRTest's embedded-python smoke test runs, so the exhaustive post-Unit-Tests dumpbin/PyInit walk is no longer needed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 8, 2026
adalisk-emikhaylov
added a commit
that referenced
this pull request
May 20, 2026
* ci(windows): use preinstalled MSYS2 + pacman-installed clang
Stop fetching the ~725 MB msys64_meshlib_mrbind.zip from S3 (which
has been seen returning 404 in CI) and stop relying on the
install-msys2-mrbind composite action. The windows-2025 runner
image already ships:
* MSYS2 base at C:\msys64 (pacman 6.1.0)
* Standalone LLVM 20.1.8 at C:\Program Files\LLVM (unused by
MRBind, kept here for reference)
For MRBind we still need the MSYS2 -clang64 environment (mrbind
links against MSYS2's libclang/libc++, not the Windows-native
LLVM build). So this change pacman-installs the minimal toolchain
into the preinstalled C:\msys64:
pacman -Sy --noconfirm --needed make \
mingw-w64-clang-x86_64-{clang,clang-tools-extra,cmake,ninja,libc++}
and points all subsequent MRBind/binding-generation steps at
C:\msys64 by setting MSYS2_DIR (read by install_mrbind_windows_msys2.bat
and generate_win.bat). GETTEXT_ROOT moves from
C:\msys64_meshlib_mrbind\clang64 to C:\msys64\clang64.
The install-msys2-mrbind composite action is no longer used and is
deleted. install_deps_windows_msys2.bat (local-developer install
path) is unchanged: it still creates a separate
C:\msys64_meshlib_mrbind tree, untouched by this CI change.
Note: this swaps an S3-mirror dependency for an MSYS2-mirror
dependency. It also moves clang from a pinned 18.1.8 to whatever
mingw-w64-clang-x86_64-clang is currently in the clang64 repo
(22.x at the time of writing). MRBind's Windows path uses bare
`clang++` (no version suffix) so this works without further
changes; if a specific clang version becomes required later, pin
via pacman or use the MSYS2 archive.
* ci(windows): also install mingw-w64-clang-x86_64-llvm package
mrbind's CMakeLists does find_package(Clang REQUIRED), which
transitively requires LLVMConfig.cmake from the llvm dev package.
That package is listed only as an *optional* dep of clang, so
pacman did not pull it in automatically — Build MRBind failed
with:
Could not find a package configuration file provided by "LLVM"
(requested version 22.1.4)
Add mingw-w64-clang-x86_64-llvm to the install list explicitly.
* Update mrbind.
* Generate fresh MSYS2 lockfiles.
* We no longer upload zipped MSYS2 to S3.
* ci(windows): make generate_win.bat fail loudly on missing MSYS2
Two bugs combined to make a real failure look green in
https://github.com/MeshInspector/MeshLib/actions/runs/25392220595/job/74469566838:
1. The 'Generate and build Python bindings' step in
build-test-windows.yml didn't carry the MSYS2_DIR=C:\msys64 env
override that the other generate_win.bat / install_mrbind_windows_msys2.bat
callers on this branch already have. So the script saw the
default MSYS2_DIR=C:\msys64_meshlib_mrbind, which doesn't exist
on the runner anymore.
2. generate_win.bat printed 'MSYS2 was NOT found' and then fell
through to a normal exit, returning code 0. The step's `call`
inherited that 0, GitHub Actions marked the step green, the
.pyd never got built, and the failure only surfaced four steps
later when 'Unit Tests' couldn't load mrmeshpy.pyd
(LoadLibrary error 126).
Fix both:
* Add `MSYS2_DIR: C:\msys64` to the 'Generate and build Python
bindings' step's env block, matching Build MRBind / Generate C
bindings / Generate C# bindings.
* Replace generate_win.bat's silent fall-through with `exit /b 1`
after the missing-MSYS2 message. Mirrors what
install_mrbind_windows_msys2.bat already does on the same
condition. Future workflow callers that forget MSYS2_DIR will
fail at the right step instead of being papered over until
something later trips on the missing artifacts.
* Try enabling the debug env.
* Hopefully fix ambiguous Python names.
* ci(windows): diagnostic step for embedded-python ImportError
Add a post-Unit-Tests step (always(), continue-on-error) that
captures state when MRTest.exe's embedded python smoke test
trips `ImportError: initialization failed` from `<string>(2):
<module>`. CPython's wrapper hides the real cause; this dumps:
* contents of source\x64\<config>\ (DLLs, .pyd, EXE) and
source\x64\<config>\meshlib\
* dumpbin /exports of MR{Test,EmbeddedPython,Python}.{exe,dll}
and each *.pyd, filtered to PyInit_* — confirms the module
init function is exported
* dumpbin /dependents of the same, filtered to python*/MR*/CRT —
shows which python.dll the bindings and the embedded
interpreter resolve (catches ABI mismatches between vcpkg's
Python 3.12 and any other python.dll on PATH)
* `py -0p` inventory of available pythons
* a standalone `py -3.12 -c "import meshlib.mrmeshpy"` with
full traceback — gives the real Python exception instead of
CPython's wrapped "initialization failed"
* python*.dll listings under C:\vcpkg\installed\...\bin and
`where.exe` for python3.dll / python312.dll
Step is purely informational; it never fails the job.
* ci(windows): drop post-Unit-Tests Python diagnostic step
The pre-Unit-Tests "Verify meshlib.mrmeshpy import" step (added in
#6069) now surfaces the import failure with a real traceback before
MRTest's embedded-python smoke test runs, so the exhaustive
post-Unit-Tests dumpbin/PyInit walk is no longer needed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ci(windows): install latest clang from MSYS2 instead of pinning clang 18
Switch the install-msys2-mrbind composite from `pacman -U` against a
sha256-pinned lockfile (master's approach via #6060, ensuring clang
18.1.8) to a plain `pacman -S --needed` against the live MSYS2
mirror — picks up whatever clang/libc++/cmake/etc. is current.
* Minimal explicit package set: clang, lld, libc++, cmake, ninja,
gettext-tools, plus msys2 `make`. Pacman resolves transitive
deps; nothing is downgraded so `--needed` skips anything the
runner image already ships.
* No `actions/cache@v5` step at all. The clang-18 cache populated
by master's composite (key `msys2-mrbind-clang18-<hash>`) is on
a different path + key and cannot be hit.
* scripts/mrbind/msys2_package_hashes_clang18.txt deleted — the
lockfile is no longer consulted on the CI install path.
Developer-bootstrap path (install_deps_windows_msys2.bat) still
uses the unsuffixed msys2_package_hashes.txt and is unaffected.
Trade-off vs master: faster (one `pacman -S`, ~30-60 s, no archive
extraction step), but exposed to mrbind regressions on newer clang
that motivated the original clang-18 pin. Whether mrbind tolerates
current clang now is what this PR validates.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ci(windows): add mingw-w64-clang-x86_64-llvm to the install list
mrbind's CMake build needs LLVMConfig.cmake (via Clang's ClangConfig
which does find_package(LLVM 22.1.4)). The earlier pacman -S call
pulled in llvm-libs as a clang dep (runtime libs) but NOT llvm
(which carries lib/cmake/llvm/LLVMConfig.cmake), so cmake fails:
CMake Error at C:/msys64/clang64/lib/cmake/clang/ClangConfig.cmake:11:
Could not find a package configuration file provided by "LLVM"
(requested version 22.1.4) with any of the following names:
LLVMConfig.cmake / llvm-config.cmake / LLVM.cps / llvm.cps
MSYS2 split the monolithic llvm package into llvm + llvm-libs + llvm-tools
since this CI's last run on this branch — used to be one package.
Add the explicit `mingw-w64-clang-x86_64-llvm` to pacman -S so the
cmake configs are present.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ci(windows): re-add cache step (key distinct from master's clang-18 cache)
Caching `C:\msys64\var\cache\pacman\pkg\` lets `pacman -S --needed`
reuse archives across runs — exact-match runs become near-instant,
partial matches (after action.yml package-list edits or mirror
updates) save the unchanged-package downloads.
Key: `msys2-mrbind-latest-<os>-<hashFiles(action.yml)>`
Restore-key: `msys2-mrbind-latest-<os>-`
Different prefix from master's `msys2-mrbind-clang18-...` so the
two caches cannot collide, and on a different path
(`C:\msys64\var\cache\pacman\pkg` here vs
`scripts/mrbind/msys2_packages` on master).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ci(windows): add clang-tools-extra to the install list
ClangTargets.cmake (shipped by mingw-w64-clang-x86_64-clang) imports
the `clangApplyReplacements` target backed by
`lib/libclangApplyReplacements.a`, which lives in the separate
`mingw-w64-clang-x86_64-clang-tools-extra` package
(clang-apply-replacements, clang-format, clang-tidy, etc.).
Without it cmake fails configuring mrbind:
CMake Error at .../ClangTargets.cmake:808:
The imported target "clangApplyReplacements" references the file
".../lib/libclangApplyReplacements.a"
but this file does not exist.
Master's clang-18 lockfile pinned clang-tools-extra explicitly;
add it here too.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ci(windows): pin clang 22 via lockfile, mirroring master's clang-18 mechanism
Replace the previous `pacman -S --needed` against live mirrors with
the same lockfile-driven `pacman -U` approach master uses for clang
18, but pinning to the currently-shipped clang 22 versions.
* New `scripts/mrbind/msys2_package_hashes_clang22.txt` — 55
packages, all clang-22.1.4-3 era + transitive deps.
* Composite action restored to two steps: cache + install. Cache
keyed on `msys2-mrbind-clang22-<lockfile-hash>`, path
`scripts/mrbind/msys2_packages` (same shape as master, just a
different lockfile / cache key).
* Reuses the existing SUFFIX-aware `msys2_download_packages.sh` /
`msys2_install_packages.sh` scripts on this branch (they accept
`_clang22` as the lockfile suffix).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Try to fix mrbind errors.
* restore comment
* ci(windows): bump mrbind to MeshInspector/mrbind#33
Picks up the fix that skips primary function templates in
`Sema::InstantiateDefaultArgument` / `Sema::InstantiateFunctionDefinition`
calls. Without the fix, mrbind parsing `<boost/multiprecision/cpp_int.hpp>`
on clang 22 segfaults inside libclang with `STATUS_ACCESS_VIOLATION` on
a null `PatternDecl`. See MeshInspector/mrbind#33 for the full repro and
stack traces.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ci(windows): pass -fuse-ld=lld on compile invocations too
Clang 22's driver pre-validates linker compatibility whenever LTO flags
are present, even when only compiling. The PCH compile rule at
generate.mk:799 passes `-flto=thin` (via EXTRA_CFLAGS), and on clang 22 it
hard-errors with `LTO requires -fuse-ld=lld` before producing any output.
Adds the flag to COMPILER so PCH compilation passes the new driver check,
mirroring what LINKER already does. Clang treats `-fuse-ld` as a no-op on
non-link invocations, so this is safe on older clangs too.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ci(windows): pass -c to the PCH compile rule
Clang 22's driver pre-validates linker compatibility whenever LTO flags
are present in a non-`-c` invocation. The PCH compile rule at
generate.mk:799 invokes `$(COMPILER) -o foo.gch -xc++-header foo.hpp ...
-flto=thin ...` with no `-c`, so v22 hard-errors with
`LTO requires -fuse-ld=lld` before producing any output.
Adding `-c` tells the driver this is a compile-only step (which PCH always
is), bypassing the precheck. More surgical than putting `-fuse-ld=lld`
on every compile invocation via COMPILER.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ci(windows): bump mrbind to capture stack trace on segfault
Picks up MeshInspector/mrbind@87d1aee, which installs LLVM's
PrintStackTraceOnErrorSignal in mrbind's main(). The previous CI
segfault during Python bindings generation printed only
`make: *** ... Segmentation fault`; with this bump the stack trace will
be in the job log, letting us pinpoint the next unguarded Sema call.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Update mrbind.
* ci(windows): bump mrbind to skip class members in buggy-substitute path
Picks up MeshInspector/mrbind@a0153e2, which adds
`!llvm::isa<clang::CXXMethodDecl>(decl)` to the
`--buggy-substitute-default-template-args` entry condition. Without it,
the path calls `Sema::SubstDecl` on a CXXConstructorDecl template's
pattern, which null-derefs inside
`TemplateDeclInstantiator::InitMethodInstantiation` on clang 22 — that's
the SIGSEGV we saw in the previous Generate C bindings failure.
Submodule also carries the in-tree LLVM stack-trace signal handler in
mrbind's `main()`, so any future libclang crash will print a backtrace
to the CI log automatically.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Udpate mrbind.
* Temporarily enable verbose mrbind logging.
* Revert Claude fix.
* Update mrbind to add more logs.
* Update mrbind.
* Bump
* Update mrbind.
---------
Co-authored-by: Egor Mikhaylov <egor.mikhaylov@meshinspector.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
When the Python bindings build but
mrmeshpy.pyd/.socan't be loaded — DLL load failure, missingPyInit_*, libpython ABI mismatch, binding-generation regression that drops a referenced class — MRTest's embedded-python smoke test surfaces it as just:…with no traceback. Diagnosing requires reproducing the import out-of-process.
#6021 added a one-off post-Unit-Tests diagnostic step that did exactly that (a standalone
py -3.12 -c "import meshlib.mrmeshpy") and turned an opaque failure into a realAttributeError: module 'meshlib.mrmeshpy' has no attribute 'std_vector_const_Mesh'. This PR promotes that "standalone import attempt" into a proper pre-flight check that runs before Unit Tests in every workflow that builds bindings.Changes
New script
scripts/ci/verify_meshlib_import.py— runsimport meshlibthenimport meshlib.mrmeshpywith PYTHONPATH set, exits non-zero with atraceback.print_exc()on failure, prints the resolved Python interpreter / sys.prefix / PYTHONPATH for context.New composite action
.github/actions/verify-meshlib-python-import— takes one input (build-bin-dir), then:<build-bin-dir>/meshlib/for the pybind11 non-limited-api shim files (pybind11nonlimitedapi_meshlib_<X.Y>.{dll,so,dylib}) — those filenames encode the exact Python the bindings were built for.py -X.Yon Windows,pythonX.Yon Unix) on the verify script. Skips with a clearSKIP: pythonX.Y not on PATHmessage if the interpreter isn't installed.shims=N attempted=N failed=N skipped=N [list], exits non-zero if any attempted import failed.This handles both the regular
build-test-*workflows (one shim per build) and thepip-build.ymlwheel jobs (a shim per Python inpython_versions.txt, currently 7 of them).Wired into all eight Unit Tests sites in the existing workflows, immediately before the
MRTest/MRTest.exeinvocation:build-bin-dirbuild-test-windows.ymlwindows-build-testmatrixsource\x64\${{ matrix.config }}build-test-linux-vcpkg.ymllinux-vcpkg-build-testmatrix./build/${{ matrix.config }}/binbuild-test-macos.ymlmacos-build-testmatrixbuild-test-ubuntu-x64.ymlbuild-test-ubuntu-arm64.ymlpip-build.ymlmanylinux-pip-build./build/Release/binpip-build.ymlwindows-pip-buildsource\x64\Releasepip-build.ymlmacos-pip-build./build/Release/binEach invocation re-uses the workflow's existing gate that decides whether bindings were built (
inputs.mrbindfor the build-test matrices, the iterator-debug-triplet exclusion on Windows, unconditional for the pip-wheel jobs which always build bindings).Why only
mrmeshpyand not every submoduleThe script imports only
meshlib.mrmeshpy. Earlier iterations of this PR widened the check to every native submodule inmeshlib/, but that surfaced unrelated false positives:mrmeshnumpyrequiresnumpyat module init — fails in the manylinux pip-build container's bare system Python (where numpy is only installed insideuv run --with-requirements).mrviewerpyaborts at Python shutdown — itsMR::CommandLoop::~CommandLoop()debug assertion fires on a non-empty queue (MRViewer/MRCommandLoop.cpp:13), killing the process despite a successful import.Both are real but pre-existing issues unrelated to the binding-load failure mode this gate is meant to catch. Their actual load failures still surface downstream in pytest collection (in environments that have the right deps).
What this catches
mrmeshpy.pyd/.so— surface here withLoadLibrary error 126etc. instead of opaque "initialization failed" later.std_vector_const_Meshcase — surface here withAttributeError: module ... has no attribute ....Failed to load library pybind11nonlimitedapi_meshlib_<X.Y>and the matching-Python lookup picks the right version.Test plan
OK: meshlib.mrmeshpy at ….