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

Python 개선 제안 한국어 번역

PEP 384 – 안정적인 ABI 정의

Author:
Martin von Löwis <martin at v.loewis.de>
Status:
Final
Type:
Standards Track
Created:
17-May-2009
Python-Version:
3.2
Post-History:


Table of Contents

번역·라이선스 안내

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

Important

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

×

See PEP 1 for how to propose changes.

초록

현재 각 기능 릴리스는 Windows에서 Python DLL에 새로운 이름을 도입하며, Unix의 확장 모듈에 호환성 문제를 일으킬 수 있습니다. 이 PEP는 Python 3의 수명 동안 사용 가능하도록 보장되고 버전 간에도 바이너리 호환성을 유지하는 안정적인 API 함수 집합을 정의할 것을 제안합니다. 확장 모듈과 Python을 임베드하는 애플리케이션은 이 안정적인 ABI로 제한하는 한 서로 다른 기능 릴리스에서도 작동할 수 있습니다.

근거

ABI 호환성 문제의 주요 원인은 메모리 내 구조체의 배치 변경입니다. 예를 들어 문자열 인터닝이 작동하는 방식이나 객체의 크기를 나타내는 데 사용되는 데이터 형식은 Python 2.x의 수명 동안 변경되었습니다. 그 결과 문자열, 리스트 또는 튜플의 필드에 직접 접근하는 확장 모듈은 다시 컴파일하지 않고 해당 코드를 더 최신 버전의 인터프리터에 로드하면 작동하지 않게 됩니다. 다른 필드의 오프셋이 변경되어 확장 모듈이 잘못된 데이터에 접근할 수 있기 때문입니다.

경우에 따라 호환성 문제는 프레임 객체나 코드 객체와 같은 인터프리터의 내부 객체에만 영향을 줍니다. 예를 들어 줄 번호가 표현되는 방식이 2.x의 수명 동안 변경되었으며, 클로저의 도입으로 인해 지역 변수가 저장되는 방식도 변경되었습니다. 대부분의 애플리케이션은 이러한 객체를 전혀 사용하지 않았을 가능성이 높지만, 이를 변경하려면 PYTHON_API_VERSION도 변경해야 했습니다.

Linux에서는 ABI 변경이 대체로 큰 문제가 되지 않습니다. 시스템이 기본 Python 설치를 제공하며 많은 확장 모듈이 이미 해당 버전에 맞게 미리 컴파일되어 제공되기 때문입니다. 추가 모듈이나 추가 Python 버전이 필요한 경우 사용자는 일반적으로 시스템에서 직접 이를 컴파일할 수 있으며, 그 결과 올바른 ABI를 사용하는 모듈이 생성됩니다.

Windows에서는 서로 다른 Python 버전의 동시 설치가 일반적이며, 확장 모듈은 최종 사용자가 아니라 작성자가 컴파일합니다. ABI 호환성 문제의 위험을 줄이기 위해 Python은 현재 실제로 ABI 호환성 문제가 존재하는지 여부와 관계없이 각 기능 릴리스마다 새로운 DLL 이름인 pythonXY.dll을 도입합니다.

이 PEP를 통해 바이너리 확장 모듈이 특정 Python 기능 릴리스에 의존하는 정도를 줄일 수 있으며, Python을 임베드하는 애플리케이션이 서로 다른 릴리스에서 작동하도록 만들 수 있습니다.

사양

ABI 사양은 두 부분으로 나뉩니다. ABI에서 사용할 수 있는 함수(그룹)를 지정하는 API 사양과 링크할 라이브러리를 지정하는 링크 사양입니다. 실제 ABI(메모리 내 구조체의 배치와 함수 호출 규약)는 지정되지 않으며 컴파일러에 의해 암시됩니다. 권장 사항으로, 선택된 플랫폼에는 특정 ABI를 사용할 것을 권장합니다.

Python이 발전하는 동안 새로운 ABI 함수가 추가됩니다. 그러면 이를 사용하는 애플리케이션에는 Python 최소 버전에 대한 요구 사항이 생기며, Python 라이브러리가 너무 오래된 경우 이러한 애플리케이션이 대체 동작으로 전환할 수 있는 메커니즘은 이 PEP에서 제공하지 않습니다.

용어

