
Some time ago, I wrote to this list about making shared libraries with GHC, in such a way that the RTS was linked and ready to go. Recently, I've been looking a similar but, in a sense, opposite problem: linking Haskell executables with some of their non-Haskell dependencies, for distribution. I tried passing a few different sets of options to the linker through GHC, with -optl: -optl'-Wl,-r' -optl'-Wl,-r,-dy' -optl'-Wl,-static,-lffi,-lgmp,-dy' None of these had the desired effect. In the end, running GHC with -v and carefully editing the linker line produced the desired change (I have linked to and provided the diff below). The effect -optl seems to be to introduce options in the linker line just before -lHSrtsmain, which would seem to prevent one from linking libffi and libgmp differently. Is editing and storing away the linker script the best option at present for partially static linking? -- Jason Dusek () ascii ribbon campaign - against html e-mail /\ www.asciiribbon.org - against proprietary attachments https://github.com/solidsnack/arx/commit/90ec5efdb0e991344aa9a4ad29456d466e0... #@@ -122,10 +122,8 @@ # -lHSarray-0.3.0.2 \ # -lHSbase-4.3.1.0 \ # -lHSinteger-gmp-0.2.0.3 \ #- -lgmp \ # -lHSghc-prim-0.2.0.0 \ # -lHSrts \ #- -lffi \ # -lm \ # -lrt \ # -ldl \ #@@ -136,4 +134,7 @@ # -lgcc_s --no-as-needed \ # /usr/lib/gcc/x86_64-linux-gnu/4.6.1/crtend.o \ # /usr/lib/gcc/x86_64-linux-gnu/4.6.1/../../../x86_64-linux-gnu/crtn.o \ #+ -static \ #+ -lgmp \ #+ -lffi \

libgmp and libffi are external libraries not associated with Haskell, so I don't think -static (which is for Haskell libraries) applies to them. You'll have the same problem with any other sort of library of this type, like libdl and friends ;-) Edward Excerpts from Jason Dusek's message of Sat Nov 26 01:59:18 -0500 2011:
Some time ago, I wrote to this list about making shared libraries with GHC, in such a way that the RTS was linked and ready to go. Recently, I've been looking a similar but, in a sense, opposite problem: linking Haskell executables with some of their non-Haskell dependencies, for distribution.
I tried passing a few different sets of options to the linker through GHC, with -optl:
-optl'-Wl,-r' -optl'-Wl,-r,-dy' -optl'-Wl,-static,-lffi,-lgmp,-dy'
None of these had the desired effect. In the end, running GHC with -v and carefully editing the linker line produced the desired change (I have linked to and provided the diff below).
The effect -optl seems to be to introduce options in the linker line just before -lHSrtsmain, which would seem to prevent one from linking libffi and libgmp differently. Is editing and storing away the linker script the best option at present for partially static linking?
-- Jason Dusek () ascii ribbon campaign - against html e-mail /\ www.asciiribbon.org - against proprietary attachments
https://github.com/solidsnack/arx/commit/90ec5efdb0e991344aa9a4ad29456d466e0... #@@ -122,10 +122,8 @@ # -lHSarray-0.3.0.2 \ # -lHSbase-4.3.1.0 \ # -lHSinteger-gmp-0.2.0.3 \ #- -lgmp \ # -lHSghc-prim-0.2.0.0 \ # -lHSrts \ #- -lffi \ # -lm \ # -lrt \ # -ldl \ #@@ -136,4 +134,7 @@ # -lgcc_s --no-as-needed \ # /usr/lib/gcc/x86_64-linux-gnu/4.6.1/crtend.o \ # /usr/lib/gcc/x86_64-linux-gnu/4.6.1/../../../x86_64-linux-gnu/crtn.o \ #+ -static \ #+ -lgmp \ #+ -lffi \

