Open minrk opened 1 month ago
xref related issue on pybind11 side:
It looks like most of the discussion is around "try to get these packages to not include the compiler version in the abi" rather than accepting the current behavior and expressing the dependencies that they have.
It looks like most of the discussion is around "try to get these packages to not include the compiler version in the abi" rather than accepting the current behavior and expressing the dependencies that they have.
Indeed, I cross-linked exactly to make sure that people looking to that discussions could find also this related discussion.
pybind11 and nanobind are both header-only packages, right? As header-only packages, "host" doesn't really have any significance for them since the same artifacts are used regardless of the host/target platform.
They could be used as build dependencies instead of host dependencies so that they can directly interact with the compiler packages. If the solution requires moving these packages to the build section, we could add a linting rule / migration to the channel to have new builds move these packages there.
The issue here is pass items at runtime between two different libraries compiled with these packages. The layout of objects in memory can differ and cause ABI issues.
Your question:
The problem
For packages built with pybind11 and nanobind, the major version of the C++ compiler is part of the ABI. That means any package built with nanobind that links to another package via its nanobind API has a runtime requirement that both were built with the same major version of the compiler. This is not currently handled by the
pybind11-abi
metapackage or other compiler run_exports.I don't think it comes up very often, but it does in the fenics stack. For fenics, I've added a
fenics-basix-nanobind-abi
package with a custom version that includes the nanobind and cxx_compiler versions. In the past, I had the same that bundled the pybind11-abi version and compiler version. I've only made one of these because everything in fenics depends on basix, but technically every package build with nanobind (that might be linked against inhost
) should have one. But this is a general problem, if not a common one. pybind11 has apybind11-abi
package, and nanobind will soon as well. But this is only half a solution, because it doesn't take the build-time compiler version into account, which is also part of the ABI in packages built with either pybind11 or nanobind.My
fenics-basix-nanobind-abi
approach also doesn't solve the problem as well as I'd like because downstream packages build just fine since the compiler version is not actually restricted in the build env, but they won't import. that means e.g. cross-compiled outputs pass all CI when they are completely broken, when really the build should have been prevented in the first place due to the compiler version conflict.Also, I've only dealt with this on linux/mac and don't actually know what needs to be restricted on Windows.
Question
I've struggled to come up with a general solution, but it seems like having
nanobind
orpybind11
in host dependencies should:One hard part is that pybind11/nanobind packages are host dependencies, so can't easily restrict the cxx compiler version in the build environment. Is there a package in the host env that could be used as a proxy? Or should we be adding a metapackage to the build env to keep things in sync?
Does anyone have a recommendation/experience for a best practice for ensuring ABI compatibility that is sensitive to the compiler version? Is defining one of these abi metapackage outputs for every nanobind-built package really the way to go?
Possible solution
My only idea so far for a general solution is to update the
pybind11/nanobind-abi
packages (or separately addnanobind-cxx-abi
) to generate a version for each compiler version with run_constrains on the compiler version and nanobind and strong run_exports on itself.so e.g.
nanobind-cxx-abi 0.13.12 gxx_*
would have:where:
cxx_compiler_version
gxx
iscxx_compiler
and would look something like:
and then packages make sure this is the same version in both the build and host requirements. But as convoluted as that is, I'm not even sure it would work.