Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell linking with dynamic libraries on Ubuntu

I am having issues linking to a Haskell library we wrote. It goes wrong on Ubuntu, but not on Arch Linux. The error on Ubuntu we get is this:

/usr/bin/ld: warning: libHSdeepseq-1.3.0.0-ghc7.4.1.so, needed by /usr/lib/ghc/containers-0.4.2.1/libHScontainers-0.4.2.1-ghc7.4.1.so, not found (try using -rpath or -rpath-link) /usr/lib/ghc/containers-0.4.2.1/libHScontainers-0.4.2.1-ghc7.4.1.so: undefined reference to 'deepseqzm1zi3zi0zi0_ControlziDeepSeq_zdfNFDataArrayzuzdcrnf1_info'

The issue seems to be caused by the fact that libHScontainers-0.4.2.1-ghc7.4.1.so is incorrectly linked as one can see by the output of 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 => not found libHSbase-4.5.0.0-ghc7.4.1.so => not found libHSghc-prim-0.2.0.0-ghc7.4.1.so => not found 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)

Apparently the dependent libraries can not be found. They are installed. However if I do the same on 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)

The libraries are found.

As suggested I can solve this on Ubuntu by using -rpath in the application we try to link to the Haskell library. But this means that we have to do this for every Haskell package which seems wrong to me. We can also fix this by adding a line to /etc/ld.so.conf.d/ghc.conf. But this also has to be done for every package and is not user-friendly.

A few questions I have:

  • What is the correct way to fix this?
  • Why are the packages in ghc-dynamic incorrectly linked?
  • Why is the linker able to find libHScontainers-0.4.2.1-ghc7.4.1.so but not libHSdeepseq-1.3.0.0-ghc7.4.1.so?
like image 386
meijuh Avatar asked Dec 04 '14 10:12

meijuh


1 Answers

I strongly suspect that this is because the Haskell libraries installed by ghc have the locations of their dependencies (the RPATH field of their ELF header; you can verify using readelf -d) defined in terms of $ORIGIN. When library X depends on library Y, library X can indicate that library Y should be found in a location relative to its own location by using $ORIGIN. This is supported by the dynamic linker, but is not supported by the static linker.

(I'm speculating here:) Your library will define the location of its direct dependencies (in your case, I'm guessing, this includes containers) in terms of its own RPATH, which is not in terms of $ORIGIN. This is why the linker can find those, but not its transitive dependencies (again, I'm guessing, this includes deepseq in your case).

So why the difference between Arch Linux and Ubuntu? (Speculating further.) This is because unlike on Arch Linux, Ubunbu's linker uses --as-needed by default. You see, ghc will link your library against all its dependencies (including transitive ones), but then the linker will omit some of those dependencies because it doesn't directly depend on them. You could verify this by relinking with --no-as-needed.

Note that these errors by the static linkers really aren't errors, but warnings: it tries to resolve symbols, but it can't; but the dynamic linker will be able to anyway. So you can instruct the linker to ignore these errors (--unresolved-symbols=ignore-all) and all should be well.

I've been battling with adding explicit support in Cabal for generating Haskell libraries for use in C programs, and found the same problem. See https://github.com/haskell/cabal/pull/2540#issuecomment-95984067 for details.

like image 64
edsko Avatar answered Oct 02 '22 09:10

edsko