PEP 3149 – ABI version tagged .so files
- Autor:
- Barry Warsaw <barry at python.org>
- Status:
- Final
- Typ:
- Standards Track
- Erstellt:
- 09-Jul-2010
- Python-Version:
- 3.2
- Post-History:
- 14-Jul-2010, 22-Jul-2010
- Resolution:
- Python-Dev Nachricht
Zusammenfassung
PEP 3147 beschrieb eine Erweiterung von Pythons Importmechanismus, die das Teilen von Python-Quellcode verbesserte, indem mehr als eine Byte-Kompilierungsdatei (.pyc) zusammen mit jeder Quelldatei abgelegt werden konnte.
Diese PEP definiert ein ergänzendes Feature, das die gleichzeitige Ablage von Erweiterungsmoduldateien (.so) in ähnlicher Weise ermöglicht. Dieses optionale, zur Build-Zeit aktivierbare Feature wird Downstream-Distributionen von Python erleichtern, mehr als eine Python-Hauptversion gleichzeitig bereitzustellen.
Hintergrund
PEP 3147 definierte das Dateisystem-Layout für ein reines Python-Paket, bei dem mehrere Python-Versionen auf dem System verfügbar sind. Zum Beispiel, wenn das Paket alpha mit den Quellmodulen one.py und two.py auf einem System mit Python 3.2 und 3.3 existiert, wäre das Dateisystem-Layout nach der Byte-Kompilierung:
alpha/
__pycache__/
__init__.cpython-32.pyc
__init__.cpython-33.pyc
one.cpython-32.pyc
one.cpython-33.pyc
two.cpython-32.pyc
two.cpython-33.pyc
__init__.py
one.py
two.py
Für Pakete mit Erweiterungsmodulen ist eine ähnliche Differenzierung für die .so-Dateien des Moduls erforderlich. Erweiterungsmodule, die für verschiedene Python-Hauptversionen kompiliert wurden, sind aufgrund von ABI-Änderungen inkompatibel. Unterschiedliche Konfigurations-/Kompilierungsoptionen für dieselbe Python-Version können zu unterschiedlichen ABIs führen (z.B. –with-wide-unicode).
Während PEP 384 eine stabile ABI definiert, wird sie Inkompatibilitäten von Erweiterungsmodulen zwischen Python-Builds oder Hauptversionen minimieren, aber nicht eliminieren. Daher wird ein Mechanismus zur Unterscheidung von Dateinamen von Erweiterungsmodulen vorgeschlagen.
Begründung
Linux-Distributionen wie Ubuntu [3] und Debian [4] stellen ihren Benutzern mehr als eine Python-Version gleichzeitig zur Verfügung. Zum Beispiel können Ubuntu 9.10 Karmic Koala-Benutzer Python 2.5, 2.6 und 3.1 installieren, wobei Python 2.6 der Standard ist.
Um so viel wie möglich zwischen den verfügbaren Python-Versionen zu teilen, installieren diese Distributionen Drittanbieter-Paketmodule (.pyc und .so Dateien) in /usr/share/pyshared und verlinken sie von /usr/lib/pythonX.Y/dist-packages. Die Symlinks existieren, weil in einer Welt vor PEP 3147 (d.h. < Python 3.2) die .pyc-Dateien, die aus der Byte-Kompilierung durch die verschiedenen installierten Pythons resultieren, Namenskollisionen untereinander verursachen werden. Für Python-Versionen >= 3.2 können alle reinen Python-Pakete geteilt werden, da die .pyc-Dateien keine Namenskonflikte im Dateisystem mehr verursachen werden. Die Eliminierung dieser Symlinks führt zu einer einfacheren und robusteren Python-Distribution.
Eine ähnliche Situation ergibt sich bei gemeinsam genutzten Bibliotheks-Erweiterungen. Da Erweiterungsmodule typischerweise foo.so für ein foo-Erweiterungsmodul heißen, würden diese ebenfalls Namenskollisionen verursachen, wenn foo für mehr als eine Python-Version bereitgestellt würde.
Darüber hinaus können unterschiedliche Konfigurations-/Kompilierungsoptionen für dieselbe Python-Version unterschiedliche ABIs für Erweiterungsmodule aufweisen. Auf POSIX-Systemen ändern beispielsweise die Konfigurationsoptionen --with-pydebug, --with-pymalloc und --with-wide-unicode die ABI. Diese PEP schlägt vor, Build-Zeit-Optionen in den Dateinamen der .so-Erweiterungsmoduldateien zu kodieren.
PyPy [5] kann ebenfalls von dieser PEP profitieren und ermöglicht es, Namenskollisionen bei Erweiterungsmodulen zu vermeiden, die für seine API, aber mit einem anderen .so-Tag erstellt wurden.
Vorschlag
Die zur Build-Zeit des Python-Interpreters gewählten Konfigurations-/Kompilierungsoptionen werden im Dateinamen der Shared-Library für Erweiterungsmodule kodiert. Dieser "Tag" erscheint zwischen dem Basisnamen des Moduls und der Dateisystemerweiterung für Shared Libraries.
Die folgenden Informationen *MÜSSEN* im Dateinamen der Shared Library enthalten sein
- Die Python-Implementierung (z.B. cpython, pypy, jython, etc.)
- Die Major- und Minor-Versionsnummern des Interpreters
Diese beiden Felder sind durch einen Bindestrich getrennt, und zwischen den Major- und Minor-Versionsnummern dürfen keine Punkte stehen. Zum Beispiel cpython-32.
Python-Implementierungen *KÖNNEN* nach Bedarf zusätzliche Flags im Dateinamen-Tag enthalten. Zum Beispiel tragen auf POSIX-Systemen diese Flags ebenfalls zum Dateinamen bei
--with-pydebug(Flag:d)--with-pymalloc(Flag:m)--with-wide-unicode(Flag:u)
Standardmäßig aktiviert configure in Python 3.2 --with-pymalloc, sodass Shared-Library-Dateinamen als foo.cpython-32m.so erscheinen würden. Wenn die beiden anderen Flags ebenfalls aktiviert sind, wären die Dateinamen foo.cpython-32dmu.so.
Der Shared-Library-Dateinamen-Tag wird bedingungslos verwendet; er kann nicht geändert werden. Der Tag und die Erweiterungsmodul-Endung sind über die sysconfig-Module über die folgenden Variablen verfügbar
>>> sysconfig.get_config_var('EXT_SUFFIX')
'.cpython-32mu.so'
>>> sysconfig.get_config_var('SOABI')
'cpython-32mu'
Beachten Sie, dass $SOABI nur den Tag enthält, während $EXT_SUFFIX die plattformspezifische Erweiterung für Shared-Library-Dateien enthält und die exakte Erweiterung ist, die dem Erweiterungsmodulnamen hinzugefügt wird.
Für ein beliebiges Paket foo könnten Sie diese Dateien sehen, wenn das Distributionspaket installiert wurde
/usr/lib/python/foo.cpython-32m.so
/usr/lib/python/foo.cpython-33m.so
(Diese Pfade dienen nur zu Beispielzwecken. Distributionen können ein beliebiges Dateisystem-Layout verwenden, und nichts in dieser PEP ändert die Speicherorte, an denen Python-Versionen aus dem Quellcode installiert werden.)
Pythons dynamischer Modul-Loader erkennt und importiert Shared-Library-Erweiterungsmodule mit einem Tag, der seinen Build-Zeit-Optionen entspricht. Aus Gründen der Abwärtskompatibilität wird Python auch weiterhin nicht-getaggte Erweiterungsmodule importieren, z.B. foo.so.
Dieser Shared-Library-Tag würde global für alle distutils-basierten Erweiterungsmodule verwendet, unabhängig davon, wo im Dateisystem sie erstellt werden. Erweiterungsmodule, die mit anderen Mitteln als distutils erstellt werden, müssten entweder den Tag manuell berechnen oder auf den nicht-getaggten .so-Dateinamen zurückfallen.
Bewährter Ansatz
Der hier beschriebene Ansatz ist in gewissem Sinne bereits auf Debian- und Ubuntu-Systemen bewährt, wo unterschiedliche Erweiterungen für Debug-Builds von Python und Erweiterungsmodulen verwendet werden. Debug-Builds unter Windows verwenden ebenfalls bereits eine andere Dateiendung für dynamische Bibliotheken und kodieren (auf eine andere Weise als in dieser PEP vorgeschlagen) die Major- und Minor-Version von Python im .dll-Dateinamen.
Windows
Diese PEP befasst sich nur mit Build-Problemen auf POSIX-Systemen, die das configure-Skript verwenden. Während Windows- oder andere Plattformunterstützungen unter dieser PEP nicht ausdrücklich untersagt sind, ist Plattformexpertise erforderlich, um Unterstützung auf solchen Plattformen zu bewerten, zu beschreiben und zu implementieren. Es ist derzeit nicht klar, ob die in dieser PEP vorgesehenen Einrichtungen für Windows überhaupt nützlich sind.
PEP 384
PEP 384 definiert eine stabile ABI für Erweiterungsmodule. Theoretisch würde die universelle Annahme von PEP 384 die Notwendigkeit dieser PEP beseitigen, da alle Erweiterungsmodule mit jeder Python-Version kompatibel sein könnten. In der Praxis wird es natürlich unmöglich sein, eine universelle Annahme zu erreichen, und wie oben beschrieben, beeinflussen unterschiedliche Build-Zeit-Flags immer noch die ABI. Daher kann diese PEP auch mit einer stabilen ABI notwendig sein. Während eine vollständige Spezifikation für PEP 384 reserviert ist, folgt hier eine Diskussion der relevanten Probleme.
PEP 384 beschreibt eine Änderung an PyModule_Create(), bei der 3 als API-Version übergeben wird, wenn die Erweiterung mit Py_LIMITED_API kompiliert wurde. Dies sollte in einem offiziellen Makro namens PYTHON_ABI_VERSION formalisiert werden, um PYTHON_API_VERSION zu spiegeln. Wenn und wenn sich die ABI auf inkompatible Weise ändert, würde diese Versionsnummer erhöht. Um die gemeinsame Nutzung zu erleichtern, würde Python erweitert, um nach Erweiterungsmodulen mit der PYTHON_ABI_VERSION Nummer im Namen zu suchen. Das Präfix abi ist für die Verwendung durch Python reserviert.
Somit würde eine anfängliche Implementierung von PEP 384, wenn Python mit dem Standard-Set von Flags konfiguriert ist, nach den folgenden Dateinamen suchen, wenn das Erweiterungsmodul foo importiert wird (in dieser Reihenfolge)
foo.cpython-XYm.so
foo.abi3.so
foo.so
Der distutils [6] build_ext-Befehl müsste ebenfalls erweitert werden, um in Shared-Library-Dateien mit dem abi3-Tag zu kompilieren, wenn der Modulautor angibt, dass seine Erweiterung diese Version der ABI unterstützt. Dies könnte auf abwärtskompatible Weise geschehen, indem ein Schlüsselwortargument zur Extension-Klasse hinzugefügt wird, wie zum Beispiel
Extension('foo', ['foo.c'], abi=3)
Martin v. Löwis beschreibt seine Gedanken [7] zur Anwendbarkeit dieser PEP auf PEP 384. Zusammenfassend
--with-pydebugwürde nicht von der stabilen ABI unterstützt, da dies das Layout vonPyObjectändert, was eine exponierte Struktur ist.--with-pymallochat keinen Einfluss auf die Angelegenheit.--with-wide-unicodeist kniffliger, obwohl Martins Neigung darin besteht, die stabile ABI zu zwingen, einPy_UNICODEzu verwenden, das mit demwchar_tder Plattform übereinstimmt.
Alternativen
In der anfänglichen python-dev-Thread [8], in der diese Idee zum ersten Mal vorgestellt wurde, wurden mehrere Alternativen vorgeschlagen. Der Vollständigkeit halber sind sie hier aufgeführt, zusammen mit den Gründen, warum sie nicht übernommen wurden.
Unabhängige Verzeichnisse oder Symlinks
Debian und Ubuntu könnten einfach ein versionsspezifisches Verzeichnis zu sys.path hinzufügen, das nur die Erweiterungsmodule für diese Python-Version enthält. Oder der in PEP 3147 eliminierte Symlink-Trick könnte nur für Shared Libraries beibehalten werden. Dieser Ansatz wird abgelehnt, da er die wesentliche Komplexität fortsetzt, die PEP 3147 zu vermeiden versucht, und potenziell mehrere zusätzliche Verzeichnisse zum Durchsuchen aller Module hinzufügt, selbst wenn die Anzahl der Erweiterungsmodule viel geringer ist als die Gesamtzahl der Python-Pakete. Zum Beispiel wurden Builds sowohl mit als auch ohne Wide Unicode, mit und ohne PyDebug und mit und ohne PyMalloc verfügbar gemacht, wodurch die Gesamtzahl der zu durchsuchenden Verzeichnisse erheblich steigt.
Referenzimplementierung
Die Arbeit an diesem Code wird in einem Bazaar-Branch auf Launchpad [9] verfolgt, bis er für den Merge in Python 3.2 bereit ist. Der Work-in-Progress-Diff kann auch [10] eingesehen werden und wird automatisch aktualisiert, sobald neue Änderungen hochgeladen werden.
Referenzen
Urheberrecht
Dieses Dokument wurde gemeinfrei erklärt.
Source: https://github.com/python/peps/blob/main/peps/pep-3149.rst
Zuletzt geändert: 2025-02-01 08:59:27 GMT