이 ABI를 사용하려는 애플리케이션과 확장 모듈을 앞으로 통칭하여 “애플리케이션”이라고 부릅니다.

헤더 파일 및 전처리기 정의

애플리케이션은 헤더 파일 Python.h만 포함해야 합니다(모든 시스템 헤더를 포함하기 전에 포함해야 함). 또는 선택적으로 pyconfig.h를 포함한 다음 Python.h를 포함할 수 있습니다.

애플리케이션을 컴파일하는 동안 전처리기 매크로 Py_LIMITED_API를 정의해야 합니다. 이렇게 하면 ABI의 일부가 아닌 모든 정의가 숨겨집니다.

구조체

애플리케이션은 다음 구조체와 구조체 필드에만 접근할 수 있습니다.

  • PyObject (ob_refcnt, ob_type)
  • PyVarObject (ob_base, ob_size)
  • PyMethodDef (ml_name, ml_meth, ml_flags, ml_doc)
  • PyMemberDef (name, type, offset, flags, doc)
  • PyGetSetDef (name, get, set, doc, closure)
  • PyModuleDefBase (ob_base, m_init, m_index, m_copy)
  • PyModuleDef (m_base, m_name, m_doc, m_size, m_methods, m_traverse, m_clear, m_free)
  • PyStructSequence_Field (name, doc)
  • PyStructSequence_Desc (name, doc, fields, sequence)
  • PyType_Slot (아래 참조)
  • PyType_Spec (아래 참조)

이러한 필드에 대한 접근자 매크로(Py_REFCNT, Py_TYPE, Py_SIZE)도 애플리케이션에서 사용할 수 있습니다.

다음 타입을 사용할 수 있지만, 불투명합니다(즉, 불완전합니다):

  • PyThreadState
  • PyInterpreterState
  • struct _frame
  • struct symtable
  • struct _node
  • PyWeakReference
  • PyLongObject
  • PyTypeObject

타입 객체

타입 객체의 구조는 애플리케이션에서 사용할 수 없습니다. “static” 타입 객체의 선언은 더 이상 가능하지 않습니다(이 ABI를 사용하는 애플리케이션의 경우). 대신 타입 객체는 동적으로 생성됩니다. 타입을 쉽게 생성할 수 있도록(특히 함수 포인터를 쉽게 채울 수 있도록) 다음 구조체와 함수를 사용할 수 있습니다.:

typedef struct{
  int slot;    /* slot id, see below */
  void *pfunc; /* function pointer */
} PyType_Slot;

typedef struct{
  const char* name;
  int basicsize;
  int itemsize;
  unsigned int flags;
  PyType_Slot *slots; /* terminated by slot==0. */
} PyType_Spec;

PyObject* PyType_FromSpec(PyType_Spec*);

슬롯을 지정하려면 고유한 슬롯 ID를 제공해야 합니다. 새로운 Python 버전에서는 새로운 슬롯 ID가 도입될 수 있지만, 슬롯 ID가 재사용되는 일은 절대 없습니다. 슬롯은 폐기될 수 있지만, Python 3.x 전체에서 계속 지원됩니다.

슬롯 ID는 Python 3.1에서 포인터를 보유하는 구조체의 필드 이름에 Py_ 접두사를 추가한 형태로 명명됩니다(즉, 단순히 tp_dealloc 대신 Py_tp_dealloc입니다):

  • tp_dealloc, tp_getattr, tp_setattr, tp_repr, tp_hash, tp_call, tp_str, tp_getattro, tp_setattro, tp_doc, tp_traverse, tp_clear, tp_richcompare, tp_iter, tp_iternext, tp_methods, tp_base, tp_descr_get, tp_descr_set, tp_init, tp_alloc, tp_new, tp_is_gc, tp_bases, tp_del
  • nb_add nb_subtract nb_multiply nb_remainder nb_divmod nb_power nb_negative nb_positive nb_absolute nb_bool nb_invert nb_lshift nb_rshift nb_and nb_xor nb_or nb_int nb_float nb_inplace_add nb_inplace_subtract nb_inplace_multiply nb_inplace_remainder nb_inplace_power nb_inplace_lshift nb_inplace_rshift nb_inplace_and nb_inplace_xor nb_inplace_or nb_floor_divide nb_true_divide nb_inplace_floor_divide nb_inplace_true_divide nb_index
  • sq_length sq_concat sq_repeat sq_item sq_ass_item sq_contains sq_inplace_concat sq_inplace_repeat
  • mp_length mp_subscript mp_ass_subscript

다음 필드는 형식 정의 중에 설정할 수 없습니다: - tp_dict tp_mro tp_cache tp_subclasses tp_weaklist tp_print - tp_weaklistoffset tp_dictoffset

typedef

위에 나열한 구조체의 typedef 외에도 다음 typedef를 사용할 수 있습니다. 이러한 typedef가 ABI에 포함된다는 것은 플랫폼에서 기반 형식이 변경되어서는 안 된다는 의미입니다(플랫폼마다 다를 수는 있습니다).

  • Py_uintptr_t Py_intptr_t Py_ssize_t
  • unaryfunc binaryfunc ternaryfunc inquiry lenfunc ssizeargfunc ssizessizeargfunc ssizeobjargproc ssizessizeobjargproc objobjargproc objobjproc visitproc traverseproc destructor getattrfunc getattrofunc setattrfunc setattrofunc reprfunc hashfunc richcmpfunc getiterfunc iternextfunc descrgetfunc descrsetfunc initproc newfunc allocfunc
  • PyCFunction PyCFunctionWithKeywords PyNoArgsFunction PyCapsule_Destructor
  • getter setter
  • PyOS_sighandler_t
  • PyGILState_STATE
  • Py_UCS4

특히 Py_UNICODE는 typedef로 사용할 수 없습니다. 동일한 Python 버전이라도 같은 플랫폼에서 이를 서로 다르게 정의할 수 있기 때문입니다(좁은 코드 단위를 사용하는지 넓은 코드 단위를 사용하는지에 따라 다릅니다). 유니코드 문자열의 내용에 액세스해야 하는 애플리케이션은 이를 wchar_t로 변환할 수 있습니다.

함수 및 함수형 매크로

기본적으로 아래에서 제외된 함수를 제외한 모든 함수를 사용할 수 있습니다. 함수가 문서화되었는지 여부는 중요하지 않습니다.

함수형 매크로(특히 필드 접근 매크로)는 애플리케이션에서 계속 사용할 수 있지만, 함수 호출로 대체됩니다(정의가 다양한 _Check 매크로와 같이 ABI의 기능만 참조하는 경우는 제외합니다).

ABI 함수 선언의 매개변수 형식이나 반환 형식은 변경되지 않습니다. 시그니처를 변경해야 하는 경우에는 새 함수가 도입됩니다. 새 함수가 소스 호환성을 유지하는 경우(예: 반환 형식만 변경되는 경우), 애플리케이션을 다시 컴파일할 때 호출을 새 함수로 리디렉션하는 별칭 매크로가 추가될 수 있습니다.

기존 함수를 계속 제공할 수 없는 경우 해당 함수는 사용 중단된 후 제거될 수 있으며, 그 함수를 사용하는 애플리케이션이 작동하지 않게 됩니다.

제외된 함수

_Py로 시작하는 모든 함수는 애플리케이션에서 사용할 수 없습니다. 또한 애플리케이션에서 사용할 수 없는 매개변수 형식을 요구하는 모든 함수도 ABI에서 제외됩니다. 예를 들어 PyAST_FromNode(node*를 요구함)가 이에 해당합니다.

다음 헤더 파일에 선언된 함수는 ABI에 포함되지 않습니다.

  • bytes_methods.h
  • cellobject.h
  • classobject.h
  • code.h
  • compile.h
  • datetime.h
  • dtoa.h
  • frameobject.h
  • funcobject.h
  • genobject.h
  • longintrepr.h
  • parsetok.h
  • pyarena.h
  • pyatomic.h
  • pyctype.h
  • pydebug.h
  • pytime.h
  • symtable.h
  • token.h
  • ucnhash.h

또한 FILE*를 예상하는 함수는 Windows에서 특정 버전의 Microsoft C 런타임 DLL에 의존하지 않도록 ABI의 일부가 아닙니다.

모듈 및 타입 초기화 함수와 종료 함수는 사용할 수 없습니다(PyByteArray_Init, PyOS_FiniInterrupts 및 _Fini 또는 _ClearFreeList로 끝나는 모든 함수).

