为什么Haskell / GHC可执行文件在文件大小上如此之大?

可能重复:
用GHC编译成的小Haskell程序变成了巨大的二进制文件

最近我注意到Haskell可执行文件的大小。 下面的所有内容都是在GHC 7.4.1上用Linux上的-O2编译的。

  • Hello World( main = putStrLn "Hello World!" )超过800 KiB。 在其上运行strip可将文件大小减少到500 KiB; 即使在编译时添加-dynamic编译也没有什么帮助,只剩下大约400 KiB的可执行文件。

  • 编译一个涉及Parsec的非常原始的例子会产生一个1.7 MiB文件。

    -- File: test.hs
    import qualified Text.ParserCombinators.Parsec as P
    import Data.Either (either)
    
    -- Parses a string of type "x y" to the tuple (x,y).
    testParser :: P.Parser (Char, Char)
    testParser = do
        a <- P.anyChar
        P.char ' '
        b <- P.anyChar
        return (a, b)
    
    -- Parse, print result.
    str = "1 2"
    main = print $ either (error . show) id . P.parse    testParser "" $ str
    -- Output: ('1','2')
    

    Parsec可能是一个更大的库,但我只使用它的一小部分,事实上上面生成的优化核心代码比可执行文件要小得多:

    $ ghc -O2 -ddump-simpl -fforce-recomp test.hs | wc -c
    49190 (bytes)
    

    因此,在程序中实际找到大量的Parsec并不是这种情况,这是我最初的假设。

  • 为什么这样庞大的可执行文件? 有什么我可以做的(除了动态链接)?


    为了有效减小格拉斯哥Haskell编译器生成的可执行文件的大小,您必须关注

  • 使用传递给ghc的-dynamic选项的动态链接,所以模块代码不会通过使用共享(动态)库而被捆绑到最终的可执行文件中。 系统中这些GHC库的共享版本的存在是必需的!
  • 删除最终可执行文件的调试信息(通过GNU binutils的strip工具)
  • 移除未使用模块的进口(不要期望在动态链接上获得收益)
  • 简单的hello world示例的最终大小为9 KiB,Parsec测试的大小为28 KiB(均为64位Linux可执行文件),我发现它非常小并且可以用于这样的高级语言实现。


    我的理解是,如果您使用包X中的单个函数,整个包会静态链接。我不认为GHC实际上按函数链接。 (除非你使用“拆分对象”破解,“这往往会让连接器失控”)。

    但是,如果你动态链接,那应该解决这个问题。 所以我不确定在这里提出什么建议...

    (我敢肯定,当动态链接第一次出现时,我看到了一篇博客文章,展示了Hello World编译为2KB二进制文件。显然,我现在找不到这篇博客文章...... grr。)

    考虑跨模块优化。 如果您正在编写Parsec解析器,GHC很可能会将所有解析器定义内联并将其简化为最高效的代码。 当然,你的几行Haskell产生了50KB的Core。 编译为机器码时,它应该增大37倍吗? 我不知道。 您也许可以尝试查看下一步中生成的STG和Cmm代码。 (对不起,我不记得编译器标志关闭了我的头顶...)

    链接地址: http://www.djcxy.com/p/33285.html

    上一篇: Why are Haskell/GHC executables so large in filesize?

    下一篇: How to compile Haskell to a static library?