Hinweis: Obwohl JavaScript für diese Website nicht unbedingt erforderlich ist, werden Ihre Interaktionsmöglichkeiten mit den Inhalten eingeschränkt sein. Bitte aktivieren Sie JavaScript für das volle Erlebnis.

Zusammenfassung der "Extension Building"-Sitzung

"Extension Building Considered Painful": Sitzungszusammenfassung

von Greg Ward

Die "Extension Building Considered Painful"-Sitzung auf der IPC7 war sehr produktiv, und es gab einen guten Konsens im Raum darüber, was benötigt wird, was für verschiedene Benutzerklassen funktionieren wird und welche Ideen von anderen verwandten Systemen übernommen werden sollen (am nächsten kommen Red Hats RPM und Perls MakeMaker).

Getroffene Entscheidungen

Alle schienen mit meinem vorgeschlagenen Betriebsmodus einverstanden zu sein: Der Benutzer lädt ein Paket herunter, packt es aus und führt ein Python-Skript aus, das vorläufig setup.py genannt wird (die Tatsache, dass dieser Name etwas mit der Modulbeschreibungsdatei in der Python-Distribution und in vielen großen Modulverteilungen überschneidet, ist beabsichtigt und kann als Fehler oder als Merkmal ausgelegt werden). Siehe unten für Argumente für setup.py und was passiert, wenn es ausgeführt wird.

Außerdem stimmte niemand meiner Behauptung zu, dass das System für "Erweiterungen" (d.h. in C geschriebene Module) oder einfache "Module" (in Python geschrieben) ohne Unterschied in der Benutzeroberfläche funktionieren sollte. Die Leute schienen auch die Idee zu akzeptieren, alles – C-Module, Python-Module, schließlich Dokumentation – in ein temporäres "Build-Bibliotheks"-Verzeichnis zu "bauen", das vorläufig blib/ genannt wird. (Dies ist eines der wenigen Implementierungsdetails von Perls MakeMaker, das die Sitzung überlebt hat.) Das blib/-Verzeichnis dient (zumindest) zwei Zwecken: Es macht die Installation nahezu trivial und bietet eine realistisch aussehende Pseudo-Installationsstruktur zum Ausführen von Testskripten. Die tatsächliche Struktur des blib/-Baums muss noch entschieden werden (obwohl ich definitive Vorstellungen davon habe, wie er aussehen sollte!)

Wir haben ein wenig über Terminologie gesprochen. Dies wird ein kniffliges Thema sein und eines der ersten Dinge sein, die wir auf einer SIG ausdiskutieren müssen. Erstens behalten *Modul*, *Erweiterungsmodul* (kurz *Erweiterung*) und *Paket* ihre konventionellen Python-Bedeutungen: eine einzelne .py-Datei, die von anderen Modulen oder Skripten importiert werden soll, ein in C geschriebenes Modul und eine Sammlung von Modulen, die unter einem Verzeichnis gruppiert sind, das eine __init__.py-Datei enthält.

Ich schlug *Distribution* (oder *Moduldistribution*, wenn absolute Klarheit erforderlich ist) als Platzhalter für *Paket* vor, das bereits belegt ist. Eine Moduldistribution enthält ein oder mehrere Module (einschließlich Erweiterungsmodule), deren Dokumentation, Testsuiten und eine setup.py-Datei. (Die Dokumentation und Testsuiten sind optional, aber dringend empfohlen, insbesondere wenn jemand jemals einen Standardweg zur Dokumentation von Python-Modulen erfindet. Aber eine Distribution *muss* mindestens ein Modul und eine setup.py enthalten.) Eine einzelne Distribution wird viele Gesichter zur Welt zeigen: den Quellcodebaum des Entwicklers, eine Quellcode-Distribution, verschiedene Binärverteilungen, das endgültige installierte Produkt usw. (Nach meinem Verständnis sind die Quellcode- und Binärverteilungen das, was Trove als *Ressourcen* bezeichnen wird.)

Eine Sache, für die wir keine Zeit hatten, eine Entscheidung zu treffen, war ein Name für das alberne Ding. Für einen langen und formellen Namen ist meine Stimme **Module Distribution Utilities** oder kurz **distutils**. Der Kurzname wird benötigt, um alle verschiedenen Module zu einem Paket zu gruppieren: Zum Beispiel planen wir, distutils.build, distutils.install, distutils.gen_make und so weiter zu haben.

