我在链接到我们编写的 Haskell 库时遇到问题。在 Ubuntu 上会出错,但在 Arch Linux 上不会。我们在 Ubuntu 上得到的错误是这样的:
/usr/bin/ld:警告:libHSdeepseq-1.3.0.0-ghc7.4.1.so,/usr/lib/ghc/containers-0.4.2.1/libHScontainers-0.4.2.1-ghc7 需要。 4.1.so,没有找到(尝试使用-rpath或-rpath-link)
/usr/lib/ghc/containers-0.4.2.1/libHScontainers-0.4.2.1-ghc7.4.1.so:对“deepseqzm1zi3zi0zi0_ControlziDeepSeq_zdfNFDataArrayzuzdcrnf1_info”的 undefined reference
问题似乎是由 libHScontainers-0.4.2.1-ghc7.4.1.so
链接不正确引起的,从 ldd
的输出可以看出:
ldd/usr/lib/ghc/containers-0.4.2.1/libHScontainers-0.4.2.1-ghc7.4.1.so
linux-vdso.so.1 => (0x00007fffe95a2000)
libHSdeepseq-1.3.0.0-ghc7.4.1.so => 未找到
libHSbase-4.5.0.0-ghc7.4.1.so => 未找到
libHSghc-prim-0.2.0.0-ghc7.4.1.so => 未找到
libpthread.so.0 =>/lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f89a5a59000)
libc.so.6 =>/lib/x86_64-linux-gnu/libc.so.6 (0x00007f89a569a000)
/lib64/ld-linux-x86-64.so.2 (0x00007f89a5fd8000)
显然找不到依赖库。它们已安装。但是,如果我在 Arch 上做同样的事情:
ldd/usr/lib/ghc-7.8.3/deepseq-1.3.0.2/libHSdeepseq-1.3.0.2-ghc7.8.3.so
linux-vdso.so.1 (0x00007fff09dfe000)
libgmp.so.10 =>/usr/lib/libgmp.so.10 (0x00007fb8d3e96000)
libm.so.6 =>/usr/lib/libm.so.6 (0x00007fb8d3b91000)
librt.so.1 =>/usr/lib/librt.so.1 (0x00007fb8d3988000)
libdl.so.2 =>/usr/lib/libdl.so.2 (0x00007fb8d3784000)
libffi.so.6 =>/usr/lib/libffi.so.6 (0x00007fb8d357b000)
libHSarray-0.5.0.0-ghc7.8.3.so =>/usr/lib/ghc-7.8.3/deepseq-1.3.0.2/../array-0.5.0.0/libHSarray-0.5.0.0-ghc7.8.3.so (0x00007fb8d32e1000)
libHSbase-4.7.0.1-ghc7.8.3.so =>/usr/lib/ghc-7.8.3/deepseq-1.3.0.2/../base-4.7.0.1/libHSbase-4.7.0.1-ghc7.8.3.so (0x00007fb8d2967000)
libHSinteger-gmp-0.5.1.0-ghc7.8.3.so =>/usr/lib/ghc-7.8.3/deepseq-1.3.0.2/../integer-gmp-0.5.1.0/libHSinteger-gmp-0.5.1.0 -ghc7.8.3.so (0x00007fb8d274c000)
libHSghc-prim-0.3.1.0-ghc7.8.3.so =>/usr/lib/ghc-7.8.3/deepseq-1.3.0.2/../ghc-prim-0.3.1.0/libHSghc-prim-0.3.1.0 -ghc7.8.3.so (0x00007fb8d24cf000)
libc.so.6 =>/usr/lib/libc.so.6 (0x00007fb8d212c000)
libpthread.so.0 =>/usr/lib/libpthread.so.0 (0x00007fb8d1f10000)
/usr/lib64/ld-linux-x86-64.so.2 (0x00007fb8d435f000)
库已找到。
正如建议的那样,我可以通过在我们尝试链接到 Haskell 库的应用程序中使用 -rpath 来在 Ubuntu 上解决这个问题。但这意味着我们必须对每个 Haskell 包都这样做,这对我来说是错误的。
我们还可以通过向 /etc/ld.so.conf.d/ghc.conf
添加一行来解决此问题。但这也必须为每个包完成,并且对用户不友好。
我有几个问题:
- 解决此问题的正确方法是什么?
- 为什么
ghc-dynamic
中的包链接不正确? - 为什么链接器能够找到
libHScontainers-0.4.2.1-ghc7.4.1.so
而不是libHSdeepseq-1.3.0.0-ghc7.4.1.so
?
最佳答案
我强烈怀疑这是因为 ghc 安装的 Haskell 库具有根据 RPATH
定义的依赖项的位置(它们的 ELF header 的 readelf -d
字段;您可以使用 $ORIGIN
进行验证)。当库 X 依赖于库 Y 时,库 X 可以指示库 Y 应该在相对位置找到使用 $ORIGIN
到它自己的位置。这是动态链接器支持的,但静态链接器不支持。
(我在这里推测:)您的库将根据其自身的 containers
定义其直接 依赖项的位置(在您的情况下,我猜这包括 RPATH
),这与 $ORIGIN
无关。这就是为什么链接器可以找到那些,但不能找到它的传递依赖项(同样,我猜,这包括 deepseq
在你的情况下)。
那么为什么 Arch Linux 和 Ubuntu 之间存在差异? (进一步推测。)这是因为与 Arch Linux 不同,Ubunbu 的链接器默认使用 --as-needed
。你看,ghc
会将你的库链接到所有它的依赖项(包括可传递的依赖项),但随后链接器将忽略其中一些依赖项,因为它不直接依赖它们。您可以通过重新链接 --no-as-needed
来验证这一点。
请注意,静态链接器的这些错误实际上不是错误,而是警告:它试图解析符号,但它不能; 但动态链接器无论如何都可以。因此,您可以指示链接器忽略这些错误 (--unresolved-symbols=ignore-all
),一切都会好起来的。
我一直在努力在 Cabal
中添加显式支持以生成用于 C 程序的 Haskell 库,但发现了同样的问题。有关详细信息,请参阅 https://github.com/haskell/cabal/pull/2540#issuecomment-95984067。
关于Haskell 在 Ubuntu 上与动态库链接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27291531/