Pequeno programa Haskell compilado com o GHC em um binário enorme

Mesmo os programas Haskell trivialmente pequenos se transformam em executáveis ​​gigantescos.

Eu escrevi um pequeno programa, que foi compilado (com GHC) para o binário com o tamanho estendendo 7 MB!

O que pode fazer com que até mesmo um pequeno programa Haskell seja compilado para o enorme binário?

O que posso fazer para reduzir isso?

Vamos ver o que está acontecendo, tente

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

Você vê na saída ldd que o GHC produziu um executável vinculado dinamicamente, mas somente as bibliotecas C são vinculadas dinamicamente ! Todas as bibliotecas do Haskell são copiadas em textualmente.

Além disso: como esse é um aplicativo com ghc -O2 charts, eu definitivamente iria compilar com o ghc -O2

Há duas coisas que você pode fazer.

Símbolos de decapagem

Uma solução fácil: tira o binário:

 $ strip A $ du -hs A 5.8MA 

Strip descarta símbolos do arquivo de object. Eles geralmente são necessários apenas para debugging.

Bibliotecas Haskell ligadas dinamicamente

Mais recentemente, o GHC ganhou suporte para vinculação dinâmica de bibliotecas C e Haskell . A maioria das distribuições agora distribui uma versão do GHC criada para suportar a vinculação dinâmica de bibliotecas Haskell. As bibliotecas compartilhadas do Haskell podem ser compartilhadas entre muitos programas do Haskell, sem serem copiadas para o executável a cada vez.

No momento da escrita, Linux e Windows são suportados.

Para permitir que as bibliotecas do Haskell sejam vinculadas dinamicamente, você precisa compilá-las com -dynamic , da seguinte forma:

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

Além disso, todas as bibliotecas que você deseja compartilhar devem ser construídas com --enabled-shared :

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

E você terminará com um executável muito menor, que tem as dependencies C e Haskell resolvidas dinamicamente.

 $ 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, Ao ) Linking A... 

E voilà!

 $ du -hs A 124K A 

que você pode tirar para ficar ainda menor:

 $ strip A $ du -hs A 84K A 

Um executável weensy eensy, construído a partir de muitas peças C e Haskell ligadas dinamicamente:

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

Um último ponto: mesmo em sistemas com apenas links estáticos, você pode usar -split-objs para obter um arquivo .o por function de nível superior, o que pode reduzir ainda mais o tamanho de bibliotecas vinculadas estaticamente. Ele precisa que o GHC seja construído com -split-objs, o que alguns sistemas se esquecem de fazer.

Haskell usa vinculação estática por padrão. Isto é, todas as ligações para o OpenGL são copiadas para o seu programa. Como eles são muito grandes, seu programa fica desnecessariamente inflado. Você pode contornar isso usando vinculação dinâmica, embora ela não esteja ativada por padrão.

    Intereting Posts