Mały program Haskell skompilowany z GHC do ogromnych binarnych

Nawet trywialnie małe programy Haskella zamieniają się w gigantyczne pliki wykonywalne.

Napisałem mały program, który został skompilowany (z GHC) do pliku binarnego o rozmiarze sięgającym 7 MB!

Co może spowodować kompilację nawet małego programu Haskell do ogromnego pliku binarnego?

Co, jeśli już, mogę zrobić, aby to zmniejszyć?

Author: Danubian Sailor, 2011-05-24

2 answers

Zobaczmy, co się dzieje, spróbuj

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

Z wyjścia ldd widać, że GHC wyprodukowało dynamicznie połączony plik wykonywalny, ale tylko biblioteki C są dynamicznie połączone! Wszystkie biblioteki Haskella są kopiowane w dosłownym tłumaczeniu.

pomijając: ponieważ jest to aplikacja intensywnie graficznie, na pewno skompilowałbym z ghc -O2

Możesz zrobić dwie rzeczy.

Usuwanie symboli

Łatwe rozwiązanie: rozebrać binarny:

$ strip A
$ du -hs A
5.8M    A

Strip odrzuca symbole z pliku obiektowego. Są one zwykle potrzebne tylko do debugowania.

Dynamicznie połączone Biblioteki Haskell

[[12]}ostatnio GHC zyskało wsparcie dla dynamicznego łączenia zarówno bibliotek C, jak i Haskell . Większość dystrybucji dystrybuuje teraz wersję GHC zbudowaną w celu obsługi dynamicznego łączenia bibliotek Haskell. Współdzielone biblioteki Haskell mogą być współdzielone pomiędzy wiele programów Haskell, bez kopiowania ich do wykonywalny za każdym razem.

W czasie pisania Linux i Windows są obsługiwane.

Aby biblioteki Haskella mogły być dynamicznie połączone, musisz skompilować je za pomocą -dynamic, Tak:

 $ ghc -O2 --make -dynamic A.hs

Również wszelkie biblioteki, które chcesz udostępnić powinny być zbudowane z --enabled-shared:

 $ cabal install opengl --enable-shared --reinstall     
 $ cabal install glfw   --enable-shared --reinstall

I skończysz z dużo mniejszym programem wykonywalnym, który dynamicznie rozwiązuje zależności C i 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...
I voila!
$ du -hs A
124K    A

Które ty może paska, aby jeszcze mniejsze:

$ strip A
$ du -hs A
84K A

Plik wykonywalny eensy weensy, zbudowany z wielu dynamicznie połączonych elementów C i 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 => ...

Ostatnia uwaga: nawet w systemach z linkowaniem statycznym, możesz użyć-split-objs , aby je uzyskać .o pliku na funkcję najwyższego poziomu, co może dodatkowo zmniejszyć rozmiar statycznie połączonych bibliotek. Potrzebuje GHC do zbudowania z-split-objs na, co niektóre systemy zapominają zrobić.

 219
Author: Don Stewart,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:04

Haskell domyślnie używa linkowania statycznego. Oznacza to, że całe wiązania do OpenGL są kopiowane do twojego programu. Ponieważ są one dość duże, Twój program jest niepotrzebnie zawyżony. Możesz obejść to, używając dynamicznego łączenia, chociaż domyślnie nie jest ono włączone.

 11
Author: fuz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-24 19:50:00