From ec26f82f58d4549d53f0790990ec2e5927e0a270 Mon Sep 17 00:00:00 2001 From: Mark Williams Date: Mon, 29 Jan 2018 00:53:52 -0800 Subject: [PATCH 1/7] Begin with PEP 513. --- pep-9999.txt | 641 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 641 insertions(+) create mode 100644 pep-9999.txt diff --git a/pep-9999.txt b/pep-9999.txt new file mode 100644 index 00000000000..06871c492f2 --- /dev/null +++ b/pep-9999.txt @@ -0,0 +1,641 @@ +PEP: 513 +Title: A Platform Tag for Portable Linux Built Distributions +Version: $Revision$ +Last-Modified: $Date$ +Author: Robert T. McGibbon , Nathaniel J. Smith +BDFL-Delegate: Nick Coghlan +Discussions-To: Distutils SIG +Status: Active +Type: Informational +Content-Type: text/x-rst +Created: 19-Jan-2016 +Post-History: 19-Jan-2016, 25-Jan-2016, 29-Jan-2016 +Resolution: https://mail.python.org/pipermail/distutils-sig/2016-January/028211.html + + +Abstract +======== + +This PEP proposes the creation of a new platform tag for Python package built +distributions, such as wheels, called ``manylinux1_{x86_64,i686}`` with +external dependencies limited to a standardized, restricted subset of +the Linux kernel and core userspace ABI. It proposes that PyPI support +uploading and distributing wheels with this platform tag, and that ``pip`` +support downloading and installing these packages on compatible platforms. + + +Rationale +========= + +Currently, distribution of binary Python extensions for Windows and OS X is +straightforward. Developers and packagers build wheels [1]_ [2]_, which are +assigned platform tags such as ``win32`` or ``macosx_10_6_intel``, and upload +these wheels to PyPI. Users can download and install these wheels using tools +such as ``pip``. + +For Linux, the situation is much more delicate. In general, compiled Python +extension modules built on one Linux distribution will not work on other Linux +distributions, or even on different machines running the same Linux +distribution with different system libraries installed. + +Build tools using PEP 425 platform tags [3]_ do not track information about the +particular Linux distribution or installed system libraries, and instead assign +all wheels the too-vague ``linux_i686`` or ``linux_x86_64`` tags. Because of +this ambiguity, there is no expectation that ``linux``-tagged built +distributions compiled on one machine will work properly on another, and for +this reason, PyPI has not permitted the uploading of wheels for Linux. + +It would be ideal if wheel packages could be compiled that would work on *any* +linux system. But, because of the incredible diversity of Linux systems -- from +PCs to Android to embedded systems with custom libcs -- this cannot +be guaranteed in general. + +Instead, we define a standard subset of the kernel+core userspace ABI that, +in practice, is compatible enough that packages conforming to this standard +will work on *many* linux systems, including essentially all of the desktop +and server distributions in common use. We know this because there are +companies who have been distributing such widely-portable pre-compiled Python +extension modules for Linux -- e.g. Enthought with Canopy [4]_ and Continuum +Analytics with Anaconda [5]_. + +Building on the compatibility lessons learned from these companies, we thus +define a baseline ``manylinux1`` platform tag for use by binary Python +wheels, and introduce the implementation of preliminary tools to aid in the +construction of these ``manylinux1`` wheels. + + +Key Causes of Inter-Linux Binary Incompatibility +================================================ + +To properly define a standard that will guarantee that wheel packages meeting +this specification will operate on *many* linux platforms, it is necessary to +understand the root causes which often prevent portability of pre-compiled +binaries on Linux. The two key causes are dependencies on shared libraries +which are not present on users' systems, and dependencies on particular +versions of certain core libraries like ``glibc``. + + +External Shared Libraries +------------------------- + +Most desktop and server linux distributions come with a system package manager +(examples include ``APT`` on Debian-based systems, ``yum`` on +``RPM``-based systems, and ``pacman`` on Arch linux) that manages, among other +responsibilities, the installation of shared libraries installed to system +directories such as ``/usr/lib``. Most non-trivial Python extensions will depend +on one or more of these shared libraries, and thus function properly only on +systems where the user has the proper libraries (and the proper +versions thereof), either installed using their package manager, or installed +manually by setting certain environment variables such as ``LD_LIBRARY_PATH`` +to notify the runtime linker of the location of the depended-upon shared +libraries. + + +Versioning of Core Shared Libraries +----------------------------------- + +Even if the developers a Python extension module wish to use no +external shared libraries, the modules will generally have a dynamic runtime +dependency on the GNU C library, ``glibc``. While it is possible, statically +linking ``glibc`` is usually a bad idea because certain important C functions +like ``dlopen()`` cannot be called from code that statically links ``glibc``. A +runtime shared library dependency on a system-provided ``glibc`` is unavoidable +in practice. + +The maintainers of the GNU C library follow a strict symbol versioning scheme +for backward compatibility. This ensures that binaries compiled against an older +version of ``glibc`` can run on systems that have a newer ``glibc``. The +opposite is generally not true -- binaries compiled on newer Linux +distributions tend to rely upon versioned functions in ``glibc`` that are not +available on older systems. + +This generally prevents wheels compiled on the latest Linux distributions +from being portable. + + +The ``manylinux1`` policy +========================= + +For these reasons, to achieve broad portability, Python wheels + +* should depend only on an extremely limited set of external shared + libraries; and +* should depend only on "old" symbol versions in those external shared + libraries; and +* should depend only on a widely-compatible kernel ABI. + +To be eligible for the ``manylinux1`` platform tag, a Python wheel must +therefore both (a) contain binary executables and compiled code that links +*only* to libraries with SONAMEs +included in the following list: :: + + libpanelw.so.5 + libncursesw.so.5 + libgcc_s.so.1 + libstdc++.so.6 + libm.so.6 + libdl.so.2 + librt.so.1 + libcrypt.so.1 + libc.so.6 + libnsl.so.1 + libutil.so.1 + libpthread.so.0 + libresolv.so.2 + libX11.so.6 + libXext.so.6 + libXrender.so.1 + libICE.so.6 + libSM.so.6 + libGL.so.1 + libgobject-2.0.so.0 + libgthread-2.0.so.0 + libglib-2.0.so.0 + +and, (b) work on a stock CentOS 5.11 [6]_ system that contains the system +package manager's provided versions of these libraries. + +Because CentOS 5 is only available for x86_64 and i686 architectures, +these are the only architectures currently supported by the ``manylinux1`` +policy. + +On Debian-based systems, these libraries are provided by the packages :: + + libncurses5 libgcc1 libstdc++6 libc6 libx11-6 libxext6 + libxrender1 libice6 libsm6 libgl1-mesa-glx libglib2.0-0 + +On RPM-based systems, these libraries are provided by the packages :: + + ncurses libgcc libstdc++ glibc libXext libXrender + libICE libSM mesa-libGL glib2 + +This list was compiled by checking the external shared library dependencies of +the Canopy [4]_ and Anaconda [5]_ distributions, which both include a wide array +of the most popular Python modules and have been confirmed in practice to work +across a wide swath of Linux systems in the wild. + +Many of the permitted system libraries listed above use symbol versioning +schemes for backward compatibility. The latest symbol versions provided with +the CentOS 5.11 versions of these libraries are: :: + + GLIBC_2.5 + CXXABI_3.4.8 + GLIBCXX_3.4.9 + GCC_4.2.0 + +Therefore, as a consequence of requirement (b), any wheel that depends on +versioned symbols from the above shared libraries may depend only on symbols +with the following versions: :: + + GLIBC <= 2.5 + CXXABI <= 3.4.8 + GLIBCXX <= 3.4.9 + GCC <= 4.2.0 + +These recommendations are the outcome of the relevant discussions in January +2016 [7]_, [8]_. + +Note that in our recommendations below, we do not suggest that ``pip`` +or PyPI should attempt to check for and enforce the details of this +policy (just as they don't check for and enforce the details of +existing platform tags like ``win32``). The text above is provided (a) +as advice to package builders, and (b) as a method for allocating +blame if a given wheel doesn't work on some system: if it satisfies +the policy above, then this is a bug in the spec or the installation +tool; if it does not satisfy the policy above, then it's a bug in the +wheel. One useful consequence of this approach is that it leaves open +the possibility of further updates and tweaks as we gain more +experience, e.g., we could have a "manylinux 1.1" policy which targets +the same systems and uses the same ``manylinux1`` platform tag (and +thus requires no further changes to ``pip`` or PyPI), but that adjusts +the list above to remove libraries that have turned out to be +problematic or add libraries that have turned out to be safe. + + +libpythonX.Y.so.1 +----------------- + +Note that ``libpythonX.Y.so.1`` is *not* on the list of libraries that +a ``manylinux1`` extension is allowed to link to. Explicitly linking +to ``libpythonX.Y.so.1`` is unnecessary in almost all cases: the way +ELF linking works, extension modules that are loaded into the +interpreter automatically get access to all of the interpreter's +symbols, regardless of whether or not the extension itself is +explicitly linked against libpython. Furthermore, explicit linking to +libpython creates problems in the common configuration where Python is +not built with ``--enable-shared``. In particular, on Debian and +Ubuntu systems, ``apt install pythonX.Y`` does not even install +``libpythonX.Y.so.1``, meaning that any wheel that *did* depend on +``libpythonX.Y.so.1`` could fail to import. + +There is one situation where extensions that are linked in this way +can fail to work: if a host program (e.g., ``apache2``) uses +``dlopen()`` to load a module (e.g., ``mod_wsgi``) that embeds the +CPython interpreter, and the host program does *not* pass the +``RTLD_GLOBAL`` flag to ``dlopen()``, then the embedded CPython will +be unable to load any extension modules that do not themselves link +explicitly to ``libpythonX.Y.so.1``. Fortunately, ``apache2`` *does* +set the ``RTLD_GLOBAL`` flag, as do all the other programs that +embed-CPython-via-a-dlopened-plugin that we could locate, so this does +not seem to be a serious problem in practice. The incompatibility with +Debian/Ubuntu is more of an issue than the theoretical incompatibility +with a rather obscure corner case. + +This is a rather complex and subtle issue that extends beyond +the scope of ``manylinux1``; for more discussion see: [9]_, [10]_, +[11]_. + + +UCS-2 vs UCS-4 builds +--------------------- + +All versions of CPython 2.x, plus CPython 3.0-3.2 inclusive, can be +built in two ABI-incompatible modes: builds using the +``--enable-unicode=ucs2`` configure flag store Unicode data in UCS-2 +(or really UTF-16) format, while builds using the +``--enable-unicode=ucs4`` configure flag store Unicode data in +UCS-4. (CPython 3.3 and greater use a different storage method that +always supports UCS-4.) If we want to make sure ``ucs2`` wheels don't +get installed into ``ucs4`` CPythons and vice-versa, then something +must be done. + +An earlier version of this PEP included a requirement that +``manylinux1`` wheels targeting these older CPython versions should +always use the ``ucs4`` ABI. But then, in between the PEP's initial +acceptance and its implementation, ``pip`` and ``wheel`` gained +first-class support for tracking and checking this aspect of ABI +compatibility for the relevant CPython versions, which is a better +solution. So we now allow the ``manylinux1`` platform tags to be used +in combination with any ABI tag. However, to maintain compatibility it +is crucial to ensure that all ``manylinux1`` wheels include a +non-trivial abi tag. For example, a wheel built against a ``ucs4`` +CPython might have a name like:: + + PKG-VERSION-cp27-cp27mu-manylinux1_x86_64.whl + ^^^^^^ Good! + +While a wheel built against the ``ucs2`` ABI might have a name like:: + + PKG-VERSION-cp27-cp27m-manylinux1_x86_64.whl + ^^^^^ Okay! + +But you should never have a wheel with a name like:: + + PKG-VERSION-cp27-none-manylinux1_x86_64.whl + ^^^^ BAD! Don't do this! + +This wheel claims to be simultaneously compatible with *both* ucs2 and +ucs4 builds, which is bad. + +We note for information that the ``ucs4`` ABI appears to be much more +widespread among Linux CPython distributors. + + +fpectl builds vs. no fpectl builds +---------------------------------- + +All extant versions of CPython can be built either with or without the +``--with-fpectl`` flag to ``configure``. It turns out that this +changes the CPython ABI: extensions that are built against a +no-``fpectl`` CPython are always compatible with yes-``fpectl`` +CPython, but the reverse is not necessarily true. (Symptom: errors at +import time complaining about ``undefined symbol: PyFPE_jbuf``.) See: +[16]_. + +For maximum compatibility, therefore, the CPython used to build +manylinux1 wheels must be compiled *without* the ``--with-fpectl`` +flag, and manylinux1 extensions must not reference the symbol +``PyFPE_jbuf``. + + +Compilation of Compliant Wheels +=============================== + +The way glibc, libgcc, and libstdc++ manage their symbol versioning +means that in practice, the compiler toolchains that most developers +use to do their daily work are incapable of building +``manylinux1``-compliant wheels. Therefore, we do not attempt to change +the default behavior of ``pip wheel`` / ``bdist_wheel``: they will +continue to generate regular ``linux_*`` platform tags, and developers +who wish to use them to generate ``manylinux1``-tagged wheels will +have to change the tag as a second post-processing step. + +To support the compilation of wheels meeting the ``manylinux1`` standard, we +provide initial drafts of two tools. + + +Docker Image +------------ + +The first tool is a Docker image based on CentOS 5.11, which is recommended as +an easy to use self-contained build box for compiling ``manylinux1`` wheels +[12]_. Compiling on a more recently-released linux distribution will generally +introduce dependencies on too-new versioned symbols. The image comes with a +full compiler suite installed (``gcc``, ``g++``, and ``gfortran`` 4.8.2) as +well as the latest releases of Python and ``pip``. + +Auditwheel +---------- + +The second tool is a command line executable called ``auditwheel`` [13]_ that +may aid in package maintainers in dealing with third-party external +dependencies. + +There are at least three methods for building wheels that use third-party +external libraries in a way that meets the above policy. + +1. The third-party libraries can be statically linked. +2. The third-party shared libraries can be distributed in + separate packages on PyPI which are depended upon by the wheel. +3. The third-party shared libraries can be bundled inside the wheel + libraries, linked with a relative path. + +All of these are valid option which may be effectively used by different +packages and communities. Statically linking generally requires +package-specific modifications to the build system, and distributing +third-party dependencies on PyPI may require some coordination of the +community of users of the package. + +As an often-automatic alternative to these options, we introduce ``auditwheel``. +The tool inspects all of the ELF files inside a wheel to check for +dependencies on versioned symbols or external shared libraries, and verifies +conformance with the ``manylinux1`` policy. This includes the ability to add +the new platform tag to conforming wheels. More importantly, ``auditwheel`` has +the ability to automatically modify wheels that depend on external shared +libraries by copying those shared libraries from the system into the wheel +itself, and modifying the appropriate ``RPATH`` entries such that these +libraries will be picked up at runtime. This accomplishes a similar result as +if the libraries had been statically linked without requiring changes to the +build system. Packagers are advised that bundling, like static linking, may +implicate copyright concerns. + + +Bundled Wheels on Linux +======================= + +While we acknowledge many approaches for dealing with third-party library +dependencies within ``manylinux1`` wheels, we recognize that the ``manylinux1`` +policy encourages bundling external dependencies, a practice +which runs counter to the package management policies of many linux +distributions' system package managers [14]_, [15]_. The primary purpose of +this is cross-distro compatibility. Furthermore, ``manylinux1`` wheels on PyPI +occupy a different niche than the Python packages available through the +system package manager. + +The decision in this PEP to encourage departure from general Linux distribution +unbundling policies is informed by the following concerns: + +1. In these days of automated continuous integration and deployment + pipelines, publishing new versions and updating dependencies is easier + than it was when those policies were defined. +2. ``pip`` users remain free to use the ``"--no-binary"`` option if they want + to force local builds rather than using pre-built wheel files. +3. The popularity of modern container based deployment and "immutable + infrastructure" models involve substantial bundling at the application + layer anyway. +4. Distribution of bundled wheels through PyPI is currently the norm for + Windows and OS X. +5. This PEP doesn't rule out the idea of offering more targeted binaries for + particular Linux distributions in the future. + +The model described in this PEP is most ideally suited for cross-platform +Python packages, because it means they can reuse much of the +work that they're already doing to make static Windows and OS X wheels. We +recognize that it is less optimal for Linux-specific packages that might +prefer to interact more closely with Linux's unique package management +functionality and only care about targeting a small set of particular distos. + + +Security Implications +--------------------- + +One of the advantages of dependencies on centralized libraries in Linux is +that bugfixes and security updates can be deployed system-wide, and +applications which depend on these libraries will automatically feel the +effects of these patches when the underlying libraries are updated. This can +be particularly important for security updates in packages engaged in +communication across the network or cryptography. + +``manylinux1`` wheels distributed through PyPI that bundle security-critical +libraries like OpenSSL will thus assume responsibility for prompt updates in +response disclosed vulnerabilities and patches. This closely parallels the +security implications of the distribution of binary wheels on Windows that, +because the platform lacks a system package manager, generally bundle their +dependencies. In particular, because it lacks a stable ABI, OpenSSL cannot be +included in the ``manylinux1`` profile. + + + +Platform Detection for Installers +================================= + +Above, we defined what it means for a *wheel* to be +``manylinux1``-compatible. Here we discuss what it means for a *Python +installation* to be ``manylinux1``-compatible. In particular, this is +important for tools like ``pip`` to know when deciding whether or not +they should consider ``manylinux1``-tagged wheels for installation. + +Because the ``manylinux1`` profile is already known to work for the +many thousands of users of popular commercial Python distributions, we +suggest that installation tools should error on the side of assuming +that a system *is* compatible, unless there is specific reason to +think otherwise. + +We know of four main sources of potential incompatibility that are +likely to arise in practice: + +* Eventually, in the future, there may exist distributions that break + compatibility with this profile (e.g., if one of the libraries in + the profile changes its ABI in a backwards-incompatible way) +* A linux distribution that is too old (e.g. RHEL 4) +* A linux distribution that does not use ``glibc`` (e.g. Alpine Linux, which is + based on musl ``libc``, or Android) + +To address these we propose a two-pronged +approach. To handle potential future incompatibilities, we standardize +a mechanism for a Python distributor to signal that a particular +Python install definitely is or is not compatible with ``manylinux1``: +this is done by installing a module named ``_manylinux``, and setting +its ``manylinux1_compatible`` attribute. We do not propose adding any +such module to the standard library -- this is merely a well-known +name by which distributors and installation tools can +rendezvous. However, if a distributor does add this module, *they +should add it to the standard library* rather than to a +``site-packages/`` directory, because the standard library is +inherited by virtualenvs (which we want), and ``site-packages/`` in +general is not. + +Then, to handle the last two cases for existing Python +distributions, we suggest a simple and reliable method to check for +the presence and version of ``glibc`` (basically using it as a "clock" +for the overall age of the distribution). + +Specifically, the algorithm we propose is:: + + def is_manylinux1_compatible(): + # Only Linux, and only x86-64 / i686 + from distutils.util import get_platform + 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 + +**Rejected alternatives:** We also considered using a configuration +file, e.g. ``/etc/python/compatibility.cfg``. The problem with this is +that a single filesystem might contain many different interpreter +environments, each with their own ABI profile -- the ``manylinux1`` +compatibility of a system-installed x86_64 CPython might not tell us +much about the ``manylinux1`` compatibility of a user-installed i686 +PyPy. Locating this configuration information within the Python +environment itself ensures that it remains attached to the correct +binary, and dramatically simplifies lookup code. + +We also considered using a more elaborate structure, like a list of +all platform tags that should be considered compatible, together with +their preference ordering, for example: ``_binary_compat.compatible = +["manylinux1_x86_64", "centos5_x86_64", "linux_x86_64"]``. However, +this introduces several complications. For example, we want to be able +to distinguish between the state of "doesn't support ``manylinux1``" +(or eventually ``manylinux2``, etc.) versus "doesn't specify either +way whether it supports ``manylinux1``", which is not entirely obvious +in the above representation; and, it's not at all clear what features +are really needed vis a vis preference ordering given that right now +the only possible platform tags are ``manylinux1`` and ``linux``. So +we're deferring a more complete solution here for a separate PEP, when +/ if Linux gets more platform tags. + +For the library compatibility check, we also considered much more +elaborate checks (e.g. checking the kernel version, searching for and +checking the versions of all the individual libraries listed in the +``manylinux1`` profile, etc.), but ultimately decided that this would +be more likely to introduce confusing bugs than actually help the +user. (For example: different distributions vary in where they +actually put these libraries, and if our checking code failed to use +the correct path search then it could easily return incorrect +answers.) + + + +PyPI Support +============ + +PyPI should permit wheels containing the ``manylinux1`` platform tag to be +uploaded. PyPI should not attempt to formally verify that wheels containing +the ``manylinux1`` platform tag adhere to the ``manylinux1`` policy described +in this document. This verification tasks should be left to other tools, like +``auditwheel``, that are developed separately. + + +Rejected Alternatives +===================== + +One alternative would be to provide separate platform tags for each Linux +distribution (and each version thereof), e.g. ``RHEL6``, ``ubuntu14_10``, +``debian_jessie``, etc. Nothing in this proposal rules out the possibility of +adding such platform tags in the future, or of further extensions to wheel +metadata that would allow wheels to declare dependencies on external +system-installed packages. However, such extensions would require substantially +more work than this proposal, and still might not be appreciated by package +developers who would prefer not to have to maintain multiple build environments +and build multiple wheels in order to cover all the common Linux distributions. +Therefore, we consider such proposals to be out-of-scope for this PEP. + + +Future updates +============== + +We anticipate that at some point in the future there will be a +``manylinux2`` specifying a more modern baseline environment (perhaps +based on CentOS 6), and someday a ``manylinux3`` and so forth, but we +defer specifying these until we have more experience with the initial +``manylinux1`` proposal. + + +References +========== + +.. [1] PEP 427 -- The Wheel Binary Package Format 1.0 + (https://www.python.org/dev/peps/pep-0427/) +.. [2] PEP 491 -- The Wheel Binary Package Format 1.9 + (https://www.python.org/dev/peps/pep-0491/) +.. [3] PEP 425 -- Compatibility Tags for Built Distributions + (https://www.python.org/dev/peps/pep-0425/) +.. [4] Enthought Canopy Python Distribution + (https://store.enthought.com/downloads/) +.. [5] Continuum Analytics Anaconda Python Distribution + (https://www.continuum.io/downloads) +.. [6] CentOS 5.11 Release Notes + (https://wiki.centos.org/Manuals/ReleaseNotes/CentOS5.11) +.. [7] manylinux-discuss mailing list discussion + (https://groups.google.com/forum/#!topic/manylinux-discuss/-4l3rrjfr9U) +.. [8] distutils-sig discussion + (https://mail.python.org/pipermail/distutils-sig/2016-January/027997.html) +.. [9] distutils-sig discussion + (https://mail.python.org/pipermail/distutils-sig/2016-February/028275.html) +.. [10] github issue discussion + (https://github.com/pypa/manylinux/issues/30) +.. [11] python bug tracker discussion + (https://bugs.python.org/issue21536) +.. [12] manylinux1 docker images + (Source: https://github.com/pypa/manylinux; + x86-64: https://quay.io/repository/pypa/manylinux1_x86_64; + x86-32: https://quay.io/repository/pypa/manylinux1_i686) +.. [13] auditwheel tool + (https://pypi.python.org/pypi/auditwheel) +.. [14] Fedora Bundled Software Policy + (https://fedoraproject.org/wiki/Bundled_Software_policy) +.. [15] Debian Policy Manual -- 4.13: Convenience copies of code + (https://www.debian.org/doc/debian-policy/ch-source.html#s-embeddedfiles) +.. [16] numpy bug report: + https://github.com/numpy/numpy/issues/8415#issuecomment-269095235 + + +Copyright +========= + +This document has been placed into the public domain. + +.. + Local Variables: + mode: indented-text + indent-tabs-mode: nil + sentence-end-double-space: t + fill-column: 70 + coding: utf-8 + End: From 990c2636dcd70f53f795910ee2f7cbb7ca8d84d3 Mon Sep 17 00:00:00 2001 From: Mark Williams Date: Tue, 30 Jan 2018 13:02:34 -0800 Subject: [PATCH 2/7] Initial draft of manylinux2 PEP. --- pep-9999.txt | 864 +++++++++++++++++---------------------------------- 1 file changed, 281 insertions(+), 583 deletions(-) diff --git a/pep-9999.txt b/pep-9999.txt index 06871c492f2..72f7f7616bd 100644 --- a/pep-9999.txt +++ b/pep-9999.txt @@ -1,629 +1,327 @@ -PEP: 513 -Title: A Platform Tag for Portable Linux Built Distributions +PEP: 9999 +Title: The manylinux2 Platform Tag Version: $Revision$ Last-Modified: $Date$ -Author: Robert T. McGibbon , Nathaniel J. Smith +Author: Mark Williams BDFL-Delegate: Nick Coghlan Discussions-To: Distutils SIG Status: Active Type: Informational Content-Type: text/x-rst -Created: 19-Jan-2016 -Post-History: 19-Jan-2016, 25-Jan-2016, 29-Jan-2016 -Resolution: https://mail.python.org/pipermail/distutils-sig/2016-January/028211.html +Created: +Post-History: +Resolution: Abstract ======== -This PEP proposes the creation of a new platform tag for Python package built -distributions, such as wheels, called ``manylinux1_{x86_64,i686}`` with -external dependencies limited to a standardized, restricted subset of -the Linux kernel and core userspace ABI. It proposes that PyPI support -uploading and distributing wheels with this platform tag, and that ``pip`` -support downloading and installing these packages on compatible platforms. - +This PEP proposes the creation of a ``manylinux2`` platform tag to +succeed the ``manylinux1`` tag introduced by PEP 513 [1]_. It also +proposes that PyPI and ``pip`` both be updated to support uploading, +downloading, and installing ``manylinux2`` distributions on compatible +platforms. Rationale ========= -Currently, distribution of binary Python extensions for Windows and OS X is -straightforward. Developers and packagers build wheels [1]_ [2]_, which are -assigned platform tags such as ``win32`` or ``macosx_10_6_intel``, and upload -these wheels to PyPI. Users can download and install these wheels using tools -such as ``pip``. - -For Linux, the situation is much more delicate. In general, compiled Python -extension modules built on one Linux distribution will not work on other Linux -distributions, or even on different machines running the same Linux -distribution with different system libraries installed. - -Build tools using PEP 425 platform tags [3]_ do not track information about the -particular Linux distribution or installed system libraries, and instead assign -all wheels the too-vague ``linux_i686`` or ``linux_x86_64`` tags. Because of -this ambiguity, there is no expectation that ``linux``-tagged built -distributions compiled on one machine will work properly on another, and for -this reason, PyPI has not permitted the uploading of wheels for Linux. - -It would be ideal if wheel packages could be compiled that would work on *any* -linux system. But, because of the incredible diversity of Linux systems -- from -PCs to Android to embedded systems with custom libcs -- this cannot -be guaranteed in general. - -Instead, we define a standard subset of the kernel+core userspace ABI that, -in practice, is compatible enough that packages conforming to this standard -will work on *many* linux systems, including essentially all of the desktop -and server distributions in common use. We know this because there are -companies who have been distributing such widely-portable pre-compiled Python -extension modules for Linux -- e.g. Enthought with Canopy [4]_ and Continuum -Analytics with Anaconda [5]_. - -Building on the compatibility lessons learned from these companies, we thus -define a baseline ``manylinux1`` platform tag for use by binary Python -wheels, and introduce the implementation of preliminary tools to aid in the -construction of these ``manylinux1`` wheels. - - -Key Causes of Inter-Linux Binary Incompatibility -================================================ - -To properly define a standard that will guarantee that wheel packages meeting -this specification will operate on *many* linux platforms, it is necessary to -understand the root causes which often prevent portability of pre-compiled -binaries on Linux. The two key causes are dependencies on shared libraries -which are not present on users' systems, and dependencies on particular -versions of certain core libraries like ``glibc``. - - -External Shared Libraries -------------------------- - -Most desktop and server linux distributions come with a system package manager -(examples include ``APT`` on Debian-based systems, ``yum`` on -``RPM``-based systems, and ``pacman`` on Arch linux) that manages, among other -responsibilities, the installation of shared libraries installed to system -directories such as ``/usr/lib``. Most non-trivial Python extensions will depend -on one or more of these shared libraries, and thus function properly only on -systems where the user has the proper libraries (and the proper -versions thereof), either installed using their package manager, or installed -manually by setting certain environment variables such as ``LD_LIBRARY_PATH`` -to notify the runtime linker of the location of the depended-upon shared -libraries. - - -Versioning of Core Shared Libraries ------------------------------------ - -Even if the developers a Python extension module wish to use no -external shared libraries, the modules will generally have a dynamic runtime -dependency on the GNU C library, ``glibc``. While it is possible, statically -linking ``glibc`` is usually a bad idea because certain important C functions -like ``dlopen()`` cannot be called from code that statically links ``glibc``. A -runtime shared library dependency on a system-provided ``glibc`` is unavoidable -in practice. - -The maintainers of the GNU C library follow a strict symbol versioning scheme -for backward compatibility. This ensures that binaries compiled against an older -version of ``glibc`` can run on systems that have a newer ``glibc``. The -opposite is generally not true -- binaries compiled on newer Linux -distributions tend to rely upon versioned functions in ``glibc`` that are not -available on older systems. - -This generally prevents wheels compiled on the latest Linux distributions -from being portable. - - -The ``manylinux1`` policy +True to its name, the ``manylinux1`` platform tag has made the +installation of binary extension modules a reality on many Linux +systems. Libraries like ``cryptography`` [2]_ and ``numpy`` [3]_ are +more accessible to Python developers now that their installation on +common architectures does not depend on fragile development +environments and build toolchains. + +``manylinux1`` wheels achieve their portability by allowing the +extension modules they contain to link against only a small set of +system-level shared libraries that export versioned symbols old enough +to benefit from backwards-compatibility policies. Extension modules +in a ``manylinux1`` wheel that rely on ``glibc``, for example, must be +built against version 2.5 or earlier; they may then be run systems +that provide more recent ``glibc`` version that still export the +required symbols at version 2.5. + +PEP 513 drew its whitelisted shared libraries and their symbol +versions from CentOS 5.11, which was the oldest supported CentOS +release at the time of its writing. Unfortunately, CentOS 5.11 +reached its end-of-life on March 31st, 2017 with a clear warning +against its continued use. [4]_ No further updates, such as security +patches, will be made available. This means that its packages will +remain at obsolete versions that hamper the efforts of Python software +packagers who use the ``manylinux1`` Docker image. + +CentOS 6.9 is now the oldest supported CentOS release, and will +receive maintenance updates through November 30th, 2020. [5]_ We +propose that a new PEP 425-style [6]_ platform tag called +``manylinux2`` be derived from CentOS 6.9 and that the ``manylinux`` +toolchain, PyPI, and ``pip`` be updated to support it. + + +The ``manylinux2`` policy ========================= -For these reasons, to achieve broad portability, Python wheels - -* should depend only on an extremely limited set of external shared - libraries; and -* should depend only on "old" symbol versions in those external shared - libraries; and -* should depend only on a widely-compatible kernel ABI. - -To be eligible for the ``manylinux1`` platform tag, a Python wheel must -therefore both (a) contain binary executables and compiled code that links -*only* to libraries with SONAMEs -included in the following list: :: - - libpanelw.so.5 - libncursesw.so.5 - libgcc_s.so.1 - libstdc++.so.6 - libm.so.6 - libdl.so.2 - librt.so.1 - libcrypt.so.1 - libc.so.6 - libnsl.so.1 - libutil.so.1 - libpthread.so.0 - libresolv.so.2 - libX11.so.6 - libXext.so.6 - libXrender.so.1 - libICE.so.6 - libSM.so.6 - libGL.so.1 - libgobject-2.0.so.0 - libgthread-2.0.so.0 - libglib-2.0.so.0 - -and, (b) work on a stock CentOS 5.11 [6]_ system that contains the system -package manager's provided versions of these libraries. - -Because CentOS 5 is only available for x86_64 and i686 architectures, -these are the only architectures currently supported by the ``manylinux1`` -policy. - -On Debian-based systems, these libraries are provided by the packages :: - - libncurses5 libgcc1 libstdc++6 libc6 libx11-6 libxext6 - libxrender1 libice6 libsm6 libgl1-mesa-glx libglib2.0-0 - -On RPM-based systems, these libraries are provided by the packages :: - - ncurses libgcc libstdc++ glibc libXext libXrender - libICE libSM mesa-libGL glib2 - -This list was compiled by checking the external shared library dependencies of -the Canopy [4]_ and Anaconda [5]_ distributions, which both include a wide array -of the most popular Python modules and have been confirmed in practice to work -across a wide swath of Linux systems in the wild. - -Many of the permitted system libraries listed above use symbol versioning -schemes for backward compatibility. The latest symbol versions provided with -the CentOS 5.11 versions of these libraries are: :: - - GLIBC_2.5 - CXXABI_3.4.8 - GLIBCXX_3.4.9 - GCC_4.2.0 - -Therefore, as a consequence of requirement (b), any wheel that depends on -versioned symbols from the above shared libraries may depend only on symbols -with the following versions: :: - - GLIBC <= 2.5 - CXXABI <= 3.4.8 - GLIBCXX <= 3.4.9 - GCC <= 4.2.0 - -These recommendations are the outcome of the relevant discussions in January -2016 [7]_, [8]_. - -Note that in our recommendations below, we do not suggest that ``pip`` -or PyPI should attempt to check for and enforce the details of this -policy (just as they don't check for and enforce the details of -existing platform tags like ``win32``). The text above is provided (a) -as advice to package builders, and (b) as a method for allocating -blame if a given wheel doesn't work on some system: if it satisfies -the policy above, then this is a bug in the spec or the installation -tool; if it does not satisfy the policy above, then it's a bug in the -wheel. One useful consequence of this approach is that it leaves open -the possibility of further updates and tweaks as we gain more -experience, e.g., we could have a "manylinux 1.1" policy which targets -the same systems and uses the same ``manylinux1`` platform tag (and -thus requires no further changes to ``pip`` or PyPI), but that adjusts -the list above to remove libraries that have turned out to be -problematic or add libraries that have turned out to be safe. - - -libpythonX.Y.so.1 ------------------ - -Note that ``libpythonX.Y.so.1`` is *not* on the list of libraries that -a ``manylinux1`` extension is allowed to link to. Explicitly linking -to ``libpythonX.Y.so.1`` is unnecessary in almost all cases: the way -ELF linking works, extension modules that are loaded into the -interpreter automatically get access to all of the interpreter's -symbols, regardless of whether or not the extension itself is -explicitly linked against libpython. Furthermore, explicit linking to -libpython creates problems in the common configuration where Python is -not built with ``--enable-shared``. In particular, on Debian and -Ubuntu systems, ``apt install pythonX.Y`` does not even install -``libpythonX.Y.so.1``, meaning that any wheel that *did* depend on -``libpythonX.Y.so.1`` could fail to import. - -There is one situation where extensions that are linked in this way -can fail to work: if a host program (e.g., ``apache2``) uses -``dlopen()`` to load a module (e.g., ``mod_wsgi``) that embeds the -CPython interpreter, and the host program does *not* pass the -``RTLD_GLOBAL`` flag to ``dlopen()``, then the embedded CPython will -be unable to load any extension modules that do not themselves link -explicitly to ``libpythonX.Y.so.1``. Fortunately, ``apache2`` *does* -set the ``RTLD_GLOBAL`` flag, as do all the other programs that -embed-CPython-via-a-dlopened-plugin that we could locate, so this does -not seem to be a serious problem in practice. The incompatibility with -Debian/Ubuntu is more of an issue than the theoretical incompatibility -with a rather obscure corner case. - -This is a rather complex and subtle issue that extends beyond -the scope of ``manylinux1``; for more discussion see: [9]_, [10]_, -[11]_. - - -UCS-2 vs UCS-4 builds ---------------------- - -All versions of CPython 2.x, plus CPython 3.0-3.2 inclusive, can be -built in two ABI-incompatible modes: builds using the -``--enable-unicode=ucs2`` configure flag store Unicode data in UCS-2 -(or really UTF-16) format, while builds using the -``--enable-unicode=ucs4`` configure flag store Unicode data in -UCS-4. (CPython 3.3 and greater use a different storage method that -always supports UCS-4.) If we want to make sure ``ucs2`` wheels don't -get installed into ``ucs4`` CPythons and vice-versa, then something -must be done. - -An earlier version of this PEP included a requirement that -``manylinux1`` wheels targeting these older CPython versions should -always use the ``ucs4`` ABI. But then, in between the PEP's initial -acceptance and its implementation, ``pip`` and ``wheel`` gained -first-class support for tracking and checking this aspect of ABI -compatibility for the relevant CPython versions, which is a better -solution. So we now allow the ``manylinux1`` platform tags to be used -in combination with any ABI tag. However, to maintain compatibility it -is crucial to ensure that all ``manylinux1`` wheels include a -non-trivial abi tag. For example, a wheel built against a ``ucs4`` -CPython might have a name like:: - - PKG-VERSION-cp27-cp27mu-manylinux1_x86_64.whl - ^^^^^^ Good! - -While a wheel built against the ``ucs2`` ABI might have a name like:: - - PKG-VERSION-cp27-cp27m-manylinux1_x86_64.whl - ^^^^^ Okay! - -But you should never have a wheel with a name like:: - - PKG-VERSION-cp27-none-manylinux1_x86_64.whl - ^^^^ BAD! Don't do this! - -This wheel claims to be simultaneously compatible with *both* ucs2 and -ucs4 builds, which is bad. - -We note for information that the ``ucs4`` ABI appears to be much more -widespread among Linux CPython distributors. - - -fpectl builds vs. no fpectl builds ----------------------------------- - -All extant versions of CPython can be built either with or without the -``--with-fpectl`` flag to ``configure``. It turns out that this -changes the CPython ABI: extensions that are built against a -no-``fpectl`` CPython are always compatible with yes-``fpectl`` -CPython, but the reverse is not necessarily true. (Symptom: errors at -import time complaining about ``undefined symbol: PyFPE_jbuf``.) See: -[16]_. - -For maximum compatibility, therefore, the CPython used to build -manylinux1 wheels must be compiled *without* the ``--with-fpectl`` -flag, and manylinux1 extensions must not reference the symbol -``PyFPE_jbuf``. - +The following criteria determine a ``linux`` wheel's eligibility for +the ``manylinux2`` tag: + +1. The wheel may only contain binary executables and shared objects + compiled for one of the two architectures supported by CentOS 6.9: + x86_64 or i686. [5]_ +2. The wheel's binary executables or shared objects may not link + against externally-provided libraries except those in the following + whitelist: :: + + libgcc_s.so.1 + libstdc++.so.6 + libm.so.6 + libdl.so.2 + librt.so.1 + libcrypt.so.1 + libc.so.6 + libnsl.so.1 + libutil.so.1 + libpthread.so.0 + libresolv.so.2 + libX11.so.6 + libXext.so.6 + libXrender.so.1 + libICE.so.6 + libSM.so.6 + libGL.so.1 + libgobject-2.0.so.0 + libgthread-2.0.so.0 + libglib-2.0.so.0 + + This list is identical to the externally-provided libraries + whitelisted for ``manylinux1``, minus ``libncursesw.so.5`` and + ``libpanelw.so.5``. [7]_ ``libpythonX.Y`` remains ineligible for + inclusion for the same reasons outlined in PEP 513. + + On Debian-based systems, these libraries are provided by the packages: + + ============ ======================================================= + Package Libraries + ============ ======================================================= + libc6 libdl.so.2, libresolv.so.2, librt.so.1, libc.so.6, + libpthread.so.0, libm.so.6, libutil.so.1, libcrypt.so.1, + libnsl.so.1 + libgcc1 libgcc_s.so.1 + libgl1 libGL.so.1 + libglib2.0-0 libgobject-2.0.so.0, libgthread-2.0.so.0, libglib-2.0.so.0 + libice6 libICE.so.6 + libsm6 libSM.so.6 + libstdc++6 libstdc++.so.6 + libx11-6 libX11.so.6 + libxext6 libXext.so.6 + libxrender1 libXrender.so.1 + ============ ======================================================= + + On RPM-based systems, they are provided by these packages: + + ============ ======================================================= + Package Libraries + ============ ======================================================= + glib2 libglib-2.0.so.0, libgthread-2.0.so.0, libgobject-2.0.so.0 + glibc libresolv.so.2, libutil.so.1, libnsl.so.1, librt.so.1, + libcrypt.so.1, libpthread.so.0, libdl.so.2, libm.so.6, + libc.so.6 + libICE libICE.so.6 + libX11 libX11.so.6 + libXext: libXext.so.6 + libXrender libXrender.so.1 + libgcc: libgcc_s.so.1 + libstdc++ libstdc++.so.6 + mesa libGL.so.1 + ============ ======================================================= + +3. If the wheel contains binary executables or shared objects linked + against any whitelisted libraries that also export versioned + symbols, they may only depend on the following maximum versions:: + + GLIBC_2.12 + CXXABI_1.3.3 + GLIBCXX_3.4.13 + GCC_4.3.0 + + As an example, ``manylinux2`` wheels may include binary artifacts + that require ``glibc`` symbols at version ``GLIBC_2.4``, because + this an earlier version than the maximum of ``GLIBC_2.12``. +4. If a wheel is built for any version of CPython 2 or CPython + versions 3.0 up to and including 3.2, it *must* include a CPython + ABI tag indicating its Unicode ABI. A ``manylinux2`` wheel built + against Python 2, then, must include either the ``cpy27mu`` tag + indicating it was built against an interpreter with the UCS-4 ABI + or the ``cpy27m`` tag indicating an interpeter with the UCS-2 + ABI. *[Citation for UCS ABI tags?]* +5. A wheel *must not* require the ``PyFPE_jbuf`` symbol. This is + achieved by building it against a Python compiled *without* the + ``--with-fpectl`` ``configure`` flag. Compilation of Compliant Wheels =============================== -The way glibc, libgcc, and libstdc++ manage their symbol versioning -means that in practice, the compiler toolchains that most developers -use to do their daily work are incapable of building -``manylinux1``-compliant wheels. Therefore, we do not attempt to change -the default behavior of ``pip wheel`` / ``bdist_wheel``: they will -continue to generate regular ``linux_*`` platform tags, and developers -who wish to use them to generate ``manylinux1``-tagged wheels will -have to change the tag as a second post-processing step. - -To support the compilation of wheels meeting the ``manylinux1`` standard, we -provide initial drafts of two tools. - - -Docker Image ------------- - -The first tool is a Docker image based on CentOS 5.11, which is recommended as -an easy to use self-contained build box for compiling ``manylinux1`` wheels -[12]_. Compiling on a more recently-released linux distribution will generally -introduce dependencies on too-new versioned symbols. The image comes with a -full compiler suite installed (``gcc``, ``g++``, and ``gfortran`` 4.8.2) as -well as the latest releases of Python and ``pip``. +Like ``manylinux1``, the ``auditwheel`` tool adds ```manylinux2`` +platform tags to ``linux`` wheels built by ``pip wheel`` or +``bdist_wheel`` a ``manylinux2`` Docker container. + +Docker Images +------------- + +``manylinux2`` Docker images based on CentOS 6.9 x86_64 and i686 are +provided for building binary ``linux`` wheels that can reliably be +converted to ``manylinux2`` wheels. [8]_ These images come with a +full compiler suite installed (``gcc``, ``g++``, and ``gfortran`` +4.8.2) as well as the latest releases of Python and ``pip``. + +Compatibility with kernels that lack ``vsyscall`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A Docker container assumes that its userland is compatible with its +host's kernel. Unfortunately, an increasingly common kernel +configuration breaks breaks this assumption for x86_64 CentOS 6.9 +Docker images. + +Versions 2.14 and earlier of ``glibc`` require the kernel provide an +archaic system call optimization known as ``vsyscall`` on x86_64. [9]_ +To effect the optimization, the kernel maps a read-only page of +frequently-called system calls -- most notably ``time(2)`` -- into +each process at a fixed memory location. ``glibc`` then invokes these +system calls by dereferencing a function pointer to the appropriate +offset into the ``vsyscall`` page and calling it. This avoids the +overhead associated with invoking the kernel that affects normal +system call invocation. ``vsyscall`` has long been deprecated in +favor of an equivalent mechanism known as vDSO, or "virtual dynamic +shared object", in which the kernel instead maps a relocatable virtual +shared object containing the optimized system calls into each +process. [10]_ + +The ``vsyscall`` page has serious security implications because it +does not participate in address space layout randomization (ASLR). +Its predictable location and contents make it a useful source of +gadgets used in return-oriented programming attacks. [11]_ At the same +time, its elimination breaks the x86_64 ABI, because ``glibc`` +versions that depend on ``vsyscall`` suffer from segmentation faults +when attempting to dereference a system call pointer into a +non-existent page. As a compromise, Linux 3.1 implemented an +"emulated" ``vsyscall`` that reduced the executable code, and thus the +material for ROP gadgets, mapped into the process. [12]_ +``vsyscall=emulated`` has been the default configuration in most +distribution's kernels for many years. + +Unfortunately, ``vsyscall`` emulation still exposes predicatable code +at a reliable memory location, and continues to be useful for +return-oriented programming. [13]_ Because most distributions have now +upgraded to ``glibc`` versions that do not depend on ``vsyscall``, +they are beginning to ship kernels that do not support ``vsyscall`` at +all. [14]_ + +CentOS 5.11 and 6.9 both include versions of ``glibc`` that depend on +the ``vsyscall`` page (2.5 and 2.12.2 respectively), so containers +based on either cannot run under kernels provided with many +distribution's upcoming releases. [15]_ Continuum Analytics faces a +related problem with its conda software suite, and as they point out, +this will pose a significant obstacle to using these tools in hosted +services. [16]_ If Travis CI, for example, begins running jobs under +a kernel that does not provide the ``vsyscall`` interface, Python +packagers will not be able to use our Docker images there to build +``manylinux`` wheels. [17]_ + +We have derived a patch from the ``glibc`` git repository that +backports the removal of all dependencies on ``vsyscall`` to the +version of ``glibc`` included with our ``manylinux2`` image. [18]_ +Rebuilding ``glibc``, and thus building ``manylinux2`` image itself, +still requires a host kernel that provides the ``vsyscall`` mechanism, +but the resulting image can be both run on hosts that provide it and +those that do not. Because the ``vsyscall`` interface is an +optimization that is only applied to running processes, the +``manylinux2`` wheels built with this modified image should be +identical to those built on an unmodified CentOS 6.9 system. Also, +the ``vsyscall`` problem applies only to x86_64; it is not part of the +i686 ABI. Auditwheel ---------- -The second tool is a command line executable called ``auditwheel`` [13]_ that -may aid in package maintainers in dealing with third-party external -dependencies. - -There are at least three methods for building wheels that use third-party -external libraries in a way that meets the above policy. - -1. The third-party libraries can be statically linked. -2. The third-party shared libraries can be distributed in - separate packages on PyPI which are depended upon by the wheel. -3. The third-party shared libraries can be bundled inside the wheel - libraries, linked with a relative path. - -All of these are valid option which may be effectively used by different -packages and communities. Statically linking generally requires -package-specific modifications to the build system, and distributing -third-party dependencies on PyPI may require some coordination of the -community of users of the package. - -As an often-automatic alternative to these options, we introduce ``auditwheel``. -The tool inspects all of the ELF files inside a wheel to check for -dependencies on versioned symbols or external shared libraries, and verifies -conformance with the ``manylinux1`` policy. This includes the ability to add -the new platform tag to conforming wheels. More importantly, ``auditwheel`` has -the ability to automatically modify wheels that depend on external shared -libraries by copying those shared libraries from the system into the wheel -itself, and modifying the appropriate ``RPATH`` entries such that these -libraries will be picked up at runtime. This accomplishes a similar result as -if the libraries had been statically linked without requiring changes to the -build system. Packagers are advised that bundling, like static linking, may -implicate copyright concerns. - - -Bundled Wheels on Linux -======================= - -While we acknowledge many approaches for dealing with third-party library -dependencies within ``manylinux1`` wheels, we recognize that the ``manylinux1`` -policy encourages bundling external dependencies, a practice -which runs counter to the package management policies of many linux -distributions' system package managers [14]_, [15]_. The primary purpose of -this is cross-distro compatibility. Furthermore, ``manylinux1`` wheels on PyPI -occupy a different niche than the Python packages available through the -system package manager. - -The decision in this PEP to encourage departure from general Linux distribution -unbundling policies is informed by the following concerns: - -1. In these days of automated continuous integration and deployment - pipelines, publishing new versions and updating dependencies is easier - than it was when those policies were defined. -2. ``pip`` users remain free to use the ``"--no-binary"`` option if they want - to force local builds rather than using pre-built wheel files. -3. The popularity of modern container based deployment and "immutable - infrastructure" models involve substantial bundling at the application - layer anyway. -4. Distribution of bundled wheels through PyPI is currently the norm for - Windows and OS X. -5. This PEP doesn't rule out the idea of offering more targeted binaries for - particular Linux distributions in the future. - -The model described in this PEP is most ideally suited for cross-platform -Python packages, because it means they can reuse much of the -work that they're already doing to make static Windows and OS X wheels. We -recognize that it is less optimal for Linux-specific packages that might -prefer to interact more closely with Linux's unique package management -functionality and only care about targeting a small set of particular distos. - - -Security Implications ---------------------- - -One of the advantages of dependencies on centralized libraries in Linux is -that bugfixes and security updates can be deployed system-wide, and -applications which depend on these libraries will automatically feel the -effects of these patches when the underlying libraries are updated. This can -be particularly important for security updates in packages engaged in -communication across the network or cryptography. - -``manylinux1`` wheels distributed through PyPI that bundle security-critical -libraries like OpenSSL will thus assume responsibility for prompt updates in -response disclosed vulnerabilities and patches. This closely parallels the -security implications of the distribution of binary wheels on Windows that, -because the platform lacks a system package manager, generally bundle their -dependencies. In particular, because it lacks a stable ABI, OpenSSL cannot be -included in the ``manylinux1`` profile. - +The ``auditwheel`` tool has also been updated to produce +``manylinux2`` wheels. [19]_ Its behavior and purpose are otherwise +unchanged from PEP 513. Platform Detection for Installers ================================= -Above, we defined what it means for a *wheel* to be -``manylinux1``-compatible. Here we discuss what it means for a *Python -installation* to be ``manylinux1``-compatible. In particular, this is -important for tools like ``pip`` to know when deciding whether or not -they should consider ``manylinux1``-tagged wheels for installation. - -Because the ``manylinux1`` profile is already known to work for the -many thousands of users of popular commercial Python distributions, we -suggest that installation tools should error on the side of assuming -that a system *is* compatible, unless there is specific reason to -think otherwise. - -We know of four main sources of potential incompatibility that are -likely to arise in practice: - -* Eventually, in the future, there may exist distributions that break - compatibility with this profile (e.g., if one of the libraries in - the profile changes its ABI in a backwards-incompatible way) -* A linux distribution that is too old (e.g. RHEL 4) -* A linux distribution that does not use ``glibc`` (e.g. Alpine Linux, which is - based on musl ``libc``, or Android) - -To address these we propose a two-pronged -approach. To handle potential future incompatibilities, we standardize -a mechanism for a Python distributor to signal that a particular -Python install definitely is or is not compatible with ``manylinux1``: -this is done by installing a module named ``_manylinux``, and setting -its ``manylinux1_compatible`` attribute. We do not propose adding any -such module to the standard library -- this is merely a well-known -name by which distributors and installation tools can -rendezvous. However, if a distributor does add this module, *they -should add it to the standard library* rather than to a -``site-packages/`` directory, because the standard library is -inherited by virtualenvs (which we want), and ``site-packages/`` in -general is not. - -Then, to handle the last two cases for existing Python -distributions, we suggest a simple and reliable method to check for -the presence and version of ``glibc`` (basically using it as a "clock" -for the overall age of the distribution). - -Specifically, the algorithm we propose is:: - - def is_manylinux1_compatible(): - # Only Linux, and only x86-64 / i686 - from distutils.util import get_platform - 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 - -**Rejected alternatives:** We also considered using a configuration -file, e.g. ``/etc/python/compatibility.cfg``. The problem with this is -that a single filesystem might contain many different interpreter -environments, each with their own ABI profile -- the ``manylinux1`` -compatibility of a system-installed x86_64 CPython might not tell us -much about the ``manylinux1`` compatibility of a user-installed i686 -PyPy. Locating this configuration information within the Python -environment itself ensures that it remains attached to the correct -binary, and dramatically simplifies lookup code. - -We also considered using a more elaborate structure, like a list of -all platform tags that should be considered compatible, together with -their preference ordering, for example: ``_binary_compat.compatible = -["manylinux1_x86_64", "centos5_x86_64", "linux_x86_64"]``. However, -this introduces several complications. For example, we want to be able -to distinguish between the state of "doesn't support ``manylinux1``" -(or eventually ``manylinux2``, etc.) versus "doesn't specify either -way whether it supports ``manylinux1``", which is not entirely obvious -in the above representation; and, it's not at all clear what features -are really needed vis a vis preference ordering given that right now -the only possible platform tags are ``manylinux1`` and ``linux``. So -we're deferring a more complete solution here for a separate PEP, when -/ if Linux gets more platform tags. - -For the library compatibility check, we also considered much more -elaborate checks (e.g. checking the kernel version, searching for and -checking the versions of all the individual libraries listed in the -``manylinux1`` profile, etc.), but ultimately decided that this would -be more likely to introduce confusing bugs than actually help the -user. (For example: different distributions vary in where they -actually put these libraries, and if our checking code failed to use -the correct path search then it could easily return incorrect -answers.) +Platforms may define a ``manylinux2_compatible`` boolean attribute on +the ``_manylinux`` module described in PEP 513. A platform is +considered incompatible with ``manylinux2`` if the attribute is +``False``. +Backwards compatibility with ``manylinux1`` wheels +================================================== + +As explained in PEP 513, the specified symbol versions for +``manylinux1`` whitelisted libraries constitute an *upper bound*. The +same is true for the symbol versions defined for ``manylinux2`` in +this PEP. As a result, ``manylinux1`` wheels are considered +``manylinux2`` wheels. A ``pip`` that recognizes the ``manylinux2`` +platform tag will thus install ``manylinux1`` wheels for +``manylinux2`` platforms -- even when explicitly set -- when no +``manylinux2`` wheels are available. [20]_ PyPI Support ============ -PyPI should permit wheels containing the ``manylinux1`` platform tag to be -uploaded. PyPI should not attempt to formally verify that wheels containing -the ``manylinux1`` platform tag adhere to the ``manylinux1`` policy described -in this document. This verification tasks should be left to other tools, like -``auditwheel``, that are developed separately. - - -Rejected Alternatives -===================== - -One alternative would be to provide separate platform tags for each Linux -distribution (and each version thereof), e.g. ``RHEL6``, ``ubuntu14_10``, -``debian_jessie``, etc. Nothing in this proposal rules out the possibility of -adding such platform tags in the future, or of further extensions to wheel -metadata that would allow wheels to declare dependencies on external -system-installed packages. However, such extensions would require substantially -more work than this proposal, and still might not be appreciated by package -developers who would prefer not to have to maintain multiple build environments -and build multiple wheels in order to cover all the common Linux distributions. -Therefore, we consider such proposals to be out-of-scope for this PEP. - - -Future updates -============== - -We anticipate that at some point in the future there will be a -``manylinux2`` specifying a more modern baseline environment (perhaps -based on CentOS 6), and someday a ``manylinux3`` and so forth, but we -defer specifying these until we have more experience with the initial -``manylinux1`` proposal. +PyPI should permit wheels containing the ``manylinux2`` platform tag +to be uploaded in the same way that it permits ``manylinux1``. It +should not attempt to verify the compatibility of ``manylinux2`` +wheels. References ========== -.. [1] PEP 427 -- The Wheel Binary Package Format 1.0 - (https://www.python.org/dev/peps/pep-0427/) -.. [2] PEP 491 -- The Wheel Binary Package Format 1.9 - (https://www.python.org/dev/peps/pep-0491/) -.. [3] PEP 425 -- Compatibility Tags for Built Distributions +.. [1] PEP 513 -- A Platform Tag for Portable Linux Built Distributions + (https://www.python.org/dev/peps/pep-0513/) +.. [2] pyca/cryptography + (https://cryptography.io/) +.. [3] numpy + (https://numpy.org) +.. [4] CentOS 5.11 EOL announcement + (https://lists.centos.org/pipermail/centos-announce/2017-April/022350.html) +.. [5] CentOS Product Specifications + (https://web.archive.org/web/20180108090257/https://wiki.centos.org/About/Product) +.. [6] PEP 425 -- Compatibility Tags for Built Distributions (https://www.python.org/dev/peps/pep-0425/) -.. [4] Enthought Canopy Python Distribution - (https://store.enthought.com/downloads/) -.. [5] Continuum Analytics Anaconda Python Distribution - (https://www.continuum.io/downloads) -.. [6] CentOS 5.11 Release Notes - (https://wiki.centos.org/Manuals/ReleaseNotes/CentOS5.11) -.. [7] manylinux-discuss mailing list discussion - (https://groups.google.com/forum/#!topic/manylinux-discuss/-4l3rrjfr9U) -.. [8] distutils-sig discussion - (https://mail.python.org/pipermail/distutils-sig/2016-January/027997.html) -.. [9] distutils-sig discussion - (https://mail.python.org/pipermail/distutils-sig/2016-February/028275.html) -.. [10] github issue discussion - (https://github.com/pypa/manylinux/issues/30) -.. [11] python bug tracker discussion - (https://bugs.python.org/issue21536) -.. [12] manylinux1 docker images - (Source: https://github.com/pypa/manylinux; - x86-64: https://quay.io/repository/pypa/manylinux1_x86_64; - x86-32: https://quay.io/repository/pypa/manylinux1_i686) -.. [13] auditwheel tool - (https://pypi.python.org/pypi/auditwheel) -.. [14] Fedora Bundled Software Policy - (https://fedoraproject.org/wiki/Bundled_Software_policy) -.. [15] Debian Policy Manual -- 4.13: Convenience copies of code - (https://www.debian.org/doc/debian-policy/ch-source.html#s-embeddedfiles) -.. [16] numpy bug report: - https://github.com/numpy/numpy/issues/8415#issuecomment-269095235 +.. [7] ncurses 5 -> 6 transition means we probably need to drop some + libraries from the manylinux whitelist + (https://github.com/pypa/manylinux/issues/94) +.. [8] manylinux2 Docker images + (https://hub.docker.com/r/markrwilliams/manylinux2/) +.. [9] On vsyscalls and the vDSO + (https://lwn.net/Articles/446528/) +.. [10] vdso(7) + (http://man7.org/linux/man-pages/man7/vdso.7.html) +.. [11] Framing Signals -- A Return to Portable Shellcode + (http://www.cs.vu.nl/~herbertb/papers/srop_sp14.pdf) +.. [12] ChangeLog-3.1 + (https://www.kernel.org/pub/linux/kernel/v3.x/ChangeLog-3.1) +.. [13] Project Zero: Three bypasses and a fix for one of Flash's Vector.<*> mitigations + (https://googleprojectzero.blogspot.com/2015/08/three-bypasses-and-fix-for-one-of.html) +.. [14] linux: activate CONFIG_LEGACY_VSYSCALL_NONE ? + (https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=852620) +.. [15] [Wheel-builders] Heads-up re: new kernel configurations breaking the manylinux docker image + (https://mail.python.org/pipermail/wheel-builders/2016-December/000239.html) +.. [16] Due to glibc 2.12 limitation, static executables that use + time(), cpuinfo() and maybe a few others cannot be run on systems + that do not support or use `vsyscall=emulate` + (https://github.com/ContinuumIO/anaconda-issues/issues/8203) +.. [17] Travis CI + (https://travis-ci.org/) +.. [18] remove-vsyscall.patch + https://github.com/markrwilliams/manylinux/commit/e9493d55471d153089df3aafca8cfbcb50fa8093#diff-3eda4130bdba562657f3ec7c1b3f5720 +.. [19] auditwheel manylinux2 branch + (https://github.com/markrwilliams/auditwheel/tree/manylinux2) +.. [20] pip manylinux2 branch + https://github.com/markrwilliams/pip/commits/manylinux2 Copyright From f48fa44ce94dda91e4bb392c8a1209f367951591 Mon Sep 17 00:00:00 2001 From: Mark Williams Date: Mon, 5 Feb 2018 19:35:03 -0800 Subject: [PATCH 3/7] Citations for ABI tags; reorder footnotes. --- pep-9999.txt | 58 ++++++++++++++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/pep-9999.txt b/pep-9999.txt index 72f7f7616bd..be5860948d0 100644 --- a/pep-9999.txt +++ b/pep-9999.txt @@ -151,7 +151,7 @@ the ``manylinux2`` tag: against Python 2, then, must include either the ``cpy27mu`` tag indicating it was built against an interpreter with the UCS-4 ABI or the ``cpy27m`` tag indicating an interpeter with the UCS-2 - ABI. *[Citation for UCS ABI tags?]* + ABI. [8]_ [9]_ 5. A wheel *must not* require the ``PyFPE_jbuf`` symbol. This is achieved by building it against a Python compiled *without* the ``--with-fpectl`` ``configure`` flag. @@ -168,7 +168,7 @@ Docker Images ``manylinux2`` Docker images based on CentOS 6.9 x86_64 and i686 are provided for building binary ``linux`` wheels that can reliably be -converted to ``manylinux2`` wheels. [8]_ These images come with a +converted to ``manylinux2`` wheels. [10]_ These images come with a full compiler suite installed (``gcc``, ``g++``, and ``gfortran`` 4.8.2) as well as the latest releases of Python and ``pip``. @@ -181,7 +181,7 @@ configuration breaks breaks this assumption for x86_64 CentOS 6.9 Docker images. Versions 2.14 and earlier of ``glibc`` require the kernel provide an -archaic system call optimization known as ``vsyscall`` on x86_64. [9]_ +archaic system call optimization known as ``vsyscall`` on x86_64. [11]_ To effect the optimization, the kernel maps a read-only page of frequently-called system calls -- most notably ``time(2)`` -- into each process at a fixed memory location. ``glibc`` then invokes these @@ -192,42 +192,42 @@ system call invocation. ``vsyscall`` has long been deprecated in favor of an equivalent mechanism known as vDSO, or "virtual dynamic shared object", in which the kernel instead maps a relocatable virtual shared object containing the optimized system calls into each -process. [10]_ +process. [12]_ The ``vsyscall`` page has serious security implications because it does not participate in address space layout randomization (ASLR). Its predictable location and contents make it a useful source of -gadgets used in return-oriented programming attacks. [11]_ At the same +gadgets used in return-oriented programming attacks. [13]_ At the same time, its elimination breaks the x86_64 ABI, because ``glibc`` versions that depend on ``vsyscall`` suffer from segmentation faults when attempting to dereference a system call pointer into a non-existent page. As a compromise, Linux 3.1 implemented an "emulated" ``vsyscall`` that reduced the executable code, and thus the -material for ROP gadgets, mapped into the process. [12]_ +material for ROP gadgets, mapped into the process. [14]_ ``vsyscall=emulated`` has been the default configuration in most distribution's kernels for many years. Unfortunately, ``vsyscall`` emulation still exposes predicatable code at a reliable memory location, and continues to be useful for -return-oriented programming. [13]_ Because most distributions have now +return-oriented programming. [15]_ Because most distributions have now upgraded to ``glibc`` versions that do not depend on ``vsyscall``, they are beginning to ship kernels that do not support ``vsyscall`` at -all. [14]_ +all. [16]_ CentOS 5.11 and 6.9 both include versions of ``glibc`` that depend on the ``vsyscall`` page (2.5 and 2.12.2 respectively), so containers based on either cannot run under kernels provided with many -distribution's upcoming releases. [15]_ Continuum Analytics faces a +distribution's upcoming releases. [17]_ Continuum Analytics faces a related problem with its conda software suite, and as they point out, this will pose a significant obstacle to using these tools in hosted -services. [16]_ If Travis CI, for example, begins running jobs under +services. [18]_ If Travis CI, for example, begins running jobs under a kernel that does not provide the ``vsyscall`` interface, Python packagers will not be able to use our Docker images there to build -``manylinux`` wheels. [17]_ +``manylinux`` wheels. [19]_ We have derived a patch from the ``glibc`` git repository that backports the removal of all dependencies on ``vsyscall`` to the -version of ``glibc`` included with our ``manylinux2`` image. [18]_ +version of ``glibc`` included with our ``manylinux2`` image. [20]_ Rebuilding ``glibc``, and thus building ``manylinux2`` image itself, still requires a host kernel that provides the ``vsyscall`` mechanism, but the resulting image can be both run on hosts that provide it and @@ -242,7 +242,7 @@ Auditwheel ---------- The ``auditwheel`` tool has also been updated to produce -``manylinux2`` wheels. [19]_ Its behavior and purpose are otherwise +``manylinux2`` wheels. [21]_ Its behavior and purpose are otherwise unchanged from PEP 513. @@ -265,7 +265,7 @@ this PEP. As a result, ``manylinux1`` wheels are considered ``manylinux2`` wheels. A ``pip`` that recognizes the ``manylinux2`` platform tag will thus install ``manylinux1`` wheels for ``manylinux2`` platforms -- even when explicitly set -- when no -``manylinux2`` wheels are available. [20]_ +``manylinux2`` wheels are available. [22]_ PyPI Support ============ @@ -294,33 +294,37 @@ References .. [7] ncurses 5 -> 6 transition means we probably need to drop some libraries from the manylinux whitelist (https://github.com/pypa/manylinux/issues/94) -.. [8] manylinux2 Docker images +.. [8] PEP 3149 + https://www.python.org/dev/peps/pep-3149/ +.. [9] SOABI support for Python 2.X and PyPy + https://github.com/pypa/pip/pull/3075 +.. [10] manylinux2 Docker images (https://hub.docker.com/r/markrwilliams/manylinux2/) -.. [9] On vsyscalls and the vDSO +.. [11] On vsyscalls and the vDSO (https://lwn.net/Articles/446528/) -.. [10] vdso(7) +.. [12] vdso(7) (http://man7.org/linux/man-pages/man7/vdso.7.html) -.. [11] Framing Signals -- A Return to Portable Shellcode +.. [13] Framing Signals -- A Return to Portable Shellcode (http://www.cs.vu.nl/~herbertb/papers/srop_sp14.pdf) -.. [12] ChangeLog-3.1 +.. [14] ChangeLog-3.1 (https://www.kernel.org/pub/linux/kernel/v3.x/ChangeLog-3.1) -.. [13] Project Zero: Three bypasses and a fix for one of Flash's Vector.<*> mitigations +.. [15] Project Zero: Three bypasses and a fix for one of Flash's Vector.<*> mitigations (https://googleprojectzero.blogspot.com/2015/08/three-bypasses-and-fix-for-one-of.html) -.. [14] linux: activate CONFIG_LEGACY_VSYSCALL_NONE ? +.. [16] linux: activate CONFIG_LEGACY_VSYSCALL_NONE ? (https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=852620) -.. [15] [Wheel-builders] Heads-up re: new kernel configurations breaking the manylinux docker image +.. [17] [Wheel-builders] Heads-up re: new kernel configurations breaking the manylinux docker image (https://mail.python.org/pipermail/wheel-builders/2016-December/000239.html) -.. [16] Due to glibc 2.12 limitation, static executables that use +.. [18] Due to glibc 2.12 limitation, static executables that use time(), cpuinfo() and maybe a few others cannot be run on systems that do not support or use `vsyscall=emulate` (https://github.com/ContinuumIO/anaconda-issues/issues/8203) -.. [17] Travis CI +.. [19] Travis CI (https://travis-ci.org/) -.. [18] remove-vsyscall.patch +.. [20] remove-vsyscall.patch https://github.com/markrwilliams/manylinux/commit/e9493d55471d153089df3aafca8cfbcb50fa8093#diff-3eda4130bdba562657f3ec7c1b3f5720 -.. [19] auditwheel manylinux2 branch +.. [21] auditwheel manylinux2 branch (https://github.com/markrwilliams/auditwheel/tree/manylinux2) -.. [20] pip manylinux2 branch +.. [22] pip manylinux2 branch https://github.com/markrwilliams/pip/commits/manylinux2 From 54c74a6895daef63042dff8376a603ac816ff6b1 Mon Sep 17 00:00:00 2001 From: Mark Williams Date: Mon, 5 Feb 2018 19:37:03 -0800 Subject: [PATCH 4/7] Replaces mentions of CentOS 6.9 with CentOS 6. CentOS is free to release Update Sets (minor version releases) through the Maintenance lifetime of CentOS 6. See: https://web.archive.org/web/20180108090257/https://wiki.centos.org/About/Product --- pep-9999.txt | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/pep-9999.txt b/pep-9999.txt index be5860948d0..bc9b39baa4e 100644 --- a/pep-9999.txt +++ b/pep-9999.txt @@ -50,11 +50,11 @@ patches, will be made available. This means that its packages will remain at obsolete versions that hamper the efforts of Python software packagers who use the ``manylinux1`` Docker image. -CentOS 6.9 is now the oldest supported CentOS release, and will -receive maintenance updates through November 30th, 2020. [5]_ We -propose that a new PEP 425-style [6]_ platform tag called -``manylinux2`` be derived from CentOS 6.9 and that the ``manylinux`` -toolchain, PyPI, and ``pip`` be updated to support it. +CentOS 6 is now the oldest supported CentOS release, and will receive +maintenance updates through November 30th, 2020. [5]_ We propose that +a new PEP 425-style [6]_ platform tag called ``manylinux2`` be derived +from CentOS 6 and that the ``manylinux`` toolchain, PyPI, and ``pip`` +be updated to support it. The ``manylinux2`` policy @@ -64,7 +64,7 @@ The following criteria determine a ``linux`` wheel's eligibility for the ``manylinux2`` tag: 1. The wheel may only contain binary executables and shared objects - compiled for one of the two architectures supported by CentOS 6.9: + compiled for one of the two architectures supported by CentOS 6: x86_64 or i686. [5]_ 2. The wheel's binary executables or shared objects may not link against externally-provided libraries except those in the following @@ -166,19 +166,19 @@ platform tags to ``linux`` wheels built by ``pip wheel`` or Docker Images ------------- -``manylinux2`` Docker images based on CentOS 6.9 x86_64 and i686 are +``manylinux2`` Docker images based on CentOS 6 x86_64 and i686 are provided for building binary ``linux`` wheels that can reliably be converted to ``manylinux2`` wheels. [10]_ These images come with a full compiler suite installed (``gcc``, ``g++``, and ``gfortran`` -4.8.2) as well as the latest releases of Python and ``pip``. +4.8.2) as well as the latest releases of Python and ``pip``. Compatibility with kernels that lack ``vsyscall`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A Docker container assumes that its userland is compatible with its host's kernel. Unfortunately, an increasingly common kernel -configuration breaks breaks this assumption for x86_64 CentOS 6.9 -Docker images. +configuration breaks breaks this assumption for x86_64 CentOS 6 Docker +images. Versions 2.14 and earlier of ``glibc`` require the kernel provide an archaic system call optimization known as ``vsyscall`` on x86_64. [11]_ @@ -214,7 +214,7 @@ upgraded to ``glibc`` versions that do not depend on ``vsyscall``, they are beginning to ship kernels that do not support ``vsyscall`` at all. [16]_ -CentOS 5.11 and 6.9 both include versions of ``glibc`` that depend on +CentOS 5.11 and 6 both include versions of ``glibc`` that depend on the ``vsyscall`` page (2.5 and 2.12.2 respectively), so containers based on either cannot run under kernels provided with many distribution's upcoming releases. [17]_ Continuum Analytics faces a @@ -234,8 +234,8 @@ but the resulting image can be both run on hosts that provide it and those that do not. Because the ``vsyscall`` interface is an optimization that is only applied to running processes, the ``manylinux2`` wheels built with this modified image should be -identical to those built on an unmodified CentOS 6.9 system. Also, -the ``vsyscall`` problem applies only to x86_64; it is not part of the +identical to those built on an unmodified CentOS 6 system. Also, the +``vsyscall`` problem applies only to x86_64; it is not part of the i686 ABI. Auditwheel From 67d260cc792b43ab2ac89c96b6b05f8e584c161f Mon Sep 17 00:00:00 2001 From: Mark Williams Date: Mon, 5 Feb 2018 19:40:49 -0800 Subject: [PATCH 5/7] Add missing preposition. --- pep-9999.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pep-9999.txt b/pep-9999.txt index bc9b39baa4e..3b0e78c3bf2 100644 --- a/pep-9999.txt +++ b/pep-9999.txt @@ -161,7 +161,7 @@ Compilation of Compliant Wheels Like ``manylinux1``, the ``auditwheel`` tool adds ```manylinux2`` platform tags to ``linux`` wheels built by ``pip wheel`` or -``bdist_wheel`` a ``manylinux2`` Docker container. +``bdist_wheel`` in a ``manylinux2`` Docker container. Docker Images ------------- From cfa12a7444617b833759395d460c377dbb8ebbb0 Mon Sep 17 00:00:00 2001 From: Nick Coghlan Date: Tue, 6 Feb 2018 17:52:28 +1000 Subject: [PATCH 6/7] Allocate PEP number --- pep-9999.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pep-9999.txt b/pep-9999.txt index 3b0e78c3bf2..1937d58ea0a 100644 --- a/pep-9999.txt +++ b/pep-9999.txt @@ -1,4 +1,4 @@ -PEP: 9999 +PEP: 571 Title: The manylinux2 Platform Tag Version: $Revision$ Last-Modified: $Date$ From 37422bb418df72a84b57a0dab42c157815fe041f Mon Sep 17 00:00:00 2001 From: Nick Coghlan Date: Tue, 6 Feb 2018 17:53:00 +1000 Subject: [PATCH 7/7] Rename pep-9999.txt to pep-0571.rst --- pep-9999.txt => pep-0571.rst | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename pep-9999.txt => pep-0571.rst (100%) diff --git a/pep-9999.txt b/pep-0571.rst similarity index 100% rename from pep-9999.txt rename to pep-0571.rst