Rollen von setup.py

Die geplante Schnittstelle zu und die Aufgaben für setup.py entwickelten sich während der Sitzung schnell, hauptsächlich durch die von Eric Raymond identifizierte Arbeitsteilung und klar von Greg Stein dokumentiert sowie durch das von ??? gezeichnete und von mir erweiterte Workflow-Diagramm (siehe unten).

Es ist klar, dass setup.py 1) Metadaten über das Paket und 2) jeden benutzerdefinierten Code enthalten muss, der zur Konfiguration der Distribution für den aktuellen Rechner benötigt wird. Es ist noch nicht klar, wie diese ausgedrückt werden sollen. Die erste Idee ist, die Idee von MakeMaker zu übernehmen, eine Funktion mit einer Reihe benannter Argumente aufzurufen, die dann alles im Hintergrund erledigt. Ein Beispiel setup.py, das dieses Schema verwendet, könnte sein

    #!/usr/bin/env python

    import distutils

    distutils.setup (name = 'mymod',
                     version_from = 'mymod.py',
                     pyfiles = ['mymod.py', 'othermod.py'],
                     cfiles = ['myext.c'])
    
Offensichtlich würde benutzerdefinierter Konfigurationscode einfach in Python vor oder nach dem Aufruf von distutils.setup geschrieben werden; es ist nicht klar, wie dieser Code mit allem interagieren soll, was hinter distutils.setup liegt.

Die wichtigste konkurrierende Idee ist, Dinge auf eine OO-Art zu tun, indem eine Unterklasse definiert und verschiedene Attribute und Methoden überschrieben werden. Hier ist eine spontane Illustration des Konzepts

    #!/usr/bin/env python

    from distutils import Setup

    class MySetup (Setup):
        name = 'mydist
        version_from = 'mymod.py'
        pyfiles = ['mymod.py', 'othermod.py']
        cfiles = ['myext.c']
    
In diesem Fall ist es etwas klarer, wie das spezifische Verhalten aller distutils-Klassen überschrieben werden kann: einfach ableiten und nach Bedarf überschreiben. Offensichtlich müssten dann alle Klassen gut dokumentiert sein!

Workflow für Moduldistributionen

Die folgende Abbildung veranschaulicht den Workflow bei der Entwicklung, Verpackung, Erstellung und Installation einer Moduldistribution (aber nicht deren Test oder Dokumentation, was letztendlich ebenfalls Teil des Plans sein sollte).

Diagram of module distribution workflow

Beachten Sie die drei Arten von Personen, die im Diagramm vorhanden sind

Entwickler
Ersteller/Pflegekraft des ursprünglichen Quellcodebaums
Packer
a) jemand (vermutlich der Entwickler, der seinen "Packer"-Hut trägt), der den ursprünglichen Quellcodebaum in die Quellcode-Distribution umwandelt; oder b) jemand (möglicherweise der Entwickler, möglicherweise ein Freund mit einem Rechner, der X ausführt, möglicherweise ein Archivierungsroboter mit Zugriff auf einen Rechner, der X ausführt), der die Quellcode-Distribution erstellt, um eine "erstellte Distribution" für die Architektur X zu erzeugen
Benutzer
der arme Tropf, der die Distribution auf seiner Maschine installieren möchte; nicht unbedingt jemand, der etwas über Python weiß (oder wissen will)
(Dies sind die von Eric Raymond und Greg Stein identifizierten Arbeitsteilungen.) Beachten Sie auch, dass der Entwickler, der Packer und der Benutzer alle lächeln. Dieses Merkmal ist geplant, aber noch nicht implementiert.

Entwickler-Dienstprogramme

Offensichtlich beginnt der Workflow oben mit dem Quellcodebaum des Entwicklers. Während der Entwickler arbeitet, wird er wahrscheinlich ein Makefile benötigen, das über das Erstellen von Python-Modulen und Erweiterungsmodulen (insbesondere letztere) informiert ist. Anstatt sein eigenes zu schreiben, kann er setup.py bitten, eines für ihn zu generieren (vermutlich unter Verwendung des distutils.gen_make-Moduls)

    ./setup.py gen_make
    
Dann kann der Entwickler make, make test usw. ausführen, so wie er es wahrscheinlich gewohnt ist (vorausgesetzt, er ist ein altmodischer Unix-Freak!). Wenn er Makefiles nicht mag oder keines benötigt, weil es sich um ein kleines Projekt handelt, kann er setup.py einfach bitten, direkt zu bauen, zu testen usw.
    ./setup.py build
    ./setup.py test
    
(Die Idee ist, dass setup.py "Befehle" – build, test usw. – unterstützt, die den Makefile-Zielen entsprechen. Auf diese Weise muss niemand jemals von einem Makefile abhängig sein, aber eines kann zur Bequemlichkeit und Effizienz des Entwicklers generiert werden (insbesondere bei der Arbeit an großen Distributionen mit vielen zu kompilierenden Erweiterungsmodulen).)

Packer-Dienstprogramme

Wenn der Entwickler mit dem aktuellen Zustand seiner Module zufrieden ist und es Zeit für eine Veröffentlichung ist, setzt er seinen "Packer"-Hut auf und erstellt eine Quellcode-Veröffentlichung

    make dist
    # or, equivalently
    ./setup.py dist
    
Dies bündelt alle Dateien in der Distribution (wie in einer MANIFEST-Datei aufgeführt) in einer Art Archivdatei – vielleicht .tar.gz unter Unix, .zip unter Windows usw. Der Name der Archivdatei würde vom Namen und der Version der Moduldistribution abgeleitet: zum Beispiel mydist-1.2.3.tar.gz.

Wenn er möchte, kann der Entwickler dort aufhören und seine Quellcode-Veröffentlichung in ein Archiv hochladen. Oder er kann für alle Architekturen, auf die er Zugriff hat, *erstellte Distributionen* erstellen. (Beachten Sie, dass ich bewusst die Verwendung des bekannteren Begriffs *Binärverteilung* vermeide. Das liegt daran, dass eine Moduldistribution möglicherweise nichts anderes als .py-Dateien und deren zugehörige Dokumentation enthält. Aber auch in diesen Fällen gibt es Gründe für eine herunterladbare Ressource, die sofort installiert werden kann. Der Hauptgrund ist Konsistenz: Es ist schön, wenn naive Benutzer nur mit einer Art von Datei für Python-Moduldistributionen umgehen müssen (z. B. Red Hat Linux-Benutzer können einfach eine Reihe von RPMs herunterladen und installieren; ob diese RPMs .py- oder .so-Dateien oder beides enthalten, ist unerheblich). Zweitens können Nicht-Binärdateien vorhanden sein, die aus Dateien in der Quellcode-Veröffentlichung generiert werden, wie z. B. Manpages, die aus SGML-Quellen generiert werden. Die erstellte Distribution für eine Unix-Plattform könnte bereit zur Installation stehende Manpages enthalten, sodass keine Dokumentationsverarbeitung erforderlich wäre.)

Es ist wichtig, das Konzept des Paketierers als Person getrennt vom Entwickler hervorzuheben. Dies ist notwendig, um erstellte Distributionen für mehrere Plattformen zu unterstützen, da nicht viele Entwickler Zugriff auf ein paar Unix-Varianten, Windows und Mac haben – sie werden vermutlich Hilfe benötigen, um erstellte Distributionen für eine oder mehrere Plattformen zu erstellen. Diese Hilfe kann in Form eines Freundes (im Flur oder auf der ganzen Welt) kommen, der Zugriff auf eine bestimmte Plattform hat; sie kann in Form von jemandem kommen, der sich freiwillig meldet, bestimmte Distributionen für bestimmte Plattformen auf dem neuesten Stand zu halten; oder sie kann die Form eines Archivierungsroboters annehmen, der das Verfahren automatisiert. Sicherheitsbedenken werden mit jedem Schritt auf dieser Liste relevanter.

Ich habe ein paar mögliche Schnittstellen für die Erstellung erstellter Distributionen im Sinn; außerdem bildet sich seit dem Developer's Day die Idee von "dummen" vs. "intelligenten" erstellten Distributionen in meinem Kopf. (Daher gehört es hier wahrscheinlich nicht wirklich hin, da dies eine Zusammenfassung der Developer's Day-Sitzung sein soll. Dann verklagen Sie mich mal.) Betrachten wir zunächst die Erstellung einer traditionellen Unix-erstellten Distribution: einer .tar.gz-Datei, die unter /usr/local (oder wahrscheinlicher im Kontext der Python-Bibliothek unter /usr/local/lib/python1.x) entpackt werden soll. Dies könnte erreicht werden mit

    ./setup.py bdist
    