Please note that when we build with in-tree GMP, we statically link it into libHSinteger-GMP.a. Also, again only with in-tree, we patch it first to use our allocator. Both of these things are to make life easier for users creating hybrid Haskell/C executables who need to use GMP from the C side, which is possible only by linking in a second copy of it.
The typical trick to force GHC to statically link a C library is to give the full path to the .a of it as one of the object files in the GHC invocation that does the final linking. This means you don't need any -l or -L flags pertaining to that library. Some libraries are very particular about the order you list them in when doing this, but I don't really understand the issues there. You usually will also have to chase dependencies by hand and list them in the same fashion.
Good luck!
Sent from my iPhone
On Dec 1, 2011, at 3:08 AM, "Edward Z. Yang"
libgmp and libffi are external libraries not associated with Haskell, so I don't think -static (which is for Haskell libraries) applies to them. You'll have the same problem with any other sort of library of this type, like libdl and friends ;-)
Edward
Excerpts from Jason Dusek's message of Sat Nov 26 01:59:18 -0500 2011:
Some time ago, I wrote to this list about making shared libraries with GHC, in such a way that the RTS was linked and ready to go. Recently, I've been looking a similar but, in a sense, opposite problem: linking Haskell executables with some of their non-Haskell dependencies, for distribution.
I tried passing a few different sets of options to the linker through GHC, with -optl:
-optl'-Wl,-r' -optl'-Wl,-r,-dy' -optl'-Wl,-static,-lffi,-lgmp,-dy'
None of these had the desired effect. In the end, running GHC with -v and carefully editing the linker line produced the desired change (I have linked to and provided the diff below).
The effect -optl seems to be to introduce options in the linker line just before -lHSrtsmain, which would seem to prevent one from linking libffi and libgmp differently. Is editing and storing away the linker script the best option at present for partially static linking?
-- Jason Dusek () ascii ribbon campaign - against html e-mail /\ www.asciiribbon.org - against proprietary attachments
https://github.com/solidsnack/arx/commit/90ec5efdb0e991344aa9a4ad29456d466e0... #@@ -122,10 +122,8 @@ # -lHSarray-0.3.0.2 \ # -lHSbase-4.3.1.0 \ # -lHSinteger-gmp-0.2.0.3 \ #- -lgmp \ # -lHSghc-prim-0.2.0.0 \ # -lHSrts \ #- -lffi \ # -lm \ # -lrt \ # -ldl \ #@@ -136,4 +134,7 @@ # -lgcc_s --no-as-needed \ # /usr/lib/gcc/x86_64-linux-gnu/4.6.1/crtend.o \ # /usr/lib/gcc/x86_64-linux-gnu/4.6.1/../../../x86_64-linux-gnu/crtn.o \ #+ -static \ #+ -lgmp \ #+ -lffi \
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

One thing I don't get is how, for GHC on Mac, this seems to work
with out any fiddling at all; but on Linux it's really quite
challenging.
--
Jason Dusek
() ascii ribbon campaign - against html e-mail
/\ www.asciiribbon.org - against proprietary attachments
2011/12/1 Irene Knapp
Please note that when we build with in-tree GMP, we statically link it into libHSinteger-GMP.a. Also, again only with in-tree, we patch it first to use our allocator. Both of these things are to make life easier for users creating hybrid Haskell/C executables who need to use GMP from the C side, which is possible only by linking in a second copy of it.
The typical trick to force GHC to statically link a C library is to give the full path to the .a of it as one of the object files in the GHC invocation that does the final linking. This means you don't need any -l or -L flags pertaining to that library. Some libraries are very particular about the order you list them in when doing this, but I don't really understand the issues there. You usually will also have to chase dependencies by hand and list them in the same fashion.
Good luck!
Sent from my iPhone
On Dec 1, 2011, at 3:08 AM, "Edward Z. Yang"
wrote: libgmp and libffi are external libraries not associated with Haskell, so I don't think -static (which is for Haskell libraries) applies to them. You'll have the same problem with any other sort of library of this type, like libdl and friends ;-)
Edward
Excerpts from Jason Dusek's message of Sat Nov 26 01:59:18 -0500 2011:
Some time ago, I wrote to this list about making shared libraries with GHC, in such a way that the RTS was linked and ready to go. Recently, I've been looking a similar but, in a sense, opposite problem: linking Haskell executables with some of their non-Haskell dependencies, for distribution.
I tried passing a few different sets of options to the linker through GHC, with -optl:
-optl'-Wl,-r' -optl'-Wl,-r,-dy' -optl'-Wl,-static,-lffi,-lgmp,-dy'
None of these had the desired effect. In the end, running GHC with -v and carefully editing the linker line produced the desired change (I have linked to and provided the diff below).
The effect -optl seems to be to introduce options in the linker line just before -lHSrtsmain, which would seem to prevent one from linking libffi and libgmp differently. Is editing and storing away the linker script the best option at present for partially static linking?
-- Jason Dusek () ascii ribbon campaign - against html e-mail /\ www.asciiribbon.org - against proprietary attachments
https://github.com/solidsnack/arx/commit/90ec5efdb0e991344aa9a4ad29456d466e0... #@@ -122,10 +122,8 @@ # -lHSarray-0.3.0.2 \ # -lHSbase-4.3.1.0 \ # -lHSinteger-gmp-0.2.0.3 \ #- -lgmp \ # -lHSghc-prim-0.2.0.0 \ # -lHSrts \ #- -lffi \ # -lm \ # -lrt \ # -ldl \ #@@ -136,4 +134,7 @@ # -lgcc_s --no-as-needed \ # /usr/lib/gcc/x86_64-linux-gnu/4.6.1/crtend.o \ # /usr/lib/gcc/x86_64-linux-gnu/4.6.1/../../../x86_64-linux-gnu/crtn.o \ #+ -static \ #+ -lgmp \ #+ -lffi \
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

