پایداری رابط برنامه‌نویسی کاربردی و رابط دودویی کاربردی C

مگر آنکه خلاف آن مستند شده باشد، C API پایتون مشمول سیاست سازگاری رو به عقب، PEP 387، است. بیشتر تغییرات آن با کد منبع سازگار هستند (source-compatible) (معمولاً فقط با افزودن API‌های جدید). تغییر API‌های موجود یا حذف API تنها پس از یک دوره‌ی منسوخ‌سازی یا برای رفع مشکلات جدی انجام می‌شود.

رابط دودویی برنامه (ABI) سی‌پایتون در طول یک انتشار جزئی، به جلو و به عقب سازگار است (اگر این‌ها به یک شکل کامپایل شده باشند؛ به ملاحظات پلتفرم در ادامه مراجعه کنید). بنابراین، کدی که برای پایتون 3.10.0 کامپایل شده باشد، روی 3.10.8 کار خواهد کرد و برعکس، اما برای 3.9.x و 3.11.x باید جداگانه کامپایل شود.

دو سطح از C API با انتظارات پایداری متفاوت وجود دارد:

  • API ناپایدار، ممکن است در نسخه‌های جزئی بدون دوره‌ی منسوخ‌سازی تغییر کند. این API با پیشوند PyUnstable در نام‌ها مشخص می‌شود.

  • API محدود، در چندین نسخه‌ی فرعی سازگار است. هنگامی که Py_LIMITED_API تعریف شود، فقط این زیرمجموعه از Python.h در دسترس قرار می‌گیرد.

این موارد در ادامه با جزئیات بیشتر بررسی می‌شوند.

نام‌هایی که با خط زیر آغاز می‌شوند، مانند _Py_InternalState، API خصوصی هستند و می‌توانند حتی در نسخه‌های وصله (patch) بدون اطلاع قبلی تغییر کنند. اگر نیاز به استفاده از این API دارید، در نظر بگیرید که با توسعه‌دهندگان سی‌پایتون ارتباط برقرار کنید تا درباره‌ی افزودن API عمومی برای مورد استفاده‌ی خود گفت‌وگو کنید.

API ناپایدار C

هر API که با پیشوند PyUnstable نام‌گذاری شده باشد، جزئیات پیاده‌سازی سی‌پایتون را آشکار می‌کند و ممکن است در هر انتشار جزئی (برای مثال از 3.9 به 3.10) بدون هیچ هشدار منسوخ‌شدن تغییر کند. با این حال، در انتشار رفع اشکال (برای مثال از 3.10.0 به 3.10.1) تغییر نخواهد کرد.

این به‌طور کلی برای ابزارهای تخصصی و سطح پایین مانند اشکال‌زداها در نظر گرفته شده است.

انتظار می‌رود پروژه‌هایی که از این API استفاده می‌کنند، توسعه‌ی سی‌پایتون را دنبال کنند و برای سازگاری با تغییرات تلاش اضافی صرف کنند.

رابط‌های دودویی کاربردی پایدار

Stable ABI پایتون به افزونه‌ها اجازه می‌دهد بدون نیاز به کامپایل مجدد، با چندین نسخه‌ی پایتون سازگار باشند.

نکته

برای سادگی، این سند درباره‌ی توسعه‌ها صحبت می‌کند، اما ABI پایدار برای همه‌ی استفاده‌های API – برای مثال، تعبیه‌ی پایتون – به همین شکل کار می‌کند.

دو ABI پایدار وجود دارد:

  • نسخه‌ی abi3 که در پایتون ۳.۲ معرفی شد، با نسخه‌های غیر-ساخت نخ‌آزاد سی‌پایتون سازگار است.

  • abi3t که در پایتون ۳.۱۵ معرفی شد، با نسخه‌های ساخت نخ‌آزاد از سی‌پایتون سازگار است. این نسخه دارای محدودیت‌های API سخت‌گیرانه‌تری نسبت به abi3 است.

    اضافه شده در نسخه‌ی 3.15: نسخه‌ی abi3t در PEP 803 اضافه شد

