Hi,

On the road of dynamic linking for Haskell executables, Magnus has pushed a commit [1] on `cblrepo` yesterday. This commit adds the cabal flag `--enable-executable-dynamic`. It follows a previous discussion on this mailing list [2] and solves some of the cited problems. I tried to build `pandoc` dynamically this morning, and there is only one issue left (unless I do something wrong?).

For dynamic linking, Cabal/GHC embed an RPATH into the executable:

    $ readelf --dynamic /usr/bin/pandoc
    [[...]]
    0x000000000000000f (RPATH)              Library rpath: [/home/fabien/archlinux/habs/haskell-pandoc/src/pandoc-1.12.1/dist/build:/usr/lib/ghc-7.6.3/site-local/zip-archive-0.1.4:/usr/lib/ghc-7.6.3/site-local/zlib-0.5.4.1:/usr/lib/ghc-7.6.3/site-local/utf8-string-0.3.7:/usr/lib/ghc-7.6.3/site-local/digest-0.0.1.2:/usr/lib/ghc-7.6.3/site-local/binary-0.7.1.0:/usr/lib/ghc-7.6.3/site-local/texmath-0.6.4:/usr/lib/ghc-7.6.3/site-local/xml-1.3.13:/usr/lib/ghc-7.6.3/site-local/temporary-1.1.2.4:/usr/lib/ghc-7.6.3/site-local/tagsoup-0.13:/usr/lib/ghc-7.6.3/site-local/random-1.0.1.1:/usr/lib/ghc-7.6.3/process-1.1.0.2:/usr/lib/ghc-7.6.3/site-local/hslua-0.3.7:/usr/lib/ghc-7.6.3/site-local/data-default-0.5.3:/usr/lib/ghc-7.6.3/site-local/data-default-instances-old-locale-0.0.1:/usr/lib/ghc-7.6.3/site-local/data-default-instances-dlist-0.0.1:/usr/lib/ghc-7.6.3/site-local/data-default-instances-containers-0.0.1:/usr/lib/ghc-7.6.3/site-local/data-default-instances-base-0.0.1:/usr/lib/ghc-7.6.3/site-local/data-default-class-0.0.1:/usr/lib/ghc-7.6.3/site-local/base64-bytestring-1.0.0.1:/usr/lib/ghc-7.6.3/site-local/yaml-0.8.5.1:/usr/lib/ghc-7.6.3/site-local/conduit-1.0.8:/usr/lib/ghc-7.6.3/site-local/void-0.6.1:/usr/lib/ghc-7.6.3/site-local/semigroups-0.11:/usr/lib/ghc-7.6.3/site-local/nats-0.1.2:/usr/lib/ghc-7.6.3/site-local/resourcet-0.4.9:/usr/lib/ghc-7.6.3/site-local/mmorph-1.0.0:/usr/lib/ghc-7.6.3/site-local/lifted-base-0.2.1.0:/usr/lib/ghc-7.6.3/site-local/monad-control-0.3.2.2:/usr/lib/ghc-7.6.3/site-local/transformers-base-0.4.1:/usr/lib/ghc-7.6.3/site-local/base-unicode-symbols-0.2.2.4:/usr/lib/ghc-7.6.3/site-local/pandoc-types-1.12.3:/usr/lib/ghc-7.6.3/site-local/highlighting-kate-0.5.5:/usr/lib/ghc-7.6.3/site-local/pcre-light-0.4:/usr/lib/ghc-7.6.3/site-local/blaze-html-0.6.1.1:/usr/lib/ghc-7.6.3/site-local/blaze-markup-0.5.1.5:/usr/lib/ghc-7.6.3/site-local/extensible-exceptions-0.1.1.4:/usr/lib/ghc-7.6.3/directory-1.2.0.1:/usr/lib/ghc-7.6.3/filepath-1.3.0.1:/usr/lib/ghc-7.6.3/site-local/aeson-0.6.2.1:/usr/lib/ghc-7.6.3/site-local/vector-0.10.9.1:/usr/lib/ghc-7.6.3/site-local/primitive-0.5.1.0:/usr/lib/ghc-7.6.3/site-local/unordered-containers-0.2.3.3:/usr/lib/ghc-7.6.3/template-haskell-2.8.0.0:/usr/lib/ghc-7.6.3/pretty-1.1.1.0:/usr/lib/ghc-7.6.3/site-local/syb-0.4.1:/usr/lib/ghc-7.6.3/site-local/hashable-1.2.1.0:/usr/lib/ghc-7.6.3/site-local/dlist-0.5:/usr/lib/ghc-7.6.3/site-local/blaze-builder-0.3.1.1:/usr/lib/ghc-7.6.3/site-local/attoparsec-0.10.4.0:/usr/lib/ghc-7.6.3/containers-0.5.0.0:/usr/lib/ghc-7.6.3/site-local/HTTP-4000.2.8:/usr/lib/ghc-7.6.3/old-time-1.1.0.1:/usr/lib/ghc-7.6.3/site-local/network-2.4.2.0:/usr/lib/ghc-7.6.3/unix-2.6.0.1:/usr/lib/ghc-7.6.3/time-1.4.0.1:/usr/lib/ghc-7.6.3/old-locale-1.0.0.5:/usr/lib/ghc-7.6.3/site-local/parsec-3.1.3:/usr/lib/ghc-7.6.3/site-local/text-0.11.3.1:/usr/lib/ghc-7.6.3/site-local/mtl-2.1.2:/usr/lib/ghc-7.6.3/site-local/transformers-0.3.0.0:/usr/lib/ghc-7.6.3/bytestring-0.10.0.2:/usr/lib/ghc-7.6.3/deepseq-1.3.0.1:/usr/lib/ghc-7.6.3/array-0.4.0.1:/usr/lib/ghc-7.6.3/base-4.6.0.1:/usr/lib/ghc-7.6.3/integer-gmp-0.5.0.0:/usr/lib/ghc-7.6.3/ghc-prim-0.3.0.0:/usr/lib/ghc-7.6.3]
    [[...]]

