Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python 개선 제안 한국어 번역

PEP 656 – Musl을 사용하는 Linux 배포판을 위한 플랫폼 태그

Author:
Tzu-ping Chung <uranusjr at gmail.com>
Sponsor:
Brett Cannon <brett at python.org>
PEP-Delegate:
Paul Moore <p.f.moore at gmail.com>
Discussions-To:
Discourse thread
Status:
Final
Type:
Standards Track
Topic:
Packaging
Created:
17-Mar-2021
Post-History:
17-Mar-2021, 18-Apr-2021
Resolution:
Discourse message

Table of Contents

번역·라이선스 안내

이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain or CC0-1.0, whichever is more permissive 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판

초록

이 PEP는 Linux 배포판에서 musl에 의존하는 Python 설치를 위한 바이너리 Python 패키지 배포에 사용할 새로운 플랫폼 태그 시리즈 musllinux를 제안합니다. 이 태그는 PEP 600에 명시된 “perennial manylinux” 플랫폼 태그와 비슷하게 동작하지만, 대신 musl 기반 플랫폼을 대상으로 합니다.

동기

컨테이너가 널리 사용되면서 Alpine Linux [alpine] 같은 배포판이 그 어느 때보다 큰 인기를 얻고 있습니다. 이들 중 상당수는 glibc와 다른 libc 구현인 musl [musl]을 기반으로 하므로 기존 manylinux 플랫폼 태그를 사용할 수 없습니다. 이는 Python 패키지 프로젝트가 이들 배포판을 위한 바이너리 배포를 PyPI에 배포할 수 없음을 의미합니다. 그러한 프로젝트의 사용자는 해당 프로젝트에 빌드 제약 조건을 요구하게 되며, 이는 프로젝트 유지 관리자에게 불필요한 부담을 줍니다.

근거

문서에 따르면 musl은 안정 ABI를 가지며 하위 호환성을 유지하므로 [musl-compatibility] [compare-libcs], 이전 버전의 musl에 대해 컴파일된 바이너리는 더 새로운 musl 런타임에서 실행되는 것이 보장됩니다 [musl-compat-ml]. 따라서 glibc 버전 기반의 manylinux 태그와 비슷한 체계를 사용하되, glibc 대신 musl 버전을 기준으로 삼습니다.

새 플랫폼 태그의 논리는 대체로 PEP 600 (“perennial manylinux”)을 따르며, 이 태그를 사용하는 휠도 비슷한 약속을 하도록 요구합니다. 설계의 근거와 추론에 관한 자세한 내용은 PEP 600을 참고하십시오.

musllinux 플랫폼 태그는 Linux 운영 체제에서 musl libc에 동적으로 링크되어 런타임 공유 라이브러리 위에서 실행되는 Python 인터프리터에만 적용됩니다. 정적으로 링크된 인터프리터나 다른 libc 구현(glibc 등)과 섞인 빌드는 범위 밖이며, 이 문서에서 정의하는 플랫폼 태그가 지원하지 않습니다. 그러한 인터프리터는 musllinux 플랫폼 태그와의 호환성을 주장해서는 안 됩니다.

명세

새 체계를 사용하는 태그는 다음 형식을 취합니다:

musllinux_${MUSLMAJOR}_${MUSLMINOR}_${ARCH}

이 태그는 영속적(perennial) 설계에 따라, musl 버전 ${MUSLMAJOR}.${MUSLMINOR}를 사용하는 모든 주류 Linux 배포판에서 wheel이 동작함을 보장합니다. 그 밖의 모든 시스템 수준 의존성 요구 사항은 PEP 600에서 도입된, 의도적으로 모호하게 둔 “주류(mainstream)”라는 표현에 대한 커뮤니티의 정의에 따릅니다. 지정된 musl 버전을 사용하는 모든 주류 배포판이 어떤 의존성을 기본으로 제공한다면 휠은 더 새로운 시스템 의존성을 사용할 수 있습니다. 해당 musl 버전의 모든 주류 배포판이 특정 의존성 버전을 기본으로 탑재하게 되면, 그보다 오래된 버전에 의존하는 사용자는 자동으로 해당 musllinux 태그의 지원 범위에서 제외됩니다.

