diff --git a/pip/pep425tags.py b/pip/pep425tags.py index 2d91ccc6d5f..555afaa7946 100644 --- a/pip/pep425tags.py +++ b/pip/pep425tags.py @@ -124,7 +124,54 @@ def get_platform(): split_ver = release.split('.') return 'macosx_{0}_{1}_{2}'.format(split_ver[0], split_ver[1], machine) # XXX remove distutils dependency - return distutils.util.get_platform().replace('.', '_').replace('-', '_') + result = distutils.util.get_platform().replace('.', '_').replace('-', '_') + if result == "linux_x86_64" and sys.maxsize == 2147483647: + result = "linux_i686" + return result + + +def is_manylinux1_compatible(): + # Only Linux, and only x86-64 / i686 + if get_platform() not in ("linux_x86_64", "linux_i686"): + return False + + # Check for presence of _manylinux module + try: + import _manylinux + return bool(_manylinux.manylinux1_compatible) + except (ImportError, AttributeError): + # Fall through to heuristic check below + pass + + # Check glibc version. CentOS 5 uses glibc 2.5. + return have_compatible_glibc(2, 5) + + +def have_compatible_glibc(major, minimum_minor): + import ctypes + process_namespace = ctypes.CDLL(None) + try: + gnu_get_libc_version = process_namespace.gnu_get_libc_version + except AttributeError: + # Symbol doesn't exist -> therefore, we are not linked to + # glibc. + return False + + # Call gnu_get_libc_version, which returns a string like "2.5". + gnu_get_libc_version.restype = ctypes.c_char_p + version_str = gnu_get_libc_version() + # py2 / py3 compatibility: + if not isinstance(version_str, str): + version_str = version_str.decode("ascii") + + # Parse string and check against requested version. + version = [int(piece) for piece in version_str.split(".")] + assert len(version) == 2 + if major != version[0]: + return False + if minimum_minor > version[1]: + return False + return True def get_supported(versions=None, noarch=False): @@ -189,6 +236,11 @@ def get_supported(versions=None, noarch=False): else: # arch pattern didn't match (?!) arches = [arch] + elif sys.platform == 'linux': + if is_manylinux1_compatible(): + arches = [arch, arch.replace('linux', 'manylinux1')] + else: + arches = [arch] else: arches = [arch] diff --git a/tests/unit/test_wheel.py b/tests/unit/test_wheel.py index e3b8b3d6816..0e626a4e74f 100644 --- a/tests/unit/test_wheel.py +++ b/tests/unit/test_wheel.py @@ -396,6 +396,33 @@ def test_manual_abi_dm_flags(self): self.abi_tag_unicode('dm', {'Py_DEBUG': True, 'WITH_PYMALLOC': True}) +class TestManylinux1Tags(object): + + @patch('pip.pep425tags.get_platform', lambda: 'linux_x86_64') + @patch('pip.pep425tags.have_compatible_glibc', lambda foo, bar: True) + def test_manylinux1_1(self): + """ + Test that manylinux1 is enabled on linux_x86_64 + """ + assert pep425tags.is_manylinux1_compatible() + + @patch('pip.pep425tags.get_platform', lambda: 'linux_x86_64') + @patch('pip.pep425tags.have_compatible_glibc', lambda foo, bar: False) + def test_manylinux1_2(self): + """ + Test that manylinux1 is disabled with incompatible glibc + """ + assert not pep425tags.is_manylinux1_compatible() + + @patch('pip.pep425tags.get_platform', lambda: 'arm6vl') + @patch('pip.pep425tags.have_compatible_glibc', lambda foo, bar: True) + def test_manylinux1_3(self): + """ + Test that manylinux1 is disabled on arm6vl + """ + assert not pep425tags.is_manylinux1_compatible() + + class TestMoveWheelFiles(object): """ Tests for moving files from wheel src to scheme paths