2019-07-20 07:36:21 -04:00
|
|
|
|
PEP: 600
|
|
|
|
|
Title: Future 'manylinux' Platform Tags for Portable Linux Built Distributions
|
|
|
|
|
Version: $Revision$
|
|
|
|
|
Last-Modified: $Date$
|
2022-04-20 05:53:08 -04:00
|
|
|
|
Author: Nathaniel J. Smith <njs@pobox.com>,
|
2019-07-20 07:36:21 -04:00
|
|
|
|
Thomas Kluyver <thomas@kluyver.me.uk>
|
|
|
|
|
Sponsor: Paul Moore <p.f.moore@gmail.com>
|
|
|
|
|
BDFL-Delegate: Paul Moore <p.f.moore@gmail.com>
|
2022-02-27 17:46:36 -05:00
|
|
|
|
Discussions-To: https://discuss.python.org/t/the-next-manylinux-specification/1043
|
2022-06-21 17:47:58 -04:00
|
|
|
|
Status: Final
|
|
|
|
|
Type: Standards Track
|
2022-06-14 17:22:20 -04:00
|
|
|
|
Topic: Packaging
|
2019-07-20 07:36:21 -04:00
|
|
|
|
Content-Type: text/x-rst
|
2021-02-09 11:54:26 -05:00
|
|
|
|
Created: 03-May-2019
|
2022-03-09 11:04:44 -05:00
|
|
|
|
Post-History: 03-May-2019
|
2021-06-26 12:11:00 -04:00
|
|
|
|
Replaces: 513, 571, 599
|
2019-12-04 18:24:33 -05:00
|
|
|
|
Resolution: https://discuss.python.org/t/pep-600-future-manylinux-platform-tags-for-portable-linux-built-distributions/2414/27
|
2019-07-20 07:36:21 -04:00
|
|
|
|
|
|
|
|
|
Abstract
|
|
|
|
|
========
|
|
|
|
|
|
2019-08-03 16:12:19 -04:00
|
|
|
|
This PEP proposes a scheme for new 'manylinux' wheel tags to be
|
|
|
|
|
defined without requiring a PEP for every specific tag, similar to how
|
|
|
|
|
Windows and macOS tags already work. This will allow package
|
|
|
|
|
maintainers to take advantage of new tags more quickly, while making
|
|
|
|
|
better use of limited volunteer time.
|
|
|
|
|
|
|
|
|
|
Non-goals include: handling non-glibc-based platforms; integrating
|
|
|
|
|
with external package managers or handling external dependencies such
|
|
|
|
|
as CUDA; making manylinux tags more sophisticated than their
|
|
|
|
|
Windows/macOS equivalents; doing anything besides taking our existing
|
|
|
|
|
tried-and-tested approach and streamlining it. These are important
|
|
|
|
|
issues and other PEPs may address them in the future, but for this PEP
|
|
|
|
|
they're out of scope.
|
2019-07-20 07:36:21 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Rationale
|
|
|
|
|
=========
|
|
|
|
|
|
2019-08-03 16:12:19 -04:00
|
|
|
|
Python users appreciate it when PyPI has pre-compiled packages for
|
|
|
|
|
their platform, because it makes installation fast and simple. But
|
|
|
|
|
distributing pre-compiled binaries on Linux is challenging because of
|
|
|
|
|
the diversity of Linux-based platforms. For example, Debian, Android,
|
|
|
|
|
and Alpine all use the Linux kernel, but with radically different
|
|
|
|
|
userspace libraries, which makes it difficult or impossible to create
|
|
|
|
|
a single wheel that works on all three. This complexity has caused
|
|
|
|
|
many previous discussions of Linux wheels to stall out.
|
|
|
|
|
|
|
|
|
|
The "manylinux" project succeeded by adopting a strategy of ruthless
|
|
|
|
|
pragmatism. We chose a large but tractable set of Linux platforms –
|
|
|
|
|
specifically, mainstream glibc-based distributions like Debian,
|
|
|
|
|
OpenSuSE, Ubuntu, RHEL, etc. – and then we did whatever it takes to
|
|
|
|
|
make wheels that work across all these platforms.
|
|
|
|
|
|
|
|
|
|
This approach requires many compromises. Manylinux wheels can only
|
2021-02-03 09:06:23 -05:00
|
|
|
|
rely on external libraries that maintain a consistent ABI and are
|
2019-08-03 16:12:19 -04:00
|
|
|
|
universally available across all these distributions, which in
|
|
|
|
|
practice restricts them to a small set of core libraries like glibc
|
|
|
|
|
and a few others. Wheels have to be built on carefully-chosen
|
|
|
|
|
platforms of the oldest possible vintage, using a Python that is
|
|
|
|
|
itself built in a carefully-chosen configuration. Other shared library
|
|
|
|
|
dependencies have to be bundled into the wheel, which requires a
|
|
|
|
|
complex process to avoid collisions between unrelated wheels. And
|
|
|
|
|
finally, the details of these requirements change over time, as new
|
|
|
|
|
distro versions are released, and old ones fall out of use.
|
|
|
|
|
|
|
|
|
|
It turns out that these requirements are not too onerous: they're
|
|
|
|
|
essentially equivalent to what you have to do to ship Windows or macOS
|
|
|
|
|
wheels, and the manylinux approach has achieved substantial uptake
|
|
|
|
|
among both package maintainers and end-users. But any manylinux PEP
|
|
|
|
|
needs some way to address these complexities.
|
|
|
|
|
|
2021-06-26 07:59:15 -04:00
|
|
|
|
In previous manylinux PEPs (:pep:`513`, :pep:`571`, :pep:`599`), we've
|
|
|
|
|
done this by attempting to write down in the PEP the exact set of
|
|
|
|
|
libraries, symbol versions, Python configuration, etc. that we
|
|
|
|
|
believed would lead to wheels that work on all mainstream glibc-based
|
|
|
|
|
Linux systems. But this created several problems:
|
2019-08-03 16:12:19 -04:00
|
|
|
|
|
|
|
|
|
First, PEPs are generally supposed to be normative references: if
|
|
|
|
|
software doesn't match the PEP, then we fix the software. But in this
|
|
|
|
|
case, the PEPs are attempting to describe Linux distributions, which
|
|
|
|
|
are a moving target, and do not consider our PEPs to constrain their
|
|
|
|
|
behavior. This means that we've been taking on an unbounded commitment
|
|
|
|
|
to keep updating every manylinux PEP whenever the Linux distro
|
|
|
|
|
landscape changes. This is a substantial commitment for unfunded
|
|
|
|
|
volunteers to take on, and it's not clear that this work produces
|
|
|
|
|
value for our users.
|
|
|
|
|
|
|
|
|
|
And second, every time we move manylinux forward to a newer range of
|
|
|
|
|
supported platforms, or add support for a new architecture, we have to
|
|
|
|
|
go through a fairly elaborate process: writing a new PEP, updating the
|
|
|
|
|
PyPI and pip codebases to recognize the new tag, waiting for the new
|
|
|
|
|
pip to percolate to users, etc. None of this happens on Windows/macOS;
|
|
|
|
|
it's only a tax on Linux maintainers. This slows deployment of new
|
|
|
|
|
manylinux versions, and consumes part of our community's limited PEP
|
|
|
|
|
review bandwidth, thus slowing progress of the Python packaging
|
|
|
|
|
ecosystem as a whole. This is especially problematic for less-popular
|
|
|
|
|
architectures, who have less volunteer resources to overcome these
|
|
|
|
|
barriers.
|
|
|
|
|
|
|
|
|
|
How can we fix it?
|
|
|
|
|
|
|
|
|
|
A manylinux PEP has to address three main audiences:
|
|
|
|
|
|
|
|
|
|
- **Package installers**, like pip, need to be able to determine which
|
|
|
|
|
wheel tags are compatible with the system they find themselves
|
|
|
|
|
running on. This requires some automated process to introspect the
|
|
|
|
|
system and match it up with wheel tags.
|
|
|
|
|
|
|
|
|
|
- **Package indexes**, like PyPI, need to be able to validate which
|
|
|
|
|
wheel tags are valid. Generally, this just requires something like a
|
|
|
|
|
list of valid tags, or regex they match, with no need to know
|
|
|
|
|
anything about the actual semantics for individual tags. (But see
|
|
|
|
|
the discussion of upload verification below.)
|
|
|
|
|
|
|
|
|
|
- **Package maintainers** need to be able to build wheels that meet
|
|
|
|
|
the requirements for a given wheel tag.
|
|
|
|
|
|
|
|
|
|
Here's the key insight behind this new PEP: it's crucial that
|
|
|
|
|
different **package installers** and **package indexes** all agree on
|
|
|
|
|
which manylinux tags are valid and which systems they install on, so
|
|
|
|
|
we need a PEP to specify these – but, these are straightforward, and
|
|
|
|
|
don't really change between manylinux versions. The complicated part
|
|
|
|
|
that keeps changing is the process of actually **building the wheels**
|
|
|
|
|
– but, if there are multiple competing build environments, it *doesn't
|
|
|
|
|
matter* whether they use exactly the same rules as each other, as long
|
|
|
|
|
as they all produce wheels that work on end-user systems. Therefore,
|
|
|
|
|
we don't need an interoperability standard for building wheels, so we
|
|
|
|
|
don't need to write the details into a PEP.
|
|
|
|
|
|
|
|
|
|
To further convince ourselves that this approach will work, let's look
|
|
|
|
|
again at how we handle wheels on Windows and macOS: the PEPs describe
|
|
|
|
|
which tags are valid, and which systems they're supposed to work on,
|
|
|
|
|
but not how to actually build wheels for those platforms. And in
|
|
|
|
|
practice, if you want to distribute Windows or macOS wheels, you might
|
|
|
|
|
have to jump through some complicated and poorly documented hoops in
|
|
|
|
|
order to bundle dependencies, target the right range of OS versions,
|
|
|
|
|
etc. But the system works, and the way to improve it is to write
|
|
|
|
|
better docs and build better tooling; no-one thinks that the way to
|
|
|
|
|
make Windows wheels work better is to publish a PEP describing
|
|
|
|
|
which symbols we think Microsoft should be including in their
|
|
|
|
|
libraries and how their linker ought to work. This PEP extends that
|
|
|
|
|
philosophy to manylinux as well.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Specification
|
|
|
|
|
=============
|
|
|
|
|
|
|
|
|
|
Core definition
|
|
|
|
|
---------------
|
2019-07-20 07:36:21 -04:00
|
|
|
|
|
|
|
|
|
Tags using the new scheme will look like::
|
|
|
|
|
|
2019-08-03 16:12:19 -04:00
|
|
|
|
manylinux_2_17_x86_64
|
|
|
|
|
|
|
|
|
|
Or more generally::
|
|
|
|
|
|
|
|
|
|
manylinux_${GLIBCMAJOR}_${GLIBCMINOR}_${ARCH}
|
|
|
|
|
|
|
|
|
|
This tag is a promise: the wheel's creator promises that the wheel
|
|
|
|
|
will work on any mainstream Linux distro that uses glibc version
|
|
|
|
|
``${GLIBCMAJOR}.${GLIBCMINOR}`` or later, and where the ``${ARCH}``
|
|
|
|
|
matches the return value from ``distutils.util.get_platform()``. (For
|
|
|
|
|
more detail about architecture tags, see :pep:`425`.)
|
|
|
|
|
|
|
|
|
|
If a user installs this wheel into an environment that matches these
|
|
|
|
|
requirements and it doesn't work, then that wheel does not comply with
|
|
|
|
|
this specification. This should be considered a bug in the wheel, and
|
|
|
|
|
it's the wheel creator's responsibility to look for a fix (possibly
|
|
|
|
|
with the help of the broader community).
|
|
|
|
|
|
|
|
|
|
The word "mainstream" is intentionally somewhat vague, and should be
|
|
|
|
|
interpreted expansively. The goal is to rule out weird homebrew Linux
|
|
|
|
|
systems; generally any distro you've actually heard of should be
|
|
|
|
|
considered "mainstream". We also provide a way for maintainers of
|
|
|
|
|
"weird" distros to manually override this check, though based on
|
|
|
|
|
experience with previous manylinux PEPs, we don't expect this feature
|
|
|
|
|
to see much use.
|
|
|
|
|
|
|
|
|
|
And finally, compliant wheels are required to "play well with others",
|
|
|
|
|
i.e., installing a manylinux wheel must not cause other unrelated
|
|
|
|
|
packages to break.
|
|
|
|
|
|
|
|
|
|
Any method of producing wheels which meets these criteria is
|
|
|
|
|
acceptable. However, in practice we expect that the auditwheel project
|
|
|
|
|
will maintain an up-to-date set of tools and build images for
|
2019-10-10 07:36:17 -04:00
|
|
|
|
producing manylinux wheels, as well as documentation about how they
|
|
|
|
|
work and how to use them, and that most maintainers will want to use
|
2019-08-03 16:12:19 -04:00
|
|
|
|
those. For the latest information on building manylinux wheels,
|
|
|
|
|
including recommendations about which build images to use, see
|
|
|
|
|
https://packaging.python.org.
|
|
|
|
|
|
|
|
|
|
Since these requirements are fairly high-level, here are some examples
|
|
|
|
|
of how they play out in specific situations:
|
|
|
|
|
|
|
|
|
|
Example: if a wheel is tagged as ``manylinux_2_17_x86_64``, but it
|
|
|
|
|
uses symbols that were only added in glibc 2.18, then that wheel won't
|
|
|
|
|
work on systems with glibc 2.17. Therefore, we can conclude that this
|
|
|
|
|
wheel is in violation of this specification.
|
|
|
|
|
|
|
|
|
|
Example: Until ~2017, all major Linux distros included
|
|
|
|
|
``libncursesw.so.5`` as part of their default install. Until that
|
|
|
|
|
date, a wheel that linked to ``libncursesw.so.5`` was compliant with
|
|
|
|
|
this specification. Then, distros started switching to ncurses 6,
|
|
|
|
|
which has a different name and incompatible ABI, and stopped
|
|
|
|
|
installing ``libncursesw.so.5`` by default. So after that date, a
|
|
|
|
|
wheel that links to ``libncursesw.so.5`` was no longer compliant with
|
|
|
|
|
this specification.
|
|
|
|
|
|
|
|
|
|
Example: The Linux ELF linker places all shared library SONAMEs into a
|
|
|
|
|
single process-global namespace. If independent wheels used the same
|
|
|
|
|
SONAME for their bundled libraries, they might end up colliding and
|
|
|
|
|
using the wrong library version, which would violate the "play well
|
|
|
|
|
with others" rule. Therefore, this specification requires that wheels
|
|
|
|
|
use globally-unique names for all bundled libraries. (Auditwheel
|
|
|
|
|
currently accomplishes this by renaming all bundled libraries to
|
|
|
|
|
include a globally-unique hash.)
|
|
|
|
|
|
|
|
|
|
Example: we've observed certain wheels using C++ in ways that
|
|
|
|
|
`interfere with other packages
|
|
|
|
|
<https://github.com/apache/arrow/pull/2210>`__ via an unclear
|
|
|
|
|
mechanism. This is also a violation of the "play well with others"
|
|
|
|
|
rule, so those wheels aren't compliant with this specification.
|
|
|
|
|
|
|
|
|
|
Example: The imaginary architecture LEG v7 has both big-endian and
|
|
|
|
|
little-endian variants. Big-endian binaries require a big-endian
|
|
|
|
|
system, and little-endian binaries require a little-endian system. But
|
|
|
|
|
unfortunately, it's discovered that due to a bug in :pep:`425`, both
|
|
|
|
|
variants use the same architecture tag, ``legv7``. This makes it
|
|
|
|
|
impossible to create a compliant ``manylinux_2_17_legv7`` wheel: no
|
|
|
|
|
matter what we do, it will crash on some user's systems. So, we write
|
|
|
|
|
a new PEP defining architecture tags ``legv7le`` and ``legv7be``; now
|
|
|
|
|
we can ship manylinux LEG v7 wheels.
|
|
|
|
|
|
|
|
|
|
Example: There's also a LEG v8. It also has big-endian and
|
|
|
|
|
little-endian variants. But fortunately, it turns out that :pep:`425`
|
|
|
|
|
already does the right thing LEG v8, so LEG v8 enthusiasts can start
|
|
|
|
|
shipping ``manylinux_2_17_legv8le`` and ``manylinux_2_17_legv8be``
|
|
|
|
|
wheels immediately once this PEP is implemented, even though the
|
|
|
|
|
authors of this PEP don't know anything at all about LEG v8.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Legacy manylinux tags
|
|
|
|
|
---------------------
|
|
|
|
|
|
|
|
|
|
The existing manylinux tags are redefined as aliases for new-style
|
|
|
|
|
tags:
|
|
|
|
|
|
|
|
|
|
- ``manylinux1_x86_64`` is now an alias for ``manylinux_2_5_x86_64``
|
|
|
|
|
- ``manylinux1_i686`` is now an alias for ``manylinux_2_5_i686``
|
|
|
|
|
- ``manylinux2010_x86_64`` is now an alias for ``manylinux_2_12_x86_64``
|
|
|
|
|
- ``manylinux2010_i686`` is now an alias for ``manylinux_2_12_i686``
|
2021-06-26 07:59:15 -04:00
|
|
|
|
- ``manylinux2014_x86_64`` is now an alias for ``manylinux_2_17_x86_64``
|
|
|
|
|
- ``manylinux2014_i686`` is now an alias for ``manylinux_2_17_i686``
|
|
|
|
|
- ``manylinux2014_aarch64`` is now an alias for ``manylinux_2_17_aarch64``
|
|
|
|
|
- ``manylinux2014_armv7l`` is now an alias for ``manylinux_2_17_armv7l``
|
|
|
|
|
- ``manylinux2014_ppc64`` is now an alias for ``manylinux_2_17_ppc64``
|
|
|
|
|
- ``manylinux2014_ppc64le`` is now an alias for ``manylinux_2_17_ppc64le``
|
|
|
|
|
- ``manylinux2014_s390x`` is now an alias for ``manylinux_2_17_s390x``
|
2019-08-03 16:12:19 -04:00
|
|
|
|
|
|
|
|
|
This redefinition is largely a no-op, but does affect a few things:
|
|
|
|
|
|
|
|
|
|
- Previously, we had an open-ended and growing commitment to keep
|
|
|
|
|
updating every manylinux PEP whenever a new Linux distro was
|
|
|
|
|
released, for the rest of time. By making this PEP normative for the
|
2019-10-10 07:36:17 -04:00
|
|
|
|
older tags, that obligation goes away. When this PEP is accepted,
|
|
|
|
|
the previous manylinux PEPs will receive a final update noting that
|
|
|
|
|
they are no longer maintained and referring to this PEP.
|
2019-08-03 16:12:19 -04:00
|
|
|
|
|
|
|
|
|
- The "play well with others" rule was always intended, but previous
|
|
|
|
|
PEPs didn't state it explicitly; now it's explicit.
|
|
|
|
|
|
|
|
|
|
- Previous PEPs assumed that glibc 3.x might be incompatible with
|
|
|
|
|
glibc 2.x, so we checked for compatibility between a system and a
|
|
|
|
|
tag using logic like::
|
|
|
|
|
|
|
|
|
|
sys_major == tag_major and sys_minor >= tag_minor
|
|
|
|
|
|
|
|
|
|
Recently the glibc maintainers `advised us
|
|
|
|
|
<https://sourceware.org/bugzilla/show_bug.cgi?id=24636>`__ that we
|
|
|
|
|
should assume that glibc will maintain backwards-compatibility
|
|
|
|
|
indefinitely, even if they bump the major version number. So the new
|
|
|
|
|
check for compatibility is::
|
|
|
|
|
|
|
|
|
|
(sys_major, sys_minor) >= (tag_major, tag_minor)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Package installers
|
|
|
|
|
------------------
|
|
|
|
|
|
|
|
|
|
Generally, package installers should install manylinux wheels on
|
|
|
|
|
systems that have an appropriate glibc and architecture, and not
|
|
|
|
|
otherwise. If there are multiple compatible manylinux wheels
|
|
|
|
|
available, then the wheel with the highest glibc version should be
|
|
|
|
|
preferred, in order to take advantage of newer compilers and glibc
|
|
|
|
|
features.
|
|
|
|
|
|
|
|
|
|
In addition, we follow previous specifications, and allow for Python
|
|
|
|
|
distributors to manually override this check by adding a
|
|
|
|
|
``_manylinux`` module to their standard library. If this package is
|
|
|
|
|
importable, and if it defines a function called
|
|
|
|
|
``manylinux_compatible``, then package installers should call this
|
|
|
|
|
function, passing in the major version, minor version, and
|
|
|
|
|
architecture from the manylinux tag, and it will either return a
|
|
|
|
|
boolean saying whether wheels with the given tag should be considered
|
|
|
|
|
compatible with the current system, or else ``None`` to indicate that
|
|
|
|
|
the default logic should be used.
|
|
|
|
|
|
|
|
|
|
For compatibility with previous specifications, if the tag is
|
|
|
|
|
``manylinux1`` or ``manylinux_2_5`` exactly, then we also check the
|
2021-06-26 07:59:15 -04:00
|
|
|
|
module for a boolean attribute ``manylinux1_compatible``, if the
|
2019-08-03 16:12:19 -04:00
|
|
|
|
tag version is ``manylinux2010`` or ``manylinux_2_12`` exactly, then
|
|
|
|
|
we also check the module for a boolean attribute
|
2021-06-26 07:59:15 -04:00
|
|
|
|
``manylinux2010_compatible``, and if the tag version is
|
|
|
|
|
``manylinux2014`` or ``manylinux_2_17`` exactly, then we also check
|
|
|
|
|
the module for a boolean attribute ``manylinux2014_compatible``. If
|
|
|
|
|
both the new and old attributes are defined, then
|
|
|
|
|
``manylinux_compatible`` takes precedence.
|
2019-08-03 16:12:19 -04:00
|
|
|
|
|
|
|
|
|
Here's some example code. You don't have to actually use this code,
|
|
|
|
|
but you can use it for reference if you have questions about the exact
|
|
|
|
|
semantics::
|
|
|
|
|
|
|
|
|
|
LEGACY_ALIASES = {
|
|
|
|
|
"manylinux1_x86_64": "manylinux_2_5_x86_64",
|
|
|
|
|
"manylinux1_i686": "manylinux_2_5_i686",
|
|
|
|
|
"manylinux2010_x86_64": "manylinux_2_12_x86_64",
|
|
|
|
|
"manylinux2010_i686": "manylinux_2_12_i686",
|
2021-06-26 07:59:15 -04:00
|
|
|
|
"manylinux2014_x86_64": "manylinux_2_17_x86_64",
|
|
|
|
|
"manylinux2014_i686": "manylinux_2_17_i686",
|
|
|
|
|
"manylinux2014_aarch64": "manylinux_2_17_aarch64",
|
|
|
|
|
"manylinux2014_armv7l": "manylinux_2_17_armv7l",
|
|
|
|
|
"manylinux2014_ppc64": "manylinux_2_17_ppc64",
|
|
|
|
|
"manylinux2014_ppc64le": "manylinux_2_17_ppc64le",
|
|
|
|
|
"manylinux2014_s390x": "manylinux_2_17_s390x",
|
2019-08-03 16:12:19 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def manylinux_tag_is_compatible_with_this_system(tag):
|
|
|
|
|
# Normalize and parse the tag
|
|
|
|
|
tag = LEGACY_ALIASES.get(tag, tag)
|
|
|
|
|
m = re.match("manylinux_([0-9]+)_([0-9]+)_(.*)", tag)
|
|
|
|
|
if not m:
|
|
|
|
|
return False
|
|
|
|
|
tag_major_str, tag_minor_str, tag_arch = m.groups()
|
|
|
|
|
tag_major = int(tag_major_str)
|
|
|
|
|
tag_minor = int(tag_minor_str)
|
|
|
|
|
|
2019-10-10 07:36:17 -04:00
|
|
|
|
if not system_uses_glibc():
|
|
|
|
|
return False
|
|
|
|
|
sys_major, sys_minor = get_system_glibc_version()
|
|
|
|
|
if (sys_major, sys_minor) < (tag_major, tag_minor):
|
|
|
|
|
return False
|
|
|
|
|
sys_arch = get_system_arch()
|
|
|
|
|
if sys_arch != tag_arch:
|
|
|
|
|
return False
|
|
|
|
|
|
2019-08-03 16:12:19 -04:00
|
|
|
|
# Check for manual override
|
|
|
|
|
try:
|
|
|
|
|
import _manylinux
|
|
|
|
|
except ImportError:
|
|
|
|
|
pass
|
|
|
|
|
else:
|
|
|
|
|
if hasattr(_manylinux, "manylinux_compatible"):
|
|
|
|
|
result = _manylinux.manylinux_compatible(
|
|
|
|
|
tag_major, tag_minor, tag_arch,
|
|
|
|
|
)
|
|
|
|
|
if result is not None:
|
|
|
|
|
return bool(result)
|
|
|
|
|
else:
|
|
|
|
|
if (tag_major, tag_minor) == (2, 5):
|
|
|
|
|
if hasattr(_manylinux, "manylinux1_compatible"):
|
|
|
|
|
return bool(_manylinux.manylinux1_compatible)
|
|
|
|
|
if (tag_major, tag_minor) == (2, 12):
|
|
|
|
|
if hasattr(_manylinux, "manylinux2010_compatible"):
|
|
|
|
|
return bool(_manylinux.manylinux2010_compatible)
|
|
|
|
|
|
2019-10-10 07:36:17 -04:00
|
|
|
|
return True
|
2019-08-03 16:12:19 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Package indexes
|
|
|
|
|
---------------
|
|
|
|
|
|
|
|
|
|
The exact set of wheel tags accepted by PyPI, or any package index, is
|
|
|
|
|
a policy question, and up to the maintainers of that index. But, we
|
|
|
|
|
recommend that package indexes accept any wheels whose platform tag
|
|
|
|
|
matches the following regexes:
|
|
|
|
|
|
|
|
|
|
- ``manylinux1_(x86_64|i686)``
|
|
|
|
|
- ``manylinux2010_(x86_64|i686)``
|
2021-06-26 07:59:15 -04:00
|
|
|
|
- ``manylinux2014_(x86_64|i686|aarch64|armv7l|ppc64|ppc64le|s390x)``
|
2019-08-03 16:12:19 -04:00
|
|
|
|
- ``manylinux_[0-9]+_[0-9]+_(.*)``
|
|
|
|
|
|
|
|
|
|
Package indexes may impose additional requirements; for example, they
|
|
|
|
|
might audit uploaded wheels and reject those that contain known
|
|
|
|
|
problems, such as a ``manylinux_2_17`` wheel that references symbols
|
|
|
|
|
from later glibc versions, or dependencies on external libraries that
|
|
|
|
|
are known not to exist on all systems. Or a package index might decide
|
|
|
|
|
to be conservative and reject wheels tagged ``manylinux_2_999``, on
|
|
|
|
|
the grounds that no-one knows what the Linux distro landscape will
|
|
|
|
|
look like when glibc 2.999 is released. We leave the details of any
|
|
|
|
|
such checks to the discretion of the package index maintainers.
|
|
|
|
|
|
2019-07-20 07:36:21 -04:00
|
|
|
|
|
|
|
|
|
Rejected alternatives
|
|
|
|
|
=====================
|
|
|
|
|
|
2019-08-03 16:12:19 -04:00
|
|
|
|
**Continuing the manylinux20XX series**: As discussed above, this
|
|
|
|
|
leads to much more effort-intensive, slower, and more complex rollouts
|
|
|
|
|
of new versions. And while there are two places where it seems at
|
|
|
|
|
first to have some compensating benefits, if you look more closely
|
|
|
|
|
this turns out not to be the case.
|
|
|
|
|
|
|
|
|
|
First, this forces us to produce human-readable descriptions of how
|
|
|
|
|
Linux distros work, in the text of the PEP. But this is less valuable
|
|
|
|
|
than it might seem at first, and can actually be handled better by the
|
|
|
|
|
new "perennial" approach anyway.
|
|
|
|
|
|
|
|
|
|
If you're trying to build wheels, the main thing you need is a
|
|
|
|
|
tutorial on how to use the build images and tooling around them. If
|
|
|
|
|
you're trying to add support for a new build profile or create a
|
|
|
|
|
competitor to auditwheel, then your best resources will be the
|
|
|
|
|
auditwheel source code and issue tracker, which are always going to be
|
|
|
|
|
more detailed, precise, and reliable than a summary spec written in
|
|
|
|
|
English and without tests. Documentation like the old manylinux20XX
|
|
|
|
|
PEPs does add value! But in both cases, it's primarily as a secondary
|
|
|
|
|
reference to provide overview and context.
|
|
|
|
|
|
|
|
|
|
And furthermore, the PEP process is poorly suited to maintaining this
|
|
|
|
|
kind of reference documentation – there's a reason we don't keep the
|
|
|
|
|
pip user manual in the PEPs repository! The auditwheel maintainers are
|
|
|
|
|
the best situated to understand what kinds of documentation are useful
|
|
|
|
|
to their users, and to maintain that documentation over time. For
|
|
|
|
|
example, there's substantial overlap between the different manylinux
|
|
|
|
|
versions, and the PEP process currently forces us to handle this by
|
|
|
|
|
copy-pasting everything between a growing list of documents; instead,
|
|
|
|
|
the auditwheel maintainers might choose to factor out the common parts
|
|
|
|
|
into a single piece of shared documentation.
|
|
|
|
|
|
|
|
|
|
A related concern was that with the perennial approach, it may become
|
|
|
|
|
harder for package maintainers to decide which build profile to
|
|
|
|
|
target: instead of having to pick between ``manylinux1``,
|
|
|
|
|
``manylinux2010``, ``manylinux2014``, ..., they now have a wider array
|
|
|
|
|
of options like ``manylinux_2_5``, ``manylinux_2_6``, ...,
|
|
|
|
|
``manylinux_2_20``, ... But again, we don't believe this will be a
|
|
|
|
|
problem in practice. In either system, most package maintainers won't
|
|
|
|
|
be starting by reading PEPs and trying to implement them from scratch.
|
|
|
|
|
If you're a particularly expert and ambitious package maintainer who
|
|
|
|
|
needs to target a new version or new architecture, the perennial
|
|
|
|
|
approach gives you additional flexibility. But for regular everyday
|
|
|
|
|
maintainers, we expect they'll start from a tutorial like
|
|
|
|
|
packaging.python.org, and by choosing from existing build images. A
|
|
|
|
|
tutorial can just as easily recommend ``manylinux_2_17`` as it can
|
|
|
|
|
recommend ``manylinux2014``, and we expect the actual set of
|
|
|
|
|
pre-provided build images to be identical in both cases. And again, by
|
|
|
|
|
maintaining this documentation in the right place, instead of trying
|
|
|
|
|
to do it PEPs repository, we expect that we'll end up with
|
|
|
|
|
documentation that's higher-quality and more fitted to purpose.
|
|
|
|
|
|
|
|
|
|
Finally, some participants have pointed out that it's very nice to be
|
|
|
|
|
able to look at a wheel and tell definitively whether it meets the
|
|
|
|
|
requirements of the spec. With the new "perennial" approach, we can
|
|
|
|
|
never say with 100% certainty that a wheel does meet the spec, because
|
|
|
|
|
that depends on the Linux distros. As engineers we have a
|
|
|
|
|
well-justified dislike for that kind of uncertainty.
|
|
|
|
|
|
|
|
|
|
However: as demonstrated by the examples above, we can still tell
|
|
|
|
|
definitively when a wheel *doesn't* meet the spec, which turns out to
|
|
|
|
|
be what's important in practice. And, in practice, with the
|
|
|
|
|
manylinux20XX approach, whenever distros change, we actually change
|
|
|
|
|
the spec; it takes a bit longer. So even if a wheel was compliant
|
|
|
|
|
today, it might be become non-compliant tomorrow. This is frustrating,
|
|
|
|
|
but unfortunately this uncertainty is unavoidable if what you care
|
|
|
|
|
about is distributing working wheels to users.
|
|
|
|
|
|
|
|
|
|
So even on these points where the old approach initially seems to have
|
|
|
|
|
advantages, we expect the new approach to actually do as well or
|
|
|
|
|
better.
|
|
|
|
|
|
|
|
|
|
**Switching to perennial tags, but continuing to write a PEP for each
|
|
|
|
|
version**: This was proposed as a kind of hybrid, to try to get some
|
|
|
|
|
of the advantages of the perennial tagging system – like easier
|
|
|
|
|
rollouts of new versions – while keeping the advantages of the
|
|
|
|
|
manylinux20XX scheme, like forcing us to write documentation about
|
|
|
|
|
Linux distros, simplifying options for package maintainers, and being
|
|
|
|
|
able to definitively tell when a wheel meets the spec. But as
|
|
|
|
|
discussed above, on a closer look, it turns out that these advantages
|
|
|
|
|
are largely illusory. And this also inherits significant
|
|
|
|
|
*dis*\advantages from the manylinux20XX scheme, like creating
|
|
|
|
|
indefinite obligations to update a growing list of copy-pasted PEPs.
|
|
|
|
|
|
|
|
|
|
**Making auditwheel normative**: Another possibility that was
|
|
|
|
|
considered was to make auditwheel the normative reference on the
|
|
|
|
|
definition of manylinux, i.e., a wheel would be compliant if and only
|
|
|
|
|
if ``auditwheel check`` completed without errors. This was rejected
|
|
|
|
|
because the point of packaging PEPs is to define interoperability
|
|
|
|
|
between tools, not to bless specific tools.
|
|
|
|
|
|
|
|
|
|
**Adding extra words to the tag string**: Another proposal we
|
|
|
|
|
considered was to add extra words to the wheel tag, e.g.
|
|
|
|
|
``manylinux_glibc_2_17`` instead of ``manylinux_2_17``. The motivation
|
|
|
|
|
would be to leave the door open to other kinds of versioning
|
|
|
|
|
heuristics in the future – for example, we could have
|
|
|
|
|
``manylinux_glibc_$VERSION`` and ``manylinux_alpine_$VERSION``.
|
|
|
|
|
|
|
|
|
|
But "manylinux" has always been a synonym for "broad compatibility
|
|
|
|
|
with mainstream glibc-based distros"; reusing it for unrelated build
|
|
|
|
|
profiles like alpine is more confusing than helpful. Also, some early
|
|
|
|
|
reviewers who aren't steeped in the details of packaging found the
|
|
|
|
|
word ``glibc`` actively misleading, jumping to the conclusion that it
|
|
|
|
|
meant they needed a system with *exactly* that glibc version. And tags
|
|
|
|
|
like ``manylinux_$VERSION`` and ``alpine_$VERSION`` also have the
|
|
|
|
|
advantages of parsimony and directness. So we'll go with that.
|