Umstieg auf das stabile ABI für freies Threading ("abi3t")
**********************************************************

Seit der Veröffentlichung von 3.15 unterstützt CPython eine Variante
des stabilen ABI, die *free-threaded* Python unterstützt: das stabile
ABI für Free-Threaded-Builds, kurz "abi3t". Dieses Dokument
beschreibt, wie du C-API-Erweiterungen anpasst, damit sie freies
Threading unterstützen.


Warum man das tun sollte
========================

Der übliche Grund, das stabile ABI zu verwenden, ist, die Zahl der
Artefakte zu verringern, die du für jede Version deiner Bibliothek
bauen und verteilen musst.

Ohne das stabile ABI musst du für jede Funktionsversion von CPython,
die du unterstützen willst, eine eigene dynamische Bibliothek und
üblicherweise eine *Wheel*-Distribution bauen. Jede Kennzeichnung in
der folgenden Tabelle steht zum Beispiel für eine eigene Bibliothek
beziehungsweise ein eigenes Wheel:

+-------------------+-------------------------+--------------------------+
| CPython-Version   | Ohne freies Threading   | Mit freiem Threading     |
|===================|=========================|==========================|
| 3.12              | "cpython-312"           | ---                      |
+-------------------+-------------------------+--------------------------+
| 3.13              | "cpython-313"           | "cpython-313t"           |
+-------------------+-------------------------+--------------------------+
| 3.14              | "cpython-314"           | "cpython-314t"           |
+-------------------+-------------------------+--------------------------+
| 3.15              | "cpython-315"           | "cpython-315t"           |
+-------------------+-------------------------+--------------------------+
| 3.16              | "cpython-316"           | "cpython-316t"           |
+-------------------+-------------------------+--------------------------+
| Spätere Versionen | "cpython-3*XX*"         | "cpython-3*XX*t"         |
+-------------------+-------------------------+--------------------------+

Das sind eine Menge Builds, besonders wenn man sie mit der Zahl der
unterstützten Plattformen multipliziert.

Mit dem stabilen ABI ("abi3", eingeführt in CPython 3.2) kann eine
einzige Erweiterung (je Plattform) alle Builds von CPython *ohne
freies Threading* abdecken:

+-------------------+---------------------+--------------------------+
| CPython-Version   | Ohne freies         | Mit freiem Threading     |
|                   | Threading           |                          |
|===================|=====================|==========================|
| 3.12              | "abi3"              | ---                      |
+-------------------+                     +--------------------------+
| 3.13              |                     | "cpython-313t"           |
+-------------------+                     +--------------------------+
| 3.14              |                     | "cpython-314t"           |
+-------------------+                     +--------------------------+
| 3.15              |                     | "cpython-315t"           |
+-------------------+                     +--------------------------+
| 3.16              |                     | "cpython-316t"           |
+-------------------+                     +--------------------------+
| Spätere Versionen |                     | "cpython-3*XX*t"         |
+-------------------+---------------------+--------------------------+

Das stabile ABI für Free-Threaded-Builds ("abi3t"), eingeführt in
CPython 3.15, tut dasselbe für Free-Threaded-Builds. Und es ist
zugleich mit denen ohne freies Threading kompatibel:

+-------------------+---------------------+--------------------+
| CPython-Version   | Ohne freies         | Mit freiem         |
|                   | Threading           | Threading          |
|===================|=====================|====================|
| 3.12              | "abi3" *            | ---                |
+-------------------+                     +--------------------+
| 3.13              |                     | "cpython-313t"     |
+-------------------+                     +--------------------+
| 3.14              |                     | "cpython-314t"     |
+-------------------+---------------------+--------------------+
| 3.15              | "abi3t"                                  |
+-------------------+                     |                    |
| 3.16              |                                          |
+-------------------+                     |                    |
| Spätere Versionen |                                          |
+-------------------+---------------------+--------------------+

* (Wie oben ist die "abi3"-Erweiterung mit allen Builds ohne freies
Threading kompatibel – auch mit denen ab 3.15, die diese Tabelle
"abi3t" „zuschreibt“.)


Warum man das *nicht* tun sollte
--------------------------------

Das stabile ABI hat zwei wesentliche Nachteile.