این امکان وجود دارد که یک افزونه برای هر دو نسخه‌ی abi3 و abi3t به طور همزمان کامپایل شود؛ نتیجه با هر دو نسخه‌ی پایتون، یعنی ساخت‌های نخ‌آزاد و غیرنخ‌آزاد، سازگار خواهد بود. در حال حاضر، این روش در مقایسه با کامپایل کردن فقط برای abi3t هیچ جنبه‌ی منفی ندارد.

هر ABI پایدار با استفاده از دو رقم اول نسخه‌ی پایتون شماره‌گذاری می‌شود. برای مثال، ABI پایدار ۳.۱۴ با پایتون ۳.۱۴ مطابقت دارد. افزونه‌ای که برای ABI پایدار ۳.x کامپایل شده باشد، از نظر ABI با پایتون ۳.x و بالاتر سازگار است.

افزونه‌هایی که یک ABI پایدار را هدف قرار می‌دهند، باید تنها از زیرمجموعه‌ی محدودی از C API استفاده کنند. این زیرمجموعه به نام Limited API شناخته می‌شود؛ محتویات آن در فهرست زیر آمده است.

روی ویندوز، توسعه‌هایی که از یک ABI پایدار استفاده می‌کنند باید به جای یک کتابخانه‌ی وابسته‌ی نسخه مانند python39.dll، به python3.dll پیوند داده شوند. این کتابخانه فقط نمادهای مربوطه را در معرض دید قرار می‌دهد.

در برخی پلتفرم‌ها، پایتون به دنبال پرونده‌های کتابخانه‌ی مشترکی با برچسب abi3 یا abi3t (برای مثال mymodule.abi3.so) می‌گردد و آن‌ها را بارگذاری می‌کند. مفسرهای توسعه‌یافته با نخ‌آزاد تنها برچسب abi3t را تشخیص می‌دهند، در حالی که مفسرهای غیر نخ‌آزاد برچسب abi3 را ترجیح می‌دهند اما به abi3t بازمی‌گردند. بنابراین، افزونه‌های سازگار با هر دو نوع ABI باید از برچسب abi3t استفاده کنند.

پایتون لزوماً بررسی نمی‌کند که افزونه‌هایی که بارگذاری می‌کند دارای ABI سازگار باشند. به توسعه‌دهندگان افزونه‌ها توصیه می‌شود با استفاده از جایگاه Py_mod_abi یا تابع PyABIInfo_Check() یک بررسی اضافه کنند، اما مسئولیت نهایی تضمین این موضوع بر عهده‌ی کاربر (یا ابزار بسته‌بندی او) است؛ برای مثال، اینکه اطمینان حاصل شود افزونه‌های ساخته‌شده برای ABI پایدار ۳.۱۰ برای نسخه‌های پایین‌تر پایتون نصب نشوند.

تمام توابع موجود در ABI پایدار به عنوان تابع در کتابخانه‌ی مشترک پایتون حضور دارند، نه صرفاً به صورت کلان‌دستورها (ماکروها). این امر باعث می‌شود که آن‌ها در زبان‌هایی که از پیش‌پردازنده‌ی C استفاده نمی‌کنند، از جمله ctypes پایتون، قابل استفاده باشند.

کامپایل کردن برای ABI پایدار

نکته

ابزارهای ساخت (مانند meson-python، scikit-build-core یا Setuptools) اغلب مکانیزمی برای تنظیم ماکروها و همگام‌سازی آن‌ها با نام‌ پرونده‌های افزونه و سایر فرااطلاعات دارند. در صورت وجود چنین مکانیزمی، استفاده از آن را به تعریف دستی ماکروها ترجیح دهید.

باقی مانده‌ی این بخش عمدتاً برای توسعه‌دهندگان ابزارها و افرادی که افزونه‌ها را به صورت دستی کامپایل می‌کنند، کاربرد دارد.

همچنین ببینید

فهرست ابزارهای پیشنهادی در راهنمای کاربر بسته‌بندی پایتون

