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)
...
Na podstawie danych ldd
wyjściowych widać, że GHC utworzył dynamicznie połączony plik wykonywalny, ale tylko biblioteki C są połączone dynamicznie ! Wszystkie biblioteki Haskell są kopiowane dosłownie.
Poza tym: ponieważ jest to aplikacja intensywnie graficzna, zdecydowanie bym się z nią skompilował ghc -O2
Możesz zrobić dwie rzeczy.
Usuwanie symboli
Proste rozwiązanie: usuń plik binarny:
$ strip A
$ du -hs A
5.8M A
Strip usuwa symbole z pliku obiektowego. Zwykle są potrzebne tylko do debugowania.
Dynamicznie połączone biblioteki Haskell
Niedawno GHC zyskało obsługę dynamicznego łączenia bibliotek C i Haskell . Większość dystrybucji dystrybuuje teraz wersję GHC zbudowaną do obsługi dynamicznego łączenia bibliotek Haskell. Współdzielone biblioteki Haskell mogą być współużytkowane przez wiele programów Haskell, bez konieczności kopiowania ich za każdym razem do pliku wykonywalnego.
W chwili pisania tego tekstu obsługiwane są systemy Linux i Windows.
Aby umożliwić dynamiczne łączenie bibliotek Haskell, musisz je skompilować za pomocą -dynamic
, na przykład:
$ ghc -O2 --make -dynamic A.hs
Ponadto wszystkie biblioteki, które chcesz udostępniać, powinny być zbudowane z --enabled-shared
:
$ cabal install opengl --enable-shared --reinstall
$ cabal install glfw --enable-shared --reinstall
Otrzymasz znacznie mniejszy plik wykonywalny, który ma dynamicznie rozwiązane zależności zarówno C, jak 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 voilà!
$ du -hs A
124K A
które możesz rozebrać na jeszcze mniejsze:
$ strip A
$ du -hs A
84K A
Eensy weensy plik wykonywalny, zbudowany z wielu dynamicznie połączonych fragmentó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 => ...
I ostatnia uwaga: nawet w systemach z łączeniem statycznym można użyć opcji -split-objs , aby uzyskać jeden plik .o na funkcję najwyższego poziomu, co może dodatkowo zmniejszyć rozmiar bibliotek połączonych statycznie. Wymaga zbudowania GHC z -split-objs, o czym niektóre systemy zapominają.