31

我对 Yesod 很陌生,我在静态构建 Yesod 时遇到了麻烦,因此我可以部署到 Heroku。

我更改了默认的 .cabal 文件以反映静态编译

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

它不再构建。我收到一大堆警告,然后是一堆未定义的引用,如下所示:

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

如果我只是编译-static而没有-optl-static 一切构建正常,但应用程序在尝试在 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

我尝试按照此处的建议将 libgmp.so.10 添加到 LD_LIBRARY_PATH 中 ,然后出现以下错误:

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

似乎我正在编译的 libc 版本不同。我还尝试像对 libgmp 一样将 libc 添加到一批库中,但是当应用程序在 Heroku 端启动时,这会导致分段错误。

在我的电脑上一切正常。我正在使用 ghc 7.0.3 运行 64 位 archlinux。 Yesod 官方博客上的博文看起来很简单,但我现在很难过。有人有想法么?如果有办法让这个东西在静态构建的情况下工作,我也愿意。

编辑

每个Employed Russians答案我做了以下来解决这个问题。

首先在项目目录下新建一个lib目录,把缺少的共享库复制进去。您可以通过运行并比较输出来获取此ldd path/to/executable信息heroku run ldd path/to/executable

然后我这样做了heroku config:add LD_LIBRARY_PATH=./lib,当应用程序启动时,动态链接器将在新的 lib 目录中查找库。

最后,我创建了一个 ubuntu 11.10 虚拟机,并从那里构建并部署到 Heroku,它有一个足够老的 glibc,可以在 Heroku 主机上运行。

编辑:我已经在Yesod wiki上写了一个教程

4

3 回答 3

63

我不知道 Yesod 是什么,但我确切地知道您的其他每个错误的含义。

首先,您不应该尝试静态链接。您收到的警告是完全正确的:如果您静态链接,并使用您收到警告的例程之一,那么您必须安排在与libc.so.6 版本完全相同的系统上运行您在构建时使用过。

与流行的看法相反,静态链接在 Linux 上生成的可移植可执行文件更少,而不是更多。

您的其他(静态)链接错误是由libopenssl.a链接时丢失引起的。

但是让我们假设您要走“理智”的路线,并使用动态链接。

对于动态链接,Linux(和大多数其他 UNIX)支持向后兼容性:旧的二进制文件继续在新的系统上工作。但是它们不支持前向兼容性(在较新系统上构建的二进制文件通常不会在旧系统上运行)。

但这就是您要尝试做的事情:您在使用 glibc-2.14(或更高版本)的系统上构建,并且在使用 glibc-2.13(或更高版本)的系统上运行。

您需要知道的另一件事是 glibc 由大约 200 多个必须完全匹配的二进制文件组成。两个关键的二进制文件是/lib/ld-linux.soand /lib/libc.so.6(但还有更多:libpthread.so.0,libnsl.so.1等)。如果其中一些二进制文件来自不同版本的 glibc,您通常会崩溃。这正是您得到的,当您尝试将 glibc-2.14libc.so.6放在LD_LIBRARY_PATH- 它不再与 system 匹配时/lib/ld-linux

那么解决方案有哪些呢?有几种可能性(难度越来越大):

  1. ld-2.14.so您可以将(/lib/ld-linux符号链接的目标)复制到目标系统,并显式调用它:

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

    这通常有效,但可能会混淆查看 的应用程序argv[0],并中断重新执行自身的应用程序。

  2. 您可以在较旧的系统上进行构建。

  3. 您可以使用appgcc(此选项已消失,请参阅以了解它曾经是什么的描述)。

  4. 您可以设置与目标系统匹配的 chroot 环境,并在该 chroot 内构建。

  5. 你可以自己构建一个 Linux 到旧的 Linux 交叉编译器

于 2011-12-28T16:23:29.047 回答
5

你有几个问题。

您不应该在前沿发行版上构建生产二进制文件。生产系统上的库将不向前兼容。

您不应该静态链接 glibc - 它总是会在运行时尝试加载其他库。例如基于 cpu 的程序集。这就是你的第一个警告。

最后一个链接器错误看起来与命令行上缺少的 openssl 库有关。

但总而言之 - 降级您的发行版。

于 2011-12-28T16:29:38.190 回答
0

我在启动 Heroku(使用 glibc-2.11)时遇到了类似的问题,我有一个需要 glibc-2.14 的应用程序,但我无法访问源代码并且无法重新构建它。我尝试了很多东西,但没有任何效果。

我的解决方法是在 Amazon Elastic Beanstalk 上启动该服务并只提供一个 API 接口。

于 2013-07-12T21:38:54.757 回答