20

Using GHC version 7.4.2 with flags like -O3, I still get huge executable produced. I understand that GHC does static linking, and dependencies of the binary looks like:

    linux-vdso.so.1 (0x00007fff49bff000)
    libpcre.so.1 => /usr/lib/libpcre.so.1 (0x00007fe658d6c000)
    librt.so.1 => /usr/lib/librt.so.1 (0x00007fe658b64000)
    libutil.so.1 => /usr/lib/libutil.so.1 (0x00007fe658961000)
    libdl.so.2 => /usr/lib/libdl.so.2 (0x00007fe65875d000)
    libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007fe658541000)
    libcurl.so.4 => /usr/lib/libcurl.so.4 (0x00007fe6582e3000)
    libgmp.so.10 => /usr/lib/libgmp.so.10 (0x00007fe658074000)
    libm.so.6 => /usr/lib/libm.so.6 (0x00007fe657d7a000)
    libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007fe657b65000)
    libc.so.6 => /usr/lib/libc.so.6 (0x00007fe6577be000)
    /lib/ld-linux-x86-64.so.2 (0x00007fe658fca000)
    libssh2.so.1 => /usr/lib/libssh2.so.1 (0x00007fe657595000)
    libssl.so.1.0.0 => /usr/lib/libssl.so.1.0.0 (0x00007fe65732b000)
    libcrypto.so.1.0.0 => /usr/lib/libcrypto.so.1.0.0 (0x00007fe656f22000)
    libz.so.1 => /usr/lib/libz.so.1 (0x00007fe656d0c000

so far it looks quite good, however inside the binary I can see the lines:

GHCi runtime linker: fatal error: I found a duplicate definition for symbol
* Specifying the same object file twice on the GHCi command line 

  ....BlockedIndefinitelyOnMVar.......BlockedIndefinitelyOnSTM........AsyncException..base....GHC.IO.FD.......FD......GHC.IO.FD.setSize.

and actually a lot of text lines, including names of my functions, functions defined in other modules and so on. The question is - is it possible to remove those texts, and can GHC eliminate unused code from external libraries?

jdevelop
  • 12,176
  • 10
  • 56
  • 112
  • 5
    you should have a look at question:http://stackoverflow.com/questions/6115459/small-haskell-program-compiled-with-ghc-into-huge-binary?lq=1 - I've flagged your question as a possible duplicate of it. – epsilonhalbe Sep 09 '12 at 09:11
  • it's not really true - I stripped the file and didn't get any difference with unstripped version. So I'm still looking for the way to reduce size of binary. – jdevelop Sep 09 '12 at 09:41
  • 1
    and did you try dynamic linking - as you see in @donstewart's answer this made the binary way more compact, than just stripping the symbols. But I am far from an expert. – epsilonhalbe Sep 09 '12 at 09:48
  • I don't want dynamic linking, I want it to be linked statically. But I don't need either to see names of my functions inside source code, as well as names of functions from another modules. – jdevelop Sep 09 '12 at 09:52
  • 1
    I believe that (as of 7.4.1) -O3 is doing the same -O2 – Vladimir Still Sep 09 '12 at 11:29
  • 1
    There is actually ticket for -O3 http://hackage.haskell.org/trac/ghc/ticket/1371 it doesn't seem to be very active though – Vladimir Still Sep 09 '12 at 11:35
  • Have you built the libraries the binary depends on with `-split-objs`? – Daniel Fischer Sep 09 '12 at 14:55
  • @Mystic nope, it doesn't – jdevelop Sep 09 '12 at 14:57
  • @DanielFischer nope, should I do that recursively for all libs? – jdevelop Sep 09 '12 at 14:57
  • Probably. If you install stuff from your distribution, and that doesn't build the libraries with `-split-objs`, you have to decide whether to drop the distribution packages and build yourself or not. If you're already building yourself, enable `-split-objs` in the cabal config and rebuild your installed libraries (what comes with GHC is already built that way). Then instead of linking in the entire module, only what you need is linked, that can potentially reduce the binary size significantly. But if you're using almost everything or the libraries are already small, not so much. – Daniel Fischer Sep 09 '12 at 15:28
  • @DanielFischer okay, I'll try that. But what about names of my functions? Are they really needed in the executable file? – jdevelop Sep 10 '12 at 07:13
  • Why was this closed as a duplicate? The questions are nothing a like as far as I can tell. This one was about if it was possible to remove unused code from being linked in. Since he didn't want dynamic linking and stripping had little to no effect for him (the exact two solutions proposed in the "duplicate" – Phyx Sep 11 '12 at 14:26
  • @Phyx right, I don't think it's duplicate – jdevelop Sep 12 '12 at 16:52

2 Answers2

2

If you use the gcc backend, you can pass the -optc-Os flag to ghc to optimize the output for size. Perhaps you can reduce your binary by some bytes. But I would also suggest using dynamic linking as suggested before, with all it's pros and cons.

UPDATE:

Compress your executable with UPX http://en.wikipedia.org/wiki/UPX or gzexe to reduce the size of the executable.

  • using dynamic linking is like moving size from one file to another. What if I want to ship my application to end users? I will need to package all those DLLs as well, so static linking works great. However the size of executable is still makeing me sad. – jdevelop Nov 09 '12 at 12:44
  • Dynamic linking pays off, if you can assume your customer has the dll already installed, otherwise you deliver the dll with your application and link your own version (the windows approach) which has the same space implication as static linking. What's exactly your concern? Memory usage when the application is running or the diskspace of the deliverable? If it is the latter, you can compress your executable with `UPX` (http://en.wikipedia.org/wiki/UPX) or `gzexe`. – Falco Hirschenberger Nov 09 '12 at 12:51
  • actually I don't like the fact that executable has a lot of weird textual data inside it. – jdevelop Nov 09 '12 at 13:03
  • 5
    Almost every exe has textual data inside, pack it with UPX and it gets reduced to 25% of the original size and only contains this ASCII string: `$Info: This file is packed with the UPX executable packer http://upx.sf.net $ $Id: UPX 3.08 Copyright (C) 1996-2011 the UPX Team. All Rights Reserved. $` – Falco Hirschenberger Nov 09 '12 at 13:07
2

LLVM can do more optimization at link time than most other compilers. Maybe GHC has an LLVM backend and you can recompile and link some/all of your dependencies with -O4.

Andrew Wagner
  • 22,677
  • 21
  • 86
  • 100