Utilisation du compilateur nuitka pour python3 sur Alpine Linux ARMHF (musl)

Motivation

pidoctor est écrit en Python (car il n'y avait pas de moyen facile de faire fonctionner Crystal sur ARMHF / musl).

Cela signifie qu'il faut dépendre de Python, ce qui ajoute des frais généraux.

Je soupçonne que cette surcharge est la raison pour laquelle pidoctor ne fonctionne pas sur les Raspberry Pi de 256 MB - parce que la RAM est épuisée par tous les paquets qui sont nécessaires.

De plus, il est souhaitable que la distribution soit un téléchargement aussi petit que possible ! Cela signifie que Python doit être retiré de l'équation d'une manière ou d'une autre, et que le paquetage doit produire un binaire (comme ce serait le cas avec Crystal).

Heureusement, il y a la nuitka.

Et - vous avez de la chance - j'ai résolu quelques problèmes d'utilisation de nuitka sur Alpine Linux, ARMHF (peut-être que cela fonctionnera aussi pour x86).

Nuitka

nuitka est un logiciel fantastique, qui prend un script Python et le compile en un exécutable, ce qui l'accélère considérablement.

nuitka fait le gros du travail, vous n'avez même pas besoin d'ajuster quoi que ce soit dans votre code source (je pense). Vous pouvez l'exécuter comme ceci :

python3 -m nuitka -follow-imports -standalone pidoctor.py

Notez le drapeau -standalone, qui compilera les bibliothèques partagées nécessaires dans votre dossier .dist - ainsi l'installation pourra fonctionner sans toute dépendance sur Python !

Veuillez noter que WordPress ne tient pas compte des doubles tirets et les transforme en tirets simples. Le -m a un tiret simple, le -follow-imports et le -standalone ont des doubles tirets.

Installation de Nuitka sur Alpine Linux (spécifiquement arhmf, pourrait fonctionner sur d'autres cibles)

apk add python3-dev

apk add chrpath

pip3 install -U nuitka

facultativement, si vous êtes en mode sans disque (pour ajouter nuitka aux fichiers qui doivent être persistés) :

lbu add /usr/bin/nuitka3-run

lbu add /usr/bin/nuitka3

lbu add /usr/lib/python3.6/site-packages/nuitka

lbu commit -d

Note : la source de nuitka est en Python.

Vérifiez que nuitka fonctionne :

python3 -m nuitka

devrait exécuter sans montrant toute erreur de syntaxe.

Correction de nuitka pour fonctionner avec Alpine Linux armhf

Important : WordPress malmène malheureusement la syntaxe. Veuillez vous référer à la question GitHUB que j'ai ouverte.où j'ai également joint les fichiers de correction pour référence.

nuitka appelle plusieurs utilitaires binaires de support sur votre système, et attend d'eux qu'ils renvoient les résultats d'une certaine manière. C'est là que nuitka trébuche.

Première erreur

pidoctor:/opt/pidoctor# python3 -m nuitka -follow-imports -standalone pidoctor.py

Traceback (dernier appel le plus récent) :

File "/usr/lib/python3.6/site-packages/nuitka/__main__.py", line 188, in

main()

Fichier "/usr/lib/python3.6/site-packages/nuitka/__main__.py", ligne 182, dans main

MainControl.main()

Fichier "/usr/lib/python3.6/site-packages/nuitka/MainControl.py", ligne 846, dans main

Plugins.considerExtraDlls(dist_dir, module)

Fichier "/usr/lib/python3.6/site-packages/nuitka/plugins/Plugins.py", ligne 102, in considerExtraDlls

for extra_dll in plugin.considerExtraDlls(dist_dir, module) :

Fichier "/usr/lib/python3.6/site-packages/nuitka/plugins/standard/ImplicitImports.py", ligne 372, in considerExtraDlls

uuid_dll_path = locateDLL("uuid")

Fichier "/usr/lib/python3.6/site-packages/nuitka/utils/SharedLibraries.py", ligne 71, in locateDLL

return dll_map[dll_name]

KeyError : 'libuuid.so.1.3.0' (erreur de clé)

La raison de l'erreur : nuitka appelle ldconfig -p et s'attend à ce qu'il énumère une liste de bibliothèques partagées mises en cache, dans un format comme celui-ci :

libICE.so.6 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libICE.so.6

sur Alpine Linux, ldconfig -p échoue - car cette option n'existe pas. ldconfig sur Alpine Linux est incapable de produire une liste de la forme que Nuitka souhaite.

Fixe :

dans /usr/lib/python3.6/site-packages/nuitka/utils/SharedLibraries.py

ajoutez le code suivant immédiatement après les déclarations d'importation en haut :

def find_alpine(name,paths) :
     pour path dans paths :
         pour root, dirs, files in os.walk(path) :
             si nom dans fichiers :
                 return os.path.join(root,name)

et dans locateDLL, avant d'importer le sous-processus, ajoutez le code suivant :

si os.path.isfile('/etc/alpine-release') :
     return find_alpine(dll_name,["/lib","/usr/lib","/usr/local/lib"])
autre :
     Importation de sous-processus

    (...)

Le (...) ci-dessus indique que le reste du code de locateDLL doit être indenté sous le else.

Ce que fait ce code : si le fichier /etc/alpine-release existe - indiquant que nous tournons sous Alpine Linux, nous recherchons la bibliothèque partagée dans trois répertoires prédéfinis :

  • /lib
  • /usr/lib
  • /usr/local/lib

et renvoie le premier fichier correspondant. Notez que nous ne gérons pas le cas où le fichier n'est pas trouvé - dans ce cas, rien n'est renvoyé..

Deuxième erreur

Traceback (dernier appel le plus récent) :
   File "/usr/lib/python3.6/site-packages/nuitka/__main__.py", line 188, in
     main()
   Fichier "/usr/lib/python3.6/site-packages/nuitka/__main__.py", ligne 182, dans main
     MainControl.main()
   Fichier "/usr/lib/python3.6/site-packages/nuitka/MainControl.py", ligne 859, dans main
     standalone_entry_points = standalone_entry_points
   Fichier "/usr/lib/python3.6/site-packages/nuitka/freezer/Standalone.py", ligne 1169, in copyUsedDLLs
     used_dlls = detectUsedDLLs(source_dir, standalone_entry_points)
   Fichier "/usr/lib/python3.6/site-packages/nuitka/freezer/Standalone.py", ligne 1062, in detectUsedDLLs
     assert os.path.isabs(dll_filename), dll_filename
AssertionError : ldd

La raison de cette erreur : nuitka appelle ldd pour chaque bibliothèque partagée ("dll_filename") à ajouter à votre dossier .dist. Le but de cette opération est de trouver les dépendances de ces bibliothèques partagées elles-mêmes. (Une recherche récursive si vous voulez).

Par exemple :

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)

Comme vous le voyez, libexpat.so.1 a deux dépendances :

  • libgcc_s.so.1 -> se trouve dans /usr/lib/libgcc_s.so.1
  • libc.musl-armhf.so.1 -> se trouve à l'adresse suivante ldd

et c'est précisément là que nuitka a des problèmes. Il veut copier un fichier avec un chemin absolu, et on lui donne le nom "ldd" à la place. Encore une fois, quelque chose qui est spécifique à Alpine Linux.

Par conséquent, l'assertion échoue, et nuitka ne continue pas.

Voici comment découvrir le fichier auquel il fait réellement référence :

pidoctor:~# qui ldd
/usr/bin/ldd

pidoctor:~# ls -alh /usr/bin/ldd
lrwxrwxrwx 1 root root 28 Jan 1 1970 /usr/bin/ldd -> ../../lib/ld-musl-armhf.so.1

Notez que ../../lib/ld-musl-armhf.so.1 est un chemin relatif, qui se réfère en fait à /lib/ld-musl-armhf.so.1 sur mon système. Et sur le vôtre, probablement, aussi.

Fixe :

recherche de libutil.so. dans le fichier /usr/lib/python3.6/site-packages/nuitka/freezer/Standalone.py

Il y a une ligne avec result.add(filename) en dessous. Juste au-dessus de cette ligne, insérer :

si le nom du fichier == 'ldd' :
     filename = os.path.join(os.path.dirname('/usr/bin/ldd'),os.readlink('/usr/bin/ldd')) 1TP3Par exemple, '/lib/ld-musl-armhf.so.1' pour Alpine.

Troisième erreur

Erreur, 'chrpath' est nécessaire sur votre système, en raison des paramètres 'RPATH' dans le partage utilisé.

Fixe :

Avez-vous installé chrpath comme conseillé ci-dessus ?

apk add chrpath

C'est tout - maintenant nuitka devrait accomplir sa magie sans accroc. Je vais envoyer à l'auteur de nuitka les correctifs et cet article de blog, il pourra peut-être les inclure dans nuitka.

Version d'usine

Mise à jour 2.2.2019 : L'auteur de Nuitka a ajouté mes correctifs (sous une forme légèrement modifiée). Dans la version actuelle "factory", la compilation -standalone fonctionne pour moi. Veuillez vous référer à cette page github pour plus de détails :

https://github.com/Nuitka/Nuitka/issues/237

http://nuitka.net/doc/factory.html