Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SOABI on Linux does not distinguish between GNU libc and musl libc #87278

Open
ncopa mannequin opened this issue Feb 3, 2021 · 19 comments
Open

SOABI on Linux does not distinguish between GNU libc and musl libc #87278

ncopa mannequin opened this issue Feb 3, 2021 · 19 comments
Labels
3.12 bugs and security fixes interpreter-core (Objects, Python, Grammar, and Parser dirs) OS-unsupported topic-sysconfig

Comments

@ncopa
Copy link
Mannequin

ncopa mannequin commented Feb 3, 2021

BPO 43112
Nosy @tiran, @dvarrazzo, @merwok, @ncopa, @henryiii, @uranusjr, @miss-islington, @tianon, @dave-shawley, @h-vetinari, @olivierlefloch
PRs
  • bpo-43112: detect musl as a separate SOABI #24502
  • bpo-43112: fix new sysconfig test #31001
  • Dependencies
  • bpo-46390: Multiple test failures on Alpine 3.15 / musl-1.2.2-r7
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = None
    created_at = <Date 2021-02-03.09:26:13.443>
    labels = ['interpreter-core', 'type-bug', '3.9', '3.10', '3.11']
    title = 'SOABI on Linux does not distinguish between GNU libc and musl libc'
    updated_at = <Date 2022-01-29.00:29:09.330>
    user = 'https://github.com/ncopa'

    bugs.python.org fields:

    activity = <Date 2022-01-29.00:29:09.330>
    actor = 'eric.araujo'
    assignee = 'none'
    closed = False
    closed_date = None
    closer = None
    components = ['Interpreter Core']
    creation = <Date 2021-02-03.09:26:13.443>
    creator = 'ncopa'
    dependencies = ['46390']
    files = []
    hgrepos = []
    issue_num = 43112
    keywords = ['patch']
    message_count = 16.0
    messages = ['386183', '386184', '386186', '386192', '386194', '386196', '386197', '386710', '386722', '386739', '386797', '405471', '406858', '406939', '410646', '412042']
    nosy_count = 12.0
    nosy_names = ['christian.heimes', 'piro', 'eric.araujo', 'Arfrever', 'ncopa', 'Henry Schreiner', 'uranusjr', 'miss-islington', 'tianon', 'dave-shawley', 'h-vetinari', 'olivierlefloch']
    pr_nums = ['24502', '31001']
    priority = 'normal'
    resolution = None
    stage = 'patch review'
    status = 'open'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue43112'
    versions = ['Python 3.9', 'Python 3.10', 'Python 3.11']

    @ncopa
    Copy link
    Mannequin Author

    ncopa mannequin commented Feb 3, 2021

    The SOABI does not make any difference between GNU libc and musl libc.

    Using official docker images:

    # debian build with GNU libc
    $ docker run --rm python:slim python -c 'import sysconfig;print(sysconfig.get_config_var("SOABI"))'
    cpython-39-x86_64-linux-gnu

    # alpine build with musl libc
    $ docker run --rm python:alpine python -c 'import sysconfig;print(sysconfig.get_config_var("SOABI"))'
    cpython-39-x86_64-linux-gnu

    Both ends with -gnu, while it would be expected that with musl it would end with -musl

    This affects the extension suffix:

    $ docker run --rm python:slim python-config --extension-suffix
    .cpython-39-x86_64-linux-gnu.so
    
    $ docker run --rm python:alpine python-config --extension-suffix
    .cpython-39-x86_64-linux-gnu.so

    Which again affects the pre-compiled binary wheels, and binary modules built with musl libc gets mixed up with the GNU libc modules due to the -gnu.so suffix.

    The source of the problem is that the configure.ac file assumes that all defined(linux) is -gnu when detecting the PLATFORM_TRIPLET.

    ...
    #if defined(__ANDROID__)
        # Android is not a multiarch system.
    #elif defined(__linux__)
    # if defined(__x86_64__) && defined(__LP64__)
            x86_64-linux-gnu
    # elif defined(__x86_64__) && defined(__ILP32__)
            x86_64-linux-gnux32
    # elif defined(__i386__)
    ...
    

    So when building python with musl libc the PLATFORM_TRIPLET always sets *-linux-gnu.

    output from configure run on musl system:

    ...
    checking for a sed that does not truncate output... /bin/sed                                                      
    checking for --with-cxx-main=<compiler>... no                                                                     
    checking for the platform triplet based on compiler characteristics... x86_64-linux-gnu  
    ...
    

    A first step in fixing this would be to make sure that we only set -gnu when __GLIBC__ is defined:

    diff --git a/configure.ac b/configure.ac
    index 1f5a008388..1b4690c90f 100644
    --- a/configure.ac
    +++ b/configure.ac
    @@ -726,7 +726,7 @@ cat >> conftest.c <<EOF
     #undef unix
     #if defined(__ANDROID__)
         # Android is not a multiarch system.
    -#elif defined(__linux__)
    +#elif defined(__linux__) && defined (__GLIBC__)
     # if defined(__x86_64__) && defined(__LP64__)
             x86_64-linux-gnu

    But that would make build with musl fail with "unknown platform triplet".

    Not sure what the proper fix would be, but one way to extract the suffix from $CPP -dumpmachine

    @ncopa ncopa mannequin added the interpreter-core (Objects, Python, Grammar, and Parser dirs) label Feb 3, 2021
    @tiran
    Copy link
    Member

    tiran commented Feb 3, 2021

    The suffix "-gnu" does not stand for "glibc".

    The triplet defines the calling convention. For example x86_64-linux-gnu means x86_64 / AMD64 CPU architecture, Linux, with standard GNU / GCC calling convention. Other calling conventions are "x86_64-linux-gnux32" for X32 on AMD64 and "arm-linux-gnueabihf" for 32bit ARM with extended ABI and hardware float support.

    The triplets are standardized beyond Python. Debian's multiarch page lists and explains a large amount of triplets, https://wiki.debian.org/Multiarch/Tuples

    @ncopa
    Copy link
    Mannequin Author

    ncopa mannequin commented Feb 3, 2021

    Does this mean that the SOABI should be the same for python built with musl libc and GNU libc?

    They are not really ABI compatible.

    @tiran
    Copy link
    Member

    tiran commented Feb 3, 2021

    SOABI basically contains the CPU architecture and Kernel ABI. The libc ABI is yet another dimension that is not encoded in the shared library ABI.

    The libc ABI is more complex than just glibc or musl. You need to include the ABI version of all core components. For example manylinux2014 defines the ABI for glibc as GLIBC_2.17, CXXABI_1.3.7, CXXABI_TM_1, GLIBCXX_3.4.19, GCC_4.8.0.

    As a rule of thumb, a SOABI like ".cpython-39-x86_64-linux-gnu.so" only works the current host. You cannot safely move the file to another host or bump the SO version of any library, unless you ensure that the ABIs of all libraries are compatible.

    @ncopa
    Copy link
    Mannequin Author

    ncopa mannequin commented Feb 3, 2021

    The referenced https://wiki.debian.org/Multiarch/Tuples doc says:

    we require unique identifiers for each architecture that identifies an incompatible set of libraries that we want to be co-installed.

    Since GNU libc and musl libc are not ABI compatible they can not share same unique identifier. I think replacing -gnu with -musl makes sense.

    @tiran
    Copy link
    Member

    tiran commented Feb 3, 2021

    Do you have glibc and musl installed side by side?

    @ncopa
    Copy link
    Mannequin Author

    ncopa mannequin commented Feb 3, 2021

    Do you have glibc and musl installed side by side?

    No. But there is nothing preventing me to have the libc runtimes installed in parallel with glibc.

    /lib/libc.so.6
    /lib/libc.musl-x86_64.so.1

    And it is not common that people copy libc.so.6 (with friends) to their alpine docker images to run both in same container. If that is a good idea is other discussion.

    I do understand that full ABI compatibility also may involve libc ABI version, but I think that is a slightly different problem. Newer versions of glibc and musl libc are backwards compatible. You can expect a binary built with old libc version to run with new libc. But you cannot expect a binary built with musl libc to run with gnu libc.

    gcc recognizes -linux-musl as a valid platform tuple different that differs from -linux-gnu:
    https://github.com/gcc-mirror/gcc/blob/master/gcc/config/t-musl

    The standard autotools' config.guess1 also recognizes -musl as different platform.

      $ ./config.guess 
      x86_64-pc-linux-musl

    So I think it makes sense to treat *-linux-musl as a different platform than *-linux-gnu.

    If you still insist that this is only about calling convention and not platform, then I think you should at least clarify that in the configure.ac script to avoid confusion:

    sed -i -e 's/PLATFORM_TRIPLET/CALLING_CONVENTION_TRIPLET/g' -e 's/platform triplet/calling convention triplet/g' configure.ac

    @tiran
    Copy link
    Member

    tiran commented Feb 9, 2021

    I stand corrected. The last element in the platform triplet does seem to indicate libc.

    Is there any formal definition of the platform triplet or is it defined by GCC's reference implementation? A quick search didn't reveal any decisive results.

    The next steps here would be:

    • document the platform triplet in regards of musl libc (and potentially other libcs like uclibc and embedded newlibc)
    • buildbot with Alpine musl

    Let's continue this on https://discuss.python.org/t/wheels-for-musl-alpine/7084

    @ncopa
    Copy link
    Mannequin Author

    ncopa mannequin commented Feb 9, 2021

    This mentions some examples for musl triplets/tuples:
    https://wiki.musl-libc.org/getting-started.html

    It points to https://github.com/richfelker/musl-cross-make/blob/master/README.md#supported-targets which I think is the best documentation. (Rich Felker is the author and lead developer or musl libc).

    I'm not sure its worth spend time on uClibc which does not seem to have any commits at all since 2015. https://git.uclibc.org/uClibc/log/

    We will work on our side on buildbot with Alpine linux.

    Thank you for being understanding.

    @Arfrever
    Copy link
    Mannequin

    Arfrever mannequin commented Feb 9, 2021

    While original uClibc is not maintained, its fork called uClibc-ng is supposedly binary-compatible with uClibc and is still somehow maintained:
    https://uclibc-ng.org/
    https://repo.or.cz/w/uclibc-ng.git

    https://www.uclibc.org/news.html also says:
    "While uClibc releases are on hold, you may use uClibc-ng"

    libc part of platform tuple on uClibc-ng systems is expected to be "uclibc".

    @ncopa
    Copy link
    Mannequin Author

    ncopa mannequin commented Feb 10, 2021

    I created a PR for this #24502

    @merwok
    Copy link
    Member

    merwok commented Nov 1, 2021

    If this is deemed a bugfix, the PR should be backported.

    @merwok merwok added 3.9 only security fixes 3.10 only security fixes 3.11 only security fixes type-bug An unexpected behavior, bug, or error labels Nov 1, 2021
    @uranusjr
    Copy link
    Mannequin

    uranusjr mannequin commented Nov 23, 2021

    Can anyone problem examples that it’s not an option to continue using the “technically incorrect” -gnu suffix on 3.9 and 3.10? From what I understand, te suffix technically works (as in the module will load correctly), it just fails to distinguish the ABI in the name.

    If that’s correct, I feel “being able to distinguish between modules built against musl and glibc” should be a feature request and only implemented for 3.11+, while versions 3.10 and prior continue to use -gnu. This will also provide a simpler way out of the wheel compatibility problem; projects can distribute different wheels for 3.10 (or lower) and 3.11 (or higher), while the former wheel continues to contain -gnu-suffixed modules, and only contain -musl-suffixed ones in the latter.

    @henryiii
    Copy link
    Mannequin

    henryiii mannequin commented Nov 24, 2021

    We had a call and have a potential path forward. Quick summary:

    • Add a patch on top of the current patch to make CPython look for -gnu on top of -musl for Alpine 3.15 and 3.14. Reverting the patch would break every Alpine wheel previously locally compiled (like NumPy) and would require rebuilding all shipped packages that depend on Python.
    • Revert the patch for CPython 3.10 in Alpine 3.16, due mid next year.
    • Take the existing patch (PR 24502) targeting upstream CPython 3.11 and change search to include abi3-gnu on musl after looking for abi3-musl. The ability to install both binaries into a single folder would be a new "feature" of CPython 3.11.
    • Optionally this could be checked and normalized by auditwheel (like changing -musl to -gnu on 3.9) if desired. ABI3 wheels targeting <3.11 could be normalized to -gnu.

    How does that sound?

    @tiran
    Copy link
    Member

    tiran commented Jan 15, 2022

    I noticed that 9 test suites are failing on Alpine 3.15, see bpo-46390. Should we require a stable buildbot before we proclaim official support for Alpine?

    @miss-islington
    Copy link
    Contributor

    New changeset 1f036ed by Natanael Copa in branch 'main':
    bpo-43112: detect musl as a separate SOABI (GH-24502)
    1f036ed

    @mattip
    Copy link
    Contributor

    mattip commented Jan 19, 2023

    In order to work around this limitation, packaging is forced to call ld to work out which libc the current python is linked to. If changing the SOABI is too much, maybe it would be possible to change either sys.implementation._multiarch or sysconfig.get_config_var('MULTIARCH') to reflect the libc?

    @merwok merwok removed type-bug An unexpected behavior, bug, or error 3.11 only security fixes labels Jan 19, 2023
    @merwok merwok added 3.12 bugs and security fixes and removed 3.10 only security fixes 3.9 only security fixes labels Jan 19, 2023
    @merwok
    Copy link
    Member

    merwok commented Jan 19, 2023

    I don’t think that multiarch is the right variable to indicate libc, but another field could be added to sys.implementation, or a variable to sysconfig, to support this. Maybe the request needs a broadest audience using discuss.python.org

    @mattip
    Copy link
    Contributor

    mattip commented Jan 19, 2023

    Maybe the request needs a broadest audience using discuss.python.org
    Done

    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    3.12 bugs and security fixes interpreter-core (Objects, Python, Grammar, and Parser dirs) OS-unsupported topic-sysconfig
    Projects
    Status: No status
    Development

    No branches or pull requests

    6 participants