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

Python 개선 제안 한국어 번역

PEP 652 – 안정 ABI 유지 관리

Author:
Petr Viktorin <encukou at gmail.com>
Discussions-To:
Discourse thread
Status:
Final
Type:
Standards Track
Created:
09-Feb-2021
Python-Version:
3.10
Resolution:
Python-Dev message

Table of Contents

번역·라이선스 안내

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

Important

This PEP is a historical document. The up-to-date, canonical documentation can now be found at C API and ABI Stability (user docs) and Changing Python’s C API (개발 문서).

×

See PEP 1 for how to propose changes.

초록

PEP 384에서 도입된 CPython의 제한된 C-API와 안정 ABI를 하나의 확정적인 파일로 공식화하고, 테스트하고, 문서화합니다.

동기

PEP 384는 제한된 API와 안정 ABI를 정의했습니다. 이를 통해 CPython을 확장하거나 임베드하는 개발자는 이후의 모든 3.x 버전과 바이너리 호환되는 확장 모듈을 컴파일할 수 있습니다. 이론적으로 이는 다음과 같은 여러 이점을 가져옵니다:

  • 모듈을 플랫폼마다 한 번만 빌드하고도 여러 버전의 Python을 지원할 수 있으므로, 빌드에 드는 시간, 전력, 유지 관리자의 수고를 줄일 수 있습니다(대신 성능이 나빠질 수 있습니다).
  • 안정 ABI를 사용하는 바이너리 휠은 사전 릴리스 기간 내내 CPython의 새 버전에서 동작하며, 소스에서 빌드하는 것이 현실적이지 않은 환경에서도 테스트할 수 있습니다.
  • 제한된 API가 구현 세부 사항을 숨기면서 생긴 반가운 부수 효과로, 이 API는 전체 C API와 호환되지 않는 대체 Python 구현이 지원 대상으로 삼을 만한 API가 되어 가고 있습니다.

그러나 돌이켜 보면 PEP 384와 그 구현에는 몇 가지 문제가 있습니다:

  • 정의가 불명확합니다. PEP 384에 따르면 함수는 옵트아웃 방식입니다. 즉, 특별히 표시되지 않은 모든 함수는 안정 ABI의 일부입니다. 실제로는 Windows용으로 옵트인 방식의 목록이 있습니다. 사용자를 위해서는 안정 ABI만 사용할 수 있게 해 주는 #define이 있지만, 이것이 최신 상태로 유지되도록 보장하는 절차는 없습니다. 문서를 갱신하는 절차도 없습니다.
  • 최근까지 안정 ABI는 전혀 테스트되지 않았습니다. 그래서 쉽게 깨지곤 합니다. 예를 들어 함수를 매크로로 바꾸면 함수 심볼이 제거되므로 안정 ABI가 깨질 수 있습니다.
  • 제한된 API의 일부를 폐지 예정(deprecated)으로 지정할 방법이 없습니다.
  • 불완전합니다. 일부 연산은 “잊어버렸다”는 것 말고는 별다른 이유 없이 안정 ABI에서 사용할 수 없습니다. (다만 이 마지막 문제는 이 PEP로도 해결되지 않습니다.)

이 PEP는 제한된 API를 더 명확하게 정의하고, 안정 ABI와 제한된 API를 더 유용하고 견고하게 만들기 위한 절차를 도입합니다.

근거

이 PEP에는 많은 설명과 정의가 담겨 있지만, 큰 기술적 변경은 단 하나입니다: 안정 ABI를 사람이 관리하는 “매니페스트” 파일에 명시적으로 나열합니다.

예를 들어 Python에서 내보낸 심볼을 스캔하는 방식으로 이러한 목록을 자동으로 수집하려는 시도가 있었습니다. 이러한 자동화는 수작업으로 만든 파일보다 유지 관리하기 쉬워 보일 수 있지만, 큰 문제가 있습니다: 예를 들어 내보낸 심볼의 집합은 플랫폼마다 다릅니다. 또한 명시적인 매니페스트를 갱신하는 비용은 영원히(또는 Python 3의 지원 종료가 더 먼저 온다면 그때까지) 지원해야 할 API를 변경하는 데 들여야 하는 전체 작업에 비하면 적습니다.

이 PEP는 매니페스트로부터 여러 가지를 자동으로 생성할 것을 제안합니다: 처음에는 문서와 DLL 내용을 생성하고, 나중에는 테스트도 자동화할 수 있습니다.