인터프리터 구현 세부 사항을 다루는 다음과 같은 여러 함수는 사용할 수 없습니다:

  • PyInterpreterState_Head, PyInterpreterState_Next, PyInterpreterState_ThreadHead, PyThreadState_Next
  • Py_SubversionRevision, Py_SubversionShortBranch

PyStructSequence_InitType은 호출자가 정적 타입 객체를 제공해야 하므로 사용할 수 없습니다.

Py_FatalError는 pydebug.h에서 다른 헤더 파일(예: pyerrors.h)로 이동될 예정입니다.

사용 가능한 함수의 정확한 목록은 Windows 모듈 정의 파일인 python3.dll [1]에 제시되어 있습니다.

전역 변수

타입과 예외를 나타내는 전역 변수는 애플리케이션에서 사용할 수 있습니다. 또한 매크로에서 참조되는 일부 전역 변수(예: Py_True 및 Py_False)도 사용할 수 있습니다.

전역 변수 정의의 전체 목록은 python3.def 파일 [1];에 제공되어 있으며, DATA로 선언된 항목은 변수를 나타냅니다.

기타 매크로

기호 상수를 정의하는 모든 매크로는 애플리케이션에서 사용할 수 있으며, 숫자 값은 변경되지 않습니다.

또한 다음 매크로를 사용할 수 있습니다:

  • Py_BEGIN_ALLOW_THREADS, Py_BLOCK_THREADS, Py_UNBLOCK_THREADS, Py_END_ALLOW_THREADS

버퍼 인터페이스

버퍼 인터페이스(Py_buffer 타입, bf_getbuffer와 bf_releasebuffer 등의 타입 슬롯)는 현재 Py_buffer 구조체의 안정성이 명확하지 않기 때문에 ABI에서 제외되었습니다. ABI에의 포함은 이후 릴리스에서 고려될 수 있습니다.

시그니처 변경

다수의 함수가 호출자가 일반적으로 PyObject*를 사용할 수 있음에도 불구하고 현재 특정 구조체를 요구합니다. 이들은 매개변수로 PyObject*를 요구하도록 변경되었으며, 이는 현재 매개변수 타입으로 명시적으로 캐스팅하는 애플리케이션에서 경고를 발생시킬 것입니다. 이 함수들은 PySlice_GetIndices, PySlice_GetIndicesEx, PyUnicode_AsWideChar, PyEval_EvalCode입니다.

링키지

Windows에서 애플리케이션은 python3.dll과 링크해야 하며, 임포트 라이브러리 python3.lib을 사용할 수 있습니다. 이 DLL은 자신의 모든 API 함수를 /export 링커 옵션을 통해 전체 인터프리터 DLL, 즉 python3y.dll로 리디렉션합니다.

Unix 시스템에서 ABI는 일반적으로 python 실행 파일 자체에 의해 제공됩니다. PyModule_Create는 확장 모듈이 Py_LIMITED_API로 컴파일된 경우 API 버전으로 3을 전달하도록 변경되었으며, API 버전 검사는 3 또는 현재의 PYTHON_API_VERSION 중 하나를 준수하는 것으로 허용합니다. Python이 공유 라이브러리로 컴파일된 경우 libpython3.so와 libpython3.y.so 둘 다로 설치되며, 이 PEP를 준수하는 애플리케이션은 전자와 링크해야 합니다(확장 모듈은 계속 libpython 공유 객체 없이 링크될 수 있으며, 대신 런타임 링킹에 의존합니다). ABI 버전은 PYTHON_ABI_VERSION으로 심볼릭하게 사용할 수 있습니다.

또한 Unix에서는 확장 모듈 파일 이름에 PEP 3149 태그 abi<PYTHON_ABI_VERSION>이 허용됩니다. 이런 방식으로 이름 붙여진 파일이 실제로 제한된 API에만 국한되어 있는지 확인하는 작업은 수행되지 않으며, distutils 코드 동결로 인해 이러한 파일을 빌드하기 위한 지원이 distutils에 추가되지도 않을 것입니다.

구현 전략

이 PEP는 브랜치[2]에서 구현될 것이며, 사용자가 자신의 모듈이 ABI를 준수하는지 확인할 수 있게 해줍니다. 사용자가 타입 정의를 다시 작성해야 하는 번거로움을 피하기 위해, 타입 정의가 포함된 C 소스 코드를 변환하는 스크립트가 제공될 것입니다[3].

참고 문헌