Piccolo programma Haskell compilato con GHC in un enorme binario


127

Anche programmi Haskell banalmente piccoli si trasformano in giganteschi eseguibili.

Ho scritto un piccolo programma, che è stato compilato (con GHC) sul binario con le dimensioni che si estendono 7 MB!

Cosa può causare la compilazione di un piccolo programma Haskell nell'enorme binario?

Cosa posso fare per ridurlo?


2
Hai provato a toglierlo?
Fred Foo,

21
Esegui il programma stripsul file binario per rimuovere la tabella dei simboli.
Fred Foo,

1
@ tm1rbt: Esegui strip test. Questo comando rimuove alcune informazioni di debug dal programma e le riduce.
fuz,

8
Per inciso, i tuoi tipi di dati nella libreria matematica 3D dovrebbero essere più rigorosi per motivi di prestazioni: data M3 = M3 !V3 !V3 !V3e data V3 = V3 !Float !Float !Float. Compila con ghc -O2 -funbox-strict-fields.
Don Stewart,

8
Questo post è discusso su meta .
Patrick Hofman,

Risposte:


215

Vediamo cosa sta succedendo, prova

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

Dall'output si vede lddche GHC ha prodotto un eseguibile collegato dinamicamente, ma solo le librerie C sono collegate dinamicamente ! Tutte le librerie di Haskell sono copiate alla lettera.

A parte: dal momento che si tratta di un'app ad alta intensità grafica, mi piacerebbe sicuramente compilare ghc -O2

Ci sono due cose che puoi fare.

Simboli di stripping

Una soluzione semplice: togli il binario:

$ strip A
$ du -hs A
5.8M    A

Strip elimina i simboli dal file oggetto. Sono generalmente necessari solo per il debug.

Librerie Haskell collegate dinamicamente

Più recentemente, GHC ha ottenuto il supporto per il collegamento dinamico di entrambe le librerie C e Haskell . La maggior parte delle distribuzioni ora distribuisce una versione di GHC creata per supportare il collegamento dinamico delle librerie Haskell. Le librerie condivise Haskell possono essere condivise tra molti programmi Haskell, senza copiarle ogni volta nell'eseguibile.

Al momento della scrittura di Linux e Windows sono supportati.

Per consentire alle librerie Haskell di essere collegate dinamicamente, è necessario compilarle -dynamic, in questo modo:

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

Inoltre, tutte le librerie che si desidera condividere devono essere create con --enabled-shared:

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

E finirai con un eseguibile molto più piccolo, che ha risolto dinamicamente sia le dipendenze C che 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...

E, voilà!

$ du -hs A
124K    A

che puoi rimuovere per renderlo ancora più piccolo:

$ strip A
$ du -hs A
84K A

Un eseguibile weensy eensy, costruito da molti pezzi C e Haskell collegati 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 => ...

Un ultimo punto: anche su sistemi con solo collegamento statico, è possibile utilizzare -split-objs , per ottenere un file .o per funzione di livello superiore, che può ridurre ulteriormente la dimensione delle librerie collegate staticamente. Ha bisogno che GHC sia costruito con -split-objs, cosa che alcuni sistemi dimenticano di fare.


7
quando dovrebbe arrivare il collegamento dinamico per ghc sul mac?
Carter Tazio Schonwald,

1
... non cabal installrimuove il file binario installato per impostazione predefinita?
hvr,

1
farlo su Windows sembra rendere il file risultante non eseguibile, si lamenta della mancanza di libHSrts-ghc7.0.3.dll
is7s

3
questo binario funzionerà su altre macchine Linux dopo queste procedure?
ア レ ッ ク ス

1
Ciao OP dal 2011! Vengo dal futuro e posso dire che l'eseguibile pandoc su Ubuntu 16.04 è grasso di 50 MB e non cambierà in base a pacchetti.ubuntu.com/zesty/pandoc . Messaggio a sé e agli altri nel prossimo futuro: contattare il manutentore del pacchetto e chiedere se è enable-sharedstato preso in considerazione. launchpad.net/ubuntu/+source/pandoc/+bugs
Stéphane Gourichon

11

Haskell utilizza il collegamento statico per impostazione predefinita. Questo significa che tutti i collegamenti a OpenGL vengono copiati nel tuo programma. Poiché sono piuttosto grandi, il tuo programma viene gonfiato inutilmente. Puoi aggirare il problema utilizzando il collegamento dinamico, sebbene non sia abilitato per impostazione predefinita.


5
È possibile collegare dinamicamente le librerie per aggirare questo problema. Non so perché sia ​​importante ciò che è predefinito, il flag è abbastanza semplice.
Thomas M. DuBuisson,

4
Il problema è che "tutte le librerie che si desidera condividere devono essere compilate --enabled-shared", quindi se la piattaforma Haskell viene fornita con librerie costruite senza --enabled sharedè necessario ricompilare le librerie di base che possono essere abbastanza dolorose.
nponeccop,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.