Al implementar Yesod en Heroku, no se puede compilar estáticamente

Resuelto asm asked hace 12 años • 4 respuestas

Soy muy nuevo en Yesod y tengo problemas para construir Yesod estáticamente para poder implementarlo en Heroku.

He cambiado el archivo .cabal predeterminado para reflejar la compilación estática

if flag(production)
   cpp-options:   -DPRODUCTION
   ghc-options:   -Wall -threaded -O2 -static -optl-static
else
   ghc-options:   -Wall -threaded -O0

Y ya no construye. Recibo un montón de advertencias y luego un montón de referencias indefinidas como esta:

Linking dist/build/personal-website/personal-website ...
/usr/lib/ghc-7.0.3/libHSrts_thr.a(Linker.thr_o): In function
`internal_dlopen':
Linker.c:(.text+0x407): warning: Using 'dlopen' in statically linked
applications requires at runtime the shared libraries from the glibc
version used for linking
/usr/lib/ghc-7.0.3/unix-2.4.2.0/libHSunix-2.4.2.0.a(HsUnix.o): In
function `__hsunix_getpwent':
HsUnix.c:(.text+0xa1): warning: Using 'getpwent' in statically linked
applications requires at runtime the shared libraries from the glibc
version used for linking
/usr/lib/ghc-7.0.3/unix-2.4.2.0/libHSunix-2.4.2.0.a(HsUnix.o): In
function `__hsunix_getpwnam_r':
HsUnix.c:(.text+0xb1): warning: Using 'getpwnam_r' in statically
linked applications requires at runtime the shared libraries from the
glibc version used for linking
/usr/lib/libpq.a(thread.o): In function `pqGetpwuid':
(.text+0x15): warning: Using 'getpwuid_r' in statically linked
applications requires at runtime the shared libraries from the glibc
version used for linking
/usr/lib/libpq.a(ip.o): In function `pg_getaddrinfo_all':
(.text+0x31): warning: Using 'getaddrinfo' in statically linked
applications requires at runtime the shared libraries from the glibc
version used for linking
/usr/lib/ghc-7.0.3/site-local/network-2.3.0.2/
libHSnetwork-2.3.0.2.a(BSD__63.o): In function `sD3z_info':
(.text+0xe4): warning: Using 'gethostbyname' in statically linked
applications requires at runtime the shared libraries from the glibc
version used for linking
/usr/lib/ghc-7.0.3/site-local/network-2.3.0.2/
libHSnetwork-2.3.0.2.a(BSD__164.o): In function `sFKc_info':
(.text+0x12d): warning: Using 'getprotobyname' in statically linked
applications requires at runtime the shared libraries from the glibc
version used for linking
/usr/lib/ghc-7.0.3/site-local/network-2.3.0.2/
libHSnetwork-2.3.0.2.a(BSD__155.o): In function `sFDs_info':
(.text+0x4c): warning: Using 'getservbyname' in statically linked
applications requires at runtime the shared libraries from the glibc
version used for linking
/usr/lib/libpq.a(fe-misc.o): In function `pqSocketCheck':
(.text+0xa2d): undefined reference to `SSL_pending'
/usr/lib/libpq.a(fe-secure.o): In function `SSLerrmessage':
(.text+0x31): undefined reference to `ERR_get_error'
/usr/lib/libpq.a(fe-secure.o): In function `SSLerrmessage':
(.text+0x41): undefined reference to `ERR_reason_error_string'
/usr/lib/libpq.a(fe-secure.o): In function `initialize_SSL':
(.text+0x2f8): undefined reference to `SSL_check_private_key'
/usr/lib/libpq.a(fe-secure.o): In function `initialize_SSL':
(.text+0x3c0): undefined reference to `SSL_CTX_load_verify_locations'
(... snip ...)

Si solo compilo con solo -staticy sin, -optl-static todo funciona bien, pero la aplicación falla cuando intenta iniciarse en Heroku.

2011-12-28T01:20:51+00:00 heroku[web.1]: Starting process with command
`./dist/build/personal-website/personal-website -p 41083`
2011-12-28T01:20:51+00:00 app[web.1]: ./dist/build/personal-website/
personal-website: error while loading shared libraries: libgmp.so.10:
cannot open shared object file: No such file or directory
2011-12-28T01:20:52+00:00 heroku[web.1]: State changed from starting
to crashed

Intenté agregar libgmp.so.10 a LD_LIBRARY_PATH como se sugiere aquí y luego obtuve el siguiente error:

2011-12-28T01:31:23+00:00 app[web.1]: ./dist/build/personal-website/
personal-website: /lib/libc.so.6: version `GLIBC_2.14' not found
(required by ./dist/build/personal-website/personal-website)
2011-12-28T01:31:23+00:00 app[web.1]: ./dist/build/personal-website/
personal-website: /lib/libc.so.6: version `GLIBC_2.14' not found
(required by /app/dist/build/personal-website/libgmp.so.10)
2011-12-28T01:31:25+00:00 heroku[web.1]: State changed from starting
to crashed
2011-12-28T01:31:25+00:00 heroku[web.1]: Process exited