برای کامپایل کردن برای یک ABI پایدار، یکی از ماکروهای زیر یا هر دو آن‌ها را روی پایین‌ترین نسخه‌ی پایتونی که افزونه‌ی شما باید پشتیبانی کند، در قالب Py_PACK_VERSION تعریف کنید. به طور معمول، به جای نسخه‌ی سرآیندهای پایتونی که در حال کامپایل کردن با آن‌ها هستید، باید مقدار خاصی را انتخاب کنید.

ماکروها باید پیش از گنجاندن Python.h تعریف شوند. از آنجا که Py_PACK_VERSION در این نقطه در دسترس نیست، لازم است مستقیماً از مقدار عددی استفاده کنید. برای مراجع، مقادیر مربوط به چند نسخه‌ی اخیر پایتون عبارتند از:

0x30a0000  /* Py_PACK_VERSION(3,10) */
0x30b0000  /* Py_PACK_VERSION(3,11) */
0x30c0000  /* Py_PACK_VERSION(3,12) */
0x30d0000  /* Py_PACK_VERSION(3,13) */
0x30e0000  /* Py_PACK_VERSION(3,14) */
0x30f0000  /* Py_PACK_VERSION(3,15) */

هنگامی که یکی از ماکروها تعریف می‌شود، Python.h تنها API سازگار با ABI پایدار داده‌شده را نمایش می‌دهد -- یعنی API محدود به علاوه برخی تعاریف که باید برای کامپایلر قابل مشاهده باشند اما نباید مستقیماً استفاده شوند. هنگامی که هر دو تعریف شوند، Python.h فقط API سازگار با هر دو ABI پایدار را نمایش خواهد داد.

Py_LIMITED_API

هدف قرار دادن abi3، یعنی ساخت‌های غیر-نخ‌آزاد سی‌پایتون. برای اطلاعات عمومی به بخش بالا مراجعه کنید.

Py_TARGET_ABI3T

هدف قرار دادن abi3t، یعنی ساخت‌های نخ‌آزاد سی‌پایتون. برای اطلاعات عمومی به بخش بالا مراجعه کنید.

اضافه شده در نسخه‌ی 3.15.

هر دو ماکرو یک ABI هدف را مشخص می‌کنند؛ سبک نام‌گذاری متفاوت به دلیل سازگاری با نسخه‌های قبلی است.

نکته‌ی تاریخی

همچنین می‌توانید Py_LIMITED_API را به عنوان 3 تعریف کنید. این کار مشابه 0x03020000 (پایتون ۳.۲، نسخه‌ای که ABI پایدار را معرفی کرد) عمل می‌کند.

هنگامی که هر دو تعریف شوند، Python.h ممکن است ماکروی Py_LIMITED_API را برای تطابق با Py_TARGET_ABI3T بازتعریف بکند یا نکند.

در یک ساخت نخ‌آزاد -- یعنی زمانی که Py_GIL_DISABLED تعریف شده باشد -- Py_TARGET_ABI3T به‌طور پیش‌فرض به مقداری که Py_LIMITED_API دارد تنظیم می‌شود. این یعنی دو راه برای ساخت هم‌زمان برای abi3 و abi3t وجود دارد:

  • تعریف کردن هر دو ماکروی Py_LIMITED_API و Py_TARGET_ABI3T، یا

  • تعریف کردن تنها ماکروی Py_LIMITED_API و:

    • در ویندوز، تعریف کردن Py_GIL_DISABLED؛

    • در سایر سیستم‌ها، استفاده از سرآیندهای ساخت نخ‌آزاد پایتون.

محدوده و کارایی ABI پایدار

هدف از ABI پایدار این است که همه‌ی کارهایی که با API کامل C امکان‌پذیر است، اما احتمالاً همراه با جریمه‌ی کارایی، اجازه داده شود. به طور کلی، سازگاری با ABI پایدار نیازمند برخی تغییرات در کد منبع توسعه است.