안정 ABI 대 제한된 API

PEP 384와 이 문서는 서로 관련되어 있지만 별개인 두 개념, 제한된 API와 안정 ABI를 다룹니다. 간단히 말하면 다음과 같습니다:

  • 안정 ABI는 CPython 3.x로 컴파일된 특정 확장이 이후의 모든 CPython 3.x 버전과 바이너리 호환된다는 약속입니다.
  • 제한된 API는 그러한 확장을 만들어 내는 CPython C API의 부분집합입니다.

이 절에서는 이 용어들을 명확히 하고, 그 의미 중 일부(기존의 것이거나 여기에서 새로 제안하는 것)를 정의합니다.

“확장”이라는 단어는 Python API를 사용하는 모든 코드(예: 확장 모듈이나 Python을 내장하는 소프트웨어)를 줄여 부르는 말로 사용됩니다.

안정 ABI

CPython 안정 ABI는 특정 안정 ABI 버전을 대상으로 빌드된 확장이 같은 메이저 버전의 모든 더 새로운 인터프리터와 호환된다는 약속입니다.

안정 ABI는 완전한 바이너리 인터페이스를 정의하지 않습니다. 메모리상의 구조체 레이아웃이나 함수 호출 규약과 같은 중요한 세부 사항은 플랫폼과 컴파일러 및 그 설정에 따라 결정됩니다. 안정 ABI의 약속은 이러한 하위 수준의 세부 사항도 안정적일 때에만 적용됩니다.

예를 들어, CPython 3.10 안정 ABI로 빌드된 확장은 CPython 3.11, 3.12 등에서 사용할 수 있습니다. 그러나 CPython 4.0과 반드시 호환되는 것은 아니며, 다른 플랫폼의 CPython 3.10과도 반드시 호환되는 것은 아닙니다.

안정 ABI는 일반적으로 상위 호환되지 않습니다. CPython 3.10으로 빌드하고 테스트한 확장은 일반적으로 CPython 3.9와 호환되지 않습니다.

Note

예를 들어, Python 3.10부터는 Py_tp_doc 슬롯을 NULL로 설정할 수 있지만, 이전 버전에서는 NULL 값이 인터프리터를 비정상 종료시킬 가능성이 높습니다.

안정 ABI는 안정성을 얻는 대신 성능을 희생합니다. 예를 들어, 특정 CPython 버전을 대상으로 빌드된 확장은 안정 ABI의 함수 대신 더 빠른 매크로를 자동으로 사용합니다.

향후 Python 버전에서는 안정 ABI의 일부 멤버가 폐지될 수 있습니다. 폐지된 멤버는 여전히 동작하지만, 성능 저하나 가장 극단적인 경우 메모리/자원 누수와 같은 문제를 겪을 수 있습니다.

제한된 API

안정 ABI 약속은 제한된 API(응용 프로그래밍 인터페이스)만 사용하도록 제한된 코드에서 컴파일된 확장에 적용됩니다. 제한된 API는 CPython C API의 부분집합입니다.

제한된 API를 대상으로 하는 확장은 전처리기 매크로 Py_LIMITED_API를 3 또는 현재 PYTHON_API_VERSION 중 하나로 정의해야 합니다. 이렇게 하면 여러 함수의 안정 ABI 버전이 활성화되고 정의가 제한된 API로 한정됩니다. (그러나 이 매크로가 완벽하지는 않다는 점에 유의하십시오. 기술적인 문제나 실수로 인해, 매크로가 정의되어 있어도 제한되지 않은 일부 API가 노출될 수 있습니다.)

제한된 API가 안정적이라는 보장은 없습니다. 향후 제한된 API의 일부가 폐지될 수 있습니다. 안정 ABI가 안정적으로 유지되고 Python의 일반적인 하위 호환성 정책인 PEP 387을 따르는 한, 이들은 제거될 수도 있습니다.

Note

예를 들어, 함수 선언이 공개 헤더 파일에서는 제거되지만 라이브러리에는 유지될 수 있습니다. 이는 현재로서는 미래의 가능성일 뿐이며, 이 PEP는 폐지 및 제거에 대한 구체적인 절차를 제안하지 않습니다.

