用GHC编译成的小Haskell程序变成了巨大的二进制文件 [英] Small Haskell program compiled with GHC into huge binary

查看:187
本文介绍了用GHC编译成的小Haskell程序变成了巨大的二进制文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

即使是普通的小型Haskell程序也会变成巨大的可执行文件。

我写了一个小程序,它被编译成(与GHC一起)的大小为7 MB的二进制文件!

什么可能导致一个小的Haskell程序被编译为巨大的二进制文件?



,我可以做些什么来减少这种情况?

解决方案

让我们来看看发生了什么,试试

  $ du -hs A 
13M A

$文件A
A:ELF 64位LSB可执行文件,x86 -64,版本1(SYSV),
动态链接(使用共享库),用于GNU / Linux 2.6.27,没有剥离

$ ldd A
linux-vdso。 so.1 => (0x00007fff1b9ff000)
libXrandr.so.2 => /usr/lib/libXrandr.so.2(0x00007fb21f418000)
libX11.so.6 => /usr/lib/libX11.so.6(0x00007fb21f0d9000)
libGLU.so.1 => /usr/lib/libGLU.so.1(0x00007fb21ee6d000)
libGL.so.1 => /usr/lib/libGL.so.1(0x00007fb21ebf4000)
libgmp.so.10 => /usr/lib/libgmp.so.10(0x00007fb21e988000)
libm.so.6 => /lib/libm.so.6(0x00007fb21e706000)
...

你从GHC生成了动态链接可执行文件的 ldd 输出,但只有C库被动态链接!除此之外:由于这是一个图形密集型应用程序,所以我一定会编译 ghc -O2



您可以做两件事。

剥离符号



一个简单的解决方案:剥离二进制文件:

  $ strip A 
$ du -hs A
5.8MA

条从对象文件中丢弃符号。它们通常只用于调试。



动态链接的Haskell库

更多最近,GHC已获得动态链接的C和Haskell库。大多数发行版现在分发构建的GHC版本,以支持Haskell库的动态链接。共享的Haskell库可以在许多Haskell程序之间共享,而不必每次都将它们复制到可执行文件中。



支持Linux和Windows。

允许Haskell库动态链接,您需要使用 -dynamic 来编译它们,如下所示:

  $ ghc -O2 --make -dynamic A.hs 

另外,您希望共享的任何库应该使用 - enabled-shared 来构建:

  $ cabal install opengl --enable-shared --reinstall 
$ cabal install glfw --enable-shared --reinstall

最后你会得到一个小得多的可执行文件,它可以动态地解决C和Haskell依赖关系。

  $ ghc -O2 -dynamic A.hs 
编译S3DM.V3(S3DM / V3.hs,S3DM / V3.o)
[2/4]编译S3DM.M3(S3DM /M3.hs,S3DM/M3.o)
[4的4]编译S3DM.X4(S3DM / X4.hs,S3DM / X4.o)
[编译Main (A.hs,Ao)
链接A ...

而且,voilà!

  $ du -hs A 
124K A

您可以剥离得更小:

  $ strip A 
$ du -hs A
84K A

一个eensy weensy可执行文件,来自许多动态链接的C和Haskell作品:

  $ ldd A 
libHSOpenGL-2.4.0.1-ghc7.0.3。所以=> ...
libHSTensor-1.0.0.1-ghc7.0.3.so => ...
libHSStateVar-1.0.0.0-ghc7.0.3.so => ...
libHSObjectName-1.0.0.0-ghc7.0.3.so => ...
libHSGLURaw-1.1.0.0-ghc7.0.3.so => ...
libHSOpenGLRaw-1.1.0.1-ghc7.0.3.so => ...
libHSbase-4.3.1.0-ghc7.0.3.so => ...
libHSinteger-gmp-0.2.0.3-ghc7.0.3.so => ...
libHSghc-prim-0.2.0.0-ghc7.0.3.so => ...
libHSrts-ghc7.0.3.so => ...
libm.so.6 => /lib/libm.so.6(0x00007ffa4ffd6000)
librt.so.1 => /lib/librt.so.1(0x00007ffa4fdce000)
libdl.so.2 => /lib/libdl.so.2(0x00007ffa4fbca000)
libHSffi-ghc7.0.3.so => ...






最后一点:即使在系统只有静态链接,您可以使用-split-objs ,为每个顶级功能获取一个.o文件,它可以进一步减少静态链接库的大小。它需要使用-split-objs来构建GHC,而某些系统会忘记这样做。


Even trivially small Haskell programs turn into gigantic executables.

I've written a small program, that was compiled (with GHC) to the binary with the size extending 7 MB!

What can cause even a small Haskell program to be compiled to the huge binary?

What, if anything, can I do to reduce this?

解决方案

Let's see what's going on, try

  $ du -hs A
  13M   A

  $ file A
  A: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), 
     dynamically linked (uses shared libs), for GNU/Linux 2.6.27, not stripped

  $ ldd A
    linux-vdso.so.1 =>  (0x00007fff1b9ff000)
    libXrandr.so.2 => /usr/lib/libXrandr.so.2 (0x00007fb21f418000)
    libX11.so.6 => /usr/lib/libX11.so.6 (0x00007fb21f0d9000)
    libGLU.so.1 => /usr/lib/libGLU.so.1 (0x00007fb21ee6d000)
    libGL.so.1 => /usr/lib/libGL.so.1 (0x00007fb21ebf4000)
    libgmp.so.10 => /usr/lib/libgmp.so.10 (0x00007fb21e988000)
    libm.so.6 => /lib/libm.so.6 (0x00007fb21e706000)
    ...      

