Program Haskell kecil dikompilasi dengan GHC menjadi biner besar

127

Bahkan program Haskell yang sangat kecil berubah menjadi executable raksasa.

Saya telah menulis sebuah program kecil, yang dikompilasi (dengan GHC) ke biner dengan ukuran 7 MB!

Apa yang dapat menyebabkan program Haskell kecil untuk dikompilasi ke biner besar?

Apa, jika ada, yang bisa saya lakukan untuk mengurangi ini?

Pelaut Danubia
sumber
2
Apakah Anda sudah mencoba melepaskannya?
Fred Foo
21
Jalankan program strippada biner untuk menghapus tabel simbol.
Fred Foo
1
@ tm1rbt: Jalankan strip test. Perintah ini menghapus beberapa informasi debug dari program dan membuatnya lebih kecil.
fuz
8
Sebagai tambahan, tipe data Anda di perpustakaan matematika 3D harus lebih ketat karena alasan kinerja: data M3 = M3 !V3 !V3 !V3dan data V3 = V3 !Float !Float !Float. Kompilasi dengan ghc -O2 -funbox-strict-fields.
Don Stewart
8
Posting ini dibahas pada meta .
Patrick Hofman

Jawaban:

215

Mari kita lihat apa yang terjadi, coba

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

Anda melihat dari lddoutput bahwa GHC telah menghasilkan executable yang terhubung secara dinamis, tetapi hanya perpustakaan C yang terhubung secara dinamis ! Semua perpustakaan Haskell disalin dalam kata demi kata.

Selain itu: karena ini adalah aplikasi intensif grafis, saya pasti akan mengompilasinya ghc -O2

Ada dua hal yang bisa Anda lakukan.

Simbol pengupasan

Solusi mudah: lepaskan biner:

$ strip A
$ du -hs A
5.8M    A

Lepaskan simbol dari file objek. Biasanya hanya diperlukan untuk debugging.

Pustaka Haskell yang ditautkan secara dinamis

Baru-baru ini, GHC telah mendapatkan dukungan untuk menghubungkan dinamis kedua perpustakaan C dan Haskell . Kebanyakan distro sekarang mendistribusikan versi GHC yang dibangun untuk mendukung tautan dinamis perpustakaan Haskell. Pustaka Haskell bersama dapat dibagikan di antara banyak program Haskell, tanpa menyalinnya ke dalam executable setiap kali.

Pada saat penulisan Linux dan Windows didukung.

Agar perpustakaan Haskell terhubung secara dinamis, Anda harus mengompilasinya -dynamic, seperti:

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

Juga, semua perpustakaan yang ingin Anda bagikan harus dibangun dengan --enabled-shared:

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

Dan Anda akan berakhir dengan executable yang jauh lebih kecil, yang memiliki dependensi C dan Haskell yang diselesaikan secara dinamis.

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

Dan, voila!

$ du -hs A
124K    A

yang bisa Anda cabut menjadi lebih kecil:

$ strip A
$ du -hs A
84K A

Eksekusi weensy eensy, dibangun dari banyak potongan C dan Haskell yang terhubung secara dinamis:

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

Satu poin terakhir: bahkan pada sistem dengan tautan statis saja, Anda dapat menggunakan -sit-objs , untuk mendapatkan satu file .o per fungsi tingkat atas, yang selanjutnya dapat mengurangi ukuran perpustakaan yang terhubung secara statis. Perlu GHC dibangun dengan -sit-objs, yang lupa dilakukan oleh beberapa sistem.

Don Stewart
sumber
7
kapan tautan dinamis akan tiba untuk ghc di mac?
Carter Tazio Schonwald
1
... tidak cabal installmenghapus biner yang diinstal secara default?
hvr
1
melakukannya pada Windows tampaknya membuat file yang dihasilkan tidak dapat dijalankan, ia mengeluh tentang hilang libHSrts-ghc7.0.3.dll
is7s
3
akankah biner ini bekerja pada mesin Linux lain setelah prosedur ini?
ア レ ッ ク ス
1
Hai OP dari 2011! Saya dari masa depan dan bisa mengatakan bahwa Pandoc dieksekusi pada Ubuntu 16.04 adalah lemak 50MB dan itu tidak akan berubah berdasarkan packages.ubuntu.com/zesty/pandoc . Pesan untuk diri sendiri dan orang lain dalam waktu dekat: hubungi pengelola paket dan tanyakan apakah enable-sharedtelah dipertimbangkan. launchpad.net/ubuntu/+source/pandoc/+bugs
Stéphane Gourichon
11

Haskell menggunakan tautan statis secara default. Ini, seluruh ikatan OpenGL disalin ke program Anda. Karena mereka cukup besar, program Anda akan meningkat tidak perlu. Anda dapat mengatasi ini dengan menggunakan tautan dinamis, meskipun tidak diaktifkan secara default.

fuz
sumber
5
Anda dapat menautkan perpustakaan secara dinamis untuk mengatasi hal ini. Tidak yakin mengapa itu penting apa yang default, bendera cukup sederhana.
Thomas M. DuBuisson
4
Masalahnya adalah bahwa "semua perpustakaan yang ingin Anda bagikan harus dibangun bersama --enabled-shared" jadi jika Platform Haskell Anda dilengkapi dengan perpustakaan yang dibangun tanpa --enabled sharedAnda harus mengkompilasi ulang perpustakaan dasar yang bisa sangat menyakitkan.
nponeccop