제한된 API의 목표는 인터프리터와 상호 작용하는 데 필요한 모든 것을 포괄하는 것입니다. 공개 API를 제한 부분 집합에 포함하지 않는 주된 이유는, 그 API가 CPython 버전 간에 변경되는 구현 세부 사항(구조체 메모리 레이아웃 등)을 필요로 한다는 것이어야 하며, 이는 대개 성능상의 이유 때문입니다.

제한된 API는 CPython에만 국한되지 않습니다. 다른 구현들도 이를 구현하고 그 설계를 이끌어 가는 데 참여하기를 권장합니다.

명세

안정 ABI를 더 유용하고 견고하게 만들기 위해 다음과 같은 변경 사항을 제안합니다.

안정 ABI 매니페스트

안정 ABI의 모든 구성원(함수, typedef, 구조체, 데이터, 매크로, 상수)은 단일 “매니페스트” 파일인 Misc/stable_abi.txt에 명시적으로 나열됩니다.

구조체의 경우, 안정 ABI 사용자가 접근할 수 있는 모든 필드가 명시적으로 나열됩니다.

매니페스트는 제한된 API의 확정 목록 역할도 합니다. 제한된 API에는 속하지 않지만 안정 ABI에는 속하는 구성원(예: Py_TYPE 매크로로 접근할 수 있는 PyObject.ob_type)에는 그러한 사실이 주석으로 표시됩니다.

일부 시스템에서만 사용할 수 있는 항목의 경우, 매니페스트에 해당 항목의 존재 여부를 결정하는 기능 매크로(MS_WINDOWS나 HAVE_FORK 등)가 기록됩니다. 구현(그리고 C 이외의 언어에서의 사용)을 쉽게 하기 위해, 이러한 매크로는 모두 단순한 이름으로 합니다. 향후 어떤 항목에 “부정” 매크로나 복잡한 표현식(가상의 예로 #ifndef MACOSX나 #if defined(POSIX) && !defined(LINUX) 등)이 필요해지면, 새로운 기능 매크로를 파생하여 만듭니다.

매니페스트의 형식은 필요할 때마다 변경될 수 있습니다. 매니페스트는 CPython 저장소에 있는 스크립트에서만 사용해야 합니다. 안정적인 목록이 필요하다면, 그러한 목록을 생성하는 스크립트를 추가할 수 있습니다.

ABI 매니페스트로부터 다음 항목이 생성됩니다:

  • Windows 공유 라이브러리의 소스인 PC/python3dll.c입니다.
  • 문서화를 위한 입력(아래 참조).
  • 심볼을 런타임에 사용할 수 있는지 확인하는 테스트 케이스(아래 참조).

지속적 통합 과정에서 다음 항목을 안정 ABI 매니페스트와 대조하여 검사합니다:

  • 참조 횟수 요약 파일인 Doc/data/refcounts.txt에는 (다른 함수와 함께) 안정 ABI의 모든 함수가 포함됩니다.
  • Py_LIMITED_API가 설정된 상태로 Python.h를 포함했을 때 선언되는 함수/구조체와 정의되는 상수/매크로입니다. (처음에는 Linux만 해당하며, 향후 다른 시스템에 대한 검사가 추가될 수 있습니다.)

초기 구현 이후에는 함수 인자 등의 세부 정보가 추가되며, 매니페스트의 내부 일관성(예: 함수 시그니처에 사용된 모든 타입이 API에 속하는지)을 검사합니다.

안정 ABI의 내용

초기 안정 ABI 매니페스트에는 다음이 포함됩니다:

  • PEP 384에 명시된 안정 ABI.
  • PC/python3dll.c에 나열된 모든 항목.
  • 이러한 함수가 반환하거나 인자로 받는 모든 구조체(구조체 typedef). (해당 구조체의 필드가 반드시 추가되는 것은 아닙니다.)
  • Py_am_aiter 등의 새로운 타입 슬롯.
  • 타입 플래그 Py_TPFLAGS_DEFAULT, Py_TPFLAGS_BASETYPE, Py_TPFLAGS_HAVE_GC, Py_TPFLAGS_METHOD_DESCRIPTOR.
  • 호출 규약 METH_*(폐지된 것은 제외).
  • 매크로에 필요한 모든 API는 안정 ABI에 포함됩니다(제한된 API에 속하지 않는다는 주석이 표시됩니다).

이 PEP가 수락되는 시점에 CPython에 더 이상 존재하지 않는 항목은 목록에서 제거됩니다.

아래 체크리스트에 따라 초기 매니페스트에 항목이 추가될 수 있습니다.

제한된 API 문서화

“제한된 API의 일부”라는 주석이 Python 문서에 자동으로 추가되며, 이는 빌린 참조를 반환하는 함수에 붙는 주석과 비슷한 방식으로 이루어집니다.

제한된 API의 모든 구성원을 담은 전체 목록도 문서에 추가됩니다.

안정 ABI 테스트

안정 ABI에 포함된 모든 심볼을 컴파일 시점에 사용할 수 있는지 확인하기 위해 자동으로 생성되는 테스트 모듈이 추가될 것입니다.

제한된 API 변경

제한된 API를 변경하기 위한 체크리스트가 Devguide에 추가될 것입니다. 여기에는 새 항목을 추가하는 작업과 기존 항목을 제거하는 작업도 포함됩니다. 이 체크리스트는 1) Python C API 설계의 모범 사례와 흔한 함정을 언급하고, 2) 제한된 API가 변경될 때 수정해야 하는 파일과 실행해야 하는 스크립트를 개발자에게 안내할 것입니다.