You see from the ldd output that GHC has produced a dynamically linked executable, but only the C libraries are dynamically linked! All the Haskell libraries are copied in verbatim.

Aside: since this is a graphics-intensive app, I'd definitely compile with ghc -O2

There's two things you can do.

Stripping symbols

An easy solution: strip the binary:

$ strip A
$ du -hs A
5.8M    A

Strip discards symbols from the object file. They are generally only needed for debugging.

Dynamically linked Haskell libraries

More recently, GHC has gained support for dynamic linking of both C and Haskell libraries. Most distros now distribute a version of GHC built to support dynamic linking of Haskell libraries. Shared Haskell libraries may be shared amongst many Haskell programs, without copying them into the executable each time.

At the time of writing Linux and Windows are supported.

To allow the Haskell libraries to be dynamically linked, you need to compile them with -dynamic, like so:

 $ ghc -O2 --make -dynamic A.hs

Also, any libraries you want to be shared should be built with --enabled-shared:

 $ cabal install opengl --enable-shared --reinstall     
 $ cabal install glfw   --enable-shared --reinstall

And you'll end up with a much smaller executable, that has both C and Haskell dependencies dynamically resolved.

$ ghc -O2 -dynamic A.hs                         
[1 of 4] Compiling S3DM.V3          ( S3DM/V3.hs, S3DM/V3.o )
[2 of 4] Compiling S3DM.M3          ( S3DM/M3.hs, S3DM/M3.o )
[3 of 4] Compiling S3DM.X4          ( S3DM/X4.hs, S3DM/X4.o )
[4 of 4] Compiling Main             ( A.hs, A.o )
Linking A...

And, voilà!

$ du -hs A
124K    A

which you can strip to make even smaller:

$ strip A
$ du -hs A
84K A

An eensy weensy executable, built up from many dynamically linked C and Haskell pieces:

$ ldd A
    libHSOpenGL-2.4.0.1-ghc7.0.3.so => ...
    libHSTensor-1.0.0.1-ghc7.0.3.so => ...
    libHSStateVar-1.0.0.0-ghc7.0.3.so =>...
    libHSObjectName-1.0.0.0-ghc7.0.3.so => ...
    libHSGLURaw-1.1.0.0-ghc7.0.3.so => ...
    libHSOpenGLRaw-1.1.0.1-ghc7.0.3.so => ...
    libHSbase-4.3.1.0-ghc7.0.3.so => ...
    libHSinteger-gmp-0.2.0.3-ghc7.0.3.so => ...
    libHSghc-prim-0.2.0.0-ghc7.0.3.so => ...
    libHSrts-ghc7.0.3.so => ...
    libm.so.6 => /lib/libm.so.6 (0x00007ffa4ffd6000)
    librt.so.1 => /lib/librt.so.1 (0x00007ffa4fdce000)
    libdl.so.2 => /lib/libdl.so.2 (0x00007ffa4fbca000)
    libHSffi-ghc7.0.3.so => ...


One final point: even on systems with static linking only, you can use -split-objs, to get one .o file per top level function, which can further reduce the size of statically linked libraries. It needs GHC to be built with -split-objs on, which some systems forget to do.

这篇关于用GHC编译成的小Haskell程序变成了巨大的二进制文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