title: How to properly link object files written in Haskell?
body: <p>Roughly following <a href="https://idontgetoutmuch.wordpress.com/2017/01/14/calling-haskell-from-c/" rel="noreferrer">this tutorial</a>, I managed to get this toy project working. It calls a Haskell function from a C++ program.</p>
  
  <ul>
  <li><p><code>Foo.hs</code>
  </p>
  
  <pre><code>{-# LANGUAGE ForeignFunctionInterface #-}
  
  module Foo where
  
  foreign export ccall foo :: Int -&gt; Int -&gt; IO Int
  
  foo :: Int -&gt; Int -&gt; IO Int
  foo n m = return . sum $ f n ++ f m
  
  f :: Int -&gt; [Int]
  f 0 = []
  f n = n : f (n-1)
  </code></pre></li>
  <li><p><code>bar.c++</code>
  </p>
  
  <pre><code>#include "HsFFI.h"
  #include FOO       // Haskell module (path defined in build script)
  
  #include &lt;iostream&gt;
  
  int main(int argc, char *argv[]) {
    hs_init(&amp;argc, &amp;argv);
  
    std::cout &lt;&lt; foo(37, 19) &lt;&lt; "\n";
  
    hs_exit();
    return 0;
  }
  </code></pre></li>
  <li><p><code>call-haskell-from-cxx.cabal</code>
  </p>
  
  <pre><code>name:                call-haskell-from-cxx
  version:             0.1.0.0
  build-type:          Simple
  cabal-version:       &gt;=1.10
  
  executable foo.so
    main-is:          Foo.hs   
    build-depends:       base &gt;=4.10 &amp;&amp; &lt;4.11
    ghc-options:         -shared -fPIC -dynamic
    extra-libraries:     HSrts-ghc8.2.1
    default-language:    Haskell2010
  </code></pre></li>
  <li><p>build script
  </p>
  
  <pre><code>#!/bin/bash
  
  hs_lib="foo.so"
  hs_obj="dist/build/$hs_lib/$hs_lib"
  
  ghc_version="8.2.1"                          # May need to be tweaked,
  ghc_libdir="/usr/local/lib/ghc-$ghc_version" # depending on system setup.
  
  set -x
  
  cabal build
  
  g++ -I "$ghc_libdir/include" -D"FOO=\"${hs_obj}-tmp/Foo_stub.h\"" -c bar.c++ -o test.o
  g++ test.o "$hs_obj" \
     -L "$ghc_libdir/rts" "-lHSrts-ghc$ghc_version" \
     -o test
  
  env LD_LIBRARY_PATH="dist/build/$hs_lib:$ghc_libdir/rts:$LD_LIBRARY_PATH" \
    ./test
  </code></pre></li>
  </ul>
  
  <p>This works (Ubuntu 16.04, GCC 5.4.0), printing <code>893</code> – but it isn't really robust, namely, if I <em>remove</em> the actual invocation of the Haskell function, i.e. the <code>std::cout &lt;&lt; foo(37, 19) &lt;&lt; "\n";</code> line, then it fails at the linking step, with the error message</p>
  
  <pre class="lang-none prettyprint-override"><code>/usr/local/lib/ghc-8.2.1/rts/libHSrts-ghc8.2.1.so: undefined reference to `base_GHCziTopHandler_flushStdHandles_closure'
  /usr/local/lib/ghc-8.2.1/rts/libHSrts-ghc8.2.1.so: undefined reference to `base_GHCziStable_StablePtr_con_info'
  /usr/local/lib/ghc-8.2.1/rts/libHSrts-ghc8.2.1.so: undefined reference to `base_GHCziPtr_FunPtr_con_info'
  /usr/local/lib/ghc-8.2.1/rts/libHSrts-ghc8.2.1.so: undefined reference to `base_GHCziWord_W8zh_con_info'
  /usr/local/lib/ghc-8.2.1/rts/libHSrts-ghc8.2.1.so: undefined reference to `base_GHCziIOziException_cannotCompactPinned_closure'
  ...
  </code></pre>
  
  <p>Apparently, the inclusion of the Haskell project pulls additional library files in that are needed. How do I explicitly depend on everything necessary, to avoid such brittleness?</p>
  
  <hr>
  
  <p>Output of the build script when the <code>foo</code> call is included, with <code>ldd</code> on the final executable:</p>
  
  <pre><code>++ cabal build
  Preprocessing executable 'foo.so' for call-haskell-from-C-0.1.0.0..
  Building executable 'foo.so' for call-haskell-from-C-0.1.0.0..
  Linking a.out ...
  Linking dist/build/foo.so/foo.so ...
  ++ g++ -I /usr/local/lib/ghc-8.2.1/include '-DFOO="dist/build/foo.so/foo.so-tmp/Foo_stub.h"' -c bar.c++ -o test.o
  ++ g++ test.o dist/build/foo.so/foo.so -L /usr/local/lib/ghc-8.2.1/rts -lHSrts-ghc8.2.1 -o test
  ++ env LD_LIBRARY_PATH=dist/build/foo.so:/usr/local/lib/ghc-8.2.1/rts: sh -c 'ldd ./test; ./test'
      linux-vdso.so.1 =&gt;  (0x00007fff23105000)
      foo.so =&gt; dist/build/foo.so/foo.so (0x00007fdfc5360000)
      libHSrts-ghc8.2.1.so =&gt; /usr/local/lib/ghc-8.2.1/rts/libHSrts-ghc8.2.1.so (0x00007fdfc52f8000)
      libstdc++.so.6 =&gt; /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fdfc4dbe000)
      libc.so.6 =&gt; /lib/x86_64-linux-gnu/libc.so.6 (0x00007fdfc49f4000)
      libHSbase-4.10.0.0-ghc8.2.1.so =&gt; /usr/local/lib/ghc-8.2.1/base-4.10.0.0/libHSbase-4.10.0.0-ghc8.2.1.so (0x00007fdfc4020000)
      libHSinteger-gmp-1.0.1.0-ghc8.2.1.so =&gt; /usr/local/lib/ghc-8.2.1/integer-gmp-1.0.1.0/libHSinteger-gmp-1.0.1.0-ghc8.2.1.so (0x00007fdfc528b000)
      libHSghc-prim-0.5.1.0-ghc8.2.1.so =&gt; /usr/local/lib/ghc-8.2.1/ghc-prim-0.5.1.0/libHSghc-prim-0.5.1.0-ghc8.2.1.so (0x00007fdfc3b80000)
      libgmp.so.10 =&gt; /usr/lib/x86_64-linux-gnu/libgmp.so.10 (0x00007fdfc3900000)
      libffi.so.6 =&gt; /usr/local/lib/ghc-8.2.1/rts/libffi.so.6 (0x00007fdfc36f3000)
      libm.so.6 =&gt; /lib/x86_64-linux-gnu/libm.so.6 (0x00007fdfc33ea000)
      librt.so.1 =&gt; /lib/x86_64-linux-gnu/librt.so.1 (0x00007fdfc31e2000)
      libdl.so.2 =&gt; /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fdfc2fde000)
      libpthread.so.0 =&gt; /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fdfc2dc1000)
      /lib64/ld-linux-x86-64.so.2 (0x00007fdfc5140000)
      libgcc_s.so.1 =&gt; /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fdfc2bab000)
  </code></pre>