was einen Build durchführen würde (um einen Mock-Installationsbaum in ./blib/ zu legen) und den Build-Baum in eine Archivdatei packen würde, die nach dem Namen und der Versionsnummer der Distribution sowie der aktuellen Plattform benannt ist, z. B. mydist-1.2.3-sunos5.tar.gz oder mydist-1.2.3-win32.zip.

Es gibt jedoch großes Interesse an "intelligenten" Installer wie Red Hat's RPM (und ich hatte den Eindruck, dass es ein paar konkurrierende Möglichkeiten für die Windows-Welt gibt – jemand von der dunklen Seite wird mich darüber aufklären müssen). Mein aktueller Gedanke ist, dass es für jeden dieser Fälle einen separaten Befehl (oder ein Makefile-Ziel) geben sollte, sodass Sie möglicherweise ausführen würden

    make rpm
    
auf einer Red Hat Linux-Box und
    setup.py xxx
    
auf einer Windows-Maschine (wobei xxx der abgekürzte Name eines intelligenten Installers für Windows ist). Die Unterstützung des altmodischen "dummen" Modells für erstellte Distributionen ist jedoch wichtig – nicht jeder wird diesen schicken neuen Installer haben (oder er hat einen anderen intelligenten Installer).

Benutzer-Dienstprogramme

Schließlich und vielleicht am wichtigsten müssen wir den glücklichen Benutzer betrachten, der eine Python-Moduldistribution auf seinem Computer installieren möchte. Benutzer gibt es in allen Formen und Größen, aber wir befassen uns hauptsächlich mit zwei Unterscheidungen

  • Benutzer von erstellten Distributionen: Jeder auf einer beliebten Plattform, für die eine erstellte Distribution verfügbar ist (oder notwendig ist: viele Mac- und Windows-Leute werden keinen Compiler haben)
  • Benutzer von Quellcode-Distributionen: Leute auf weniger beliebten Plattformen, für die wahrscheinlich ein Compiler (und andere möglicherweise notwendige Werkzeuge) verfügbar sein wird
Offensichtlich sollten die Dinge für naive Benutzer, die einfach nur einige Module (möglicherweise reine Python-Module, möglicherweise Erweiterungen – das sollte keine Rolle spielen!) installieren möchten, um etwas anderes zum Laufen zu bringen, absolut schmerzfrei und einfach sein. Intelligente Installer wie RPM werden hier helfen, aber es sollte fast genauso einfach sein, mit einer "dummen" erstellten Distribution oder einer Quellcode-Distribution zu beginnen. Wir müssen auch bedenken, dass es viele Leute geben wird, die Quellcode-Distributionen verwenden müssen, die nicht unbedingt Programmierer sind, und einfach nur diese alberne Sache installiert und zum Laufen bekommen wollen – daher sollte die Verwendung einer Quellcode-Distribution genauso einfach sein (obwohl sie mehr Rechenzeit und ein paar mehr Befehle erfordern wird) wie die Verwendung einer erstellten Distribution. Selbst erfahrene Hacker, die in den Quellcode eintauchen und damit herumspielen, Makefiles bearbeiten oder die Speicherorte benötigter Bibliotheken angeben könnten, wollen das selten tun.

Nächste Schritte

Erstens denke ich, dass dieses Thema groß genug ist, um eine neue SIG zu rechtfertigen, die ich vorläufig distutils-sig nenne. Der vorgeschlagene Charter dafür {wird|wurde} auf der Meta-SIG gepostet, also gehen Sie dorthin, wenn Sie das gesamte Konzept für hoffnungslos halten und mich in Flammen setzen wollen, bevor es überhaupt losgeht (oder wenn Sie denken, der Name ist Mist).

Sobald die SIG erstellt ist, möchte ich *etwas* Zeit mit Meta-Themen verbringen: Hat jemand grundsätzlich etwas gegen die ganze Idee? Ist 'distutils' ein guter Name? Welche Funktionalität sollte in der ersten Version vorhanden sein und was wird für eine vollständige Veröffentlichung benötigt? Dann können wir uns mit den Feinheiten von Design und Implementierung befassen.