Re: [Python-Help] Unable to bootstrap Python 3 install
Dave Blanchard <[email protected]>
| Newsgroups | gmane.comp.python.devel |
|---|---|
| Message-ID | <[email protected]> |
Thanks for your reply Matt. Here's what's happening. This is a very old problem reported ages ago which has never been fixed. If I set the target arch to i686 (on an x86_64 build system) Python will cross-compile and bootstrap just fine. But if the host and build triple are the same, then the problem will occur. Python seems to be ASSuming that if the build and host triple match (in this case, both being 'x86_64-linux-gnu') therefore the host and build libraries are binary-compatible--which is NOT actually the case when one is cross-compiling to a different libc, for example. Actually it's kind of brain dead how this is implemented. Some prior discussions/years-old bug reports: https://bugs.python.org/issue39399 https://bugs.python.org/issue22724 https://bugs.gentoo.org/705970 In those links, various hacks are attempted with various degrees of success, but then Xavier de Gaye reworked the build system, apparently fixing the problem with this pull request in Dec. 2019: https://github.com/python/cpython/pull/17420 Unfortunately he became annoyed in the comments, seemingly mostly due to the lack of interest from Python to actually do anything about this problem, and cancelled his pull request. His fix was never implemented, and Python cross-compiling remains broken to this day. I downloaded his patches, made a minor fix or two, and merged them all together into the one patch attached to this email. When applied to both my build system and target Python, this problem seems to be resolved, for me at least. I'll know more later tonight as I get further into the distro build process. It's surprising to hear that cross-compiling Python would be any kind of "unusual" thing, considering this is something that *always* has to be done any time one is bootstrapping anything on a new or different system. It surprises me further to see that Python actually requires the *minor* version number to be the same for bootstrapping, also. So not only is Python 3 essentially a different language from Python 2, each point release is different and incompatible also. Amazing. I guess this shouldn't be surprising, after all of the other questionable design decisions this project has made over the years. I probably also shouldn't be surprised to see such an incredibly important bug going unfixed after all this time. It's Python--by far the #1 biggest annoyance and pain in the ass out of the 1,000+ packages on my distro, ranking just above CUPS and Texlive. Dave On Mon, 13 Jun 2022 16:12:26 -0500 (CDT) Matthew Dixon Cowles <[email protected]> wrote: > Dear Dave, > > > Hello, I'm trying to cross compile a new version of my Linux system > > with some upgraded packages, including a new Glibc. > > I've never had to do that and I am beginning to suspect, from the > lack of replies here better than this one, that nobody else here has > had to either. > > > I've hit a major snag with Python 3.7 (also tried 3.9 with same > > result) which makes it through the compile OK, but then bombs when > > running ensurepip at the end. > > If it were me, I'd set --with-ensurepip to no, declare victory, and > run ensurepip on the target machine. > > I haven't been able to find any very good evidence, but I wouldn't be > surprised if the option to turn ensurepip off is there to help out > with cross-compiling. For example, here it's being turned off for > compiling to web assembly: > > https://t.ly/_ZE3 > > (alternatively: > > https://github.com/python/cpython/commit/ > 9deb83468c56c7484645e6e3a6d0183cd6a0afd7 > > ) > > which looks to me a lot like what you're doing. > > What seems to be happening is that in Lib/esurepip/__init__.py is > calling run_module() in Lib/runpy.py and that's calling > _run_module_code() which is getting the new, but wrong libraries. > > I suspect that it's possible to hack that to do what you want, but as > far as a moderately close look tells me, it's not written with > cross-compiling in mind. If I had to do make it work, I'd break out > into the debugger and fiddle around on a mostly trial-and-error basis. > > Even then, I'd have a hacked version of ensurepip/__init__.py and/or > runpy.py, which I'd want to replace with the originals in the end. > > I'm pretty sure that running ensurepip on the target would be easier. > > If that's not useful to you, let us know what you think and I'll try > to think some more. > > Regards, > Matt > -- Dave Blanchard <[email protected]>
python-3.9.13-cross-compile-fix.patch
(application/octet-stream, 17.8 KB)
Patch created by Xavier de Gaye
--- ./configure.ac.orig 2022-05-17 06:12:56.000000000 -0500
+++ ./configure.ac 2022-06-13 17:24:43.097338878 -0500
@@ -83,5 +83,5 @@
fi
AC_MSG_RESULT($interp)
- PYTHON_FOR_BUILD='_PYTHON_PROJECT_BASE=$(abs_builddir) _PYTHON_HOST_PLATFORM=$(_PYTHON_HOST_PLATFORM) PYTHONPATH=$(shell test -f pybuilddir.txt && echo $(abs_builddir)/`cat pybuilddir.txt`:)$(srcdir)/Lib _PYTHON_SYSCONFIGDATA_NAME=_sysconfigdata_$(ABIFLAGS)_$(MACHDEP)_$(MULTIARCH) '$interp
+ PYTHON_FOR_BUILD='PYTHON_PROJECT_BASE=$(abs_builddir) '$interp
fi
elif test "$cross_compiling" = maybe; then
--- ./configure.orig 2022-05-17 06:12:56.000000000 -0500
+++ ./configure 2022-06-13 17:24:43.096338878 -0500
@@ -2992,5 +2992,5 @@
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $interp" >&5
$as_echo "$interp" >&6; }
- PYTHON_FOR_BUILD='_PYTHON_PROJECT_BASE=$(abs_builddir) _PYTHON_HOST_PLATFORM=$(_PYTHON_HOST_PLATFORM) PYTHONPATH=$(shell test -f pybuilddir.txt && echo $(abs_builddir)/`cat pybuilddir.txt`:)$(srcdir)/Lib _PYTHON_SYSCONFIGDATA_NAME=_sysconfigdata_$(ABIFLAGS)_$(MACHDEP)_$(MULTIARCH) '$interp
+ PYTHON_FOR_BUILD='PYTHON_PROJECT_BASE=$(abs_builddir) '$interp
fi
elif test "$cross_compiling" = maybe; then
--- ./Lib/distutils/command/build_ext.py.orig 2022-05-17 06:12:56.000000000 -0500
+++ ./Lib/distutils/command/build_ext.py 2022-06-13 17:24:43.093338878 -0500
@@ -238,5 +238,9 @@
else:
# building python standard extensions
- self.library_dirs.append('.')
+ if 'PYTHON_PROJECT_BASE' in os.environ:
+ self.library_dirs.append(os.path.realpath(
+ os.environ['PYTHON_PROJECT_BASE']))
+ else:
+ self.library_dirs.append('.')
# The argument parsing will result in self.define being a string, but
@@ -741,5 +745,5 @@
elif sys.platform == 'cygwin':
link_libpython = True
- elif '_PYTHON_HOST_PLATFORM' in os.environ:
+ elif 'PYTHON_PROJECT_BASE' in os.environ:
# We are cross-compiling for one of the relevant platforms
if get_config_var('ANDROID_API_LEVEL') != 0:
--- ./Lib/distutils/command/install.py.orig 2022-05-17 06:12:56.000000000 -0500
+++ ./Lib/distutils/command/install.py 2022-06-13 17:24:43.093338878 -0500
@@ -9,5 +9,5 @@
from distutils.core import Command
from distutils.debug import DEBUG
-from distutils.sysconfig import get_config_vars
+from distutils.sysconfig import get_config_vars, cross_compiling
from distutils.errors import DistutilsPlatformError
from distutils.file_util import write_file
@@ -282,10 +282,8 @@
py_version = sys.version.split()[0]
- (prefix, exec_prefix) = get_config_vars('prefix', 'exec_prefix')
- try:
- abiflags = sys.abiflags
- except AttributeError:
- # sys.abiflags may not be defined on all platforms.
- abiflags = ''
+ prefix, exec_prefix, abiflags = get_config_vars('prefix',
+ 'exec_prefix', 'ABIFLAGS')
+ # sys.abiflags may not be defined on all platforms.
+ abiflags = '' if abiflags is None else abiflags
self.config_vars = {'dist_name': self.distribution.get_name(),
'dist_version': self.distribution.get_version(),
@@ -420,6 +418,11 @@
"must not supply exec-prefix without prefix")
- self.prefix = os.path.normpath(sys.prefix)
- self.exec_prefix = os.path.normpath(sys.exec_prefix)
+ if cross_compiling:
+ prefix, exec_prefix = get_config_vars('prefix',
+ 'exec_prefix')
+ else:
+ prefix, exec_prefix = sys.prefix, sys.exec_prefix
+ self.prefix = os.path.normpath(prefix)
+ self.exec_prefix = os.path.normpath(exec_prefix)
else:
--- ./Lib/distutils/sysconfig.py.orig 2022-05-17 06:12:56.000000000 -0500
+++ ./Lib/distutils/sysconfig.py 2022-06-13 17:24:46.196339101 -0500
@@ -15,4 +15,5 @@
import sys
+from sysconfig import cross_compiling, get_project_base, get_build_time_vars
from .errors import DistutilsPlatformError
@@ -26,6 +27,11 @@
# live in project/PCbuild/win32 or project/PCbuild/amd64.
# set for cross builds
-if "_PYTHON_PROJECT_BASE" in os.environ:
- project_base = os.path.abspath(os.environ["_PYTHON_PROJECT_BASE"])
+if cross_compiling:
+ project_base = get_project_base()
+ build_time_vars = get_build_time_vars()
+ PREFIX = build_time_vars['prefix']
+ BASE_PREFIX = PREFIX
+ EXEC_PREFIX = build_time_vars['exec_prefix']
+ BASE_EXEC_PREFIX = EXEC_PREFIX
else:
if sys.executable:
@@ -46,5 +52,5 @@
return False
-_sys_home = getattr(sys, '_home', None)
+_sys_home = getattr(sys, '_home', None) if not cross_compiling else None
if os.name == 'nt':
@@ -64,4 +70,7 @@
python_build = _python_build()
+if cross_compiling and not python_build:
+ raise RuntimeError('PYTHON_PROJECT_BASE is not a build directory')
+
# Calculate the build qualifier flags if they are defined. Adding the flags
@@ -263,6 +272,8 @@
lib_dir = get_python_lib(plat_specific=0, standard_lib=1)
config_file = 'config-{}{}'.format(get_python_version(), build_flags)
- if hasattr(sys.implementation, '_multiarch'):
- config_file += '-%s' % sys.implementation._multiarch
+ multiarch = (get_config_var('MULTIARCH') if cross_compiling else
+ getattr(sys.implementation, '_multiarch', ''))
+ if multiarch:
+ config_file += '-%s' % multiarch
return os.path.join(lib_dir, config_file, 'Makefile')
@@ -438,13 +449,5 @@
def _init_posix():
"""Initialize the module as appropriate for POSIX systems."""
- # _sysconfigdata is generated at build time, see the sysconfig module
- name = os.environ.get('_PYTHON_SYSCONFIGDATA_NAME',
- '_sysconfigdata_{abi}_{platform}_{multiarch}'.format(
- abi=sys.abiflags,
- platform=sys.platform,
- multiarch=getattr(sys.implementation, '_multiarch', ''),
- ))
- _temp = __import__(name, globals(), locals(), ['build_time_vars'], 0)
- build_time_vars = _temp.build_time_vars
+ build_time_vars = get_build_time_vars()
global _config_vars
_config_vars = {}
--- ./Lib/distutils/util.py.orig 2022-05-17 06:12:56.000000000 -0500
+++ ./Lib/distutils/util.py 2022-06-13 17:24:43.093338878 -0500
@@ -15,4 +15,5 @@
from distutils import log
from distutils.errors import DistutilsByteCompileError
+from distutils.sysconfig import cross_compiling, get_config_var
def get_host_platform():
@@ -46,6 +47,6 @@
# Set for cross builds explicitly
- if "_PYTHON_HOST_PLATFORM" in os.environ:
- return os.environ["_PYTHON_HOST_PLATFORM"]
+ if cross_compiling:
+ return get_config_var('PYTHON_HOST_PLATFORM')
if os.name != "posix" or not hasattr(os, 'uname'):
--- ./Lib/sysconfig.py.orig 2022-05-17 06:12:56.000000000 -0500
+++ ./Lib/sysconfig.py 2022-06-13 17:24:49.845339363 -0500
@@ -118,7 +118,18 @@
_PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir, pardir))
+cross_compiling = False
# set for cross builds
-if "_PYTHON_PROJECT_BASE" in os.environ:
- _PROJECT_BASE = _safe_realpath(os.environ["_PYTHON_PROJECT_BASE"])
+if "PYTHON_PROJECT_BASE" in os.environ:
+ cross_compiling = True
+ _PROJECT_BASE = _safe_realpath(os.environ["PYTHON_PROJECT_BASE"])
+
+ # Not used when cross compiling.
+ _PREFIX = None
+ _BASE_PREFIX = None
+ _EXEC_PREFIX = None
+ _BASE_EXEC_PREFIX = None
+
+def get_project_base():
+ return _PROJECT_BASE
def _is_python_source_dir(d):
@@ -128,5 +139,36 @@
return False
-_sys_home = getattr(sys, '_home', None)
+_PYTHON_CONFIG = None
+def _get_python_config(name):
+ """Return the value of a python configuration variable."""
+
+ assert cross_compiling
+ global _PYTHON_CONFIG
+ if _PYTHON_CONFIG is None:
+ # The import would fail when building a native interpreter since,
+ # at the time generate-posix-vars is run, the _posixsubprocess
+ # module has not been built yet. This does not happen when
+ # generate-posix-vars is run during cross-compilation as the
+ # native interpreter being used is a full-fledged interpreter.
+ import subprocess
+
+ python_config = os.path.join(_PROJECT_BASE, 'python-config')
+ vars_ = ['version', 'abiflags', 'machdep', 'multiarch']
+ args = ['/bin/sh', python_config]
+ args.extend('--' + v for v in vars_)
+ output = subprocess.check_output(args, universal_newlines=True)
+ _PYTHON_CONFIG = dict(zip(vars_, output.split('\n')))
+ assert len(_PYTHON_CONFIG) == len(vars_)
+
+ # The specification of the sysconfigdata file name may differ
+ # across versions, so forbid Python versions mismatch.
+ sys_version = '%d.%d' % sys.version_info[:2]
+ if _PYTHON_CONFIG['version'] != sys_version:
+ raise RuntimeError('the running python version (%s) does '
+ 'not match the cross-compiled version (%s)' %
+ (sys_version, _PYTHON_CONFIG['version']))
+ return _PYTHON_CONFIG.get(name)
+
+_sys_home = getattr(sys, '_home', None) if not cross_compiling else None
if os.name == 'nt':
@@ -150,4 +192,6 @@
_INSTALL_SCHEMES[scheme]['include'] = '{srcdir}/Include'
_INSTALL_SCHEMES[scheme]['platinclude'] = '{projectbase}/.'
+elif cross_compiling:
+ raise RuntimeError('PYTHON_PROJECT_BASE is not a build directory')
@@ -353,11 +397,17 @@
def _get_sysconfigdata_name():
- return os.environ.get('_PYTHON_SYSCONFIGDATA_NAME',
- '_sysconfigdata_{abi}_{platform}_{multiarch}'.format(
- abi=sys.abiflags,
- platform=sys.platform,
- multiarch=getattr(sys.implementation, '_multiarch', ''),
- ))
-
+ if cross_compiling:
+ abiflags = _get_python_config('abiflags')
+ platform = _get_python_config('machdep')
+ multiarch = _get_python_config('multiarch')
+ else:
+ abiflags = sys.abiflags
+ platform = sys.platform
+ multiarch = getattr(sys.implementation, '_multiarch', '')
+
+ sysconf_name = '_sysconfigdata_%s_%s' % (abiflags, platform)
+ if multiarch:
+ sysconf_name = '%s_%s' % (sysconf_name, multiarch)
+ return sysconf_name
def _generate_posix_vars():
@@ -401,6 +451,7 @@
# This is more than sufficient for ensuring the subsequent call to
# get_platform() succeeds.
+ # The same situation exists when cross compiling.
name = _get_sysconfigdata_name()
- if 'darwin' in sys.platform:
+ if 'darwin' in sys.platform or cross_compiling:
import types
module = types.ModuleType(name)
@@ -409,5 +460,6 @@
pybuilddir = 'build/lib.%s-%s' % (get_platform(), _PY_VERSION_SHORT)
- if hasattr(sys, "gettotalrefcount"):
+ if (cross_compiling and 'd' in vars['ABIFLAGS'] or
+ (not cross_compiling and hasattr(sys, "gettotalrefcount"))):
pybuilddir += '-pydebug'
os.makedirs(pybuilddir, exist_ok=True)
@@ -424,10 +476,37 @@
f.write(pybuilddir)
+def _get_module_attr(module, attribute):
+ _temp = __import__(module, globals(), locals(), [attribute], 0)
+ return getattr(_temp, attribute)
+
+_BUILD_TIME_VARS = None
+def get_build_time_vars():
+ global _BUILD_TIME_VARS
+ if _BUILD_TIME_VARS is None:
+ # _sysconfigdata is generated at build time, see _generate_posix_vars()
+ sysconfigdata = _get_sysconfigdata_name()
+ if cross_compiling:
+ if _is_python_source_dir(_PROJECT_BASE):
+ bdir = os.path.join(_PROJECT_BASE, 'pybuilddir.txt')
+ with open(bdir, encoding='ascii') as f:
+ libdir = f.read().strip()
+ libdir = os.path.join(_PROJECT_BASE, libdir)
+ else:
+ libdir = os.path.join(_PROJECT_BASE,
+ 'lib', 'python%s' % _get_python_config('version'))
+ sys.path.insert(0, libdir)
+ try:
+ _BUILD_TIME_VARS = _get_module_attr(sysconfigdata,
+ 'build_time_vars')
+ finally:
+ sys.path.pop(0)
+ else:
+ _BUILD_TIME_VARS = _get_module_attr(sysconfigdata,
+ 'build_time_vars')
+ return _BUILD_TIME_VARS
+
def _init_posix(vars):
"""Initialize the module as appropriate for POSIX systems."""
- # _sysconfigdata is generated at build time, see _generate_posix_vars()
- name = _get_sysconfigdata_name()
- _temp = __import__(name, globals(), locals(), ['build_time_vars'], 0)
- build_time_vars = _temp.build_time_vars
+ build_time_vars = get_build_time_vars()
vars.update(build_time_vars)
@@ -637,4 +716,7 @@
"""
+ if cross_compiling:
+ return get_config_var('PYTHON_HOST_PLATFORM')
+
if os.name == 'nt':
if 'amd64' in sys.version.lower():
@@ -650,8 +732,4 @@
return sys.platform
- # Set for cross builds explicitly
- if "_PYTHON_HOST_PLATFORM" in os.environ:
- return os.environ["_PYTHON_HOST_PLATFORM"]
-
# Try to distinguish various flavours of Unix
osname, host, release, version, machine = os.uname()
--- ./Makefile.pre.in.orig 2022-05-17 06:12:56.000000000 -0500
+++ ./Makefile.pre.in 2022-06-13 17:24:44.562338984 -0500
@@ -257,5 +257,7 @@
UPDATE_FILE=@PYTHON_FOR_REGEN@ $(srcdir)/Tools/scripts/update_file.py
PYTHON_FOR_BUILD=@PYTHON_FOR_BUILD@
-_PYTHON_HOST_PLATFORM=@_PYTHON_HOST_PLATFORM@
+# To enable setup.py and sysconfig to pick up this AC_SUBST() var.
+PYTHON_HOST_PLATFORM=@_PYTHON_HOST_PLATFORM@
+
BUILD_GNU_TYPE= @build@
HOST_GNU_TYPE= @host@
@@ -475,5 +477,5 @@
all: @DEF_MAKE_ALL_RULE@
build_all: check-clean-src $(BUILDPYTHON) oldsharedmods sharedmods gdbhooks \
- Programs/_testembed python-config
+ Programs/_testembed
# Check that the source is clean when building out of source.
@@ -602,5 +604,7 @@
# initialization to succeed. It will be overwritten by generate-posix-vars
# or removed in case of failure.
-pybuilddir.txt: $(BUILDPYTHON)
+# python-config is a prerequisite as it is used when generating the posix
+# variables if cross-compiling.
+pybuilddir.txt: python-config $(BUILDPYTHON)
@echo "none" > ./pybuilddir.txt
$(RUNSHARED) $(PYTHON_FOR_BUILD) -S -m sysconfig --generate-posix-vars ;\
@@ -1543,6 +1547,10 @@
done; \
done
- $(INSTALL_DATA) `cat pybuilddir.txt`/_sysconfigdata_$(ABIFLAGS)_$(MACHDEP)_$(MULTIARCH).py \
- $(DESTDIR)$(LIBDEST); \
+ sysconf_name=_sysconfigdata_$(ABIFLAGS)_$(MACHDEP); \
+ if test -n "$(MULTIARCH)"; then \
+ sysconf_name=$${sysconf_name}_$(MULTIARCH); \
+ fi; \
+ $(INSTALL_DATA) `cat pybuilddir.txt`/$$sysconf_name.py \
+ $(DESTDIR)$(LIBDEST)
$(INSTALL_DATA) $(srcdir)/LICENSE $(DESTDIR)$(LIBDEST)/LICENSE.txt
if test -d $(DESTDIR)$(LIBDEST)/distutils/tests; then \
@@ -1699,5 +1707,9 @@
--install-platlib=$(DESTSHARED) \
--root=$(DESTDIR)/
- -rm $(DESTDIR)$(DESTSHARED)/_sysconfigdata_$(ABIFLAGS)_$(MACHDEP)_$(MULTIARCH).py
+ -sysconf_name=_sysconfigdata_$(ABIFLAGS)_$(MACHDEP); \
+ if test -n "$(MULTIARCH)"; then \
+ sysconf_name=$${sysconf_name}_$(MULTIARCH); \
+ fi; \
+ rm $(DESTDIR)$(DESTSHARED)/$$sysconf_name.py
-rm -r $(DESTDIR)$(DESTSHARED)/__pycache__
--- ./Misc/python-config.sh.in.orig 2022-05-17 06:12:56.000000000 -0500
+++ ./Misc/python-config.sh.in 2022-06-13 17:24:43.094338878 -0500
@@ -5,5 +5,7 @@
exit_with_usage ()
{
- echo "Usage: $0 --prefix|--exec-prefix|--includes|--libs|--cflags|--ldflags|--extension-suffix|--help|--abiflags|--configdir|--embed"
+ echo "Usage: $0 --prefix|--exec-prefix|--includes|--libs|--cflags|\
+ --ldflags|--extension-suffix|--help|--abiflags|--configdir|--embed|\
+ --version|--machdep|--multiarch"
exit $1
}
@@ -67,5 +69,7 @@
PY_EMBED=1
;;
- --prefix|--exec-prefix|--includes|--libs|--cflags|--ldflags|--extension-suffix|--abiflags|--configdir)
+ --prefix|--exec-prefix|--includes|--libs|--cflags|--ldflags|\
+ --extension-suffix|--abiflags|--configdir|\
+ --version|--machdep|--multiarch)
;;
*)
@@ -113,4 +117,13 @@
echo "$LIBPL"
;;
+ --version)
+ echo "$VERSION"
+ ;;
+ --machdep)
+ echo "@MACHDEP@"
+ ;;
+ --multiarch)
+ echo "@MULTIARCH@"
+ ;;
esac
done
--- ./setup.py.orig 2022-05-17 06:12:56.000000000 -0500
+++ ./setup.py 2022-06-13 17:24:43.097338878 -0500
@@ -31,4 +31,5 @@
+from sysconfig import cross_compiling as CROSS_COMPILING
from distutils import log
from distutils.command.build_ext import build_ext
@@ -49,7 +50,6 @@
def get_platform():
- # Cross compiling
- if "_PYTHON_HOST_PLATFORM" in os.environ:
- return os.environ["_PYTHON_HOST_PLATFORM"]
+ if CROSS_COMPILING:
+ return sysconfig.get_config_var('PYTHON_HOST_PLATFORM')
# Get value of sys.platform
@@ -59,5 +59,4 @@
-CROSS_COMPILING = ("_PYTHON_HOST_PLATFORM" in os.environ)
HOST_PLATFORM = get_platform()
MS_WINDOWS = (HOST_PLATFORM == 'win32')
--- /dev/null 2022-06-07 13:19:00.445169466 -0500
+++ ./Misc/NEWS.d/next/Build/2019-11-30-21-53-38.bpo-28833.14IeXH.rst 2022-06-13 17:28:23.273354712 -0500
@@ -0,0 +1,11 @@
+Fix cross-compilation of third-party extension modules. The
+``PYTHON_PROJECT_BASE`` environment variable is the path to the directory
+where Python has been cross-compiled. It is used by the native python
+interpreter to find the target ``sysconfigdata`` module. For example the
+following command builds a wheel file to be transfered and installed with
+pip on the target platform, provided the native python interpreter and the
+cross-compiled one both have the wheel package installed:
+
+.. code-block:: shell
+
+ $ PYTHON_PROJECT_BASE=/path/to/builddir python setup.py bdist_wheel