Nawet banalnie małe programy Haskell zamieniają się w gigantyczne pliki wykonywalne.
Napisałem mały program, który został skompilowany (z GHC) do pliku binarnego o rozmiarze do 7 MB!
Co może spowodować, że nawet mały program Haskell zostanie skompilowany do ogromnego pliku binarnego?
Co, jeśli cokolwiek, mogę zrobić, aby to zmniejszyć?
strip
na pliku binarnym, aby usunąć tablicę symboli.strip test
. To polecenie usuwa niektóre informacje debugowania z programu i zmniejsza je.data M3 = M3 !V3 !V3 !V3
idata V3 = V3 !Float !Float !Float
. Skompiluj zghc -O2 -funbox-strict-fields
.Odpowiedzi:
Zobaczmy, co się dzieje, spróbuj
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 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:Ponadto wszystkie biblioteki, które chcesz udostępniać, powinny być zbudowane z
--enabled-shared
:Otrzymasz znacznie mniejszy plik wykonywalny, który ma dynamicznie rozwiązane zależności zarówno C, jak i Haskell.
I voilà!
które możesz rozebrać na jeszcze mniejsze:
Eensy weensy plik wykonywalny, zbudowany z wielu dynamicznie połączonych fragmentów C i Haskell:
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ą.
źródło
cabal install
domyślnie zainstalowanego pliku binarnego?enable-shared
została uwzględniona. launchpad.net/ubuntu/+source/pandoc/+bugsHaskell domyślnie używa statycznego łączenia. Oznacza to, że całe powiązania z OpenGL są kopiowane do twojego programu. Ponieważ są one dość duże, program niepotrzebnie się zawyża. Możesz obejść ten problem, używając dynamicznego łączenia, chociaż nie jest ono domyślnie włączone.
źródło
--enabled-shared
”, więc jeśli Twoja platforma Haskell zawiera biblioteki zbudowane bez--enabled shared
konieczności ponownej kompilacji bibliotek podstawowych, co może być dość bolesne.