아래는 체크리스트의 초기 제안입니다. (PEP가 수락된 후에는 Devguide에서 최신 버전을 확인하십시오.)

이 체크리스트는 새로운 변경 사항에 적용된다는 점에 유의하십시오. 기존 제한된 API의 여러 항목은 예외적으로 인정된 것으로, 지금이라면 추가될 수 없었을 것입니다.

설계 시 고려 사항:

  • 변경 사항이 3.5 이후 어떤 Python 버전의 안정 ABI도 깨뜨리지 않는지 확인하십시오.
  • 노출된 이름 중 비공개(즉, 밑줄로 시작하는) 이름이 없는지 확인하십시오.
  • 새 API가 잘 문서화되어 있는지 확인하십시오.
  • 추가된 함수의 모든 매개변수와 반환값의 타입, 그리고 추가된 구조체의 모든 필드의 타입이 제한된 API(또는 표준 C)의 일부인지 확인하십시오.
  • 새 API와 그 의도된 사용 방식이 현재 지원되는 플랫폼의 기능만이 아니라 표준 C를 따르는지 확인하십시오. 구체적으로는 PEP 7에 명시된 C 방언을 따르십시오.
    • 함수 포인터를 void* (데이터 포인터)로 캐스팅하거나 그 반대로 캐스팅하지 마십시오.
  • 새 API가 참조 카운팅 규칙을 따르는지 확인하십시오. (이 규칙을 따르면 API를 이해하기가 더 쉬워지고, 다른 Python 구현에서도 더 쉽게 사용할 수 있습니다.)
    • 함수에서 빌린 참조(borrowed reference)를 반환하지 마십시오.
    • 함수 인자에 대한 참조를 훔치지(steal) 마십시오.
  • 해당하는 모든 구조체 필드, 인자, 반환값의 소유권 규칙과 수명이 명확하게 정의되어 있는지 확인하십시오.
  • 사용자의 사용 편의성을 고려하십시오. (C에서는 사용 편의성 자체는 그다지 중요하지 않습니다. 정말로 유용한 것은 API를 사용하는 데 필요한 보일러플레이트 코드를 줄이는 것입니다. 버그는 보일러플레이트에 숨어 있기를 좋아합니다.)
    • 어떤 함수가 특정 인자에 특정 값을 넘기는 방식으로 자주 호출될 것이라면, 그 값을 기본값으로 만드는 것(NULL이 전달될 때 사용)을 고려하십시오.
  • 향후 확장을 고려하십시오. 예를 들어, 향후 Python 버전에서 여러분의 구조체에 새 필드를 추가해야 할 가능성이 있다면 그것을 어떻게 하시겠습니까?
  • 향후 CPython 버전에서 바뀌거나 C API 구현마다 다를 수 있는 세부 사항에 대해서는 가능한 한 적게 가정하십시오:
    • GIL
    • 가비지 컬렉션
    • PyObject, 리스트/튜플 및 기타 구조체의 메모리 레이아웃

이 지침을 따르는 것이 성능을 해친다면, 제한되지 않은 API에는 빠른 함수(또는 매크로)를 추가하고 제한된 API에는 그에 상응하는 안정적인 버전을 추가하십시오.

불명확한 점이 있거나 지침을 어길 타당한 이유가 있다면, capi-sig 메일링 리스트에서 변경 사항을 논의하는 것을 고려하십시오.

절차:

  • 선언을 Include/ 바로 아래에 있는 헤더 파일의 #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03yy0000 블록 안으로 옮기십시오(yy는 대상 CPython 버전에 해당합니다).
  • 안정 ABI 매니페스트인 Misc/stable_abi.txt에 항목을 추가하십시오.
  • make regen-all을 사용하여 자동 생성 파일을 다시 생성합니다. (make를 사용하지 않는 플랫폼에서는 그에 대응하는 방법을 사용합니다.)
  • Python을 빌드하고 make check-abi를 사용하여 검사를 실행하십시오. (make를 사용하지 않는 플랫폼에서는 그에 상응하는 대안을 사용하십시오.)

확장 및 내장 개발자를 위한 조언

다음 내용은 이 주제와 우리가 제공하는 보장에 관한 더 나은 정보와 함께 문서에 추가될 것입니다:

확장 작성자는 지원하는 모든 Python 버전으로 테스트해야 하며, 가급적 그중 가장 낮은 버전으로 빌드해야 합니다.

Py_LIMITED_API를 정의한 상태로 컴파일한다고 해서 코드가 제한된 API나 안정 ABI를 준수한다고 보장되는 것은 아닙니다. Py_LIMITED_API는 정의만 다루지만, API에는 예상되는 의미 체계와 같은 다른 사항도 포함됩니다.

Py_LIMITED_API가 막아 주지 못하는 문제의 예는 다음과 같습니다:

  • 잘못된 인자로 함수 호출하기
  • Python 3.9에서 인자로 NULL 값을 받기 시작한 함수는 Python 3.8에서 NULL이 전달되면 실패합니다. 3.8(또는 더 낮은 버전)으로 테스트해야만 이 문제를 발견할 수 있습니다.
  • 일부 구조체에는 안정 ABI에 속하는 필드 몇 개와 그렇지 않은 다른 필드가 함께 들어 있습니다. Py_LIMITED_API는 이러한 “비공개” 필드를 걸러 내지 않습니다.
  • 안정 ABI의 일부로 문서화되지 않았지만 Py_LIMITED_API를 정의해도 노출되는 것을 사용하는 코드는 향후 동작하지 않을 수 있습니다. 팀이 최선을 다하더라도 이러한 문제는 발생할 수 있습니다.

Python 재배포자를 위한 참고 사항

안정 ABI의 약속은 메모리상의 구조체 배치나 함수 호출 규약처럼 그 기반이 되는 ABI 세부 사항이 안정적이라는 데 의존하며, 이러한 세부 사항은 컴파일러와 그 설정의 영향을 받습니다. 이 약속이 지켜지려면 특정 플랫폼에서 CPython 3.x 릴리스 간에 이러한 세부 사항이 바뀌어서는 안 됩니다.

하위 호환성

하위 호환성은 아주 훌륭한 아이디어입니다!

이 PEP는 기존의 안정 ABI 및 제한된 API와 완전히 호환되는 것을 목표로 하지만, 그 용어들을 더 명확하게 정의합니다. 기존의 안정 ABI/제한된 API가 무엇인지에 대한 일부 해석과는 일치하지 않을 수 있습니다.

보안 영향

알려진 바 없습니다.

교육 방법

기술 문서는 Doc/c-api/stable에 제공되며 What’s New 문서에서 링크될 것입니다. CPython 코어 개발자를 위한 문서는 devguide에 추가될 것입니다.

참조 구현

issue 43795를 참조하십시오.

향후 아이디어

다음 사항은 이 PEP의 범위를 벗어나지만, 향후 나아갈 수 있는 방향을 보여 줍니다.

폐지/제거 절차 정의하기

이 PEP는 제한된 API의 일부가 향후 폐지되거나 제거될 수 있음을 인정하지만, 이를 위한 절차는 범위에 포함되지 않으며 향후 있을 수 있는 PEP에 맡깁니다.

ABI 매니페스트를 위한 C 문법

ABI 매니페스트를 C 헤더 파일로 만들거나 매니페스트에서 헤더 파일을 생성하면 유용할 수 있습니다. 다시 말하지만, 두 가지 모두 향후에 고려할 수 있는 선택지입니다.

미해결 문제

현재까지는 없습니다.

참고 문헌