This is working to find all libraries except one: `libHSpandoc-1.12.1-ghc7.6.3.so`. The reason is the following: At compile time, cabal first builds the pandoc library, then the pandoc executable which is using this library. But because the library is not installed at this moment (understand: not located in the final place `/usr/lib/ghc-7.6.3/site-local/pandoc-1.12.1/`) the RPATH embeds its *current* location, in my case `/home/fabien/archlinux/habs/haskell-pandoc/src/pandoc-1.12.1/dist/build` (see the output above). So as long as the library is present in this folder, pandoc works, but obviously that is not working to distribute it. I suppose this method is working for cabal-install because the library stays at its place once built, which is not the case here: the library is moved once built.

Also I suppose this problem doesn't appear with library-only package, because each package generate only one `*.so` file (as far as I have seen), so no need to link against another library of the same package at build time.

Up to my knowledge I see three solutions:

  1. Find a way to build and install in two passes, something like separating in haskell-pandoc and haskell-pandoc-libs (first build and install pandoc-libs, then build and install pandoc)
    - Requires to find a way to create separate PKGBUILDs for the same hackage package. Elegant but complicated solution, so not very convenient.
  2. Try to modify the RPATH inside the executable
    - Seems to be possible, see [3], but complicated and not very elegant solution.
  3. Change the linking paradigm to use /etc/ld.so.conf.d/* instead of the embedded RPATH
    - Requires to put or link all `*.so` libraries into on place, and add a `/etc/ld.so.conf.d/haskell.conf` file to ghc installation. The most tractable solution imho.

Does anyone has remarks/suggestions/ideas/solutions about this problem?

Best regards,
Fabien

[1] https://github.com/magthe/cblrepo/commit/de9df07d398d70255c852f4de53e3d14c4eeb0b4
[2] http://www.haskell.org/pipermail/arch-haskell/2013-October/004600.html
[3] http://stackoverflow.com/questions/13769141/can-i-change-rpath-in-an-already-compiled-binary