簡體   English   中英

小 Haskell 程序用 GHC 編譯成巨大的二進制文件

[英]Small Haskell program compiled with GHC into huge binary

即使是很小的 Haskell 程序也會變成巨大的可執行文件。

我編寫了一個小程序,它被編譯(使用 GHC)為大小擴展為 7 MB 的二進制文件!

是什么導致即使是小的 Haskell 程序也被編譯成巨大的二進制文件?

如果有的話,我能做些什么來減少這種情況?

讓我們看看發生了什么,試試

  $ 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)
    ...      

您從ldd output 看到 GHC 已經生成了動態鏈接的可執行文件,但只有 C 庫是動態鏈接的 所有 Haskell 庫都逐字復制。

另外:因為這是一個圖形密集型應用程序,我肯定會用ghc -O2編譯

你可以做兩件事。

剝離符號

一個簡單的解決方案:剝離二進制文件:

$ strip A
$ du -hs A
5.8M    A

Strip 丟棄 object 文件中的符號。 它們通常僅用於調試。

動態鏈接 Haskell 庫

最近,GHC 獲得了對 C 和 Haskell 庫的動態鏈接的支持。 大多數發行版現在都發布了一個 GHC 版本,它支持 Haskell 庫的動態鏈接。 共享的 Haskell 庫可以在許多 Haskell 程序之間共享,而無需每次都將它們復制到可執行文件中。

在撰寫本文時,支持 Linux 和 Windows。

要允許動態鏈接-dynamic庫,您需要使用 -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                         
[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...

而且,瞧!

$ du -hs A
124K    A

您可以將其剝離以使其更小:

$ strip A
$ du -hs A
84K A

一個小巧的可執行文件,由許多動態鏈接的 C 和 Haskell 片段組成:

$ 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 => ...

最后一點:即使在僅使用 static 鏈接的系統上,您也可以使用 -split- objs 為每個頂級 function 獲取一個.o 文件,這可以進一步減小靜態鏈接庫的大小。 它需要使用 -split-objs 構建 GHC,而某些系統忘記了這樣做。

Haskell 默認使用 static 鏈接。 也就是說,與 OpenGL 的整個綁定都將復制到您的程序中。 由於它們很大,您的程序會不必要地膨脹。 您可以通過使用動態鏈接來解決此問題,盡管默認情況下未啟用它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM