Usare il compilatore nuitka per python3 su Alpine Linux ARMHF (musl)

Motivazione

pidoctor è scritto in Python (poiché non c'era un modo semplice per far funzionare Crystal su ARMHF / musl).

Questo significa una dipendenza da Python - che aggiunge overhead.

Sospetto che questo overhead sia la ragione per cui pidoctor non funziona su Raspberry Pi da 256 MB - perché la RAM è esaurita da tutti i pacchetti richiesti.

Inoltre, è auspicabile che la distribuzione sia il più piccolo download possibile! Questo significa che Python deve essere rimosso dall'equazione in qualche modo, il pacchetto dovrebbe produrre un binario (come sarebbe il modo con Crystal).

Per fortuna, c'è la nuitka.

E - per tua fortuna - ho risolto alcuni problemi di utilizzo di nuitka su Alpine Linux, ARMHF (forse funzionerà anche per x86).

Nuitka

nuitka è un fantastico software che prende uno script Python e lo compila in un eseguibile, velocizzandolo drasticamente.

nuitka fa tutto il lavoro pesante, non hai nemmeno bisogno di aggiustare qualcosa nel tuo codice sorgente (mi sembra). Puoi eseguirlo in questo modo:

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

Notate il flag -standalone, che compilerà le librerie condivise necessarie nella vostra cartella .dist - quindi l'installazione sarà in grado di funzionare senza qualsiasi dipendenza su Python!

Nota: WordPress sfortunatamente incasina i doppi trattini e li trasforma in trattini singoli. la -m ha un trattino singolo, la -follow-imports e la -standalone hanno doppi trattini.

Installazione di Nuitka su Alpine Linux (in particolare arhmf, potrebbe funzionare su altri obiettivi)

apk add python3-dev

apk aggiungere chrpath

pip3 install -U nuitka

opzionalmente, se si sta eseguendo in modalità senza disco (per aggiungere nuitka ai file che dovrebbero essere persistiti):

lbu add /usr/bin/nuitka3-run

lbu add /usr/bin/nuitka3

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

lbu commit -d

Nota: il sorgente di nuitka è in Python.

Controlla che nuitka funzioni:

python3 -m nuitka

dovrebbe eseguire senza mostrando eventuali errori di sintassi.

Fissare nuitka per funzionare con Alpine Linux armhf

Importante: WordPress purtroppo mastica male la sintassi. Si prega di fare riferimento al problema GitHUB che ho apertodove ho anche allegato i file della patch come riferimento.

nuitka chiama diverse utility binarie di supporto sul vostro sistema, e si aspetta che restituiscano i risultati in un certo modo. È qui che nuitka inizialmente inciampa.

Primo errore

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

Traceback (ultima chiamata più recente):

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

main()

File "/usr/lib/python3.6/site-packages/nuitka/__main__.py", linea 182, in main

MainControl.main()

File "/usr/lib/python3.6/site-packages/nuitka/MainControl.py", linea 846, in main

Plugins.considerExtraDlls(dist_dir, module)

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

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

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

uuid_dll_path = locateDLL("uuid")

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

return dll_map[dll_name]

KeyError: 'libuuid.so.1.3.0'

Motivo dell'errore: nuitka chiama ldconfig -p e si aspetta che elenchi una lista di librerie condivise nella cache, in un formato come questo:

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

su Alpine Linux, ldconfig -p fallisce - in quanto non esiste tale opzione. ldconfig su Alpine Linux è incapace di produrre una lista della forma che Nuitka vuole.

Correggere:

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

aggiungete il seguente codice subito dopo le dichiarazioni di importazione all'inizio:

def find_alpine(name,paths):
     per percorso in percorsi:
         per root, dirs, files in os.walk(path):
             se il nome in file:
                 return os.path.join(root,name)

e in locateDLL, prima di importare il sottoprocesso, aggiungere il seguente codice:

se os.path.isfile('/etc/alpine-release'):
     return find_alpine(dll_name,["/lib","/usr/lib","/usr/local/lib"])
altro:
     importa subprocesso

    (...)

Il (...) sopra indica che il resto del codice di locateDLL dovrebbe essere rientrato sotto else.

Cosa fa questo codice: se il file /etc/alpine-release esiste - indicando che stiamo girando su Alpine Linux, cerchiamo la libreria condivisa in tre directory predefinite:

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

e restituisce il primo file corrispondente. Nota, non gestiamo la situazione nel caso in cui il file non venga trovato - in questo caso non viene restituito nulla.

Secondo errore

Traceback (ultima chiamata più recente):
   File "/usr/lib/python3.6/site-packages/nuitka/__main__.py", linea 188, in
     main()
   File "/usr/lib/python3.6/site-packages/nuitka/__main__.py", linea 182, in main
     MainControl.main()
   File "/usr/lib/python3.6/site-packages/nuitka/MainControl.py", linea 859, in main
     standalone_entry_points = standalone_entry_points
   File "/usr/lib/python3.6/site-packages/nuitka/freezer/Standalone.py", linea 1169, in copyUsedDLLs
     used_dlls = detectUsedDLLs(source_dir, standalone_entry_points)
   File "/usr/lib/python3.6/site-packages/nuitka/freezer/Standalone.py", linea 1062, in detectUsedDLLs
     assert os.path.isabs(dll_filename), dll_filename
Errore di asserzione: ldd

Motivo dell'errore: nuitka chiama ldd con ogni libreria condivisa ("dll_filename") da aggiungere alla vostra cartella .dist. Lo scopo è quello di trovare le dipendenze di queste stesse librerie condivise. (Una ricerca ricorsiva, se volete).

Per esempio:

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)

Come vedete, libexpat.so.1 ha due dipendenze:

  • libgcc_s.so.1 -> da trovare in /usr/lib/libgcc_s.so.1
  • libc.musl-armhf.so.1 -> si trova a ldd

ed è proprio qui che nuitka ha problemi. Vuole copiare un file con un percorso assoluto, e invece gli viene dato il nome "ldd". Di nuovo, qualcosa che è specifico di Alpine Linux.

Perciò l'affermazione fallisce, e nuitka non continua.

Ecco come scoprire a quale file fa effettivamente riferimento:

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

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

Si noti che ../../lib/ld-musl-armhf.so.1 è un percorso relativo, che in realtà si riferisce a /lib/ld-musl-armhf.so.1 sul mio sistema. E probabilmente anche sul vostro.

Correggere:

ricerca di libutil.so. nel file /usr/lib/python3.6/site-packages/nuitka/freezer/Standalone.py

C'è una linea con result.add(filename) sotto di essa. Solo sopra questa linea, inserire:

se nome del file == 'ldd':
     filename = os.path.join(os.path.dirname('/usr/bin/ldd'),os.readlink('/usr/bin/ldd')) #e.g. '/lib/ld-musl-armhf.so.1' fix per Alpine

Terzo errore

Errore, ha bisogno di 'chrpath' sul tuo sistema, a causa delle impostazioni 'RPATH' in usato condiviso

Correggere:

Hai installato chrpath come consigliato sopra?

apk aggiungere chrpath

Questo è tutto - ora nuitka dovrebbe eseguire la sua magia senza intoppi. Invierò all'autore di nuitka le patch e questo articolo del blog, forse potrà includerle in nuitka.

Versione di fabbrica

Aggiornamento 2.2.2019: l'autore di Nuitka ha aggiunto le mie patch (in una forma leggermente modificata). Nell'attuale versione "fabbrica", la compilazione -standalone funziona per me. Si prega di fare riferimento a questa pagina github per i dettagli:

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

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