Fixing cross CPython3 modules in Void Linux, pt. 1
Context
Last week i have been working on getting a particularly complex beast to be cross-compilable under Void Linux's xbps-src: GObject Introspection.
While work was done on xbps-src cross compilation of CPython3 modules, 2 problems were found.
The first problem, which will be discussed and fixed in this topic, is that
modules cross-compiled used the ABI extension tag in their .so files.
Example: .cpython-36m-x86_64-linux-gnu.so
for x86_64.
That value is defined by the PEP 3149 and conveniently is available as the EXT_SUFFIX variable in the sysconfig module.
Examples for x86_64 and aarch64:
$ python3 >>> import sysconfig >>> sysconfig.get_config_var('EXT_SUFFIX') '.cpython-36m-x86_64-linux-gnu.so'
$ python3 >>> import sysconfig >>> sysconfig.get_config_var('EXT_SUFFIX') '.cpython-36m-aarch64-linux-gnu.so'
Problem
The problem occurs when cross compiling, the python3
used belongs to the build
system and not of the target system, consequently the EXT_SUFFIX used is the
build system one, not of the target one as it should be.
As an example, cross-compiling the python-yaml package with xbps-src will produce the binaries with the wrong name:
$ xbps-src -a aarch64 pkg python-yaml $ env XBPS_TARGET_ARCH=aarch64 xls python3-yaml | grep .cpython /usr/lib/python3.6/site-packages/_yaml.cpython-36m-x86_64-linux-gnu.so
See what's wrong ? A package compiled for aarch64 (ARM 64bits) has the prefix of x86_64. That's not right!
Let's push this further and actually try to load another package that uses CPython on aarch64, python-bluez!
$ python3 >>> import bluetooth Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/home/terran/usr/src/void-packages/masterdir/usr/aarch64-linux-gnu/usr/lib/python3.6/site-packages/bluetooth/__init__.py", line 45, in <module> from bluetooth.bluez import * File "/home/terran/usr/src/void-packages/masterdir/usr/aarch64-linux-gnu/usr/lib/python3.6/site-packages/bluetooth/bluez.py", line 10, in <module> import bluetooth._bluetooth as _bt ModuleNotFoundError: No module named 'bluetooth._bluetooth'
That is borked!, but do not despair, lets remove the EXT_SUFFIX.
$ mv -v usr/lib/python3.6/site-packages/bluetooth/_bluetooth{.cpython-36m-x86_64-linux-gnu,}.so
And let's try again!
$ python3 >>> import bluetooth >>>
Success! So our solution is simply to just remove the EXT_SUFFIX from all modules.
Solving
For this xbps-src has a very nifty mechanism, hooks.
Hooks are files with the .sh extension that provide a hook() function, depending on where the file is located it will be run during a specific stage of the package build process.
As an example: hooks in common/hooks/post-install will run after the do_install() function is ran, these hooks are available for all major stages of building a package, before (pre-<stage>) during (do-<stage>) and after (post-<stage>).
So let's just write a hook that does the renaming for us!
# This hook executes the following tasks: # - renames cpython binding files to not include the arch-specific extension suffix hook() { if [ ! -d ${PKGDESTDIR}/${py3_sitelib} ]; then return 0 fi find "${PKGDESTDIR}/${py3_sitelib}" -type f -executable -iname '*.cpython*.so' \ | while read -r file; do filename="${file##*/}" modulename="${filename%%.*}" msg_warn "${pkgver}: renamed '${filename}' to '${modulename}.so'.\n" mv ${file} ${file%/*}/${modulename}.so done }
Heh, looks good enough to me. Improvements can be made with a pull request to void-packages.
Let's try building our package again!
$ xbps-src -a aarch64 pkg python-yaml => WARNING: python3-yaml-3.13_2: renamed '_yaml.cpython-36m-x86_64-linux-gnu.so' to '_yaml.so'. $ env XBPS_TARGET_ARCH=aarch64 xls python3-yaml | grep '.so$' /usr/lib/python3.6/site-packages/_yaml.so
Nice! Our work here is done. Meet me up in pt. 2 for a similar story around another problem.