Skip to content

don't embed Python code into libwallycore.so #501

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

whitslack
Copy link
Contributor

Embedding SWIG Python code into libwallycore.so ties the library to a specific version of Python, thereby precluding concurrent installation of the wallycore Python module for multiple implementations of Python on the same system if the Python modules are linked with a system-wide libwallycore.so. On Gentoo at least, linking libwallycore.so with libpython3.14.so and then attempting to use the wallycore Python module from Python 3.11, 3.12, or 3.13 causes an immediate segfault.

Rather than injecting Python-specific glue into libwallycore.so, we can and should keep it contained within the Python native extension library that we build for each Python implementation. The Python wheel actually already compiles swig_python_wrap.c and links it into the native extension library, so linking it into libwallycore.so as well is redundant and harmful.

  • Remove libswig_python.la from libwallycore_la_LIBADD, and expunge its existence from Makefile.am entirely since it's now unused.

  • The Python wheel build for each Python implementation compiles swig_python_wrap.c against the headers for that particular Python implementation, ensuring that the resulting native extension library matches the ABI of the Python implementation for which it is installed. This may be a different Python implementation than the one found by Autoconf, the only relevance of which now is in finding the interpreter with which to run the tests.

  • Since we no longer link libwallycore.so with libpython*.so, there should no longer be any manylinux compatibility issues, so drop the --enable-python-manylinux Autoconf option and the PYTHON_MANYLINUX Automake conditional. This also means that the test programs no longer need to link with $(PYTHON_LIBS) since libwallycore.la now never has any dependence on Python (implicit or explicit).

  • Note that the Python native extension libraries do not explicitly link with libpython*.so either. This is correct, as the dynamic linker resolves their undefined Py* symbols when it loads them into the Python interpreter.

After applying these changes, the Gentoo ebuild for libwally-core 1.5.0 now successfully runs the SWIG Python tests on all currently supported versions of Python (3.11 through 3.14), all using the same libwallycore.so.6.


For reference, this is a follow-up to a comment I made back in November 2023:

The one gripe I still have, which I am okay to address in a later release, is that the libwally-core library differs depending on whether the Python module is configured to be built. Really, libwallycore.so should have no awareness of Python in any configuration, and all necessary Python glue should reside in the Python native extension library. This is especially important when we install the Python module concurrently for multiple versions of Python. For instance, on my system I have the wallycore Python module installed for both Python 3.11 and 3.12, but /usr/lib64/libwallycore.so.1.0.0 specifies a dynamic link with libpython3.12.so.1.0. I don't have a good feeling about that link when the module is loaded under Python 3.11. Really, libwallycore.so should not link with any libpython*.so at all, as such a link indicates an abstraction leak / layer violation.

That bad feeling has indeed blossomed into an actual segfault as of Python 3.14.

At that same time, @jgriffiths noted:

I am open to addressing [your final point] in a future release[…]. Feel free to raise an issue with this info for tracking.

Embedding SWIG Python code into libwallycore.so ties the library to a
specific version of Python, thereby precluding concurrent installation
of the wallycore Python module for multiple implementations of Python
on the same system if the Python modules are linked with a system-wide
libwallycore.so. On Gentoo at least, linking libwallycore.so with
libpython3.14.so and then attempting to use the wallycore Python module
from Python 3.11, 3.12, or 3.13 causes an immediate segfault.

Rather than injecting Python-specific glue into libwallycore.so, we can
and should keep it contained within the Python native extension library
that we build for each Python implementation. The Python wheel actually
already compiles swig_python_wrap.c and links it into the native
extension library, so linking it into libwallycore.so as well is
redundant and harmful.

* Remove libswig_python.la from libwallycore_la_LIBADD, and expunge its
  existence from Makefile.am entirely since it's now unused.

* The Python wheel build for each Python implementation compiles
  swig_python_wrap.c against the headers for that particular Python
  implementation, ensuring that the resulting native extension library
  matches the ABI of the Python implementation for which it is
  installed. This may be a different Python implementation than the one
  found by Autoconf, the only relevance of which now is in finding the
  interpreter with which to run the tests.

* Since we no longer link libwallycore.so with libpython*.so, there
  should no longer be any manylinux compatibility issues, so drop the
  --enable-python-manylinux Autoconf option and the PYTHON_MANYLINUX
  Automake conditional. This also means that the test programs no longer
  need to link with $(PYTHON_LIBS) since libwallycore.la now never has
  any dependence on Python (implicit or explicit).

* Note that the Python native extension libraries do not explicitly link
  with libpython*.so either. This is correct, as the dynamic linker
  resolves their undefined Py* symbols when it loads them into the
  Python interpreter.

After applying these changes, the Gentoo ebuild for libwally-core 1.5.0
now successfully runs the SWIG Python tests on all currently supported
versions of Python (3.11 through 3.14), all using the same
libwallycore.so.6.
@jgriffiths
Copy link
Contributor

Hi @whitslack the CI does not like these changes, that will need to be fixed. The CI build results must be uploadable to PyPI as complete wheels, i.e. if a new venv is created then pip install wallycore==<version> must result in a usable installed wheel with no external dependencies other than libc.

You may need to gate this change behind a configure flag.

manylinux intentionally omits libpython*.so libraries from its build
containers to discourage/prevent wheels' native extension libraries from
linking against the Python DSO. We don't do that (anymore), but the
AX_PYTHON_DEVEL Autoconf macro expects to be able to find it and fails
its final sanity check if it can't. Thankfully, more recent versions of
the macro support an 'optional' flag that allows configure to proceed
even if the check fails. So now we set that flag and just check that we
have a value in $PYTHON_CPPFLAGS, which is all the SWIG_PYTHON macro
cares about in the first place.
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.

2 participants