2011/12/1 Irene Knapp
The typical trick to force GHC to statically link a C library is to give the full path to the .a of it as one of the object files in the GHC invocation that does the final linking. This means you don't need any -l or -L flags pertaining to that library. Some libraries are very particular about the order you list them in when doing this, but I don't really understand the issues there. You usually will also have to chase dependencies by hand and list them in the same fashion.
I recently tried using this method to create static binary; but I was not able to get it to work. I thought I would revive this old thread and see if anyone else has given it a shot. What I attempted was building a binary with only some C libraries statically linked, with this command line: # Build https://github.com/erudify/sssp on Ubunut 12.04 ghc -outputdir ./tmp -v --make -O2 sssp.hs -o sssp.ubuntu \ /usr/lib/x86_64-linux-gnu/libffi.a \ /usr/lib/x86_64-linux-gnu/libgmp.a \ /usr/lib/x86_64-linux-gnu/libz.a However, this really made no difference. Running `ldd' on the resulting binary reveals that libz and friends are still dynamically linked: ldd sssp.ubuntu linux-vdso.so.1 => (0x00007fff94253000) libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f0ddfdbb000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f0ddfb9e000) libgmp.so.10 => /usr/lib/x86_64-linux-gnu/libgmp.so.10 (0x00007f0ddf92f000) libffi.so.6 => /usr/lib/x86_64-linux-gnu/libffi.so.6 (0x00007f0ddf727000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f0ddf42d000) librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f0ddf224000) libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f0ddf020000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0ddec63000) /lib64/ld-linux-x86-64.so.2 (0x00007f0ddffdb000) There is always -optl-static which, nowadays, results in a truly static executable; but it leads to a lot of warnings, too. -- Jason Dusek pgp // solidsnack // C1EBC57DC55144F35460C8DF1FD4C6C1FED18A2B