برای مثال، در حالی که PyList_GetItem() در دسترس است، نوع مشتق‌شده‌ی ناامن آن یعنی کلان‌دستور PyList_GET_ITEM() در دسترس نیست. این کلان‌دستور می‌تواند سریع‌تر باشد زیرا می‌تواند به جزئیات پیاده‌سازی وابسته‌ی نسخه‌ی شیء فهرست تکیه کند.

برای مثالی دیگر، هنگام عدم کامپایل برای ABI پایدار، برخی از توابع API پایتون درون‌خطی می‌شوند یا با کلان‌دستورها جایگزین می‌شوند. کامپایل کردن برای ABI پایدار این درون‌خطی‌سازی را غیرفعال می‌کند، و با بهبود ساختارهای داده‌ی پایتون اجازه می‌دهد پایداری حفظ شود، اما احتمالاً کارایی را کاهش می‌دهد.

با کنار گذاشتن تعریف Py_LIMITED_API یا Py_TARGET_ABI3T، امکان کامپایل کد منبع سازگار با Stable-ABI برای یک ABI خاصِ نسخه وجود دارد. سپس می‌توان یک افزونه‌ی خاصِ نسخه‌ی احتمالاً سریع‌تر را در کنار نسخه‌ای که برای Stable ABI کامپایل شده است (یک جایگزین کندتر اما سازگارتر) توزیع کرد.

هشدارهای ABI پایدار

توجه داشته باشید که کامپایل کردن برای Stable ABI تضمین کامل نمی‌کند که کد با نسخه‌های مورد انتظار پایتون سازگار باشد. Stable ABI از مشکلات ABI، مانند خطاهای پیونددهنده به دلیل نمادهای مفقود یا خرابی داده‌ها به دلیل تغییرات در طرح‌بندی ساختارها یا امضای تابع، جلوگیری می‌کند. با این حال، سایر تغییرات در پایتون می‌تواند رفتار افزونه‌ها را تغییر دهد.

یکی از مشکلاتی که ماکروهای Py_TARGET_ABI3T و Py_LIMITED_API از آن جلوگیری نمی‌کنند، فراخوانی یک تابع با آرگومان‌هایی است که در یک نسخه‌ی پایین‌تر پایتون نامعتبر هستند. برای مثال، تابعی را در نظر بگیرید که شروع به پذیرش NULL برای یک آرگومان می‌کند. در پایتون ۳.۹، مقدار NULL اکنون یک رفتار پیش‌فرض را انتخاب می‌کند، اما در پایتون ۳.۸، آرگومان مستقیماً استفاده خواهد شد که باعث رفع ارجاع NULL و فروپاشی می‌شود. استدلال مشابهی برای فیلدهای structها نیز صادق است.

به همین دلیل، توصیه می‌کنیم یک افزونه را با تمام نسخه‌های فرعی پایتون که پشتیبانی می‌کند، آزمایش کنید.

همچنین توصیه می‌کنیم مستندات تمام API‌های استفاده‌شده را بررسی کنید تا مشخص شود که آیا به‌طور صریح بخشی از API محدود هستند یا خیر. حتی با تعریف Py_LIMITED_API، چند اعلان خصوصی به دلایل فنی (یا حتی ناخواسته، به‌عنوان باگ) در دسترس قرار می‌گیرند.

همچنین توجه داشته باشید که اگرچه کامپایل کردن با Py_LIMITED_API ۳.۸ به این معنی است که افزونه باید روی پایتون ۳.۱۲ بارگذاری شود و با پایتون ۳.۱۲ کامپایل شود، اما همان سورس لزوماً با تنظیم Py_LIMITED_API روی ۳.۱۲ کامپایل نخواهد شد. به طور کلی، بخش‌هایی از API محدود ممکن است منسوخ و حذف شوند، مشروط بر اینکه Stable ABI پایدار بماند.

ملاحظات پلتفرم

پایداری ABI نه تنها به پایتون، بلکه به کامپایلر استفاده‌شده، کتابخانه‌های سطح پایین‌تر و گزینه‌های کامپایلر نیز بستگی دارد. برای اهداف Stable ABIs، این جزئیات یک «پلتفرم» را تعریف می‌کنند. آن‌ها معمولاً به نوع سیستم‌عامل و معماری پردازنده بستگی دارند.

