Uso del compilador nuitka para python3 en Alpine Linux ARMHF (musl)
Motivación
pidoctor está escrito en Python (ya que no había una manera fácil de conseguir que Crystal funcionara en ARMHF / musl).
Esto significa una dependencia de Python, lo que añade una sobrecarga.
Sospecho que esta sobrecarga es la razón por la que pidoctor no se ejecutará en Raspberry Pi's de 256 MB - porque la RAM se agota por todos los paquetes que se requieren.
Además, es deseable que la distribución sea una descarga lo más pequeña posible. Esto significa que Python tiene que ser eliminado de la ecuación de alguna manera, el paquete debe producir un binario (como sería el camino con Crystal).
Por suerte, existe la nuitka.
Y - por suerte - he resuelto algunos problemas de uso de nuitka en Alpine Linux, ARMHF (tal vez funcione para x86 también).
Nuitka
nuitka es una pieza fantástica de software, que tomará un script de Python y lo compilará a un ejecutable, acelerándolo así dramáticamente.
nuitka hace todo el trabajo pesado, ni siquiera necesitas ajustar nada en tu código fuente (me parece). Puedes ejecutarlo así:
python3 -m nuitka -follow-imports -standalone pidoctor.py
Tenga en cuenta la bandera -standalone, que compilará las bibliotecas compartidas necesarias en su carpeta .dist - de este modo la instalación podrá ejecutarse sin cualquier dependencia ¡en Python!
Por favor, tenga en cuenta: WordPress lamentablemente jode los guiones dobles y los convierte en guiones simples. el -m tiene un guión simple, el -follow-imports y el -standalone tienen guiones dobles.
Instalación de Nuitka en Alpine Linux (específicamente arhmf, podría funcionar en otros objetivos)
apk add python3-dev
apk add chrpath
pip3 install -U nuitka
opcionalmente, si se está ejecutando en modo sin disco (para añadir nuitka a los archivos que deben persistir):
lbu add /usr/bin/nuitka3-run
lbu add /usr/bin/nuitka3
lbu add /usr/lib/python3.6/site-packages/nuitka
lbu commit -d
Nota: la fuente de nuitka está en Python.
Comprueba que la nuitka funciona:
python3 -m nuitka
debe ejecutar sin mostrando cualquier error de sintaxis.
Arreglar nuitka para que funcione con Alpine Linux armhf
Importante: WordPress desgraciadamente manipula mal la sintaxis. Por favor, consulte la cuestión de GitHUB que he abiertodonde también he adjuntado los archivos del parche como referencia.
nuitka llama a varias utilidades binarias de apoyo en su sistema, y espera que devuelvan los resultados de una manera determinada. Esto es, donde nuitka inicialmente tropieza.
Primer error
pidoctor:/opt/pidoctor# python3 -m nuitka -follow-imports -standalone pidoctor.py
Traceback (última llamada más reciente):
File "/usr/lib/python3.6/site-packages/nuitka/__main__.py", line 188, in .
main()
File "/usr/lib/python3.6/site-packages/nuitka/__main__.py", line 182, in main
MainControl.main()
File "/usr/lib/python3.6/site-packages/nuitka/MainControl.py", line 846, in main
Plugins.considerExtraDlls(dist_dir, module)
File "/usr/lib/python3.6/site-packages/nuitka/plugins/Plugins.py", line 102, in considerExtraDlls
for extra_dll in plugin.considerExtraDlls(dist_dir, module):
File "/usr/lib/python3.6/site-packages/nuitka/plugins/standard/ImplicitImports.py", line 372, in considerExtraDlls
uuid_dll_path = locateDLL("uuid")
File "/usr/lib/python3.6/site-packages/nuitka/utils/SharedLibraries.py", line 71, in locateDLL
return dll_map[dll_name]
KeyError: 'libuuid.so.1.3.0'
Razón detrás del error: nuitka llama a ldconfig -p y espera que liste una lista de bibliotecas compartidas en caché, en un formato como este:
libICE.so.6 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libICE.so.6
en Alpine Linux, ldconfig -p falla - ya que no existe tal opción. ldconfig en Alpine Linux es incapaz de producir una lista de la forma que Nuitka quiere.
Arreglar:
en /usr/lib/python3.6/site-packages/nuitka/utils/SharedLibraries.py
añada el siguiente código inmediatamente después de las declaraciones de importación en la parte superior:
def encontrar_alpino(nombre,rutas):
para la ruta en las rutas:
para root, dirs, files en os.walk(path):
si el nombre en los archivos:
return os.path.join(raíz,nombre)
y en locateDLL, antes de importar el subproceso, añade el siguiente código:
si os.path.isfile('/etc/alpine-release'):
return find_alpine(nombre_dll,["/lib","/usr/lib","/usr/local/lib"])
Si no:
importar subproceso(...)
El (...) de arriba indica que el resto del código de locateDLL debe ser sangrado bajo el else.
Lo que hace este código: si el archivo /etc/alpine-release existe - indicando que estamos corriendo en Alpine Linux, buscamos la biblioteca compartida en tres directorios predefinidos:
- /lib
- /usr/lib
- /usr/local/lib
y devuelve el primer archivo que coincida. Tenga en cuenta que no manejamos la situación en caso de que no se encuentre el archivo - en este caso no se devuelve nada.
Segundo error
Traceback (última llamada más reciente):
File "/usr/lib/python3.6/site-packages/nuitka/__main__.py", line 188, in .
main()
File "/usr/lib/python3.6/site-packages/nuitka/__main__.py", line 182, in main
MainControl.main()
File "/usr/lib/python3.6/site-packages/nuitka/MainControl.py", line 859, in main
puntos_de_entrada_estándar = puntos_de_entrada_estándar
File "/usr/lib/python3.6/site-packages/nuitka/freezer/Standalone.py", line 1169, in copyUsedDLLs
used_dlls = detectUsedDLLs(source_dir, standalone_entry_points)
File "/usr/lib/python3.6/site-packages/nuitka/freezer/Standalone.py", line 1062, in detectUsedDLLs
assert os.path.isabs(dll_filename), dll_filename
AssertionError: ldd
Razón detrás del error: nuitka llama a ldd con cada biblioteca compartida ("dll_filename") que se añade a su carpeta .dist. El propósito de esto es encontrar las dependencias de estas bibliotecas compartidas en sí. (Una búsqueda recursiva si se quiere).
Por ejemplo:
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)
Como ves, libexpat.so.1 tiene dos dependencias:
- libgcc_s.so.1 -> se encuentra en /usr/lib/libgcc_s.so.1
- libc.musl-armhf.so.1 -> que se encuentra en ldd
y es precisamente aquí donde nuitka tiene problemas. Quiere copiar un archivo con una ruta absoluta, y en su lugar recibe el nombre "ldd". De nuevo, algo que es específico de Alpine Linux.
Por lo tanto, la afirmación falla, y la nuitka no continúa.
A continuación se explica cómo averiguar a qué archivo hace referencia realmente:
pidoctor:~# que ldd
/usr/bin/lddpidoctor:~# ls -alh /usr/bin/ldd
lrwxrwx 1 root 28 Ene 1 1970 /usr/bin/ldd -> ../../lib/ld-musl-armhf.so.1
Tenga en cuenta que ../../lib/ld-musl-armhf.so.1 es una ruta relativa, que en realidad se refiere a /lib/ld-musl-armhf.so.1 en mi sistema. Y en el tuyo, probablemente, también.
Arreglar:
buscar libutil.so. en el archivo /usr/lib/python3.6/site-packages/nuitka/freezer/Standalone.py
Hay una línea con result.add(filename) debajo. Sólo por encima de esta línea, inserte:
si filename == '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 for Alpine
Tercer error
Error, necesita 'chrpath' en su sistema, debido a la configuración de 'RPATH' en el compartido utilizado
Arreglar:
¿Instalaste chrpath como se aconseja arriba?
apk add chrpath
Eso es todo - ahora nuitka debe realizar su magia sin hipo. Enviaré al autor de nuitka los parches y este artículo del blog, tal vez pueda incluirlos en nuitka.
Versión de fábrica
Actualización 2.2.2019: El autor de Nuitka ha añadido mis parches (de forma ligeramente modificada). En la versión "de fábrica" actual, la compilación -standalone me funciona. Por favor, consulte esta página de github para más detalles: