โปรแกรม Small Haskell ที่คอมไพล์ด้วย GHC เป็นไบนารีขนาดใหญ่


127

แม้แต่โปรแกรม Haskell ขนาดเล็กเล็กน้อยก็กลายเป็นโปรแกรมปฏิบัติการขนาดมหึมา

ฉันได้เขียนโปรแกรมขนาดเล็กที่คอมไพล์ (ด้วย GHC) เป็นไบนารีโดยมีขนาดขยาย 7 MB!

อะไรทำให้แม้แต่โปรแกรม Haskell ขนาดเล็กที่คอมไพล์เป็นไบนารีขนาดใหญ่ได้

ฉันจะทำอะไรได้บ้างเพื่อลดสิ่งนี้


2
คุณได้ลองลอกมันหรือยัง?
Fred Foo

21
รันโปรแกรมstripบนไบนารีเพื่อลบตารางสัญลักษณ์
Fred Foo

1
@ tm1rbt: strip testRun คำสั่งนี้จะลบข้อมูลการดีบักบางส่วนออกจากโปรแกรมและทำให้มีขนาดเล็กลง
fuz

8
เช่นกันประเภทข้อมูลของคุณในห้องสมุดคณิตศาสตร์ 3D ควรจะเข้มงวดสำหรับเหตุผลประสิทธิภาพ: และdata M3 = M3 !V3 !V3 !V3 data V3 = V3 !Float !Float !Floatรวบรวมด้วยghc -O2 -funbox-strict-fields.
Don Stewart

8
โพสต์นี้จะกล่าวถึงในเมตา
Patrick Hofman

คำตอบ:


215

มาดูกันว่ามีอะไรบ้างลอง

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

คุณเห็นจากlddเอาต์พุตที่ GHC สร้างไฟล์ปฏิบัติการที่เชื่อมโยงแบบไดนามิก แต่เฉพาะไลบรารี C เท่านั้นที่เชื่อมโยงแบบไดนามิก ! ไลบรารี Haskell ทั้งหมดจะถูกคัดลอกแบบคำต่อคำ

นอกเหนือจาก: เนื่องจากนี่เป็นแอปที่เน้นกราฟิกมากฉันจึงรวบรวมด้วย ghc -O2

มีสองสิ่งที่คุณทำได้

สัญลักษณ์การลอก

วิธีง่ายๆ: ดึงไบนารีออก:

$ strip A
$ du -hs A
5.8M    A

Strip ละทิ้งสัญลักษณ์จากอ็อบเจ็กต์ไฟล์ โดยทั่วไปจำเป็นสำหรับการดีบักเท่านั้น

ไลบรารี Haskell ที่เชื่อมโยงแบบไดนามิก

การสนับสนุนเมื่อเร็ว ๆ นี้ได้รับ GHC สำหรับเชื่อมโยงแบบไดนามิกของทั้งสองซีและ Haskell ห้องสมุด ปัจจุบัน distros ส่วนใหญ่แจกจ่าย GHC เวอร์ชันที่สร้างขึ้นเพื่อรองรับการเชื่อมโยงแบบไดนามิกของไลบรารี Haskell ไลบรารี Haskell ที่ใช้ร่วมกันอาจใช้ร่วมกันระหว่างโปรแกรม Haskell จำนวนมากโดยไม่ต้องคัดลอกลงในไฟล์ปฏิบัติการในแต่ละครั้ง

ในขณะที่เขียน Linux และ Windows ได้รับการสนับสนุน

ในการอนุญาตให้เชื่อมโยงไลบรารี Haskell แบบไดนามิกคุณต้องคอมไพล์ด้วย-dynamicดังนี้:

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

นอกจากนี้ไลบรารีใด ๆ ที่คุณต้องการแชร์ควรสร้างด้วย--enabled-shared:

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

และคุณจะจบลงด้วยไฟล์ปฏิบัติการที่เล็กกว่ามากซึ่งมีทั้งการอ้างอิง C และ 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...

และ voila!

$ du -hs A
124K    A

ซึ่งคุณสามารถตัดให้เล็กลงได้:

$ strip A
$ du -hs A
84K A

ไฟล์ปฏิบัติการที่น่าทึ่งสร้างขึ้นจากชิ้นส่วน C และ Haskell ที่เชื่อมโยงแบบไดนามิกจำนวนมาก:

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

จุดสุดท้าย: แม้ในระบบที่มีการลิงก์แบบคงที่เท่านั้นคุณสามารถใช้ -split-objsเพื่อรับไฟล์. o หนึ่งไฟล์ต่อฟังก์ชันระดับบนสุดซึ่งสามารถลดขนาดของไลบรารีที่ลิงก์แบบสแตติกได้มากขึ้น ต้องสร้าง GHC ด้วย -split-objs ซึ่งบางระบบลืมที่จะทำ


7
การเชื่อมโยงแบบไดนามิกจะมาถึงเมื่อใดสำหรับ ghc บนเครื่อง Mac
Carter Tazio Schonwald

1
... ไม่cabal installตัดไบนารีที่ติดตั้งไว้ตามค่าเริ่มต้น?
hvr

1
การทำเช่นนั้นบน Windows ดูเหมือนว่าจะทำให้ไฟล์ผลลัพธ์ไม่สามารถรันได้มันบ่นเกี่ยวกับ libHSrts-ghc7.0.3.dll ที่หายไป
is7s

3
ไบนารีนี้จะทำงานบนเครื่อง Linux อื่น ๆ หลังจากขั้นตอนเหล่านี้หรือไม่
アレックス

1
สวัสดี OP จาก 2011! ผมมาจากอนาคตและสามารถบอกได้ว่าปฏิบัติการ pandoc บน Ubuntu 16.04 เป็นไขมัน 50MB และมันจะไม่เกิดการเปลี่ยนแปลงขึ้นอยู่กับpackages.ubuntu.com/zesty/pandoc ข้อความถึงตัวเองและคนอื่น ๆ ในอนาคต: ติดต่อผู้ดูแลแพ็คเกจและถามว่าenable-sharedได้รับการพิจารณาหรือไม่ Launchpad.net/ubuntu/+source/pandoc/+bugs
Stéphane Gourichon

11

Haskell ใช้การลิงก์แบบคงที่โดยค่าเริ่มต้น นี่คือการเชื่อมโยงทั้งหมดกับ OpenGL จะถูกคัดลอกลงในโปรแกรมของคุณ เนื่องจากมีขนาดค่อนข้างใหญ่โปรแกรมของคุณจึงสูงเกินความจำเป็นโดยไม่จำเป็น คุณสามารถแก้ไขปัญหานี้ได้โดยใช้การลิงก์แบบไดนามิกแม้ว่าจะไม่ได้เปิดใช้งานโดยค่าเริ่มต้นก็ตาม


5
คุณสามารถเชื่อมโยงไลบรารีแบบไดนามิกเพื่อแก้ไขปัญหานี้ ไม่แน่ใจว่าเหตุใดจึงมีความสำคัญกับค่าเริ่มต้นแฟล็กนั้นง่ายพอ
Thomas M. DuBuisson

4
ปัญหาคือ "ควรสร้างไลบรารีใด ๆ ที่คุณต้องการแชร์--enabled-shared" ดังนั้นหากแพลตฟอร์ม Haskell ของคุณมาพร้อมกับไลบรารีที่สร้างขึ้นโดยที่--enabled sharedคุณไม่ต้องคอมไพล์ไลบรารีฐานใหม่ซึ่งอาจทำให้เจ็บปวดได้มาก
nponeccop
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.