Erstens kann deine Erweiterung langsamer werden, weil das stabile ABI
die Kompatibilität über die Leistung stellt. Der Unterschied ist
üblicherweise nicht bemerkbar und lässt sich oft abmildern, indem du
aus derselben Quelle sowohl einen Build mit stabilem ABI als auch
einige versionsspezifische Builds für die CPython-Versionen der „Stufe
1“ erzeugst.

Zweitens ist nicht die gesamte C-API verfügbar. Erweiterungen müssen
portiert werden, um für das stabile ABI gebaut werden zu können, und
das kann schwierig oder in seltenen Fällen unmöglich sein.

Insbesondere setzt "abi3t" APIs voraus, die in CPython 3.15 ergänzt
wurden. Wenn du deine Erweiterung aus derselben Quelle auch für ältere
CPython-Versionen bauen willst, hast du zwei wesentliche
Möglichkeiten:

* Verwende Bedingungen des Präprozessors.

  Verwende beim Befolgen dieser Anleitung "#ifdef
  Py_TARGET_ABI3T"-Blöcke, wann immer du eine Änderung vornehmen
  sollst, die den Build auf CPython-Versionen bricht, die dir wichtig
  sind. Behalte den bisherigen Code in "#else"-Blöcken.

  Für handgeschriebene C-Erweiterungen ist dieser Ansatz dank der
  Ergänzungen aus **PEP 697** bis hinunter zu CPython 3.12 vernünftig.
  Die Kompatibilität mit 3.11 und älter aufrechtzuerhalten, kann sich
  für Codegeneratoren lohnen (zum Beispiel für Cython).

* Portiere nicht auf "abi3t" und baue weiterhin eigene Erweiterungen
  für jede CPython-Version, bis du die Unterstützung für die älteren
  Versionen aufgeben kannst.

  Das ist ein gültiger Ansatz. Nicht jede Erweiterung muss jetzt schon
  auf "abi3t" umsteigen.


Voraussetzungen
===============

Diese Anleitung geht davon aus, dass du eine unmittelbar in C (oder
C++) geschriebene Erweiterung hast, die du auf "abi3t" portieren
willst.

Wenn deine Erweiterung einen Codegenerator (wie Cython) oder eine
Sprachanbindung (wie PyO3) verwendet, ist es am besten, zu warten, bis
dieses Werkzeug "abi3t" unterstützt. Wenn du ein solches Werkzeug
pflegst, kannst du die Hinweise hier möglicherweise für dein Werkzeug
anpassen.


Stabiles ABI ohne freies Threading
----------------------------------

Deine Erweiterung sollte das stabile ABI ohne freies Threading
("abi3") unterstützen. Falls nicht, portiere sie entweder zuerst
darauf oder folge dieser Anleitung und sei darauf vorbereitet,
Probleme zu beheben, die sie nicht erwähnt.


Unterstützung für freies Threading
----------------------------------

Es ist technisch gesehen keine harte Voraussetzung, aber du wirst
deine Erweiterung höchstwahrscheinlich auf freies Threading
vorbereiten wollen, bevor du sie auf "abi3t" portierst. Hinweise dazu
stehen unter Unterstützung von freiem Threading in C-API-
Erweiterungen.

Siehe auch:

  Porting Extension Modules to Support Free-Threading: eine von der
  Gemeinschaft gepflegte Portierungsanleitung für Autoren von
  Erweiterungen.


Erweiterungsmodule isolieren
----------------------------

Dein Modul sollte eine mehrphasige Initialisierung verwenden und
entweder isoliert sein oder sich darauf beschränken, je Prozess
höchstens einmal geladen zu werden. Ist das bei dir nicht der Fall,
folge zuerst Erweiterungsmodule isolieren. (Eine Abkürzung findest du
im Abschnitt zum Verzicht.)


Typen mit veränderlicher Größe vermeiden
----------------------------------------

Wenn deine Erweiterung Typen mit veränderlicher Größe definiert (über
"Py_tp_itemsize" oder "PyTypeObject.tp_itemsize"), lässt sie sich
nicht auf "abi3t" 3.15 portieren.


Den Build einrichten
====================

If you use a build tool, search its documentation for ""abi3t"", and
follow any instructions to select the ABI. For reference, here are
direct links for several popular build tools:

* meson-python

* scikit-build-core

* Maturin

You may want to verify that the tool set the right flag by temporarily
adding the following just after "#include <Python.h>":

   #if Py_TARGET_ABI3T+0 <= 0x30f0000
   #error "abi3t define is not set!"
   #endif

Das sollte zu einem anderen Fehler führen als „"abi3t" define is not
set“.

Siehe auch:

  Building and distributing abi3t extensions: Build configuration and
  wheel testing examples in the community-maintained Python Free-
  Threading Guide.

Bemerkung:

  Wenn dein Build-Werkzeug "abi3t" noch nicht unterstützt, setze vor
  dem Einbinden von "Python.h" das folgende Makro:

     #define Py_TARGET_ABI3T 0x30f0000

  oder gib es als Compilerflag an, zum Beispiel:

     -DPy_TARGET_ABI3T=0x30f0000

  Sobald deine Erweiterung mit dieser Einstellung baut, ist sie mit
  CPython 3.15 und neuer kompatibel.Wenn du dieses Makro von Hand
  setzt, musst du die entstehende Erweiterung später ebenfalls von
  Hand benennen und kennzeichnen. Das wird unten unter Kennzeichnen
  und Verteilen behandelt.

Diese Anleitung bittet dich, eine Reihe von Änderungen vorzunehmen.
Prüfe nach jeder einzelnen, ob deine Erweiterung in der ursprünglichen
Konfiguration (ohne "abi3t") noch baut, und lasse im Idealfall die
Tests auf allen Python-Versionen laufen, die du unterstützt. So
stellst du sicher, dass beim Portieren nichts bricht.


Export-Haken des Moduls
=======================

Unless you've done this step already, your extension module defines a
module initialization function named "PyInit_*<modname>*" (where
"modname" is the name of your module). You will need to port it to a
module export hook, "PyModExport_*<modname>*", a feature added in
CPython 3.15 in **PEP 793**.

Deine bestehende init-Funktion sollte so aussehen (mit deinen eigenen
Namen für "<modname>" und "<moddef>"):

   PyMODINIT_FUNC
   PyInit_<modname>(void)
   {
       return PyModuleDef_Init(&<moddef>);
   }

Steht vor dem "return" noch Code, verschiebe ihn in eine Slot-Funktion
"Py_mod_create" oder "Py_mod_exec". Verwandte Informationen stehen in
der PyInit-Dokumentation.

Die Funktion verweist auf ein "PyModuleDef"-Objekt ("<moddef>" im
obigen Code). Dessen Definition dürfte dem Folgenden ähneln, mit
anderen Werten und vielleicht einigen unbenannten oder weggelassenen
Feldern:

   static PyModuleDef <moddef> = {
       PyModuleDef_HEAD_INIT,
       .m_name = "my_module",
       .m_doc = "my docstring",
       .m_size = sizeof(my_state_struct),
       .m_methods = my_methods,
       .m_slots = my_slots,
       .m_traverse = my_traverse,
       .m_clear = my_clear,
       .m_free = my_free,
   };

Entferne diese Definition und die "PyInit"-Funktion (oder stecke sie
in einen "#ifndef Py_TARGET_ABI3T"-Block, um die
Rückwärtskompatibilität zu erhalten) und ersetze sie durch Folgendes:

   PyABIInfo_VAR(abi_info);

   static PySlot my_slot_array[] = {
       PySlot_STATIC_DATA(Py_mod_abi, &abi_info),
       PySlot_STATIC_DATA(Py_mod_name, "my_module"),
       PySlot_STATIC_DATA(Py_mod_doc, "my docstring"),
       PySlot_SIZE(Py_mod_state_size, sizeof(my_state_struct)),
       PySlot_STATIC_DATA(Py_mod_methods, my_methods),
       PySlot_STATIC_DATA(Py_mod_slots, my_slots),
       PySlot_FUNC(Py_mod_state_traverse, my_traverse),
       PySlot_FUNC(Py_mod_state_clear, my_clear),
       PySlot_FUNC(Py_mod_state_free, my_free),
       PySlot_END
   };

   PyMODEXPORT_FUNC
   PyModExport_<modname>(void)
   {
       return my_slot_array;
   }

Lasse alle Felder weg, die gefehlt haben (außer dem neuen
"Py_mod_abi"), und setze deine eigenen Werte ein.

Einzelheiten zu dieser API stehen in der Dokumentation zu "PySlot" und
zum Export-Haken.

Wie im Beispiel sollte deine "PyModExport_"-Funktion *nur* einen
Zeiger auf statische Daten zurückgeben. Wenn du zusätzlichen Code
nicht vermeiden kannst, lies die Vorbehalte in der PyModExport-
Dokumentation.

Bemerkung:

  When building for Windows using the Setuptools build tool, removing
  the "PyInit_*<modname>*" function may result in the linker error
  "LINK : error LNK2001: unresolved external symbol
  PyInit_*<modname>*". This is caused by Setuptools passing an
  "/EXPORT" linker flag, which is redundant since Python 3.15 (see
  gh-141671). A workaround is to add a dummy "PyInit_*<modname>*"
  function to your code. Python 3.15+ will never call this function if
  "PyModExport_*<modname>*" is present, so it can always fail:

     // Workaround for https://github.com/pypa/distutils/issues/387
     PyMODINIT_FUNC
     PyInit_<modname>(void)
     {
         PyErr_SetString(PyExc_SystemError,
                         "PyInit_* called for module with PyModExport_*");
         return NULL;
     }

  (This issue is present in Setuptools 84.0.0; it might be fixed in
  newer versions.)


Bestehende Slots
----------------

Wenn du einen "Py_mod_slots"-Slot hast, prüfe das Feld, auf das er
verweist. Es sollte ein "PyModuleDef_Slot"-Feld wie das folgende sein:

   static PyObject *create_module(PyObject *spec, PyModuleDef *def) { ... }
   static int my_first_module_exec(PyObject *module) { ... }
   static int my_second_module_exec(PyObject *module) { ... }

   static PyModuleDef_Slot my_slots[] = {
      {Py_mod_gil, Py_MOD_GIL_NOT_USED},
      {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
      {Py_mod_create, my_module_create},
      {Py_mod_exec, my_first_module_exec},
      {Py_mod_exec, my_second_module_exec},
      {0, NULL}
   };


"py_mod_create"
~~~~~~~~~~~~~~~

Wenn du einen "Py_mod_create"-Eintrag hast, stelle sicher, dass die
Funktion mit "NULL" als zweitem Argument aufgerufen werden kann
(anstelle des "PyModuleDef", das du entfernst). Oft wird dieses
Argument überhaupt nicht verwendet. Du kannst das prüfen, indem du es
umbenennst:

   static PyObject *create_module(PyObject *spec, PyModuleDef *_unused) { ... }

Wird das Argument verwendet, finde einen anderen Weg, die Daten
hineinzugeben. Üblicherweise ist die Information statisch und du
kannst unmittelbar darauf verweisen. (Wenn du eine einzige Funktion
für mehrere verschiedene Module wiederverwendest, erwäge, stattdessen
mehrere Funktionen zu definieren.)


Multiple "py_mod_exec"
~~~~~~~~~~~~~~~~~~~~~~

Wenn du *mehr als einen* "Py_mod_exec"-Eintrag hast, fasse sie
zusammen: Erzeuge eine neue Funktion, die die anderen aufruft, und
ersetze die bestehenden Slots durch sie.

   static int my_module_exec(PyObject *module) {
      if (my_first_module_exec(module) < 0) return -1;
      if (my_second_module_exec(module) < 0) return -1;
   }

   static PyModuleDef_Slot my_slots[] = {
      ...
      /* (remove other Py_mod_exec slots) */
      ...
      {Py_mod_exec, my_module_exec},
      {0, NULL}
   };

Werden die Funktionen nicht anderswo verwendet, kannst du ihre Rümpfe
stattdessen zusammenlegen.


Slot-Felder zusammenführen
~~~~~~~~~~~~~~~~~~~~~~~~~~

Wenn du die Kompatibilität mit Python 3.14 aufgibst, kannst du den
Code auf Wunsch aufräumen, indem du die Slots in das "PySlot"-Feld
verschiebst und die Definitionen auf "PySlot_DATA" und "PySlot_FUNC"
umstellst:

   static PySlot my_slot_array[] = {
       ...
       PySlot_DATA(Py_mod_gil, Py_MOD_GIL_NOT_USED),
       PySlot_DATA(Py_mod_multiple_interpreters,
            Py_MOD_PER_INTERPRETER_GIL_SUPPORTED)
       PySlot_FUNC(Py_mod_create, my_module_create),
       PySlot_FUNC(Py_mod_exec, my_module_exec),
       PySlot_END
   };

Wenn du das tust, lösche das ursprüngliche "PyModuleDef_Slot"-Feld und
seinen "Py_mod_slots"-Eintrag.


Zugehöriges "PyModuleDef"
-------------------------

Da die neue API keine "PyModuleDef"-Struktur verwendet, wird dem
entstehenden Modul keine Definition zugeordnet. Das ändert das
Verhalten der folgenden Funktionen:

* "PyModule_GetDef()"

* "PyType_GetModuleByDef()"

Prüfe deinen Code auf diese Funktionen. Wenn du sie nicht verwendest,
kannst du diesen Abschnitt überspringen.

Diese Funktionen werden üblicherweise für zwei Zwecke verwendet:

1. Um die Definition zu bekommen, mit der das Modul erzeugt wurde. Mit
   der neuen API ist das nicht mehr möglich. Module halten keine
   Referenz mehr auf die Definition. Du musst dir also einen anderen
   Weg überlegen, die relevanten Daten weiterzugeben.

2. Um zu prüfen, ob ein gegebenes Modulobjekt „deines“ ist. Dieser
   Anwendungsfall wird jetzt über Modul-Token abgedeckt –
   undurchsichtige Zeiger, die ein Modul kennzeichnen. Um ein Token zu
   verwenden, deklariere (oder wiederverwende) eine eindeutige
   statische Variable, zum Beispiel:

      static char my_token;

   und ergänze in einem neuen Eintrag des "PySlot"-Feldes deines
   Moduls einen Zeiger darauf:

      static PySlot my_slot_array[] = {
         ...
         PySlot_STATIC_DATA(Py_mod_token, &my_token),
         PySlot_END
      }

   Wechsle dann von "PyModule_GetDef()"-Aufrufen wie:

      PyModuleDef *def = PyModule_GetDef(module);

   zu "PyModule_GetToken()" (das ein Ausgabeargument verwendet und mit
   einer Ausnahme scheitern kann):

      void *token;
      if (PyModule_GetToken(module, &token) < 0) {
          /* handle error */
      }

   und von "PyType_GetModuleByDef()"-Aufrufen wie:

      PyObject *module = PyType_GetModuleByDef(type, my_def);
      /* handle error; use module */

   zu "PyType_GetModuleByToken()" (das eine starke Referenz
   zurückgibt):

      PyObject *module = PyType_GetModuleByToken(type, my_token);
      /* handle error; use module */
      Py_XDECREF(module);


Undurchsichtigkeit von "PyObject"
=================================

Die Strukturen "PyObject" und "PyVarObject" sind in "abi3t"
undurchsichtig.

Der Zugriff auf ihre Felder ist verboten. Wenn du das tust, wechsle zu
den Lese- und Schreibfunktionen, die in deren Dokumentation genannt
sind:

* "PyObject.ob_type"

* "PyObject.ob_refcnt"

* "PyVarObject.ob_size"

Außerdem ist die *Größe* der "PyObject"-Strukturen dem Compiler
unbekannt. Sie kann sich zwischen verschiedenen CPython-Builds ändern
– und sie *tut* es.

Bemerkung:

  Die Größe ist zur Laufzeit zwar verfügbar (in Python-Code zum
  Beispiel als "sys.getsizeof(object())"), du solltest der Versuchung
  aber widerstehen, daraus Zeigerversätze zu berechnen. Die
  Speicheranordnung der Objekte kann sich in künftigen
  "abi3t"-Implementierungen ändern.


Eigene Typdefinitionen
----------------------

Da "PyObject" undurchsichtig ist, funktioniert der herkömmliche Weg,
eigene Typen zu definieren, nicht mehr:

   typedef struct {
      PyObject_HEAD  // expands to `PyObject ob_base;` which has unknown size

      int my_data;
   } CustomObject;

   static PyType_Spec CustomType_spec = {
      ...
      .basicsize = sizeof(CustomObject),
      ...
   };

Höchstwahrscheinlich müssen alle deine Klassendefinitionen *und* aller
Code, der auf die Daten deiner Klassen zugreift, neu geschrieben
werden. Das dürfte die größte Änderung sein, die du für "abi3t"
brauchst.

Definiere für jeden solchen Typ, anstelle einer "struct" für die
gesamte Instanz, eine mit ausschließlich den „zusätzlichen“ Feldern –
denen, die zu deiner Klasse gehören und nicht zu ihren Oberklassen:

   typedef struct {
      int my_data;
   } CustomObjectData;

Ändere den Namen. Fast aller Code, der die Struktur verwendet, muss
sich ändern (vor allem lassen sich Zeiger auf die neue Struktur nicht
von und nach "PyObject*" umwandeln), und die Namensänderung hebt die
Verwendungsstellen als Compilerfehler hervor. (Wenn du "typeof",
"auto" aus C++ oder ähnliche Wege nutzt, um den Typnamen nicht
ausschreiben zu müssen, funktioniert das nicht. Sei dann besonders
vorsichtig und erwäge, Werkzeuge zum Aufspüren undefinierten
Verhaltens laufen zu lassen.)

Verwende dann zum Erzeugen der Klasse eine *negative* "basicsize", um
„zusätzlichen“ Speicherplatz anzugeben und nicht die *gesamte*
Instanzgröße:

   static PyType_Spec CustomType_spec = {
      ...
      .basicsize = -sizeof(CustomObjectData), /* note the minus sign */
      ...
   };

Wenn du "Py_tp_members" verwendest, setze bei jedem Feld das Flag
"Py_RELATIVE_OFFSET" und gib den "offset" relativ zu deiner neuen
Struktur an.


Zugriff auf die Daten eigener Typen
-----------------------------------

Dann kommt der schwierige Teil: In allem Code, der auf diese Struktur
zugreifen muss, brauchst du einen zusätzlichen Aufruf von
"PyObject_GetTypeData()", um aus einem "PyObject *" einen Zeiger
"CustomObjectData *" zu gewinnen:

   PyObject *obj = ...;
   CustomObjectData *data = PyObject_GetTypeData(obj, cls);

Beachte, dass dieser Aufruf das *Typobjekt* deiner Klasse ("cls")
verlangt.

Ist deine Klasse nicht ableitbar (verwendet sie also nicht das Flag
"Py_TPFLAGS_BASETYPE"), ist "cls" gleich "Py_TYPE(obj)". Andernfalls
**VERWENDE** "Py_TYPE" **NICHT** mit "PyObject_GetTypeData()": Es
könnte Speicher zurückgeben, der einer nicht verwandten Unterklasse
vorbehalten ist! Wenn ein Benutzer zum Beispiel eine Unterklasse wie
diese anlegt:

   class Sub(YourCustomClass):
      __slots__ = ('a', 'b')

dann ist "Py_TYPE(obj)" gleich "Sub", und der darunterliegende
Speicher kann so aussehen:

   ╭─ PyObject *obj
   │              ╭─ the pointer you want
   │              │                    ╭─ PyObject_GetTypeData(obj, Py_TYPE(obj))
   ▼              ▼                    ▼
   ┌──────────┬───┬────────────────┬───┬─────────────┬───┬─────────────┐
   │ PyObject │...│ CustomTypeData │...│ PyObject *a │...│ PyObject *b │
   └──────────┴───┴────────────────┴───┴─────────────┴───┴─────────────┘

(Auslassungspunkte deuten möglichen Füllraum an. Beachte, dass diese
Speicheranordnung nicht zugesichert ist: Künftige Python-Versionen
können anderen Füllraum ergänzen oder sogar die Reihenfolge der
Strukturen ändern.)

Es gibt zwei wesentliche Wege, die richtige Klasse zu bekommen:

* In Instanzmethoden kann deine Implementierung die Signatur
  "PyCMethod" verwenden (und das Bit "METH_METHOD" in
  "PyMethodDef.ml_flags") und die Klasse als Argument "defining_class"
  bekommen.

* Andernfalls gib deiner Klasse über den Slot "Py_tp_token" ein
  eindeutiges statisches Token und verwende:

     PyTypeObject cls;
     if (PyType_GetBaseByToken(Py_TYPE(obj), my_tp_token, &cls) < 0) {
         /* handle error */
     }
     CustomObjectData *data = PyObject_GetTypeData(obj, cls);

  Typ-Token arbeiten ähnlich wie die Modul-Token, die früher in dieser
  Anleitung behandelt wurden.


Bedingungen zur Build-Zeit vermeiden
====================================

Prüfe deinen Code auf APIs, die die Python-Version bestimmen, mit der
deine Erweiterung *gebaut* wurde. Diese entspricht nicht mehr dem
Python, auf dem deine Erweiterung läuft; Code, der diese Information
nutzt, muss daher häufig geändert werden. Die Makros, auf die zu
prüfen ist, sind:

* "PY_VERSION_HEX", "PY_MAJOR_VERSION", "PY_MINOR_VERSION":

  * um die Laufzeitversion zu bekommen, verwende "Py_Version";

  * um zu bestimmen, welche C-API verfügbar ist, verwende
    "Py_TARGET_ABI3T". Dieses Makro ist auf die mindestens
    unterstützte Version gesetzt.

* "Py_GIL_DISABLED": Unter "abi3t" ist dieses Makro immer definiert.
  Code, der mit Python mit freiem Threading arbeitet, *sollte* auch
  mit eingeschaltetem GIL arbeiten (weil der GIL zur Laufzeit
  eingeschaltet werden kann), und üblicherweise *tut* er das auch
  (sofern er nicht aus irgendeinem Grund mehr als einen *angehängten
  Thread-Zustand* gleichzeitig braucht).


Weitere Codeänderungen
======================

Wenn dir noch Compilerfehler oder Warnungen bleiben, finde einen Weg,
sie zu beheben. Diese Anleitung ist leider begrenzt und kann nicht
alle möglichen Codeänderungen abdecken, die Erweiterungen brauchen
können.

Wenn du ein Problem findest, auf das auch andere Autoren von
Erweiterungen stoßen könnten, erwäge, für diese Anleitung ein Problem
zu melden (oder einen Pull Request zu schicken).

Es ist möglich, dass dein Problem für die aktuelle Fassung von "abi3t"
nicht behoben werden kann. In diesem Fall kann eine Meldung helfen,
dass es für die nächste CPython-Version vorgezogen wird.


Kennzeichnen und Verteilen
==========================

Wenn du ein Build-Werkzeug mit "abi3t"-Unterstützung verwendest, ist
deine Erweiterung fertig, aber du solltest vielleicht prüfen, ob sie
richtig gebaut wurde.

Erweiterungen, die mit "abi3t" gebaut wurden, sollten die folgende
Dateiendung haben:

* Unter Windows: ".pyd" (wie jede andere Erweiterung);

* Unter Linux, macOS und anderen Systemen, die die Endung ".so"
  verwenden: ".abi3t.so" (**nicht** ".cpython-315t.so" oder
  ".abi3.so"). Beachte, dass sowohl Builds mit als auch ohne freies
  Threading ".abi3t.so"-Erweiterungen laden;

* Andere Systeme: Frage bei deinem Distributor nach und ergänze diese
  Anleitung vielleicht.

Wenn du die Erweiterung als *Wheel* verteilst, verwende die folgenden
Kennzeichnungen:

* Python-Kennzeichnung: "cp3*XX*", wobei *XX* die kleinste Python-
  Version ist, für die die Erweiterung gebaut wurde. (Zum Beispiel
  "cp315", wenn du "Py_TARGET_ABI3T" auf "0x30f0000" gesetzt hast.
  Weitere Werte stehen unter Compiling for Stable ABI.)

* ABI-Kennzeichnung: "abi3.abi3t". Das ist ein *komprimierter
  Kennzeichnungssatz*, der die Unterstützung für Builds sowohl mit als
  auch ohne freies Threading angibt.

Der Dateiname des Wheels kann zum Beispiel so aussehen:

   myproject-1.0-cp315-abi3.abi3t-macosx_11_0_arm64.whl

Siehe auch:

  Platform Compatibility Tags in den Metadaten zur Paketverteilung der
  PyPA.

Wenn der Dateiname oder die Kennzeichnungen falsch sind, korrigiere
sie.


Testen
======

Beachte: Wenn du eine Erweiterung baust, die mit mehreren CPython-
Versionen kompatibel ist, solltest du sie immer mit jeder
unterstützten Version *testen* (zum Beispiel 3.15, 3.16 und so
weiter). Das stabile ABI sichert nur die *ABI*-Kompatibilität zu. Es
kann auch Verhaltensänderungen geben – sowohl beabsichtigte (abgedeckt
durch **PEP 387**) als auch Fehler.

Lasse die Tests unbedingt auf Builds von CPython sowohl mit als auch
ohne freies Threading laufen.

Wenn sie durchlaufen: Gratulation! Du hast eine "abi3t"-Erweiterung.
