You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
extension built with a shared python cannot be loaded with a static python #65735
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
assignee=Noneclosed_at=<Date2019-04-29.14:44:31.749>created_at=<Date2014-05-19.18:50:02.385>labels= ['3.8', 'type-feature', 'library']
title='extension built with a shared python cannot be loaded with a static python'updated_at=<Date2020-12-14.09:17:25.183>user='https://github.com/pitrou'
When a C extension is built (using distutils) with a shared library Python, it cannot be loaded with an otherwise identical statically linked Python. The other way round works fine. Trivial example using the _ssl module:
>>> import sys
>>> sys.path.insert(0, '/home/antoine/cpython/shared/build/lib.linux-x86_64-3.5/')
>>> import _ssl
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: libpython3.5m.so.1.0: cannot open shared object file: No such file or directory
This is probably because of an additional -L flag that is passed when linking a C extension with a shared library Python. I don't think the flag is useful under Linux (or perhaps under any other OS at all), since the relevant symbols are already loaded when the interpreter tries to load the C extension.
(AFAIK, systems notorious for providing shared library Pythons are RedHat-alike systems, while Debian/Ubuntu provide statically linked Pythons)
Actually, it's not a -L flag but a -l flag. Removing the "-lpython3.5m" flag from the linker line works fine under Linux, and allows the resulting extension to be loaded with both a shared libary Python and a statically-linked Python.
loewis commented on May 19, 2014
loewismannequin
Mannequin
More actions
I think you are right. It would IMO be useful to research a few comparable systems. E.g. Apache modules don't link a shared library, but still refer to apr_ functions as undefined symbols - but then, there isn't an APR shared library in the first place (at least not on Debian - how about Redhat?)
PHP might be close to our case: Debian includes a libphp5.so (in /usr/lib/php5), yet neither /usr/bin/php5 nor the Apache libphp5.so link against it, and all the PHP modules (in /usr/lib/php5/20100525+lfs/) don't link with the shared library - on Debian. I wonder how it is on systems that actually use the PHP shared library.
PHP might be close to our case: Debian includes a libphp5.so
(in /usr/lib/php5), yet neither /usr/bin/php5 nor the Apache libphp5.so
link against it, and all the PHP modules (in
/usr/lib/php5/20100525+lfs/) don't link with the shared library -
on Debian. I wonder how it is on systems that actually use the PHP
shared library.
Regardless of libphp5.so, the modules in /usr/lib/php5/20100525 don't link against /usr/lib/apache2/modules/libphp5.so, though the latter is obviously able to load those modules.
Hmm, apparently the -l flag was added in bpo-832799, for a rather complicated case where the interpreter is linked with a library dlopened by an embedding application (I suppose for some kind of plugin system). The OP there also mentions RTLD_GLOBAL as a workaround (or perhaps the right way of achieving the desired effect).
(also, the OP didn't mention why he used a shared library build, instead of linking Python statically with the dlopened library)
Hmm, apparently the -l flag was added in bpo-832799, for a rather complicated case where the interpreter is linked with a library dlopened by an embedding application (I suppose for some kind of plugin system). The OP there also mentions RTLD_GLOBAL as a workaround (or perhaps the right way of achieving the desired effect).
(also, the OP didn't mention why he used a shared library build, instead of linking Python statically with the dlopened library)
bpo-34814 is linked to this use case: https://bugzilla.redhat.com/show_bug.cgi?id=1585201 is an example of Python embedded in C using dlopen("libpython2.7.so.1.0", RTLD_LOCAL | RTLD_NOW). Problem: some C extensions of the standard library cannot be loaded in this case, like _struct.
On Fedora and RHEL, some C extensions like _struct are built by the "*shared*" section of Modules/Setup. In this case, these C extensions are not explicitly linked to libpython.
IHMO it's a bad usage of dlopen(): libpython must always be loaded with RTLD_GLOBAL.
bpo-832799 has been fixed by the following commit which modify distutils to link C extensions to libpython:
bpo-34814 is linked to this use case: https://bugzilla.redhat.com/show_bug.cgi?id=1585201 is an example of Python embedded in C using dlopen("libpython2.7.so.1.0", RTLD_LOCAL | RTLD_NOW). Problem: some C extensions of the standard library cannot be loaded in this case, like _struct.
I wrote PR 12946: "On Unix, C extensions are no longer linked to libpython".
Using PR 12946, the use case described in the initial message (msg218806) now works as expected. I can load a C extension built by a shared library Python with a statically linked Python:
/opt/py38notshared/bin/python3.8 is statically linked, whereas /opt/py38shared/lib/python3.8/lib-dynload/_ssl.cpython-38-x86_64-linux-gnu.so comes from a shared library Python.
Install shared libray Python into /opt/py38shared:
git clean -fdx; ./configure CFLAGS="-O0" --enable-shared --prefix /opt/py38shared && make && make install
Install statically linked Python into /opt/py38notshared:
git clean -fdx; ./configure CFLAGS="-O0" --prefix /opt/py38notshared && make && make install
--
As Antoine said, the opposite already works. Just in case, I also tested and I confirm that it still works:
This completely breaks building extension modules on Windows-based platforms like Cygwin and MinGW, where it is necessary when building even shared libraries for all global symbols to resolvable at link time.
C extensions are always linked to libpython on Android. I'm open to do something similar for Cygwin and/or MinGW if you can come up with a PR :-) See LIBPYTHON variable in configure.ac.
You can use Xavier's change as an example: commit 254b309, PR 12989.
New changeset c994c8f by Victor Stinner (E. M. Bray) in branch 'master': bpo-21536: On Cygwin, C extensions must be linked with libpython (GH-13549) c994c8f
New changeset b1fc417 by Victor Stinner (E. M. Bray) in branch 'master': bpo-21536: Fix configure.ac for LIBPYTHON on Android/Cygwin (GH-13552) b1fc417
xdegaye commented on May 24, 2019
xdegayemannequin
Mannequin
More actions
FWIW I checked the Android build after those last changes.
FWIW I checked the Android build after those last changes.
Thank you! I was overconfident when I merged the Cygwin which looked good to me, whereas it broke Android :-( Hopefully it was quickly fixed. I hope that everything will be alright for the the beta1 to start from a good milestone!
Just ran into this issue while cross-compiling python 3.9.2 for Android API 32 and managed to get the shared extensions working. Made only a few small modifications to the Makefile.
First added -Wl,-Bsymbolic to all shared libraries in the Android build as the Debian package has a patch to add this to the Linux build (actually -Wl,-Bsymbolic-functions) and i seemed like a good idea to copy that. Mainly because some time ago it was a de-facto standard to add this flag to every native library build [0]. Probably this is unrelated and not required [1].
Then found an interesting section in the man page of ld:
global
This option is only meaningful when building a shared
object. It makes the symbols defined by this shared
object available for symbol resolution of subsequently
loaded libraries.
So rebuilt libpython3.9.so with -Wl,-z,global
And voila, it rocks! Virtually this marks the shared library to be treated as if it had been loaded with RTLD_GLOBAL, moving all its symbols to the global namespace.
The parameter just turns on a flag in the ELF header, so it could be possible to try its effect with an ELF editor much faster than recompiling.
0x000000000000001e (FLAGS) SYMBOLIC BIND_NOW
0x000000006ffffffb (FLAGS_1) Flags: NOW GLOBAL
Activity
pitrou commentedon May 19, 2014
When a C extension is built (using distutils) with a shared library Python, it cannot be loaded with an otherwise identical statically linked Python. The other way round works fine. Trivial example using the _ssl module:
This is probably because of an additional -L flag that is passed when linking a C extension with a shared library Python. I don't think the flag is useful under Linux (or perhaps under any other OS at all), since the relevant symbols are already loaded when the interpreter tries to load the C extension.
(AFAIK, systems notorious for providing shared library Pythons are RedHat-alike systems, while Debian/Ubuntu provide statically linked Pythons)
pitrou commentedon May 19, 2014
Actually, it's not a -L flag but a -l flag. Removing the "-lpython3.5m" flag from the linker line works fine under Linux, and allows the resulting extension to be loaded with both a shared libary Python and a statically-linked Python.
loewis commentedon May 19, 2014
I think you are right. It would IMO be useful to research a few comparable systems. E.g. Apache modules don't link a shared library, but still refer to apr_ functions as undefined symbols - but then, there isn't an APR shared library in the first place (at least not on Debian - how about Redhat?)
PHP might be close to our case: Debian includes a libphp5.so (in /usr/lib/php5), yet neither /usr/bin/php5 nor the Apache libphp5.so link against it, and all the PHP modules (in /usr/lib/php5/20100525+lfs/) don't link with the shared library - on Debian. I wonder how it is on systems that actually use the PHP shared library.
pitrou commentedon May 26, 2014
Regardless of libphp5.so, the modules in /usr/lib/php5/20100525 don't link against /usr/lib/apache2/modules/libphp5.so, though the latter is obviously able to load those modules.
pitrou commentedon May 26, 2014
Hmm, apparently the -l flag was added in bpo-832799, for a rather complicated case where the interpreter is linked with a library dlopened by an embedding application (I suppose for some kind of plugin system). The OP there also mentions RTLD_GLOBAL as a workaround (or perhaps the right way of achieving the desired effect).
(also, the OP didn't mention why he used a shared library build, instead of linking Python statically with the dlopened library)
pitrou commentedon Jun 11, 2014
Martin, what do you think about the aforementioned use case?
vstinner commentedon Apr 25, 2019
See also bpo-34814.
vstinner commentedon Apr 25, 2019
Antoine:
bpo-34814 is linked to this use case: https://bugzilla.redhat.com/show_bug.cgi?id=1585201 is an example of Python embedded in C using dlopen("libpython2.7.so.1.0", RTLD_LOCAL | RTLD_NOW). Problem: some C extensions of the standard library cannot be loaded in this case, like _struct.
On Fedora and RHEL, some C extensions like _struct are built by the "*shared*" section of Modules/Setup. In this case, these C extensions are not explicitly linked to libpython.
IHMO it's a bad usage of dlopen(): libpython must always be loaded with RTLD_GLOBAL.
bpo-832799 has been fixed by the following commit which modify distutils to link C extensions to libpython:
commit 10acfd0
Author: Martin v. Löwis <martin@v.loewis.de>
Date: Mon Apr 10 12:39:36 2006 +0000
vstinner commentedon Apr 25, 2019
bpo-1429775 is another example of RTLD_LOCAL usage, see:
https://mail.python.org/pipermail/python-dev/2006-February/060533.html
vstinner commentedon Apr 25, 2019
I wrote PR 12946: "On Unix, C extensions are no longer linked to libpython".
Using PR 12946, the use case described in the initial message (msg218806) now works as expected. I can load a C extension built by a shared library Python with a statically linked Python:
/opt/py38notshared/bin/python3.8 is statically linked, whereas /opt/py38shared/lib/python3.8/lib-dynload/_ssl.cpython-38-x86_64-linux-gnu.so comes from a shared library Python.
Install shared libray Python into /opt/py38shared:
git clean -fdx; ./configure CFLAGS="-O0" --enable-shared --prefix /opt/py38shared && make && make install
Install statically linked Python into /opt/py38notshared:
git clean -fdx; ./configure CFLAGS="-O0" --prefix /opt/py38notshared && make && make install
--
As Antoine said, the opposite already works. Just in case, I also tested and I confirm that it still works:
_ssl comes from statically linked Python (/opt/py38notshared) and is loaded in shared library Python (/opt/py38shared).
22 remaining items
vstinner commentedon May 24, 2019
C extensions are always linked to libpython on Android. I'm open to do something similar for Cygwin and/or MinGW if you can come up with a PR :-) See LIBPYTHON variable in configure.ac.
You can use Xavier's change as an example: commit 254b309, PR 12989.
vstinner commentedon May 24, 2019
New changeset c994c8f by Victor Stinner (E. M. Bray) in branch 'master':
bpo-21536: On Cygwin, C extensions must be linked with libpython (GH-13549)
c994c8f
vstinner commentedon May 24, 2019
I merged E. M. Bray's PR to get in Python 3.8 beta 1. If anything goes wrong, we can fix it later ;-)
vstinner commentedon May 24, 2019
New changeset b1fc417 by Victor Stinner (E. M. Bray) in branch 'master':
bpo-21536: Fix configure.ac for LIBPYTHON on Android/Cygwin (GH-13552)
b1fc417
xdegaye commentedon May 24, 2019
FWIW I checked the Android build after those last changes.
vstinner commentedon May 24, 2019
Thank you! I was overconfident when I merged the Cygwin which looked good to me, whereas it broke Android :-( Hopefully it was quickly fixed. I hope that everything will be alright for the the beta1 to start from a good milestone!
embray commentedon May 27, 2019
Thanks everyone. And FWIW I agree the original change is positive overall, if a bit presumptuous about different linkers' behaviors :)
kpajko79 commentedon Sep 2, 2022
Just ran into this issue while cross-compiling python 3.9.2 for Android API 32 and managed to get the shared extensions working. Made only a few small modifications to the Makefile.
First added -Wl,-Bsymbolic to all shared libraries in the Android build as the Debian package has a patch to add this to the Linux build (actually -Wl,-Bsymbolic-functions) and i seemed like a good idea to copy that. Mainly because some time ago it was a de-facto standard to add this flag to every native library build [0]. Probably this is unrelated and not required [1].
Then found an interesting section in the man page of ld:
So rebuilt libpython3.9.so with -Wl,-z,global
And voila, it rocks! Virtually this marks the shared library to be treated as if it had been loaded with RTLD_GLOBAL, moving all its symbols to the global namespace.
The parameter just turns on a flag in the ELF header, so it could be possible to try its effect with an ELF editor much faster than recompiling.
[0] https://gcc.gcc.gnu.narkive.com/ceGm0WCb/android-the-reason-why-bsymbolic-is-turned-on-by-default
[1] https://www.technovelty.org/c/what-exactly-does-bsymblic-do.html
Add the libvaccel-python.so helper lib
Add the libvaccel-python.so helper lib
Add the libvaccel-python.so helper lib
Add the libvaccel-python.so helper lib
Add the libvaccel-python.so helper lib (#54)
generator: C extensions no longer linked with libpython