musl 버전 읽기

musl 버전 값은 Python 인터프리터가 현재 실행 중인 musl libc 공유 라이브러리를 실행하고 그 출력을 파싱하여 얻을 수 있습니다:

import re
import subprocess

def get_musl_major_minor(so: str) -> tuple[int, int] | None:
    """Detect musl runtime version.

    Returns a two-tuple ``(major, minor)`` that indicates musl
    library's version, or ``None`` if the given libc .so does not
    output expected information.

    The libc library should output something like this to stderr::

        musl libc (x86_64)
        Version 1.2.2
        Dynamic Program Loader
    """
    proc = subprocess.run([so], stderr=subprocess.PIPE, text=True)
    lines = (line.strip() for line in proc.stderr.splitlines())
    lines = [line for line in lines if line]
    if len(lines) < 2 or lines[0][:4] != "musl":
        return None
    match = re.match(r"Version (\d+)\.(\d+)", lines[1])
    if match:
        return (int(match.group(1)), int(match.group(2)))
    return None

현재 Python 인터프리터가 실행 중인 musl 라이브러리의 위치를 찾는 방법은 두 가지가 있습니다. 시스템의 ldd 명령을 사용하는 방법 [ldd]과, 실행 파일의 ELF 헤더에서 PT_INTERP 섹션의 값을 파싱하는 방법 [elf]입니다.

태그 포맷팅

이 태그를 사용하는 배포물은 PEP 600에 설명된 것과 비슷한 약속을 하며, 여기에는 다음이 포함됩니다:

  1. 이 배포는 musl 버전 ${MUSLMAJOR}.${MUSLMINOR} 이상을 사용하는 모든 주류 Linux 배포판에서 동작합니다.
  2. 배포의 ${ARCH}는 PEP 425와 PEP 427에 설명된 대로, 호스트 시스템에서 sysconfig.get_platform()의 반환값에서 마침표(.)와 하이픈(-) 문자를 밑줄(_)로 바꾼 값과 일치합니다.

예시 값:

musllinux_1_1_x86_64   # musl 1.1 running on x86-64.
musllinux_1_2_aarch64  # musl 1.2 running on ARM 64-bit.

이 값은 다음 Python 코드로 형식화할 수 있습니다:

import sysconfig

def format_musllinux(musl_version: tuple[int, int]) -> str:
    os_name, sep, arch = sysconfig.get_platform().partition("-")
    assert os_name == "linux" and sep, "Not a Linux"
    arch = arch.replace(".", "_").replace("-", "_")
    return f"musllinux_{musl_version[0]}_{musl_version[1]}_{arch}"

패키지 색인에 대한 권고 사항

PyPI를 포함한 Python 패키지 저장소는 다음 정규 표현식과 일치하는 플랫폼 태그를 허용할 것을 권장합니다:

musllinux_([0-9]+)_([0-9]+)_([^.-]+)

Python 패키지 저장소는 알려진 문제가 있는 Wheel을 거부하기 위해 추가 요구 사항을 부과할 수 있으며, 여기에는 다음이 포함되지만 이에 국한되지 않습니다:

  • musl 1.2 이상에서만 사용할 수 있는 심볼을 포함하는 musllinux_1_1 휠.
  • 패키지 색인의 대상 사용자가 일반적으로 사용할 수 있다고 보기 어려운 외부 라이브러리에 의존하는 휠.
  • 존재하지 않는 musl 버전과의 호환성을 주장하는 플랫폼 태그(예: musllinux_9000_0).

이러한 정책은 궁극적으로 개별 패키지 저장소가 결정할 사항입니다. 유지 관리자에게 제한을 부과하는 것은 작성자의 의도가 아닙니다.

하위 호환성

이 PEP에는 하위 호환성 문제가 없습니다.

기각된 아이디어

Alpine Linux 전용 플랫폼 태그 만들기

manylinux 태그 시리즈의 과거 경험을 보면 이 접근 방식은 시간 면에서 비용이 너무 많이 듭니다. 저자는 “다른 것들과 잘 어울린다(works well with others)”는 규칙이 더 포용적이면서도 실제로 충분히 잘 작동한다고 생각합니다.

참고 문헌