218 lines
9.5 KiB
ReStructuredText
218 lines
9.5 KiB
ReStructuredText
PEP: 600
|
||
Title: Future 'manylinux' Platform Tags for Portable Linux Built Distributions
|
||
Version: $Revision$
|
||
Last-Modified: $Date$
|
||
Author: Nathaniel J. Smith <njs@pobox.com>
|
||
Thomas Kluyver <thomas@kluyver.me.uk>
|
||
Sponsor: Paul Moore <p.f.moore@gmail.com>
|
||
BDFL-Delegate: Paul Moore <p.f.moore@gmail.com>
|
||
Discussions-To: Discourse https://discuss.python.org/t/the-next-manylinux-specification/1043
|
||
Status: Draft
|
||
Type: Informational
|
||
Content-Type: text/x-rst
|
||
Created: 3-May-2019
|
||
Post-History: 3-May-2019
|
||
|
||
Abstract
|
||
========
|
||
|
||
This PEP proposes a scheme for new 'manylinux' distribution tags to be defined
|
||
without requiring a PEP for every specific tag. The naming scheme is based on
|
||
glibc versions, with profiles in the auditwheel tool defining what other
|
||
external libraries and symbols a compatible wheel may link against.
|
||
|
||
While there is interest in defining tags for non-glibc Linux platforms,
|
||
this PEP does not attempt to address that.
|
||
|
||
Rationale
|
||
=========
|
||
|
||
Distributing compiled code for Linux is more complicated than for other popular
|
||
operating systems, because the Linux kernel and the libraries which typically
|
||
accompany it are built in different configurations and combinations for different
|
||
distributions. However, there are certain core libraries which can be expected in
|
||
many common distributions and are reliably backwards compatible, so binaries
|
||
built with older versions of these libraries will work with newer versions.
|
||
:pep:`513` describes these ideas in much more detail.
|
||
|
||
The ``manylinux1`` (:pep:`513`) and ``manylinux2010`` (:pep:`571`) tags make
|
||
use of these features. They define a set of core libraries and symbol versions
|
||
which wheels may expect on the system, based on CentOS 5 and 6 respectively.
|
||
Typically, packages are built in Docker containers based on these old CentOS
|
||
versions, and then the ``auditwheel`` tool is used to check them and bundle any
|
||
other linked libraries into the wheel.
|
||
|
||
If we were to define a ``manylinux2014`` tag based on CentOS 7, there would be
|
||
five steps involved to make it practically useful:
|
||
|
||
1. Write a PEP
|
||
2. Prepare docker images based on CentOS 7.
|
||
3. Add the definition to auditwheel
|
||
4. Allow uploads with the new tag on PyPI
|
||
5. Add code to pip to recognise the new tag and check if the platform is
|
||
compatible
|
||
|
||
Although preparing the docker images and updating auditwheel take more work,
|
||
these parts can be used as soon as that work is complete. The changes to pip
|
||
are more straightforward, but not all users will promptly install a new version
|
||
of pip, so distributors are concerned about moving to a new tag too quickly.
|
||
|
||
This PEP aims to remove the need for steps 1 and 5 above, so new manylinux tags
|
||
can be adopted more easily.
|
||
|
||
Naming
|
||
======
|
||
|
||
Tags using the new scheme will look like::
|
||
|
||
manylinux_glibc_2_17_x86_64
|
||
|
||
Where ``2_17`` is the major and minor version of glibc. I.e. for this example,
|
||
the platform must have glibc 2.17 or newer. Installer tools should be prepared
|
||
to handle any numeric values here, but building and publishing wheels to PyPI
|
||
will probably be constrained to specific profiles defined by auditwheel.
|
||
|
||
The existing manylinux tags can also be represented in the new scheme,
|
||
for instance:
|
||
|
||
- ``manylinux1_x86_64`` becomes ``manylinux_glibc_2_5_x86_64``
|
||
- ``manylinux2010_x86_64`` becomes ``manylinux_glibc_2_12_x86_64``
|
||
|
||
``x86_64`` refers to the CPU architecture, as in previous tags.
|
||
|
||
While this PEP does not attempt to define tags for non-glibc Linux, the name
|
||
glibc is included to leave room for future efforts in that direction.
|
||
|
||
Wheel compatibility
|
||
===================
|
||
|
||
There are two components to a tag definition: a specification of what makes a
|
||
compatible wheel, and of what makes a compatible platform.
|
||
|
||
A wheel may never use symbols from a newer version of glibc than that indicated
|
||
by its tag. Likewise, a wheel with a glibc tag under this scheme may not be
|
||
linked against another libc implementation.
|
||
|
||
As with the previous manylinux tags, wheels will be allowed to link against
|
||
a limited set of external libraries and symbols. These will be defined by
|
||
profiles documented on https://packaging.python.org/ and implemented in
|
||
auditwheel. At least initially, they will likely be similar to
|
||
the list for manylinux2010 (:pep:`571`), and based on library versions in
|
||
newer versions of CentOS.
|
||
|
||
The overall goal is to ensure that if a wheel is tagged as
|
||
``manylinux_glibc_2_Y``, then users can be reasonably confident that this wheel
|
||
will work in any real-world linux-based python environment that uses
|
||
``glibc 2.Y`` or later and matches the other wheel compatibility tags.
|
||
For example, this includes making sure that the wheel only uses symbols that
|
||
are available in the oldest supported glibc, and doesn't rely on the system to
|
||
provide any libraries that aren't universally available.
|
||
|
||
One of the central points of this PEP is to move away from defining each
|
||
compatibility profile in its own PEP.
|
||
In part, this is to acknowledge that the details of compatibility profiles
|
||
evolve over time as the Linux distribution landscape changes and as we learn
|
||
more about real-world compatibility pitfalls.
|
||
For instance, Fedora 30 `removed <https://github.com/pypa/manylinux/issues/305>`__
|
||
``libcrypt.so.1``, which both ``manylinux1`` and ``manylinux2010`` previously
|
||
allowed wheels to externally link.
|
||
Auditwheel and the manylinux build images will be updated to avoid new wheels
|
||
relying on this as an external library.
|
||
|
||
As with the previous manylinux tags, required libraries which are not on
|
||
the whitelist will need to be bundled into the wheel.
|
||
|
||
Building compatible wheels
|
||
--------------------------
|
||
|
||
For each profile defined on https://packaging.python.org/, we plan to provide
|
||
a canonical build environment, such as a Docker image, available for people to
|
||
build wheels for that profile.
|
||
People can build in other environments, so long as the
|
||
resulting wheels can be verified by auditwheel, but the canonical environments
|
||
hopefully provide an easy answer for most packages.
|
||
|
||
The definition of a new profile may well precede the construction of its
|
||
build environment; it's not expected that the definition in auditwheel
|
||
is held up until a corresponding environment is ready to use.
|
||
|
||
Verification on upload
|
||
----------------------
|
||
|
||
In the future, PyPI may begin using auditwheel to automatically validate
|
||
uploaded manylinux wheels, and reject wheels that it can't determine are
|
||
compliant. If PyPI does this, then it will mean that only wheels that have a
|
||
corresponding auditwheel profile can be distributed publicly.
|
||
|
||
If you need manylinux support for a platform that currently has no profile
|
||
in auditwheel, then you're encouraged to contribute a profile to auditwheel.
|
||
If that's not possible for some reason, then other tools can be used,
|
||
as long as you try to meet the same goal as auditwheel (i.e., the wheel should
|
||
work in all environments with the given glibc version and architecture) –
|
||
though you may not be able to upload these wheels to PyPI.
|
||
|
||
Platform compatibility
|
||
======================
|
||
|
||
The checks for a compatible platform on installation consist of a heuristic
|
||
and an optional override. The heuristic is that the platform is compatible if
|
||
and only if it has a version of glibc equal to or greater than that indicated
|
||
in the tag name.
|
||
|
||
The override is defined in an importable ``_manylinux`` module,
|
||
the same as already used for manylinux1 and manylinux2010 overrides.
|
||
For the new scheme, this module must define a function rather than an
|
||
attribute. ``manylinux_glibc_compatible(major, minor)`` takes two integers
|
||
for the glibc version number in the tag, and returns True, False or None.
|
||
If it is not defined or it returns None, the default heuristic is used.
|
||
|
||
The compatibility check could be implemented like this::
|
||
|
||
def is_manylinux_glibc_compatible(major, minor):
|
||
# Check for presence of _manylinux module
|
||
try:
|
||
import _manylinux
|
||
f = _manylinux.manylinux_glibc_compatible
|
||
except (ImportError, AttributeError):
|
||
# Fall through to heuristic check below
|
||
pass
|
||
else:
|
||
compat = f(major, minor)
|
||
if compat is not None:
|
||
return bool(compat)
|
||
|
||
# Check glibc version.
|
||
# PEP 513 contains an implementation of this function.
|
||
return have_compatible_glibc(major, minor)
|
||
|
||
The installer should also check that the platform is Linux and that the
|
||
architecture in the tag matches that of the running interpreter.
|
||
These checks are not illustrated here.
|
||
|
||
Next steps
|
||
==========
|
||
|
||
There is pressure to create a new manylinux tag to supersede manylinux2010.
|
||
If this PEP is accepted, a priority would be to define and support a
|
||
``manylinux_glibc_2_17`` profile, based on CentOS 7, equivalent to manylinux2014
|
||
in the previous numbering system.
|
||
This would be essentially the same process as defining manylinux2014, and
|
||
could build upon the research already started for this.
|
||
|
||
Beyond that, pip would need changes to allow it to recognise any
|
||
``manylinux_glibc_2_*`` tag and check platform compatibility, rather than
|
||
handling only a whitelist of specific tags.
|
||
|
||
Rejected alternatives
|
||
=====================
|
||
|
||
Early versions of this proposed specifying only that wheels using a given tag
|
||
must work on all mainstream platforms with glibc at or above the version
|
||
which the tag referred to. This would have left the library and symbol
|
||
whitelists as implementation details of auditwheel. This was felt to be
|
||
insufficient, so the proposal now includes an intent to document specific
|
||
compatibility profiles as well as defining them in auditwheel.
|
||
In keeping with the goal of reducing the work involved in defining a new tag,
|
||
it does not attempt to prescribe exactly how to create and update profiles:
|
||
the ways to do this should evolve with experience.
|