Parece que la versión de libc con la que estoy compilando es diferente. También intenté agregar libc al lote de bibliotecas de la misma manera que lo hice con libgmp, pero esto genera un error de segmentación cuando la aplicación se inicia en el lado de Heroku.

Todo funciona bien en mi PC. Estoy ejecutando archlinux de 64 bits con ghc 7.0.3. La publicación en el blog oficial de Yesod parecía bastante fácil, pero en este punto estoy perplejo. ¿Alguien tiene alguna idea? Si hay una manera de hacer que esto funcione sin construir estáticamente, también estoy abierto a ello.

EDITAR

Por Employed Russiansrespuesta, hice lo siguiente para solucionar este problema.

Primero creó un nuevo directorio liben el directorio del proyecto y copió en él las bibliotecas compartidas que faltaban. Puede obtener esta información ejecutando ldd path/to/executabley heroku run ldd path/to/executablecomparando la salida.

Luego lo hice heroku config:add LD_LIBRARY_PATH=./libcuando se inicia la aplicación, el vinculador dinámico buscará bibliotecas en el nuevo directorio lib.

Finalmente, creé una máquina virtual ubuntu 11.10 y la construí e implementé en Heroku desde allí. Tiene una glibc lo suficientemente antigua como para funcionar en el host de Heroku.

Editar: desde entonces escribí un tutorial en la wiki de Yesod

asm avatar Dec 28 '11 22:12 asm
Aceptado

No tengo idea de qué es Yesod, pero sé exactamente qué significa cada uno de tus otros errores.

Primero, no deberías intentar vincular estáticamente. La advertencia que recibe es exactamente correcta: si se vincula estáticamente y utiliza una de las rutinas para las cuales recibe la advertencia, entonces debe organizar la ejecución en un sistema con exactamente la misma versión de libc.so.6 que la anterior. usaste en el momento de la construcción.

Contrariamente a la creencia popular, los enlaces estáticos producen menos , no más, archivos ejecutables portátiles en Linux.

Sus otros errores de enlace (estáticos) se deben a que faltan libopenssl.aen el momento del enlace.

Pero supongamos que va a seguir la ruta "sensata" y utilizará enlaces dinámicos.

Para los enlaces dinámicos, Linux (y la mayoría de los demás UNIX) admiten compatibilidad con versiones anteriores: un binario antiguo continúa funcionando en sistemas más nuevos. Pero no admiten compatibilidad hacia adelante (un binario creado en un sistema más nuevo generalmente no se ejecutará en uno más antiguo).

Pero eso es lo que estás intentando hacer: compilaste en un sistema con glibc-2.14 (o posterior) y estás ejecutando en un sistema con glibc-2.13 (o anterior).

La otra cosa que necesitas saber es que glibc se compone de más de 200 archivos binarios que deben coincidir exactamente . Dos binarios clave son /lib/ld-linux.soy /lib/libc.so.6(pero hay muchos más: libpthread.so.0, libnsl.so.1, etc., etc.). Si algunos de estos binarios provienen de diferentes versiones de glibc, normalmente se produce un fallo. Y eso es exactamente lo que obtuvo cuando intentó colocar su glibc-2.14 libc.so.6en el LD_LIBRARY_PATH... ya no coincide con el sistema /lib/ld-linux.

Entonces, ¿cuáles son las soluciones? Hay varias posibilidades (en dificultad creciente):

  1. Puede copiar ld-2.14.so(el destino del /lib/ld-linuxenlace simbólico) al sistema de destino e invocarlo explícitamente:

    /path/to/ld-2.14.so --library-path <whatever> /path/to/your/executable
    

    Esto generalmente funciona, pero puede confundir a una aplicación que mira argv[0]y se interrumpe para aplicaciones que se vuelven a ejecutar.

  2. Podrías construir sobre un sistema más antiguo.

  3. Podrías usar appgcc(esta opción ha desaparecido, consulta esto para obtener una descripción de lo que solía ser).

  4. Podría configurar un entorno chroot que coincida con el sistema de destino y construir dentro de ese chroot.

  5. Podrías crear tú mismo un compilador cruzado de Linux a versiones anteriores de Linux.

Employed Russian avatar Dec 28 '2011 16:12 Employed Russian

Tienes varios problemas.

No debe crear archivos binarios de producción en distribuciones de última generación. Las bibliotecas del sistema de producción no serán compatibles con versiones posteriores.

No debe vincular glibc estáticamente; siempre, en tiempo de ejecución, intentará cargar bibliotecas adicionales. Por ejemplo, ensamblaje basado en CPU. De eso se tratan sus primeras advertencias.

Los últimos errores del vinculador parecen estar relacionados con una biblioteca openssl que falta en la línea de comando.

Pero, en definitiva, reduzca su distribución.

user239558 avatar Dec 28 '2011 16:12 user239558