2012-10-04 59 views
13

可能重複:
Small Haskell program compiled with GHC into huge binary爲什麼Haskell/GHC可執行文件在文件大小上如此之大?

最近我注意到大Haskell的可執行文件是如何。下面的所有內容都是在GHC 7.4.1上編譯的,在Linux上是-O2

  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') 
    

    秒差距可以是更大的庫,但我只使用它的一個微小的子集,並且確實通過上述生成的優化核心代碼是比可執行顯着更小:

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

    因此,在程序中實際找到大量的Parsec並不是這種情況,這是我最初的假設。

爲什麼這麼龐大的可執行文件?有什麼我可以做的(除了動態鏈接)?

+0

@DanielWagner另一個問題當然是相關的,但即使使用了描述的技術,Hello World仍然很大。另外:爲什麼編譯時應該包含整個程序的小核心代碼變得如此之大? – David

+2

有一個相當大的運行時系統。 – augustss

+2

@大衛:核心不包含整個程序,除非一切都被內聯了,這是不太可能的。所以它會在Parsec中鏈接,除非你用'-split-objs'構建它(見[相關答案](http://stackoverflow.com/a/9198223/98117)),它必須鏈接到所有的。 – hammar

回答

3

我的理解是,如果您使用軟件包X中的單一功能,,整個軟件包會得到靜態鏈接。我不認爲GHC實際上按功能鏈接。 (除非你使用「拆分對象」破解,「這往往會讓連接器變得怪異」)。

但是,如果你是動態鏈接的,那就應該解決這個問題。所以我不知道這裏有什麼建議...

(我很確定我看到一篇博客文章,當動態鏈接第一次出現時,展示了Hello World編譯爲2KB二進制文件。顯然我找不到這個博客現在 ... grr。)

也考慮跨模塊優化。如果您正在編寫Parsec解析器,GHC很可能會將所有解析器定義內聯並將其簡化爲最高效的代碼。當然,你的幾行Haskell產生了50KB的Core。編譯爲機器碼時,它應該增大37倍嗎?我不知道。您也許可以嘗試查看下一步中生成的STG和Cmm代碼。 (對不起,我不記得編譯器標誌了我的頭頂部...)

+0

事實並非如此。這取決於系統。在大多數使用靜態鏈接的系統中,GHC使用「分割對象」,這樣每個函數就可以獲得一個對象。 –

+0

@DonStewart但是你需要在cabal配置文件中啓用split-objs來獲得用分割對象構建的cabal-installed庫,不是嗎? –

11

爲了有效地減少格拉斯哥Haskell編譯產生的,你必須專注於

  • 使用的可執行文件的大小動態鏈接與傳遞給ghc的-dynamic選項,所以模塊代碼不會通過使用共享(動態)庫而被捆綁到最終的可執行文件中。系統中這些GHC庫的共享版本的存在是必需的!
  • 刪除最終可執行文件的調試信息(f.E.通過
  • 去除未使用的模塊的進口GNU的的binutils條工具)(不期望在動態鏈接9 KIB和秒差距測試約28 KIB增益)

的簡單的Hello World示例具有最終尺寸(均64位Linux可執行文件),我發現它非常小,可以接受這種高級語言實現。

+0

如果我使用'-dynamic'鏈接,Hello World只有9 KiB。在Parsec案例中,我遇到了安裝動態版本的問題(cabal install parsec --enable-shared --reinstall'導致cabal抱怨我沒有「包'mtl-2.1.1'的dyn庫」 ,但那會提出另一個問題,無論如何,謝謝。 – David

相關問題