Linux 将 Yesod 部署到 Heroku,无法静态构建

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8657908/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 03:50:40  来源:igfitidea点击:

Deploying Yesod to Heroku, can't build statically

linuxhaskellherokustatic-linkingyesod

提问by asm

I'm very new to Yesod and I'm having trouble building Yesod statically so I can deploy to Heroku.

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

I have changed the default .cabal file to reflect static compilation

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

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

And it no longer builds. I get a whole bunch of warnings and then a slew of undefined references like this:

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

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

If I just compile with just -staticand without -optl-staticeverything builds fine but the application crashes when it tries to start on Heroku.

如果我只是编译-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

I tried adding libgmp.so.10 to the LD_LIBRARY_PATH as suggested in hereand then got the following error:

我尝试按照此处的建议将 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

It seems that the version of libc that I'm compiling against is different. I tried also adding libc to the batch of libraries the same way I did for libgmp but this results in a segmentation fault when the application starts on the Heroku side.

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

Everything works fine on my PC. I'm running 64bit archlinux with ghc 7.0.3. The blog post on the official Yesod bloglooked pretty easy but I'm stumped at this point. Anyone have any ideas? If there's a way to get this thing working withoutbuilding statically I'm open to that too.

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

EDIT

编辑

Per Employed Russiansanswer I did the following to fix this.

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

First created a new directory libunder the project directory and copied the missing shared libraries into it. You can get this information by running ldd path/to/executableand heroku run ldd path/to/executableand comparing the output.

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

I then did heroku config:add LD_LIBRARY_PATH=./libso when the application is started the dynamic linker will look for libraries in the new lib directory.

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

Finally I created an ubuntu 11.10 virtual machine and built and deployed to Heroku from there, this has an old enough glibc that it works on the Heroku host.

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

Edit: I've since written a tutorial on the Yesod wiki

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

采纳答案by Employed Russian

I have no idea what Yesod is, but I know exactlywhat each of your other errors means.

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

First, you should nottry to link statically. The warning you get is exactly right: ifyou link statically, and use one of the routines for which you are getting the warning, then you must arrange to run on a system with exactlythe same version of libc.so.6 as the one you used at build time.

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

Contrary to popular belief, static linking produces less, not more, portable executables on Linux.

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

Your other (static) link errors are caused by missing libopenssl.aat link time.

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

But let's assume that you are going to go the "sane" route, and use dynamic linking.

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

For dynamic linking, Linux (and most other UNIXes) support backward compatibility: an old binary continues to work on newer systems. But they don't support forward compatibility (a binary built on a newer system will generally notrun on an older one).

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

But that's what you are trying to do: you built on a system with glibc-2.14 (or newer), and you are running on a system with glibc-2.13 (or older).

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

The other thing you need to know is that glibc is composed of some 200+ binaries that must all match exactly. Two key binaries are /lib/ld-linux.soand /lib/libc.so.6(but there are many more: libpthread.so.0, libnsl.so.1, etc. etc). If some of these binaries came from different versions of glibc, you usually get a crash. And that is exactly what you got, when you tried to place your glibc-2.14 libc.so.6on the LD_LIBRARY_PATH-- it no longer matches the system /lib/ld-linux.

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

So what are the solutions? There are several possibilities (in increasing difficulty):

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

  1. You could copy ld-2.14.so(the target of /lib/ld-linuxsymlink) to the target system, and invoke it explicitly:

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

    This generally works, but can confuse an application that looks at argv[0], and breaks for applications that re-exec themselves.

  2. You could build on an older system.

  3. You could use appgcc(this option has disappeared, see thisfor description of what it used to be).

  4. You could set up a chroot environment matching the target system, and build inside that chroot.

  5. You could build yourself a Linux-to-olderLinux crosscompiler

  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 的交叉编译器

回答by user239558

You have several issues.

你有几个问题。

You should not build production binaries on bleeding edge distributions. The libraries on the production system will not be forward compatible.

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

You should not link glibc statically - it will always at runtime try to load additional libraries. For example cpu-based assembly. That is what your first warnings are about.

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

The last linker errors look like they are related to a missing openssl library on the command line.

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

But all in all - downgrade your distribution.

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

回答by idrinkpabst

I had similar problems launching to Heroku (which uses glibc-2.11) where I had an application that required glibc-2.14, but I did not have access to the source and could not re-build it. I tried many things and nothing worked.

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

My workaround was to launch the service on Amazon Elastic Beanstalk and just provide an API interface.

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