مسئولیت هر توزیع‌کننده‌ی خاص پایتون است که اطمینان حاصل کند تمام نسخه‌های پایتون روی یک پلتفرم خاص به گونه‌ای ساخته شده‌اند که Stable ABIها یا ABIهای خاصِ نسخه را مختل نکنند. این مورد در خصوص نسخه‌های ویندوز و macOS ارائه شده از سوی python.org و بسیاری از توزیع‌کنندگان شخص ثالث صادق است.

بررسی ABI

اضافه شده در نسخه‌ی 3.15.

پایتون شامل یک بررسی مقدماتی برای سازگاری ABI است.

این بررسی جامع نیست. این بررسی تنها در برابر موارد رایج نصب ماژول‌های ناسازگار برای مفسر اشتباه محافظت می‌کند. همچنین ناسازگاری‌های platform incompatibilities را در نظر نمی‌گیرد. این کار تنها پس از بارگذاری موفقیت‌آمیز یک افزونه قابل انجام است.

با وجود این محدودیت‌ها، توصیه می‌شود که ماژول‌های توسعه‌ای از این مکانیزم استفاده کنند تا ناسازگاری‌های قابل‌تشخیص به جای فروپاشی، استثناهایی را ایجاد کنند.

بیشتر ماژول‌ها می‌توانند از طریق جایگاه Py_mod_abi و کلان‌دستور PyABIInfo_VAR از این بررسی استفاده کنند، برای مثال به این شکل:

PyABIInfo_VAR(abi_info);

static PyModuleDef_Slot mymodule_slots[] = {
   {Py_mod_abi, &abi_info},
   ...
};

API کامل در ادامه برای موارد استفاده‌ی پیشرفته شرح داده شده است.

int PyABIInfo_Check(PyABIInfo *info, const char *module_name)
قسمتی از ABI پایدار از نسخه‌ی 3.15.

بررسی کنید که info داده‌شده با مفسر در حال اجرا سازگار باشد.

در صورت موفقیت مقدار ۰ را برمی‌گرداند. در صورت شکست، یک استثنا ایجاد کرده و ۱- برمی‌گرداند.

اگر ABI ناسازگار باشد، استثنای ایجادشده ImportError خواهد بود.

آرگومان module_name می‌تواند NULL باشد، یا به یک رشته‌ی کدگذاری‌شده با UTF-8 و پایان‌یافته با NUL که برای پیام‌های خطا استفاده می‌شود، اشاره کند.

توجه داشته باشید که اگر info نشان‌دهنده‌ی ABI باشد که کد فعلی از آن استفاده می‌کند (همان‌طور که توسط PyABIInfo_VAR تعریف شده است، برای مثال)، استفاده از هر API C دیگری از پایتون ممکن است منجر به فروپاشی شود. به‌ویژه، بررسی استثنای ایجادشده ایمن نیست.

اضافه شده در نسخه‌ی 3.15.

PyABIInfo_VAR(NAME)
This macro is available when compiling for the ABI پایدار از نسخه‌ی 3.15.

یک متغیر استاتیک PyABIInfo با نام NAME داده‌شده تعریف کنید که ABI مورد استفاده‌ی کد فعلی را توصیف می‌کند. این کلان‌دستور به شکل زیر باز می‌شود:

static PyABIInfo NAME = {
    1, 0,
    PyABIInfo_DEFAULT_FLAGS,
    PY_VERSION_HEX,
    PyABIInfo_DEFAULT_ABI_VERSION
}

اضافه شده در نسخه‌ی 3.15.

type PyABIInfo
قسمتی از ABI پایدار شامل تمام اعضا از نسخه‌ی 3.15.
uint8_t abiinfo_major_version

نسخه‌ی اصلی PyABIInfo. می‌تواند روی موارد زیر تنظیم شود:

  • 0 برای رد کردن تمام بررسی‌ها، یا

  • 1 برای مشخص کردن این نسخه از PyABIInfo.

uint8_t abiinfo_minor_version

