web-dev-qa-db-de.com

Das Bereitstellen von Yesod auf Heroku kann nicht statisch erstellt werden

Ich bin sehr neu in Yesod und habe Probleme, Yesod statisch aufzubauen, damit ich mich in Heroku entfalten kann.

Ich habe die Standard-CABAL-Datei geändert, um die statische Kompilierung widerzuspiegeln

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

Und es baut nicht mehr. Ich bekomme eine ganze Reihe von Warnungen und dann eine Menge undefinierter Referenzen wie diese:

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 ...)

Wenn ich nur mit -static und ohne -optl-static kompiliere, funktioniert alles einwandfrei, aber die Anwendung stürzt ab, wenn sie versucht, Heroku zu starten.

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

Ich habe versucht, libgmp.so.10 zum LD_LIBRARY_PATH hinzuzufügen, wie in hier vorgeschlagen, und habe dann den folgenden Fehler erhalten:

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

Es scheint, dass die Version von libc, mit der ich kompiliere, anders ist. Ich habe versucht, libc auf die gleiche Weise wie libgmp zum Stapel der Bibliotheken hinzuzufügen, aber dies führt zu einem Segmentierungsfehler, wenn die Anwendung auf der Heroku-Seite gestartet wird.

Alles funktioniert gut auf meinem PC. Ich verwende 64-Bit-Archlinux mit Ghc 7.0.3. Der Blog-Beitrag auf dem offiziellen Yesod-Blog sah ziemlich einfach aus, aber ich bin an dieser Stelle ratlos. Hat jemand irgendwelche Ideen? Wenn es eine Möglichkeit gibt, dieses Ding zum Laufen zu bringen ohne statisch zu bauen, bin ich auch dafür offen.

EDIT

Per Employed Russians antwort habe ich folgendes getan um das zu beheben.

Erstellen Sie zunächst ein neues Verzeichnis lib unter dem Projektverzeichnis und kopieren Sie die fehlenden gemeinsam genutzten Bibliotheken in dieses Verzeichnis. Sie können diese Informationen abrufen, indem Sie ldd path/to/executable und heroku run ldd path/to/executable ausführen und die Ausgabe vergleichen.

Ich habe dann heroku config:add LD_LIBRARY_PATH=./lib ausgeführt. Wenn die Anwendung gestartet wird, sucht der Dynamic Linker im neuen lib-Verzeichnis nach Bibliotheken.

Schließlich habe ich eine virtuelle Ubuntu 11.10-Maschine erstellt und von dort aus für Heroku implementiert. Diese verfügt über einen hinreichend alten Fehler, der auf dem Heroku-Host funktioniert.

Edit: Ich habe seitdem ein Tutorial über das Yesod Wiki geschrieben.

25
asm

Ich habe keine Ahnung, was Yesod ist, aber ich weiß genau was jeder Ihrer anderen Fehler bedeutet.

Zuerst sollten Sie nicht versuchen, statisch zu verknüpfen. Die Warnung, die Sie erhalten, ist genau richtig: Wenn Sie statisch verknüpfen und eine der Routinen verwenden, für die Sie die Warnung erhalten, müssen Sie die Ausführung auf einem System mit genau veranlassen. Die gleiche Version von libc.so.6 wie bei der Erstellung.

Entgegen der weit verbreiteten Meinung erzeugt das statische Linking less und nicht mehr tragbare ausführbare Dateien unter Linux.

Ihre anderen (statischen) Verknüpfungsfehler werden durch das Fehlen von libopenssl.a zum Zeitpunkt der Verknüpfung verursacht.

Nehmen wir jedoch an, dass Sie die "gesunde" Route gehen und dynamische Verknüpfungen verwenden.

Bei der dynamischen Verknüpfung unterstützen Linux (und die meisten anderen UNIX-Geräte) die Abwärtskompatibilität: Eine alte Binärdatei funktioniert auf neueren Systemen weiterhin. Sie unterstützen jedoch keine Vorwärtskompatibilität (eine auf einem neueren System erstellte Binärdatei wird in der Regel auf einem älteren nicht ausgeführt).

Aber das ist, was Sie versuchen: Sie haben auf einem System mit glibc-2.14 (oder neuer) aufgebaut und Sie laufen auf einem System mit glibc-2.13 (oder älter).

Das andere, was Sie wissen müssen, ist, dass glibc aus mehr als 200 Binärdateien besteht, die alle mit genau übereinstimmen müssen. Zwei wichtige Binärdateien sind /lib/ld-linux.so und /lib/libc.so.6 (es gibt jedoch noch viele weitere: libpthread.so.0, libnsl.so.1 usw. usw.). Wenn einige dieser Binärdateien aus verschiedenen Versionen von glibc stammen, kommt es normalerweise zu einem Absturz. Und genau das haben Sie bekommen, als Sie versucht haben, Ihren glibc-2.14 libc.so.6 auf den LD_LIBRARY_PATH zu setzen - er stimmt nicht mehr mit dem System /lib/ld-linux überein.

Also, was sind die Lösungen? Es gibt mehrere Möglichkeiten (in zunehmendem Schwierigkeitsgrad):

  1. Sie können ld-2.14.so (das Ziel von /lib/ld-linux symlink) in das Zielsystem kopieren und explizit aufrufen:

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

    Dies funktioniert im Allgemeinen, kann jedoch eine Anwendung verwirren, die argv[0] betrachtet und für Anwendungen abbricht, die sich selbst erneut ausführen.

  2. Sie könnten auf einem älteren System aufbauen.

  3. Sie könnten appgcc verwenden (diese Option ist verschwunden, siehe this für eine Beschreibung dessen, was sie früher war).

  4. Sie könnten eine Chroot-Umgebung einrichten, die zum Zielsystem passt, und innerhalb dieser Chroot-Umgebung bauen.

  5. Sie könnten sich einen Linux-zu-älterer Linux-Crosscompiler bauen

51

Sie haben mehrere Probleme.

Sie sollten keine Produktionsbinärdateien auf Bleeding Edge-Distributionen erstellen. Die Bibliotheken im Produktionssystem sind nicht vorwärtskompatibel.

Sie sollten glibc nicht statisch verknüpfen - es wird immer versucht, zur Laufzeit weitere Bibliotheken zu laden. Zum Beispiel eine CPU-basierte Assembly. Darum geht es in Ihren ersten Warnungen.

Die letzten Linker-Fehler sehen so aus, als ob sie mit einer fehlenden openssl-Bibliothek in der Befehlszeile zusammenhängen.

Aber alles in allem - Downgrade Sie Ihre Distribution.

5
user239558

Ich hatte ähnliche Probleme beim Start von Heroku (das glibc-2.11 verwendet), wo ich eine Anwendung hatte, die glibc-2.14 benötigte, aber ich hatte keinen Zugriff auf die Quelle und konnte sie nicht neu erstellen. Ich habe viele Dinge ausprobiert und nichts hat funktioniert.

Mein Workaround bestand darin, den Dienst auf Amazon Elastic Beanstalk zu starten und lediglich eine API-Schnittstelle bereitzustellen.

0
idrinkpabst