¿Hay alguna forma de compilar una aplicación de Python en binario estático?

83

Lo que estoy tratando de hacer es enviar mi código a un servidor remoto, que puede tener una versión de Python diferente instalada y / o puede que no tenga los paquetes que requiere mi aplicación.

En este momento, para lograr tal portabilidad, tengo que construir virtualenv reubicable con intérprete y código. Ese enfoque tiene algunos problemas (por ejemplo, debe copiar manualmente un montón de bibliotecas en su virtualenv, ya --always-copyque no funciona como se esperaba) y generalmente es lento.

Hay (en teoría) una forma de construir Python de forma estática.

Me pregunto si podría empaquetar el intérprete con mi código en un binario y ejecutar mi aplicación como módulo. Algo así: ./mypython -m myapp runo ./mypython -m gunicorn -c ./gunicorn.conf myapp.wsgi:application.

roboslone
fuente
¿Quieres decir algo como cx_freeze?
TigerhawkT3
@ TigerhawkT3, nunca había oído hablar de cx_freeze hasta hoy. Revisé los documentos, parece que es lo que quiero, pero no se puede compilar en Ubuntu 12.04.5 con python3.5.1. Estoy buscando alternativas, gracias por ir en la dirección correcta.
roboslone
Lamentablemente, pyinstaller no funciona con Django 1.9 y py2app / py2exe no es compatible con linux :(
roboslone
2
si cx_Freeze y pyinstaller no funcionan, todavía hay esperanza. Puede crear paquetes para su (s) distribución (es) de destino que resolverán todas las dependencias de la instalación. O tal vez use algo como Docker para ejecutar su aplicación.
KeatsPeeks
1
otras opciones son nuitka y cython
denfromufa

Respuestas:

116

Hay dos formas de resolver su problema.

  1. Utilice un constructor estático, como congelar o pyinstaller, opy2exe
  2. Compilar usando cython

Explicaré cómo puede hacerlo usando el segundo, ya que el primer método no es multiplataforma y versión, y se ha explicado en otras respuestas. Además, el uso de programas como pyinstaller generalmente da como resultado tamaños de archivo enormes, mientras que el uso de cython dará como resultado un archivo que tiene un tamaño de KB.

Primero, instale cython. Luego, cambie el nombre de su archivo de Python (por ejemplo test.py) a un .pyxarchivo

sudo pip install cython
mv test.py test.pyx

Luego, puede usarlo cythonjunto con GCC para compilarlo ( cythongenera un archivo C a partir de un .pyxarchivo Python y luego GCC compila el archivo C)

(en referencia a https://stackoverflow.com/a/22040484/5714445 )

cython test.pyx --embed
gcc -Os -I /usr/include/python3.5m -o test test.c -lpython3.5m -lpthread -lm -lutil -ldl

NOTA : Dependiendo de su versión de Python, es posible que deba cambiar el último comando. Para saber qué versión de Python está usando, simplemente use

$ python -V

Ahora tendrá un archivo binario 'prueba', que es lo que está buscando

Otras cosas a tener en cuenta :

  1. Cython se usa para usar definiciones de Variables de tipo C para la asignación de memoria estática para acelerar los programas de Python. Sin embargo, en su caso, seguirá utilizando las definiciones tradicionales de Python.
  2. Si está utilizando bibliotecas adicionales (como opencv, por ejemplo), es posible que deba proporcionarles el directorio usando -Ly luego especificar el nombre de la biblioteca usando -len las banderas GCC. Para obtener más información sobre esto, consulte las banderas de GCC
RS Nikhil Krishna
fuente
19
Hola, ¿qué pasa si mi aplicación abarca varios archivos? Este enfoque parece compilar solo el script actual y no todas las dependencias de Python.
RChat
2
no es necesario cambiar el nombre de su archivo de Python (digamos test.py) a un Pyx en este momento
iMath
3
Esto fue de gran ayuda para mí. Para responder a la pregunta sobre varios archivos, puede usar cythonize: cythonize -i file_0.py [...] file_n.pypara todos sus módulos de Python, luego cython main_file.py --embedpara su script principal. Terminará con un ejecutable y archivos .so (.dll, .dylib dependiendo de su sistema operativo) que puede usar juntos como una solución independiente.
afp
Recibo "No hay módulos con nombre de codificaciones". Llegué a saber que necesito ciertos archivos de la instalación de Python. Sin embargo, mi sistema de destino no tiene Python. Por favor ayuda.
abhiarora
8

Es posible que desee investigar Nuitka . Toma el código fuente de Python y lo convierte en llamadas a la API de C ++. Luego se compila en un binario ejecutable (ELF en Linux). Ha existido durante algunos años y es compatible con una amplia gama de versiones de Python.

Probablemente también obtendrá una mejora de rendimiento si lo usa. Recomendado.

Prakhar Agarwal
fuente
No pude encontrar ninguna información sobre el uso de Nuitka con Django. ¿Tiene usted, por casualidad, tal experiencia?
roboslone
@roboslone, Prakhar Agarwal Cython admite bibliotecas externas muy bien, en comparación con el constructor estático de Nuitka PyPy. Por ejemplo, en el enlace al final de este comentario, "la gente usa Cython porque les ayuda a resolver un problema. Que es que quieren conectarse a bibliotecas externas que no sean de Python desde el código de Python o que quieren poder optimizar manualmente su código, o ambos. ", siendo el enlace blog.behnel.de/posts/indexp241.html
RS Nikhil Krishna
1
RS Nikhil Krishna, no estoy tratando de hacer mi código más rápido, estoy tratando de enviarlo en un binario con un intérprete de Python adentro.
roboslone
Aah está bien. Pensé que querías vincularlo con alguna biblioteca externa. Culpa mía.
RS Nikhil Krishna
0

Opciones de congelación:

Sin embargo, su servidor de destino debe tener el entorno que desea -> debería poder 'crearlo'. Si no es así, debe crear su software para que coincida con el entorno.

Encontré esta útil guía sobre cómo instalar una versión personalizada de python en un virtualenv, suponiendo que tenga acceso ssh: https://stackoverflow.com/a/5507373/5616110

En virtualenv, debería poder instalar cualquier cosa con pip y no debería tener que preocuparse por los privilegios de sudo. Por supuesto, tenerlos y acceso al administrador de paquetes como apt hace que todo sea mucho más fácil.

iScrE4m
fuente
Ya estoy usando virtualenv, este no es el caso. Mi pregunta es sobre Python compilado estáticamente con los módulos y aplicaciones requeridos.
roboslone
Entonces tienes que congelarlo, no hay otra forma de evitarlo.
iScrE4m
0

Si está en una Mac, puede usar py2app para crear un paquete .app, que inicia su aplicación Django cuando hace doble clic en ella.

Describí cómo agrupar Django y CherryPy en un paquete de este tipo en https://moosystems.com/articles/14-distribute-django-app-as-native-desktop-app-01.html

En el artículo, uso pywebview para mostrar su sitio Django en una ventana de aplicación local.

André Aulich
fuente
Mi aplicación se ejecuta en Linux en su mayoría, por lo que no se aplica py2app
roboslone
Aunque el artículo usa py2app, también se puede hacer usando pyinstaller.
André Aulich