Есть ли простой ответ: почему GHC такой большой?
- OCaml: 2MB
- Python: 15 МБ
- SBCL: 9 МБ
- OpenJRE - 26MB
- GHC: 113MB
Не интересуется евангелизмом "Почему я не должен заботиться о размере, если Haskell - правильный инструмент"; это технический вопрос.
Есть ли простой ответ: почему GHC такой большой?
Не интересуется евангелизмом "Почему я не должен заботиться о размере, если Haskell - правильный инструмент"; это технический вопрос.
Это немного глупо. Каждая библиотека, которая поставляется с GHC, предоставляется не менее 4 ароматов:
Версия GHCi - это статическая версия, связанная вместе в одном файле .o
. В остальных трех версиях есть собственный набор файлов интерфейса (.hi
files). Профилированные версии, по-видимому, примерно в два раза превышают непрофилированные версии (что немного подозрительно, я должен посмотреть, почему это так).
Помните, что GHC - это библиотека, поэтому вы получаете 4 копии GHC. Не только это, но сам бинарный GHC статически связан, так что 5 копий GHC.
Недавно мы сделали так, чтобы GHCi мог использовать статические файлы .a
. Это позволит нам избавиться от одного из этих вкусов. В долгосрочной перспективе мы должны динамически связывать GHC, но это большее изменение, потому что это повлечет за собой динамическое связывание с дефолтом - в отличие от C, с GHC вам нужно решить, будете ли вы динамически связываться или нет. И нам нужно больше изменений (например, для Cabal и системы пакетов, среди прочего), прежде чем это действительно практично.
Возможно, мы должны сравнить яблоки с яблоками и апельсинами с апельсинами. JRE - это среда исполнения, а не набор разработчика. Мы можем сравнить: размер источника комплекта разработки, размер скомпилированного набора разработчика и скомпилированный размер минимального времени выполнения.
Исходный пакет OpenJDK 7 составляет 82 МБ (download.java.net/openjdk/jdk7) и исходный пакет GHC 7, который составляет 23 МБ (haskell.org/ghc/download_ghc_7_0_1). GHC здесь не большой. Размер Runtime: openjdk-6-jre-headless на Ubuntu - 77 МБ несжатого vs Haskell helloworld, статически связанный с его временем выполнения, который составляет < 1 МБ. GHC здесь невелика.
Где GHC большой, это размер скомпилированного набора для разработки:
Сам GHC занимает 270 МБ, а со всеми библиотеками и утилитами, которые объединяются, он принимает более 500 МБ. И да, это много, даже с базовыми библиотеками и менеджером сборки/менеджером зависимостей. Платформа разработки Java меньше.
GHC:
$ 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
Но это все еще более 100 МБ, а не 26 МБ при написании.
Тяжелые вещи в ghc6 и ghc6-prof:
$ 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
. Таким образом, ответ кажется статическим связующим и профилирующим версиями для каждой библиотеки.
Мое предположение - много-много статических ссылок. Каждая библиотека должна статически связывать свои зависимости, которые, в свою очередь, должны статически связывать их и так далее. И это все скомпилировано часто как с профилированием, так и без него, и даже без профилирования двоичные файлы не разделяются и поэтому содержат много информации отладчика.
Поскольку он объединяет gcc и набор библиотек, все статически связаны.
По крайней мере, в Windows.
Короткий ответ заключается в том, что, поскольку все исполняемые файлы статически связаны, у них может быть отладочная информация, а библиотеки включены в несколько копий. Об этом уже говорили другие комментаторы.
Динамическое связывание возможно и значительно уменьшит размер. Вот пример Hello.hs
:
main = putStrLn "Hello world"
Я строю с GHC 7.4.2 в Windows.
ghc --make -O2
дает Hello.exe
1105Ks
Запуск strip
на нем оставляет 630K
ghc --make -O2 -dynamic
дает 40K
Зачистка оставляет только 13K.
Взаимозависимости - это 5 библиотек DLL с общим размером 9,2 МБ без ограничений и 5,7 МБ.
Здесь разброс размера каталога в моем поле:
https://spreadsheets.google.com/ccc?key=0AveoXImmNnZ6dDlQeHY2MmxPcEYzYkpweEtDSS1fUlE&hl=en
Похоже, что самый большой каталог (123 МБ) - это двоичные файлы для компиляции самого компилятора. Документы взвешиваются с поразительным 65 МБ. Третье место - Cabal на 41 МБ.
Каталог bin имеет размер 33 Мбайт, и я думаю, что для сборки приложений Haskell требуется только часть этого набора.