Hi, I usually just copy those .a files (that should be linked statically) into `ghc --print-libdir`. HTH Christian Am 19.09.2012 13:06, schrieb Jason Dusek:
2011/12/1 Irene Knapp
: The typical trick to force GHC to statically link a C library is to give the full path to the .a of it as one of the object files in the GHC invocation that does the final linking. This means you don't need any -l or -L flags pertaining to that library. Some libraries are very particular about the order you list them in when doing this, but I don't really understand the issues there. You usually will also have to chase dependencies by hand and list them in the same fashion.
I recently tried using this method to create static binary; but I was not able to get it to work. I thought I would revive this old thread and see if anyone else has given it a shot.
What I attempted was building a binary with only some C libraries statically linked, with this command line:
# Build https://github.com/erudify/sssp on Ubunut 12.04 ghc -outputdir ./tmp -v --make -O2 sssp.hs -o sssp.ubuntu \ /usr/lib/x86_64-linux-gnu/libffi.a \ /usr/lib/x86_64-linux-gnu/libgmp.a \ /usr/lib/x86_64-linux-gnu/libz.a
However, this really made no difference. Running `ldd' on the resulting binary reveals that libz and friends are still dynamically linked:
ldd sssp.ubuntu linux-vdso.so.1 => (0x00007fff94253000) libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f0ddfdbb000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f0ddfb9e000) libgmp.so.10 => /usr/lib/x86_64-linux-gnu/libgmp.so.10 (0x00007f0ddf92f000) libffi.so.6 => /usr/lib/x86_64-linux-gnu/libffi.so.6 (0x00007f0ddf727000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f0ddf42d000) librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f0ddf224000) libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f0ddf020000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0ddec63000) /lib64/ld-linux-x86-64.so.2 (0x00007f0ddffdb000)
There is always -optl-static which, nowadays, results in a truly static executable; but it leads to a lot of warnings, too.
-- Jason Dusek pgp // solidsnack // C1EBC57DC55144F35460C8DF1FD4C6C1FED18A2B

2012/9/19 Christian Maeder
I usually just copy those .a files (that should be linked statically) into `ghc --print-libdir`.
Wow, it worked! But this isn't the sort of change I'd to a user's system that I'd like to encode in a Makefile... -- Jason Dusek pgp // solidsnack // C1EBC57DC55144F35460C8DF1FD4C6C1FED18A2B

On Wed, Sep 19, 2012 at 7:06 AM, Jason Dusek
What I attempted was building a binary with only some C libraries statically linked, with this command line:
# Build https://github.com/erudify/sssp on Ubunut 12.04 ghc -outputdir ./tmp -v --make -O2 sssp.hs -o sssp.ubuntu \ /usr/lib/x86_64-linux-gnu/libffi.a \ /usr/lib/x86_64-linux-gnu/libgmp.a \ /usr/lib/x86_64-linux-gnu/libz.a
However, this really made no difference. Running `ldd' on the resulting binary reveals that libz and friends are still dynamically linked:
On Linux you probably need -optl--whole-archive for this to do anything; alternately, you would need to get the final ld command line out of ghc and insert the above libraries into it *after* the package .a files. Putting them before the packages (including the GHC runtime) that need them, as will happen by default, will cause them to be ignored because they contain no required symbols *at that point* in the link. --whole-archive tells to blindly link the whole static archive in instead of ignoring it. -- brandon s allbery allbery.b@gmail.com wandering unix systems administrator (available) (412) 475-9364 vm/sms

2012/9/19 Brandon Allbery
On Wed, Sep 19, 2012 at 7:06 AM, Jason Dusek
wrote: What I attempted was building a binary with only some C libraries statically linked, with this command line:
# Build https://github.com/erudify/sssp on Ubunut 12.04 ghc -outputdir ./tmp -v --make -O2 sssp.hs -o sssp.ubuntu \ /usr/lib/x86_64-linux-gnu/libffi.a \ /usr/lib/x86_64-linux-gnu/libgmp.a \ /usr/lib/x86_64-linux-gnu/libz.a
However, this really made no difference. Running `ldd' on the resulting binary reveals that libz and friends are still dynamically linked:
On Linux you probably need -optl--whole-archive for this to do anything; alternately, you would need to get the final ld command line out of ghc and insert the above libraries into it *after* the package .a files.
Putting them before the packages (including the GHC runtime) that need them, as will happen by default, will cause them to be ignored because they contain no required symbols *at that point* in the link. --whole-archive tells to blindly link the whole static archive in instead of ignoring it.
Hi Brandon, This turned out to be the right ticket. The full command line is like this: ghc -outputdir ./tmp --make -O2 sssp.hs -o sssp.ubuntu \ -optl-Wl,--whole-archive \ /usr/lib/x86_64-linux-gnu/libffi.a \ /usr/lib/x86_64-linux-gnu/libgmp.a \ /usr/lib/x86_64-linux-gnu/libz.a \ -optl-Wl,--no-whole-archive Without the --no-whole-archive at the end, I get errors like: (.text+0x880): multiple definition of `__morestack_unblock_signals' /usr/lib/gcc/x86_64-linux-gnu/4.6/libgcc.a(generic-morestack.o):(.text+0x880): first defined here /usr/lib/gcc/x86_64-linux-gnu/4.6/libgcc.a(generic-morestack.o): In function `__morestack_allocate_stack_space': I am not sure why that happens -- libgcc.a wasn't explicitly asked for; but it stands to reason that one shouldn't specify --whole-archive for everything GHC links, just the archives of interest. Life is short and art is long. -- Jason Dusek pgp // solidsnack // C1EBC57DC55144F35460C8DF1FD4C6C1FED18A2B

On Mon, Sep 24, 2012 at 7:42 AM, Jason Dusek
I am not sure why that happens -- libgcc.a wasn't explicitly asked for; but it stands to reason that one shouldn't specify
No, but it's required for anything that uses the C compiler (which in this case would be glibc and any foreign libraries) --- it contains the implementation of things like (long long) support on 32-bit platforms, exception unwinding, and other compiler intrinsics. You may not use them but glibc does. -- brandon s allbery allbery.b@gmail.com wandering unix systems administrator (available) (412) 475-9364 vm/sms

Hi,
I made a mistake when I said this worked, earlier. My experiment
was run on a system where I had implemented Christian Maeder's
suggestion, by symlinking some static libs in to GHC's libdir.
Naturally, everything appeared to work.
It turns out we have to pass the libraries with -optl, to
prevent GHC from reordering them relative to the other linker
options we've passed.
ghc -outputdir ./tmp --make -O2 sssp.hs -o sssp.ubuntu \
-optl-Wl,--whole-archive \
-optl/usr/lib/x86_64-linux-gnu/libffi.a \
-optl/usr/lib/x86_64-linux-gnu/libgmp.a \
-optl/usr/lib/x86_64-linux-gnu/libz.a \
-optl-Wl,--no-whole-archive
The next great discovery in this area could be an automated, and
general, way of generating the static libraries list. At
present, what I have to do is:
1. compile the executable once with plain `ghc --make',
2. use `ldd' to find shared libraries used by this executable
and correlate these with debs use `dpkg -S',
3. throw away shared libraries that are part of the `libc'
Debian package,
4. find the corresponding `.a' files for each `.so', use find
and some Sed trickery and
5. construct the appropriate linker linker before compiling
everything again.
I could probably skip recompiling everything in step 5 and just
relink. I've made steps 2, 3 and 4 into a shell script that
could be easily adapted to other projects:
https://github.com/erudify/sssp/blob/master/ubuntu/util
I wonder how much of this we could legitimately ask GHC to do
for us. Statically linking every C dependency is unwise -- it's
not supposed to work to link libc and its immediate dependencies
-- and it does seem odd to ask that GHC have knowledge of this.
--
Jason Dusek
pgp // solidsnack // C1EBC57DC55144F35460C8DF1FD4C6C1FED18A2B
2012/9/24 Jason Dusek
2012/9/19 Brandon Allbery
: On Wed, Sep 19, 2012 at 7:06 AM, Jason Dusek
wrote: What I attempted was building a binary with only some C libraries statically linked, with this command line:
# Build https://github.com/erudify/sssp on Ubunut 12.04 ghc -outputdir ./tmp -v --make -O2 sssp.hs -o sssp.ubuntu \ /usr/lib/x86_64-linux-gnu/libffi.a \ /usr/lib/x86_64-linux-gnu/libgmp.a \ /usr/lib/x86_64-linux-gnu/libz.a
However, this really made no difference. Running `ldd' on the resulting binary reveals that libz and friends are still dynamically linked:
On Linux you probably need -optl--whole-archive for this to do anything; alternately, you would need to get the final ld command line out of ghc and insert the above libraries into it *after* the package .a files.
Putting them before the packages (including the GHC runtime) that need them, as will happen by default, will cause them to be ignored because they contain no required symbols *at that point* in the link. --whole-archive tells to blindly link the whole static archive in instead of ignoring it.
Hi Brandon,
This turned out to be the right ticket. The full command line is like this:
ghc -outputdir ./tmp --make -O2 sssp.hs -o sssp.ubuntu \ -optl-Wl,--whole-archive \ /usr/lib/x86_64-linux-gnu/libffi.a \ /usr/lib/x86_64-linux-gnu/libgmp.a \ /usr/lib/x86_64-linux-gnu/libz.a \ -optl-Wl,--no-whole-archive
Without the --no-whole-archive at the end, I get errors like:
(.text+0x880): multiple definition of `__morestack_unblock_signals' /usr/lib/gcc/x86_64-linux-gnu/4.6/libgcc.a(generic-morestack.o):(.text+0x880): first defined here /usr/lib/gcc/x86_64-linux-gnu/4.6/libgcc.a(generic-morestack.o): In function `__morestack_allocate_stack_space':
I am not sure why that happens -- libgcc.a wasn't explicitly asked for; but it stands to reason that one shouldn't specify --whole-archive for everything GHC links, just the archives of interest. Life is short and art is long.
-- Jason Dusek pgp // solidsnack // C1EBC57DC55144F35460C8DF1FD4C6C1FED18A2B
participants (5)
-
Brandon Allbery
-
Christian Maeder
-
Edward Z. Yang
-
Irene Knapp
-
Jason Dusek