Verwendung des nuitka-Compilers für python3 auf Alpine Linux ARMHF (musl)
Motivation
pidoctor ist in Python geschrieben (da es keine einfache Möglichkeit gab, Crystal unter ARMHF / musl zum Laufen zu bringen).
Dies bedeutet eine Abhängigkeit von Python, was zusätzlichen Aufwand bedeutet.
Ich vermute, dass dieser Overhead der Grund dafür ist, dass pidoctor nicht auf 256 MB Raspberry Pi's läuft - weil der Arbeitsspeicher durch alle benötigten Pakete erschöpft ist.
Außerdem ist es wünschenswert, dass die Distribution so klein wie möglich ist! Das bedeutet, dass Python irgendwie aus der Gleichung entfernt werden muss, das Paket sollte eine Binärdatei erzeugen (wie es bei Crystal der Fall wäre).
Zum Glück gibt es nuitka.
Und - du hast Glück - ich habe einige Probleme bei der Verwendung von nuitka unter Alpine Linux, ARMHF, gelöst (vielleicht funktioniert es auch für x86).
Nuitka
nuitka ist eine phantastische Software, die ein Python-Skript zu einer ausführbaren Datei kompiliert und damit die Ausführung erheblich beschleunigt.
nuitka erledigt die ganze Arbeit, Sie müssen nicht einmal etwas in Ihrem Quellcode anpassen (denke ich). Sie können es wie folgt ausführen:
python3 -m nuitka -follow-imports -standalone pidoctor.py
Beachten Sie das Flag -standalone, mit dem die erforderlichen Bibliotheken in den Ordner .dist kompiliert werden - dadurch kann die Installation auch ohne jede Abhängigkeit auf Python!
Bitte beachten Sie: WordPress versaut leider die doppelten Bindestriche und macht sie zu einfachen Bindestrichen. Das -m hat einen einfachen Bindestrich, das -follow-imports und das -standalone haben doppelte Bindestriche.
Installation von Nuitka auf Alpine Linux (speziell arhmf, kann auch auf anderen Targets funktionieren)
apk hinzufügen python3-dev
apk chrpfad hinzufügen
pip3 install -U nuitka
optional, wenn Sie im Diskless-Modus arbeiten (um nuitka zu den Dateien hinzuzufügen, die persistiert werden sollen):
lbu add /usr/bin/nuitka3-run
lbu add /usr/bin/nuitka3
lbu add /usr/lib/python3.6/site-packages/nuitka
lbu commit -d
Hinweis: Der Quelltext von nuitka ist in Python.
Prüfen Sie, ob nuitka läuft:
python3 -m nuitka
ausführen sollte ohne und zeigt Syntaxfehler an.
nuitka mit Alpine Linux armhf zum Laufen bringen
Wichtig: WordPress verfälscht leider die Syntax. Bitte beziehen Sie sich auf das GitHUB-Problem, das ich eröffnet habe, wo ich auch die Patchdateien als Referenz angehängt habe.
nuitka ruft verschiedene binäre Hilfsprogramme auf Ihrem System auf und erwartet, dass diese die Ergebnisse auf eine bestimmte Weise zurückgeben. Dies ist der Punkt, an dem nuitka zunächst strauchelt.
Erster Fehler
pidoctor:/opt/pidoctor# python3 -m nuitka -follow-imports -standalone pidoctor.py
Traceback (letzter Aufruf):
Datei "/usr/lib/python3.6/site-packages/nuitka/__main__.py", Zeile 188, in
main()
Datei "/usr/lib/python3.6/site-packages/nuitka/__main__.py", Zeile 182, in main
MainControl.main()
Datei "/usr/lib/python3.6/site-packages/nuitka/MainControl.py", Zeile 846, in main
Plugins.considerExtraDlls(dist_dir, module)
Datei "/usr/lib/python3.6/site-packages/nuitka/plugins/Plugins.py", Zeile 102, in considerExtraDlls
for extra_dll in plugin.considerExtraDlls(dist_dir, module):
Datei "/usr/lib/python3.6/site-packages/nuitka/plugins/standard/ImplicitImports.py", Zeile 372, in considerExtraDlls
uuid_dll_path = locateDLL("uuid")
Datei "/usr/lib/python3.6/site-packages/nuitka/utils/SharedLibraries.py", Zeile 71, in locateDLL
return dll_map[dll_name]
KeyError: 'libuuid.so.1.3.0'
Grund für den Fehler: nuitka ruft ldconfig -p auf und erwartet eine Liste der zwischengespeicherten gemeinsamen Bibliotheken in einem Format wie diesem:
libICE.so.6 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libICE.so.6
auf Alpine Linux schlägt ldconfig -p fehl, da es diese Option nicht gibt. ldconfig auf Alpine Linux ist nicht in der Lage, eine Liste in der von Nuitka gewünschten Form zu erstellen.
Reparieren:
in /usr/lib/python3.6/site-packages/nuitka/utils/SharedLibraries.py
Fügen Sie den folgenden Code unmittelbar nach den Import-Anweisungen am Anfang ein:
def find_alpine(name,pfade):
für Pfad in Pfade:
for root, dirs, files in os.walk(path):
wenn Name in Dateien:
return os.path.join(root,name)
und fügen Sie in locateDLL vor dem Import von subprocess den folgenden Code ein:
if os.path.isfile('/etc/alpine-release'):
return find_alpine(dll_name,["/lib","/usr/lib","/usr/local/lib"])
sonst:
importieren subprocess(...)
Das (...) oben zeigt an, dass der Rest des Codes von locateDLL unter dem else eingerückt werden sollte.
Was dieser Code macht: Wenn die Datei /etc/alpine-release existiert - was anzeigt, dass wir auf Alpine Linux laufen - suchen wir in drei vordefinierten Verzeichnissen nach der gemeinsamen Bibliothek:
- /lib
- /usr/lib
- /usr/local/lib
und gibt die erste passende Datei zurück. Bitte beachten Sie, dass wir die Situation nicht behandeln, wenn die Datei nicht gefunden wird - in diesem Fall wird nichts zurückgegeben.
Zweiter Fehler
Traceback (letzter Aufruf):
Datei "/usr/lib/python3.6/site-packages/nuitka/__main__.py", Zeile 188, in
main()
Datei "/usr/lib/python3.6/site-packages/nuitka/__main__.py", Zeile 182, in main
MainControl.main()
Datei "/usr/lib/python3.6/site-packages/nuitka/MainControl.py", Zeile 859, in main
standalone_entry_points = standalone_entry_points
Datei "/usr/lib/python3.6/site-packages/nuitka/freezer/Standalone.py", Zeile 1169, in copyUsedDLLs
used_dlls = detectUsedDLLs(source_dir, standalone_entry_points)
Datei "/usr/lib/python3.6/site-packages/nuitka/freezer/Standalone.py", Zeile 1062, in detectUsedDLLs
assert os.path.isabs(dll_filename), dll_filename
AssertionError: ldd
Grund für den Fehler: nuitka ruft ldd mit jeder gemeinsam genutzten Bibliothek ("dll_filename") auf, die dem Ordner .dist hinzugefügt werden soll. Dies dient dazu, die Abhängigkeiten dieser gemeinsam genutzten Bibliotheken selbst zu finden. (Eine rekursive Suche, wenn Sie so wollen).
Zum Beispiel:
pidoctor:/opt/pidoctor# ldd /usr/lib/libexpat.so.1
ldd (0x76f43000)
libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x76efd000)
libc.musl-armhf.so.1 => ldd (0x76f43000)
Wie Sie sehen, hat libexpat.so.1 zwei Abhängigkeiten:
- libgcc_s.so.1 -> zu finden unter /usr/lib/libgcc_s.so.1
- libc.musl-armhf.so.1 -> zu finden unter ldd
und das ist genau der Punkt, an dem nuitka Probleme hat. Es möchte eine Datei mit einem absoluten Pfad kopieren und erhält stattdessen den Namen "ldd". Auch dies ist etwas, das spezifisch für Alpine Linux ist.
Daher scheitert die Behauptung, und nuitka wird nicht fortgesetzt.
So finden Sie heraus, auf welche Datei sie tatsächlich verweist:
pidoctor:~# der ldd
/usr/bin/lddpidoctor:~# ls -alh /usr/bin/ldd
lrwxrwxrwx 1 root root 28 Jan 1 1970 /usr/bin/ldd -> ../../lib/ld-musl-armhf.so.1
Beachten Sie, dass ../../lib/ld-musl-armhf.so.1 ein relativer Pfad ist, der sich eigentlich auf /lib/ld-musl-armhf.so.1 auf meinem System. Und auf Ihrem wahrscheinlich auch.
Reparieren:
Suche nach libutil.so. in der Datei /usr/lib/python3.6/site-packages/nuitka/freezer/Standalone.py
Es gibt eine Zeile mit result.add(filename) darunter. Einfach über diese Zeile, einfügen:
wenn Dateiname == 'ldd':
Dateiname = os.path.join(os.path.dirname('/usr/bin/ldd'),os.readlink('/usr/bin/ldd')) 1TP3Z.B. '/lib/ld-musl-armhf.so.1' Fix für Alpine
Dritter Fehler
Fehler, benötigt 'chrpath' auf Ihrem System, aufgrund der 'RPATH'-Einstellungen in den verwendeten gemeinsamen
Reparieren:
Haben Sie chrpath wie oben beschrieben installiert?
apk chrpfad hinzufügen
Das war's - jetzt sollte nuitka seine Magie ohne Schluckauf vollbringen. Ich werde dem Autor von nuitka die Patches und diesen Blogartikel schicken, vielleicht kann er sie in nuitka einbauen.
Werksversion
Update 2.2.2019: Der Autor von Nuitka hat meine Patches (in leicht veränderter Form) hinzugefügt. In der aktuellen "Fabrik"-Version funktioniert die -Standalone-Kompilierung bei mir. Bitte beachten Sie diese Github-Seite für Details: