gpt4 book ai didi

haskell - 用 GHC 编译成巨大的二进制文件的小型 Haskell 程序

转载 作者:行者123 更新时间:2023-12-03 04:32:56 25 4
gpt4 key购买 nike

即使是很小的 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 输出中可以看到,GHC 已生成动态链接的可执行文件,但只有 C 库是动态链接的!所有 Haskell 库均逐字复制。

旁白:由于这是一个图形密集型应用程序,我肯定会使用 ghc -O2

进行编译

您可以做两件事。

剥离符号

一个简单的解决方案:剥离二进制文件:

$ strip A
$ du -hs A
5.8M A

Strip 丢弃目标文件中的符号。它们通常仅用于调试。

动态链接的 Haskell 库

最近,GHC 获得了 dynamic linking of both C and Haskell libraries 的支持。大多数发行版现在都分发一个 GHC 版本,该版本是为了支持 Haskell 库的动态链接而构建的。共享 Haskell 库可以在许多 Haskell 程序之间共享,而无需每次都将它们复制到可执行文件中。

在撰写本文时,支持 Linux 和 Windows。

要允许动态链接 Haskell 库,您需要使用 -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 => ...
<小时/>

最后一点:即使在仅具有静态链接的系统上,您也可以use -split-objs ,为每个顶级函数获取一个.o文件,这可以进一步减少静态链接库的大小。它需要使用 -split-objs 来构建 GHC,但有些系统忘记了这样做。

关于haskell - 用 GHC 编译成巨大的二进制文件的小型 Haskell 程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6115459/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com