نسخه‌ی فرعی PyABIInfo. باید روی 0 تنظیم شود؛ مقادیر بزرگ‌تر برای نسخه‌های آینده‌ی سازگار با عقب PyABIInfo رزرو شده‌اند.

uint16_t flags

این فیلد معمولاً روی کلان‌دستور زیر تنظیم می‌شود:

PyABIInfo_DEFAULT_FLAGS
قسمتی از ABI پایدار از نسخه‌ی 3.15.

پرچم‌های پیش‌فرض، بر اساس مقادیر فعلی کلان‌دستورهایی مانند Py_LIMITED_API و Py_GIL_DISABLED.

به‌عنوان جایگزین، این فیلد می‌تواند روی پرچم‌های زیر تنظیم شود که با عملگر بیتی OR ترکیب شده‌اند. بیت‌های استفاده‌نشده باید روی صفر تنظیم شوند.

نوع ABI -- یکی از موارد زیر:

PyABIInfo_STABLE
قسمتی از ABI پایدار از نسخه‌ی 3.15.

مشخص می‌کند که از ABI پایدار استفاده می‌شود.

PyABIInfo_INTERNAL

ABI مختص یک ساخت خاص از سی‌پایتون را مشخص می‌کند. فقط برای استفاده‌ی داخلی.

سازگاری با نخ‌بندی آزاد -- یکی از موارد زیر:

PyABIInfo_FREETHREADED
قسمتی از ABI پایدار از نسخه‌ی 3.15.

ABI سازگار با ساخت‌های نخ‌آزاد سی‌پایتون را مشخص می‌کند (یعنی آن‌هایی که با --disable-gil کامپایل شده‌اند؛ با t در sys.abiflags).

PyABIInfo_GIL
قسمتی از ABI پایدار از نسخه‌ی 3.15.

ABI سازگار با ساخت‌های غیرنخ‌آزاد سی‌پایتون را مشخص می‌کند (آن‌هایی که بدون --disable-gil کامپایل شده‌اند).

PyABIInfo_FREETHREADING_AGNOSTIC
قسمتی از ABI پایدار از نسخه‌ی 3.15.

ABI سازگار با هر دو ساخت نخ‌آزاد و غیرنخ‌آزاد سی‌پایتون را مشخص می‌کند، یعنی هر دو مقدار abi3 و abi3t.

uint32_t build_version

نسخه‌ی سرآیندهای پایتون که برای ساخت کد استفاده شده‌اند، در قالبی که PY_VERSION_HEX استفاده می‌کند.

این مقدار را می‌توان روی 0 تنظیم کرد تا هرگونه بررسی مربوط به این فیلد رد شود. این گزینه‌ی اصلی برای پروژه‌هایی در نظر گرفته شده است که مستقیماً از سرآیندهای سی‌پایتون استفاده نمی‌کنند و نسخه‌ی خاصی از آن‌ها را شبیه‌سازی نمی‌کنند.

uint32_t abi_version

نسخه‌ی ABI.

برای ABI پایدار، این فیلد باید مقدار Py_LIMITED_API یا Py_TARGET_ABI3T باشد. اگر هر دو تعریف شده باشند، مقدار کوچک‌تر را استفاده کنید. (اگر Py_LIMITED_API برابر با 3 است؛ به‌جای 3 از Py_PACK_VERSION(3, 2) استفاده کنید.)

در غیر این صورت، باید روی PY_VERSION_HEX تنظیم شود.

همچنین می‌توان آن را روی 0 تنظیم کرد تا هرگونه بررسی مربوط به این فیلد رد شود.

PyABIInfo_DEFAULT_ABI_VERSION
قسمتی از ABI پایدار از نسخه‌ی 3.15.

مقداری که باید برای این فیلد استفاده شود، بر اساس مقادیر فعلی کلان‌دستورهایی مانند Py_LIMITED_API، PY_VERSION_HEX و Py_GIL_DISABLED.

اضافه شده در نسخه‌ی 3.15.

محتویات API محدود

این فهرست قطعی Limited API برای پایتون 3.15 است: