You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

crossenv

Package Overview
Dependencies
Maintainers
1
Versions
19
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

crossenv - pypi Package Compare versions

Comparing version
1.4.0
to
1.5.0
+21
crossenv/scripts/importlib-metadata-patch.py.tmpl
@property
def _Context_path(self):
path = vars(self).get('path')
if path is not None:
return path
import sysconfig
import sys
stdlib = sysconfig.get_path('stdlib')
path = list(sys.path)
try:
i = path.index(stdlib)
path[i:i] = sys.build_path
except ValueError:
pass
return path
# This will apply to all created instances of Context(), so we don't need to
# patch the default argument to any find_distribution() functions out there.
DistributionFinder.Context.path = _Context_path
# By default we disable manylinux/manymusl tags. However, we allow users to opt
# in.
def _linux_platforms():
yield from {{repr(self.platform_tags)}}
arch = _normalize_string({{repr(self.host_machine)}})
archs = {"armv8l": ["armv8l", "armv7l"]}.get(arch, [arch])
yield from archs
##########################
# Basic download/compile
#########################
from textwrap import dedent
import os
import copy
import zipfile
import pytest
from .testutils import make_crossenv
def test_build_simple(tmp_path, host_python, build_python, get_resource):
# It's a huge PITA to do out-of-source with setuptools, so we'll just
# make a copy.
source = get_resource('hello-module:source')
build = source.make_copy()
# Take care to prevent creation of a .pth file; we don't want to have to mess
# with sitecustomize.py stuff to make this work.
crossenv = make_crossenv(tmp_path, host_python, build_python)
crossenv.check_call(['python', 'setup.py', 'install',
'--single-version-externally-managed',
'--root', build.path,
'--install-lib', '.'], cwd=build.path)
host_python.setenv('PYTHONPATH', str(build.path) + ':$PYTHONPATH')
host_python.check_call([host_python.binary, '-c', dedent('''\
import hello
assert hello.hello() == 'Hello, world'
''')])
def test_wheel_simple(tmp_path, host_python, build_python, get_resource):
source = get_resource('hello-module:source')
build = source.make_copy()
crossenv = make_crossenv(tmp_path, host_python, build_python)
crossenv.check_call(['pip', 'install', 'wheel'])
crossenv.check_call(['python', 'setup.py', 'bdist_wheel'], cwd=build.path)
mods = build.path / 'mods'
for whl in build.path.glob('dist/*.whl'):
with zipfile.ZipFile(whl) as zp:
zp.extractall(mods)
host_python.setenv('PYTHONPATH', str(mods) + ':$PYTHONPATH')
host_python.check_call([host_python.binary, '-c', dedent('''\
import hello
assert hello.hello() == 'Hello, world'
''')])
def test_pip_install_numpy(tmp_path, host_python, build_python, python_version):
crossenv = make_crossenv(tmp_path, host_python, build_python)
# Numpy is far too clever, and if it detects that any linear algebra
# libraries are available on the build system, then it will happily try to
# include them in the host build. Disable them so we have a consistent
# environment for our tests.
crossenv.setenv('BLAS', 'None')
crossenv.setenv('LAPACK', 'None')
crossenv.setenv('ATLAS', 'None')
if python_version == 'main':
# Not sure whose fault this sort of thing is.
pytest.xfail("Known broken against master branch")
crossenv.check_call(['cross-pip', '--no-cache-dir', 'install',
'numpy==1.18.1', 'pytest==5.3.5'])
# Run some tests under emulation. We don't do the full numpy test suite
# because 1) it's very slow, and 2) there are some failing tests.
# The failing tests might be an issue with numpy on the given archtecture,
# or with qemu, or who knows, but in any case, it's really beyond the scope
# of this project to address. We'll choose a quick, but nontrivial set of
# tests to run.
host_python.setenv('PYTHONPATH',
str(crossenv.cross_site_packages) + ':$PYTHONPATH')
host_python.check_call([host_python.binary, '-c', dedent('''\
import sys, numpy
ok = numpy.test(tests=['numpy.polynomial'])
sys.exit(ok != True)
''')])
def test_pip_install_bcrypt(tmp_path, host_python, build_python):
crossenv = make_crossenv(tmp_path, host_python, build_python)
crossenv.check_call(['build-pip', '--no-cache-dir', 'install', 'cffi'])
crossenv.check_call(['cross-pip', '--no-cache-dir', 'install', 'bcrypt~=3.1.0'])
# From the bcrypt test suites
host_python.setenv('PYTHONPATH',
str(crossenv.cross_site_packages) + ':$PYTHONPATH')
output = host_python.check_output([host_python.binary, '-c', dedent('''
import bcrypt, sys
pw = b"Kk4DQuMMfZL9o"
salt = b"$2b$04$cVWp4XaNU8a4v1uMRum2SO"
print(bcrypt.hashpw(pw, salt).decode('ascii'))
''')])
output = output.strip()
expected = b"$2b$04$cVWp4XaNU8a4v1uMRum2SO026BWLIoQMD/TXg5uZV.0P.uO8m3YEm"
assert output == expected
def test_build_pyproject_cffi(tmp_path, host_python, build_python):
# Adapted from https://github.com/benfogle/crossenv/issues/108
crossenv = make_crossenv(tmp_path, host_python, build_python)
proj = tmp_path / "myproj"
proj.mkdir()
with open(proj / "dummy.py", "w"):
pass
with open(proj / "pyproject.toml", "w") as fp:
fp.write(dedent("""
[build-system]
requires = ["setuptools", "cffi"]
"""))
crossenv.check_call(['cross-pip', '--no-cache-dir', 'install', '-U',
'pip==23.2.1', 'setuptools==68.0.0', 'wheel==0.41.1', 'build==0.10.0'])
crossenv.check_call(['build-pip', '--no-cache-dir', 'install', '-U',
'pip==23.2.1', 'setuptools==68.0.0', 'wheel==0.41.1', 'build==0.10.0'])
crossenv.check_call(['build-pip', '--no-cache-dir', 'install', 'cffi==1.15.1'])
crossenv.check_call(['cross-expose', 'cffi'])
crossenv.check_call(['cross-python', '-m', 'build', '--no-isolation'],
cwd=proj)
########################################
# Test options that alter the compiler
########################################
from textwrap import dedent
import re
import platform
from .testutils import make_crossenv
def test_set_c_compiler(tmp_path, host_python, build_python):
crossenv = make_crossenv(tmp_path, host_python, build_python,
'--cc=/bin/true')
compiler = crossenv.check_output(['python', '-c', dedent('''\
import sysconfig
print(sysconfig.get_config_var("CC"))
''')])
compiler = compiler.split()[0]
assert compiler == b'/bin/true'
def test_set_cxx_compiler(tmp_path, host_python, build_python):
crossenv = make_crossenv(tmp_path, host_python, build_python,
'--cxx=/bin/true')
compiler = crossenv.check_output(['python', '-c', dedent('''\
import sysconfig
print(sysconfig.get_config_var("CXX"))
''')])
compiler = compiler.split()[0]
assert compiler == b'/bin/true'
def test_set_ar(tmp_path, host_python, build_python):
crossenv = make_crossenv(tmp_path, host_python, build_python,
'--ar=/bin/true')
compiler = crossenv.check_output(['python', '-c', dedent('''\
import sysconfig
print(sysconfig.get_config_var("AR"))
''')])
compiler = compiler.split()[0]
assert compiler == b'/bin/true'
def test_wrong_architecture(tmp_path, host_python, build_python,
architecture):
"""Make sure we get a warning if the compiler doesn't seem right. Requires
gcc."""
# N/A when the host and build systems share the same architecture.
if architecture.machine == platform.machine():
return
crossenv = make_crossenv(tmp_path, host_python, build_python,
'--cc=/usr/bin/gcc')
for line in crossenv.creation_log.splitlines():
if re.match(r'WARNING:.*architecture', line):
return
assert False, "Crossenv did not detect wrong architecture"
import os
import re
from textwrap import dedent
from .testutils import make_crossenv
def test_uname(crossenv, architecture):
# We don't test all of uname. We currently have no values for release or
# version, and we don't really care about node.
out = crossenv.check_output(['python', '-c', dedent('''\
import os
print(os.uname().sysname, os.uname().machine)
''')],
universal_newlines=True)
out = out.strip()
expected = '{} {}'.format(architecture.system, architecture.machine)
assert out == expected
def test_platform(crossenv, architecture):
# Since uname isn't 100%, platform.platform() still looks a bit strange.
# Test platform.uname() components
#
# Also: don't run 'python -m platform'. The way this works, a __main__
# module is created and populated with code from the system library
# platform module. This __main__ module is completely separate from what
# you get from 'import platform', so none of our patches apply to it!
# There's no good way around that that I can think of.
out = crossenv.check_output(['python', '-c', dedent('''\
import platform
print(platform.uname().system,
platform.uname().machine,
platform.uname().processor)
''')],
universal_newlines=True)
out = out.strip()
expected = '{0} {1} {1}'.format(architecture.system, architecture.machine)
assert out == expected
def test_sysconfig_platform(crossenv, architecture):
out = crossenv.check_output(['python', '-c', dedent('''\
import sysconfig
print(sysconfig.get_platform())
''')],
universal_newlines=True)
out = out.strip()
expected = '{}-{}'.format(architecture.system, architecture.machine)
expected = expected.lower()
assert out == expected
def test_no_manylinux(crossenv, architecture):
crossenv.check_call(['pip', 'install', 'packaging'])
out = crossenv.check_output(['python', '-c', dedent('''\
from packaging.tags import compatible_tags
platforms = set(tag.platform for tag in compatible_tags())
print('\\n'.join(platforms))
''')],
universal_newlines=True)
out = out.strip()
assert 'manylinux' not in out
def test_explicit_platform_tags(tmp_path, host_python, build_python, architecture):
crossenv = make_crossenv(
tmp_path,
host_python,
build_python,
'--platform-tag=foobar1234',
'--platform-tag=mytag',
)
crossenv.check_call(['pip', 'install', 'packaging'])
out = crossenv.check_output(['python', '-c', dedent('''\
from packaging.tags import compatible_tags
platforms = set(tag.platform for tag in compatible_tags())
print('\\n'.join(platforms))
''')],
universal_newlines=True)
out = out.strip()
assert 'foobar1234' in out
assert 'mytag' in out
def test_explicit_manylinux(tmp_path, host_python, build_python, architecture):
# not defined for all architectures, so pass them
if architecture.machine not in ('x86_64', 'aarch64'):
return
crossenv = make_crossenv(tmp_path, host_python, build_python,
'--manylinux=manylinux2014')
crossenv.check_call(['pip', 'install', 'packaging'])
out = crossenv.check_output(['python', '-c', dedent('''\
from packaging.tags import compatible_tags
platforms = set(tag.platform for tag in compatible_tags())
print('\\n'.join(platforms))
''')],
universal_newlines=True)
out = out.strip()
assert 'manylinux2014' in out
assert 'manylinux_2_17' in out
def test_very_long_paths(tmp_path_factory, host_python, build_python):
tmp = tmp_path_factory.mktemp('A'*128)
dirname = tmp / ('B'*128)
os.mkdir(dirname)
assert len(str(dirname)) >= 256
crossenv = make_crossenv(dirname, host_python, build_python)
crossenv.check_call(['python', '--version'])
def test_very_long_paths(tmp_path_factory, host_python, build_python):
tmp = tmp_path_factory.mktemp('A'*128)
dirname = tmp / ('B'*128)
os.mkdir(dirname)
assert len(str(dirname)) >= 256
crossenv = make_crossenv(dirname, host_python, build_python)
crossenv.check_call(['python', '--version'])
def test_environment_leak(crossenv):
# a regression test that used to cause scary warnings during build
# processes. Triggered with subprocess.Popen with explicit environ
out = crossenv.check_output(['python', '-c', dedent('''\
import subprocess
import sys
import os
env = os.environ.copy()
python = sys.executable
result = subprocess.run([python, '-c', 'print("ok")'], env=env)
sys.exit(result.returncode)
''')],
universal_newlines=True)
assert 'Crossenv has leaked' not in out
def test_run_sysconfig_module(crossenv):
# a regression test that 'python -m sysconfig' works as well as 'import
# sysconfig'
out = crossenv.check_output(['python', '-m', 'sysconfig'],
universal_newlines=True)
m = re.search(r'^\s*DESTDIRS = "(.*)"$', out, re.M)
assert m is not None
destdirs_cmdline = m.group(1)
out = crossenv.check_output(['python', '-c', dedent('''\
import sysconfig
print(sysconfig.get_config_var('DESTDIRS'))
''')],
universal_newlines=True)
out = out.strip()
assert destdirs_cmdline == out
def test_cross_expose(crossenv):
out = crossenv.check_output(['pip', 'freeze'])
assert b'colorama' not in out
crossenv.check_call(['build-pip', 'install', 'colorama'])
out = crossenv.check_output(['pip', 'freeze'])
assert b'colorama' not in out
crossenv.check_call(['cross-expose', 'colorama'])
out = crossenv.check_output(['pip', 'freeze'])
assert b'colorama' in out
out = crossenv.check_output(['cross-expose', '--list'])
assert b'colorama' in out
crossenv.check_call(['cross-expose', '-u', 'colorama'])
out = crossenv.check_output(['pip', 'freeze'])
assert b'colorama' not in out
out = crossenv.check_output(['cross-expose', '--list'])
assert b'colorama' not in out
def test_machine_override(tmp_path, host_python, build_python):
crossenv = make_crossenv(tmp_path, host_python, build_python,
'--machine=foobar')
out = crossenv.check_output(['python', '-c', dedent('''\
import os, platform
print(os.uname().machine, platform.machine())
''')],
universal_newlines=True)
out = out.strip()
assert out == 'foobar foobar'
#######################################################################
# These are tests to make sure that our prebuilt files are working
# correctly.
#######################################################################
from textwrap import dedent
import os
import subprocess
import pytest
def test_build_python_runs(build_python):
build_python.check_call([build_python.binary, '--version'])
def test_host_python_emulates(host_python):
host_python.check_call([host_python.binary, '--version'])
def test_cross_compiler_runs(build_python, host_python):
cc = host_python.check_output([host_python.binary, '-c', dedent('''\
import sysconfig
print(sysconfig.get_config_var("CC"))
''')],
universal_newlines=True)
# Build-python should come with the correct path to the cross compiler
# could be a whole shell command in there, so run with shell=True
cmdline = cc.strip() + ' --version'
build_python.check_call(cmdline, shell=True)
########################################
# Test general usage
########################################
import subprocess
import pytest
from .testutils import make_crossenv
def test_no_pip(tmp_path, host_python, build_python):
crossenv = make_crossenv(tmp_path, host_python, build_python,
'--without-pip')
# pip and pip3 could be in the user PATH, so call exactly the one we
# expect
pip_variants = [
'pip',
'pip3',
'cross-pip',
'cross-pip3',
'build-pip',
'build-pip3',
]
bin_variants = [
crossenv.bindir,
crossenv.cross_bindir,
crossenv.build_bindir,
]
for bindir in bin_variants:
for pip in pip_variants:
pip = bindir / pip
with pytest.raises(FileNotFoundError):
crossenv.check_call([pip, '--version'])
python_variants = [
'python',
'python3',
'cross-python',
'cross-python3',
'build-python',
'build-python3',
]
for python in python_variants:
result = crossenv.run(
[python, '-m', 'pip', '--version'],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
universal_newlines=True)
assert result.returncode != 0, \
"'%s -m pip' shouldn't succeed" % python
assert 'no module named pip' in result.stdout.lower()
def test_no_cross_pip(tmp_path, host_python, build_python):
crossenv = make_crossenv(tmp_path, host_python, build_python,
'--without-cross-pip')
# pip and pip3 could be in the user PATH, so call exactly the one we
# expect
pip_variants = [
'pip',
'pip3',
'cross-pip',
'cross-pip3',
]
bin_variants = [
crossenv.bindir,
crossenv.cross_bindir,
]
for bindir in bin_variants:
for pip in pip_variants:
pip = bindir / pip
with pytest.raises(FileNotFoundError):
crossenv.check_call([pip, '--version'])
# cross-python -m pip will still work, because cross-python
# can import build-python's modules.
def test_cross_prefix(tmp_path, host_python, build_python):
env = tmp_path / 'cross'
prefix = tmp_path / 'this_is_a_test'
crossenv = make_crossenv(env, host_python, build_python,
'--without-pip', '--cross-prefix={}'.format(prefix))
cross_python = prefix / 'bin' / 'python'
assert cross_python.is_file()
activate = env / 'bin' / 'activate'
out = crossenv.check_output(
['bash', '-c', '. {}; echo $PS1'.format(activate)],
universal_newlines=True)
assert '(this_is_a_test)' in out
import os
import hashlib
import subprocess
import string
import fcntl
from contextlib import contextmanager
def hash_file(path):
ctx = hashlib.sha256()
with open(path, 'rb') as fp:
data = fp.read(0x4000)
while data:
ctx.update(data)
data = fp.read(0x4000)
return ctx.hexdigest()
class ExecEnvironment:
'''Mostly some wrappers around popen'''
def __init__(self):
# prepopulate the environment
self.environ = {
'PATH': os.environ.get('PATH', ''),
}
self.cwd = None
def expand_environ(self, value):
# os.path.expandvars exists, but doesn't operate on an arbitrary
# environment. We might clobber changes to $PATH, etc. if we use
# it.
class EnvDict:
'''trick Template.substitute into converting $NOTFOUND into '''
def __init__(self, src):
self.src = src
def __getitem__(self, key):
return self.src.get(key, '')
if value is None:
return value
value = str(value)
return string.Template(value).substitute(EnvDict(self.environ))
def setenv(self, name, value):
if value is None:
self.environ.pop(name, None)
else:
value = self.expand_environ(value)
self.environ[name] = value
def _alter_env(self, updated, original):
env = original.copy()
# Calculate all new values without updating
new_env = {}
for name, value in updated.items():
if value is not None:
value = self.expand_environ(value)
new_env[name] = value
# Update new values, remove as necessary
for name, value in new_env.items():
if value is None and name in env:
del env[name]
else:
env[name] = value
return env
def _popen(self, func, *args, **kwargs):
if self.environ:
env = kwargs.get('env', os.environ)
env = self._alter_env(self.environ, env)
kwargs['env'] = env
if self.cwd and 'cwd' not in kwargs:
kwargs['cwd'] = self.cwd
return func(*args, **kwargs)
def run(self, *args, **kwargs):
return self._popen(subprocess.run, *args, **kwargs)
def popen(self, *args, **kwargs):
return self._popen(subprocess.Popen, *args, **kwargs)
def check_call(self, *args, **kwargs):
return self._popen(subprocess.check_call, *args, **kwargs)
def check_output(self, *args, **kwargs):
return self._popen(subprocess.check_output, *args, **kwargs)
class CrossenvEnvironment(ExecEnvironment):
def __init__(self, build_python, crossenv_dir, creation_log=''):
super().__init__()
self.creation_log = creation_log
self.environ = build_python.environ.copy()
self.cwd = build_python.cwd
self.crossenv_dir = crossenv_dir
self.bindir = crossenv_dir / 'bin'
site = sorted(crossenv_dir.glob('build/lib/python*/site-packages'))[0]
self.build_bindir = crossenv_dir / 'build/bin'
self.build_site_packages = site
sites = crossenv_dir.glob('cross/lib/python*/site-packages')
sites = sorted(sites)
if sites:
self.cross_site_packages = sites[0]
self.cross_bindir = crossenv_dir / 'cross/bin'
else:
self.cross_site_packages = None
self.cross_bindir = None
# Mimic some of what crossenv_dir/bin/activate would do
self.setenv('PATH', '{}:{}:$PATH'.format(self.bindir,
self.cross_bindir))
def make_crossenv(crossenv_dir, host_python, build_python, *args, **kwargs):
cmdline = [ build_python.binary, '-m', 'crossenv', host_python.binary,
crossenv_dir ]
cmdline.extend(args)
result = build_python.run(cmdline,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, universal_newlines=True,
**kwargs)
if result.returncode:
print(result.stdout) # capture output on error
assert False, "Could not make crossenv!"
return CrossenvEnvironment(build_python, crossenv_dir,
creation_log=result.stdout)
@contextmanager
def open_lock_file(path):
fd = os.open(path, os.O_RDWR | os.O_CREAT, 0o660)
with open(fd, 'r+') as fp:
fcntl.flock(fp, fcntl.LOCK_EX)
try:
data = fp.read(64)
if data:
try:
yield int(data)
return
except ValueError:
fp.truncate(0)
yield None
fp.write(str(os.getpid()))
finally:
fp.flush()
fcntl.flock(fp, fcntl.LOCK_UN)
+1
-1
Metadata-Version: 2.1
Name: crossenv
Version: 1.4.0
Version: 1.5.0
Summary: A cross-compiling tool for Python extension modules

@@ -5,0 +5,0 @@ Home-page: https://github.com/benfogle/crossenv

@@ -17,3 +17,5 @@ LICENSE.txt

crossenv/scripts/importlib-machinery-patch.py.tmpl
crossenv/scripts/importlib-metadata-patch.py.tmpl
crossenv/scripts/os-patch.py.tmpl
crossenv/scripts/packaging-tags-patch.py.tmpl
crossenv/scripts/pkg_resources-patch.py.tmpl

@@ -24,2 +26,8 @@ crossenv/scripts/platform-patch.py.tmpl

crossenv/scripts/sys-patch.py.tmpl
crossenv/scripts/sysconfig-patch.py.tmpl
crossenv/scripts/sysconfig-patch.py.tmpl
tests/test_basic.py
tests/test_compiler.py
tests/test_environment.py
tests/test_resources.py
tests/test_usage.py
tests/testutils.py

@@ -22,3 +22,3 @@ import venv

__version__ = '1.4.0'
__version__ = '1.5.0'

@@ -106,2 +106,5 @@ logger = logging.getLogger(__name__)

:param manylinux_tags: Manylinux tags that are acceptable when downloading
from PyPI. Merged with platform_tags and retained for
compatibility only.
:param platform_tags: Platform tags that are acceptable when downloading
from PyPI.

@@ -127,2 +130,3 @@ :param host_machine: Host machine override seen by cross-python at

manylinux_tags=(),
platform_tags=(),
host_machine=None):

@@ -156,2 +160,3 @@ self.host_sysroot = host_sysroot

self.manylinux_tags = manylinux_tags
self.platform_tags = platform_tags
self.host_machine = host_machine

@@ -162,3 +167,3 @@

self.get_uname_info()
self.expand_manylinux_tags()
self.expand_platform_tags()

@@ -279,3 +284,4 @@ super().__init__(

self.host_home = self.find_installed_host_home()
python_ver = 'python' + sysconfig.get_config_var('py_version_short')
py_thread = 't' if sysconfig.get_config_var('Py_GIL_DISABLED') else ''
python_ver = 'python' + sysconfig.get_config_var('py_version_short') + py_thread
libdir = os.path.join(self.host_home, 'lib', python_ver)

@@ -510,6 +516,11 @@ sysconfig_paths = [

if self.host_machine is None:
if len(host_info) > 1 and host_info[-1] == "powerpc64le":
platform2uname = {
# On uname.machine=ppc64, _PYTHON_HOST_PLATFORM is linux-powerpc64
"powerpc64": "ppc64",
# On uname.machine=ppc64le, _PYTHON_HOST_PLATFORM is linux-powerpc64le
"powerpc64le": "ppc64le",
}
if len(host_info) > 1 and host_info[-1] in platform2uname:
# Test that this is still a special case when we can.
# On uname.machine=ppc64le, _PYTHON_HOST_PLATFORM is linux-powerpc64le
self.host_machine = "ppc64le"
self.host_machine = platform2uname[host_info[-1]]
else:

@@ -544,3 +555,3 @@ self.host_machine = self.host_gnu_type.split('-')[0]

def expand_manylinux_tags(self):
def expand_platform_tags(self):
"""

@@ -551,3 +562,4 @@ Convert legacy manylinux tags to PEP600, because pip only looks for one

manylinux_tags = set(self.manylinux_tags)
platform_tags = set(self.platform_tags)
platform_tags.update(self.manylinux_tags)
extra_tags = set()

@@ -558,26 +570,31 @@ effective_glibc = None

# manylinux1 and so on.
if 'manylinux1' in manylinux_tags:
if 'manylinux1' in platform_tags:
extra_tags.add('manylinux_2_5')
effective_glibc = (2, 5)
if 'manylinux2010' in manylinux_tags:
if 'manylinux2010' in platform_tags:
extra_tags.add('manylinux_2_12')
effective_glibc = (2, 12)
if 'manylinux2014' in manylinux_tags:
if 'manylinux2014' in platform_tags:
extra_tags.add('manylinux_2_17')
effective_glibc = (2, 17)
if 'manylinux_2_5' in manylinux_tags:
if 'manylinux_2_5' in platform_tags:
extra_tags.add('manylinux1')
if 'manylinux_2_12' in manylinux_tags:
if 'manylinux_2_12' in platform_tags:
extra_tags.add('manylinux2010')
if 'manylinux_2_17' in manylinux_tags:
if 'manylinux_2_17' in platform_tags:
extra_tags.add('manylinux2014')
manylinux_tags.update(extra_tags)
self.manylinux_tags = manylinux_tags
platform_tags.update(extra_tags)
self.platform_tags = platform_tags
for tag in manylinux_tags:
# Retain the spell check from earlier versions just in case
for tag in self.manylinux_tags:
# I know *I* mistype it alot.
if not re.search(r'manylinux', tag):
logger.warning("Tag %r does not contain 'manylinux'")
if 'manylinux' not in tag:
logger.warning("Tag %r does not contain 'manylinux'" % tag)
# This is for patching confstr() in a few places where pip, setuptools,
# and packaging try to get the glibc version. Only glibc reports its
# version this way, so this is not necessary for, e.g., musl.
for tag in self.platform_tags:
m = re.match(r'manylinux_(\d+)_(\d+)', tag)

@@ -590,3 +607,2 @@ if not m:

self.effective_glibc = effective_glibc

@@ -783,2 +799,3 @@

'importlib-machinery-patch.py',
'importlib-metadata-patch.py',
'platform-patch.py',

@@ -788,2 +805,3 @@ 'sysconfig-patch.py',

'pkg_resources-patch.py',
'packaging-tags-patch.py',
]

@@ -1050,3 +1068,8 @@

enable pre-compiled wheels. This argument may be given multiple
times.""")
times. This is identical to --platform-tag and is retained for
compatibility only.""")
parser.add_argument('--platform-tag', action='append', default=[],
help="""Declare compatibility with the given platform tag to enable
pre-compiled wheels. This argument may be given multiple
times. Examples include manylinux_2_17 and musllinux_1_2.""")
parser.add_argument('--machine', action='store',

@@ -1098,2 +1121,3 @@ help="""Override the value of os.uname().machine if cross-python is

manylinux_tags=args.manylinux,
platform_tags=args.platform_tag,
host_machine=args.machine,

@@ -1100,0 +1124,0 @@ )

@@ -105,2 +105,3 @@ # Import only what we absolutely need before the path fixup

'importlib.machinery': '{{context.lib_path}}/importlib-machinery-patch.py',
'importlib.metadata': '{{context.lib_path}}/importlib-metadata-patch.py',
'sys': '{{context.lib_path}}/sys-patch.py',

@@ -114,2 +115,3 @@ 'os': '{{context.lib_path}}/os-patch.py',

'pip._vendor.pkg_resources': '{{context.lib_path}}/pkg_resources-patch.py',
'packaging.tags': '{{context.lib_path}}/packaging-tags-patch.py',
}

@@ -116,0 +118,0 @@

Metadata-Version: 2.1
Name: crossenv
Version: 1.4.0
Version: 1.5.0
Summary: A cross-compiling tool for Python extension modules

@@ -5,0 +5,0 @@ Home-page: https://github.com/benfogle/crossenv