Chương trình Haskell nhỏ được biên dịch với GHC thành nhị phân lớn


127

Ngay cả các chương trình Haskell nhỏ tầm thường cũng biến thành các tệp thực thi khổng lồ.

Tôi đã viết một chương trình nhỏ, được biên dịch (với GHC) thành nhị phân với kích thước mở rộng 7 MB!

Điều gì có thể khiến ngay cả một chương trình Haskell nhỏ được biên dịch thành nhị phân lớn?

Tôi có thể làm gì để giảm bớt điều này?


2
Bạn đã thử chỉ tước nó?
Fred Foo

21
Chạy chương trình striptrên nhị phân để loại bỏ bảng ký hiệu.
Fred Foo

1
@ tm1rbt: Chạy strip test. Lệnh này loại bỏ một số thông tin gỡ lỗi khỏi chương trình và làm cho nó nhỏ hơn.
fuz

8
Vì các loại dữ liệu của bạn trong thư viện toán học 3D nên nghiêm ngặt hơn vì lý do hiệu suất: data M3 = M3 !V3 !V3 !V3data V3 = V3 !Float !Float !Float. Biên dịch với ghc -O2 -funbox-strict-fields.
Don Stewart

8
Bài này được thảo luận về meta .
Patrick Hofman

Câu trả lời:


215

Hãy xem những gì đang xảy ra, hãy thử

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

Bạn thấy từ lddđầu ra mà GHC đã tạo ra một tệp thực thi được liên kết động, nhưng chỉ các thư viện C được liên kết động ! Tất cả các thư viện Haskell được sao chép nguyên văn.

Ngoài ra: vì đây là một ứng dụng chuyên sâu về đồ họa, tôi chắc chắn sẽ biên dịch với ghc -O2

Có hai điều bạn có thể làm.

Tước biểu tượng

Một giải pháp dễ dàng: tước nhị phân:

$ strip A
$ du -hs A
5.8M    A

Dải loại bỏ các ký hiệu từ tệp đối tượng. Chúng thường chỉ cần để gỡ lỗi.

Các thư viện Haskell được liên kết động

Gần đây, GHC đã đạt được sự hỗ trợ cho liên kết động của cả thư viện C và Haskell . Hầu hết các bản phân phối hiện phân phối một phiên bản GHC được xây dựng để hỗ trợ liên kết động của các thư viện Haskell. Các thư viện Haskell được chia sẻ có thể được chia sẻ giữa nhiều chương trình Haskell mà không cần sao chép chúng vào tệp thực thi mỗi lần.

Tại thời điểm viết Linux và Windows được hỗ trợ.

Để cho phép các thư viện Haskell được liên kết động, bạn cần biên dịch chúng với -dynamic, như vậy:

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

Ngoài ra, bất kỳ thư viện nào bạn muốn được chia sẻ nên được xây dựng với --enabled-shared:

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

Và bạn sẽ kết thúc với một thực thi nhỏ hơn nhiều, có cả hai phụ thuộc C và Haskell được giải quyết một cách linh hoạt.

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

Và Voila!

$ du -hs A
124K    A

mà bạn có thể tước để làm cho nhỏ hơn nữa:

$ strip A
$ du -hs A
84K A

Một tập tin eensy thực thi, được xây dựng từ nhiều phần C và Haskell được liên kết động:

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

Điểm cuối cùng: ngay cả trên các hệ thống chỉ có liên kết tĩnh, bạn có thể sử dụng -split-objs , để lấy một tệp .o cho mỗi hàm cấp cao nhất, có thể giảm thêm kích thước của các thư viện được liên kết tĩnh. Nó cần GHC để được xây dựng với -split-objs, điều mà một số hệ thống quên làm.


7
Khi nào thì liên kết động do đến ghc trên mac?
Carter Tazio Schonwald

1
... không cabal installloại bỏ nhị phân được cài đặt theo mặc định?
hvr

1
làm như vậy trên Windows dường như làm cho tệp kết quả không thể chạy được, nó phàn nàn về việc thiếu libHSrts-ghc7.0.3.dll
is7s

3
nhị phân này sẽ hoạt động trên các máy Linux khác sau các thủ tục này?
レ ッ

1
Chào OP từ năm 2011! Tôi đến từ tương lai và có thể nói rằng pandoc thực thi trên Ubuntu 16.04 là 50 MB chất béo và nó sẽ không thay đổi dựa trên các gói.ub Ubuntu.com/zesty/pandoc . Thông báo cho bản thân trong tương lai gần và những người khác: liên hệ với người duy trì gói và hỏi xem có enable-sharedđược xem xét không. launchpad.net/ubfox/+source/pandoc/+bugs
Stéphane Gourichon

11

Haskell sử dụng liên kết tĩnh theo mặc định. Đây là, toàn bộ các ràng buộc với OpenGL được sao chép vào chương trình của bạn. Vì chúng khá lớn, chương trình của bạn bị thổi phồng không cần thiết. Bạn có thể giải quyết vấn đề này bằng cách sử dụng liên kết động, mặc dù nó không được bật theo mặc định.


5
Bạn có thể tự động liên kết các thư viện để làm việc xung quanh này. Không chắc chắn tại sao nó quan trọng những gì mặc định, cờ là đủ đơn giản.
Thomas M. DuBuisson

4
Vấn đề là "bất kỳ thư viện nào bạn muốn chia sẻ nên được xây dựng cùng --enabled-shared" vì vậy nếu Nền tảng Haskell của bạn đi kèm với các thư viện được xây dựng mà --enabled sharedbạn không phải biên dịch lại các thư viện cơ sở có thể khá đau đớn.
nponeccop
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.