19

重複の可能性:
GHC で巨大なバイナリにコンパイルされた小さな Haskell プログラム

最近、Haskell の実行可能ファイルがいかに大きいかに気付きました。以下はすべて GHC 7.4.1 と-O2Linux でコンパイルされたものです。

  1. Hello World ( main = putStrLn "Hello World!") は 800 KiB を超えています。それを実行stripすると、ファイルサイズが 500 KiB に減少します。コンパイルに追加-dynamicしてもあまり役に立たず、約 400 KiB のストリップされた実行可能ファイルが残ります。

  2. 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 が含まれているわけではありません。

実行可能ファイルのサイズが非常に大きいのはなぜですか? それについて何かできることはありますか (動的リンクを除く)?

4

2 に答える 2

14

Glasgow Haskell Compiler によって生成される実行可能ファイルのサイズを効果的に縮小するには、次の点に注意する必要があります。

  • -dynamicghc に渡されるオプションを使用した動的リンクの使用。これにより、共有 (動的) ライブラリを利用して、モジュール コードが最終的な実行可能ファイルにバンドルされなくなります。これらの GHC ライブラリの共有バージョンがシステムに存在することが必要です!
  • 最終的な実行可能ファイルのデバッグ情報を削除する (GNU の binutils の strip ツールによる fE)
  • 未使用のモジュールのインポートを削除する (動的リンクでの利益は期待しないでください)

単純な hello world の例では、最終的なサイズが 9 KiB で、Parsec テストは約 28 KiB (両方とも 64 ビット Linux 実行可能ファイル) であり、これは非常に小さく、このような高レベル言語の実装には受け入れられると思います。

于 2012-10-04T15:08:41.293 に答える
5

私の理解では、パッケージ X の単一の関数を使用すると、パッケージ全体が静的にリンクされます。GHC が実際に関数ごとにリンクするとは思いません。(「リンカを驚かせる傾向がある」「分割オブジェクト」ハックを使用しない限り。)

ただし、動的にリンクしている場合は、これで解決するはずです。だから、ここで何を提案すればいいのかわからない...

(動的リンクが最初に登場したときに、Hello World が 2KB のバイナリにコンパイルされていることを示すブログ記事を見たのは確かです。明らかに、このブログ記事は今は見つかりません... うーん。)

モジュール間の最適化も検討してください。Parsec パーサーを作成している場合、GHC はすべてのパーサー定義をインライン化し、最も効率的なコードに単純化する可能性があります。そして、案の定、Haskell の数行で 50KB のコアが生成されました。マシンコードにコンパイルすると、37 倍大きくなるはずですか? 知らない。次のステップで生成される STG および Cmm コードを確認してみてください。(申し訳ありませんが、頭のてっぺんからコンパイラフラグを思い出せません...)

于 2012-10-04T08:23:11.450 に答える