为什么 GHC 这么大?

有没有一个简单的答案: 为什么 GHC 这么大?

  • OCaml: 2MB
  • Python: 15MB
  • SBCL: 9 MB
  • OpenJRE-26MB
  • GHC: 113 MB

对“如果 Haskell 是正确的工具,为什么我不应该关心大小”这样的布道不感兴趣; 这是一个技术问题。

19082 次浏览

下面是我机器上的目录大小分类:

Https://spreadsheets.google.com/ccc?key=0aveoximmnnz6ddlqehy2mmxpceyzykpweetdss1fule&hl=en

看起来最大的目录(123MB)是用于编译编译器本身的二进制文件。这些文档的重量达到了惊人的65MB。第三名是41MB 的 Cabal。

Bin 目录是33MB,我认为构建 Haskell 应用程序在技术上只需要这个目录的一个子集。

我猜是很多很多静态链接。每个库都需要静态链接它的依赖项,而依赖项又需要静态链接它们的依赖项和其他依赖项。这些都是通过分析和不分析进行编译的,即使没有分析,二进制文件也不会被剥离,因此会保存大量的调试器信息。

因为它捆绑了 GCC和许多库,所有这些都是静态链接的。

至少在 Windows 上是这样。

也许我们应该把苹果比作苹果,把橘子比作橘子。JRE 是一个运行时,而不是一个开发工具包。我们可以比较: 开发工具包的源代码大小、已编译开发工具包的大小和最小运行时的已编译大小。

OpenJDk7源代码包是82MB ( download.java.net/OpenJDK/jdk7) ,而 GHC7源代码包是23MB ( haskell.org/GHC/download_ghc_7_0_1)。GHC 在这里并不大。运行时大小: Ubuntu 上的 openjdk-6-jre-headless 是77 MB 未压缩的,相对于 Haskell helloworld,静态链接到它的运行时,小于1 MB。GHC 在这里并不大。

GHC 最大的地方在于编译后的开发工具包的规模:

GHC disk usage

GHC 本身需要270MB,加上所有的库和实用程序,它需要超过500MB。是的,即使使用基本库和构建工具/依赖管理器,数量也很多。Java 开发平台更小。

返回文章页面

$ aptitude show ghc6 | grep Size
Uncompressed Size: 388M

具有依赖性的 OpenJDK:

$ aptitude show openjdk-6-jdk openjdk-6-jre openjdk-6-jre-headless ant maven2 ivy | grep Size
Uncompressed Size: 34.9M
Uncompressed Size: 905k
Uncompressed Size: 77.3M
Uncompressed Size: 1,585k
Uncompressed Size: 3,736k
Uncompressed Size: 991k

但它仍然超过100MB,而不是您编写时的26MB。

Ghc6和 ghc6教授的重量级物品是:

$ dpkg -L ghc6 | grep '\.a$' | xargs ls -1ks | sort -k 1 -n -r | head -3
57048 /usr/lib/ghc-6.12.1/ghc-6.12.1/libHSghc-6.12.1.a
22668 /usr/lib/ghc-6.12.1/Cabal-1.8.0.2/libHSCabal-1.8.0.2.a
21468 /usr/lib/ghc-6.12.1/base-4.2.0.0/libHSbase-4.2.0.0.a
$ dpkg -L ghc6-prof | grep '\.a$' | xargs ls -1ks | sort -k 1 -n -r | head -3
112596 /usr/lib/ghc-6.12.1/ghc-6.12.1/libHSghc-6.12.1_p.a
33536 /usr/lib/ghc-6.12.1/Cabal-1.8.0.2/libHSCabal-1.8.0.2_p.a
31724 /usr/lib/ghc-6.12.1/base-4.2.0.0/libHSbase-4.2.0.0_p.a

请注意 libHSghc-6.12.1_p.a有多大。因此,答案似乎是每个库的静态链接和概要版本。

这真的有点愚蠢。每一个与 GHC 一起提供的库都提供了不少于 四种口味的内容:

  • 静电干扰
  • 充满活力
  • 侧写
  • 高桥

GHCi 版本只是在单个 .o文件中链接在一起的静态版本。其他三个版本也都有自己的一组接口文件(.hi文件)。分析版本的大小似乎是未分析版本的两倍(这有点可疑,我应该研究一下为什么)。

记住这个 GHC 本身就是一个库所以你会得到4份 GHC。不仅如此,GHC 二进制文件本身是静态链接的,所以有5个 GHC 拷贝。

我们最近做了这样的 GHCi 可以使用静态 .a文件。这样我们就可以去掉其中一种味道。从长远来看,我们应该动态链接 GHC,但这是一个更大的变化,因为这将需要使动态链接的默认-不像在 C,与 GHC,你必须先决定是否要链接动态或不。我们需要更多的改变(例如 Cabal 和软件包系统等等) ,这才是真正可行的。

简短的回答是,这是因为所有的可执行文件都是静态链接的,可能包含调试信息,并且库包含在多个副本中。其他评论者已经说过了。

动态链接是可能的,并将大大减少大小。这里是一个例子 Hello.hs:

main = putStrLn "Hello world"

我在 Windows 上用 GHC 7.4.2构建。

ghc --make -O2给出 Hello.exe的1105K

运行 strip会有63万

ghc --make -O2 -dynamic出价4万

只剩下一万三了。

它的依赖关系是5个 dlls,总大小为9.2 MB 未剥离,5.7 MB 未剥离。