programar - El pequeño programa Haskell compilado con GHC en un enorme binario
instalar haskell en ubuntu (2)
Haskell usa enlaces estáticos por defecto. Es decir, todas las vinculaciones de OpenGL se copian en su programa. Como son bastante grandes, su programa se inflará innecesariamente. Puede solucionar esto utilizando enlaces dinámicos, aunque no está habilitado de manera predeterminada.
Incluso los programas de Haskell trivialmente pequeños se convierten en ejecutables gigantescos.
He escrito un pequeño programa, que fue compilado (con GHC) para el binario con un tamaño de 7 MB.
¿Qué puede hacer que incluso un pequeño programa Haskell se compile en el enorme binario?
¿Qué puedo hacer, si hay algo, para reducir esto?
Veamos qué está pasando, intente
$ 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)
...
Verá desde la salida de ldd
que GHC ha producido un ejecutable enlazado dinámicamente, ¡pero solo las bibliotecas C están dinámicamente vinculadas ! Todas las bibliotecas de Haskell están copiadas textualmente.
Aparte: dado que esta es una aplicación de gráficos intensivos, definitivamente compilaría con ghc -O2
Hay dos cosas que puedes hacer.
Despojar símbolos
Una solución fácil: quitar el binario:
$ strip A
$ du -hs A
5.8M A
Strip descarta símbolos del archivo objeto. Por lo general, solo son necesarios para la depuración.
Bibliotecas Haskell enlazadas dinámicamente
Más recientemente, GHC ha ganado soporte para el enlace dinámico de las bibliotecas C y Haskell . La mayoría de las distribuciones ahora distribuyen una versión de GHC construida para admitir el enlace dinámico de las bibliotecas de Haskell. Las bibliotecas compartidas de Haskell se pueden compartir entre muchos programas Haskell, sin copiarlos en el ejecutable cada vez.
En el momento de escribir Linux y Windows son compatibles.
Para permitir que las bibliotecas de Haskell se vinculen dinámicamente, debe compilarlas con -dynamic
, así:
$ ghc -O2 --make -dynamic A.hs
Además, cualquier biblioteca que desee compartir se debe --enabled-shared
con --enabled-shared
:
$ cabal install opengl --enable-shared --reinstall
$ cabal install glfw --enable-shared --reinstall
Y terminará con un ejecutable mucho más pequeño, que tiene las dependencias C y Haskell resueltas dinámicamente.
$ 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...
¡Y voilá!
$ du -hs A
124K A
que puedes desnudar para hacer aún más pequeño:
$ strip A
$ du -hs A
84K A
Un ejecutable eensy weensy, creado a partir de muchas piezas C y Haskell enlazadas dinámicamente:
$ 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 último punto: incluso en sistemas con enlaces estáticos solamente, puede usar -split-objs para obtener un archivo .o por función de nivel superior, lo que puede reducir aún más el tamaño de las bibliotecas vinculadas estáticamente. Necesita que GHC se genere con -split-objs on, algo que algunos sistemas olvidan hacer.