Haskell Stack静态二进制重定位R_X86_64_32针对`__TMC_END__'无法在创建共享对象时使用。

8
当我在stack.yaml中使用以下内容来尝试通过Stack编译静态二进制文件时:
ghc-options:
    "*": -static -optc-static -optl-static -optl-pthread -fPIC

我遇到了这个错误:

usr/bin/ld: /usr/lib/gcc/x86_64-amazon-linux/4.8.3/crtbeginT.o: relocation R_X86_64_32 against `__TMC_END__' can not be used when making a shared object; recompile with -fPIC
/usr/lib/gcc/x86_64-amazon-linux/4.8.3/crtbeginT.o: could not read symbols: Bad value
collect2: error: ld returned 1 exit status
`gcc' failed in phase `Linker'. (Exit code: 1)

我正在使用启用了docker的stack,并使用定制的Amazon Linux镜像构建静态二进制文件以用于AWS Lambda。

我之前没有静态二进制编译的经验,所以对这个链接错误感到有些困惑。请问有什么建议吗?

以下是使用-v选项的gcc参数:

/usr/bin/gcc -fno-stack-protector -DTABLES_NEXT_TO_CODE '-Wl,--hash-size=31' -Wl,--reduce-memory-overheads -Wl,--no-as-needed -Wl,-rpath<snipped LOADS> -lHSghc<SNIPPED LOADS> -lpq -lz -lrt -lutil -ldl -lgmp

2
如果您能提供失败的 gcc 调用,那将非常有帮助。也许在 ghc-options 行中添加 -v 可以解决问题。 - Reid Barton
1
请返回翻译后的文本:类似这样的内容? https://ghc.haskell.org/trac/ghc/ticket/12759 - d8d0d65b3f7cf42
2
这篇博客文章使用Alpine和Musl可能是一种更可靠的方法。您可以在此构建脚本中看到它的实践:https://github.com/fpco/stack-docker-image-build/blob/master/build-static.sh。 - Michael Snoyman
为什么需要静态链接? - ondra
我觉得你在gcc调用中漏掉了许多重要的标志,比如实际的目标文件应该链接的标志,或者-o标志。 - Reid Barton
显示剩余4条评论
2个回答

5

@Reid Barton是正确的,关于这个问题的根本原因。真正的问题在于stack默认构建一个共享二进制文件。通过传递选项-static或ghc-options:-optl-static,我们只分别处理ghc层和ld层。

stack
 |_ cabal
      |_ ghc
          |_ gcc
              |_ ld (linker)

解决问题的正确方法是告诉Cabal我们需要一个静态二进制文件,因为它驱动了构建过程。

如何做到这一点呢?Reddit上的sausade提供了答案:只需在可执行部分的.cabal文件中添加以下内容:

directive:

`ld-options: -static`

这将提示cabal我们需要一个静态二进制文件,因此它不会将-shared传递给ghc。 因此,一旦您在cabal文件中添加了此指令,您只需运行: stack install --ghc-options="-fPIC" 就可以啦! P.S:如果您的系统上没有静态库(例如Archlinux),则ld将回退到动态链接。
之前的回答: 那是一个旧的gcc问题,没有人关心修复。 https://bugs.launchpad.net/ubuntu/+source/gcc-4.4/+bug/640734 对于您的原始问题,这里有两个有用的链接,可以向您展示如何解决:

2
我猜这只是在绕过构建系统的背后而导致了一些问题。
写成这样是错误的:
ghc-options:
    "*": -static

因为选择构建动态库或静态库对其余构建的影响,这需要考虑到。在这里,看起来 Stack 或 Cabal 告诉 ghc 构建一个动态库,这个标志覆盖了你尝试设置的 -static。因此,gcc 可能最终采用了选项组合 -shared -static,这导致了 Erèbe 的答案中提到的 bug。(如果你的标志 -static 胜过了 -dynamic,那么 ghc 可能已经成功地构建了一个静态库,但 Stack/Cabal 就会困惑于接下来要做什么。)

正确的做法不是在 ghc-options 中使用 -static,而是告诉 Stack 首先不要构建共享库。我不知道你如何在 Stack 中实现这一点,但 Cabal 的标志是 --disable-shared


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接