[英]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.