GHC로 거대한 바이너리로 컴파일 된 작은 Haskell 프로그램


127

사소한 하스켈 프로그램조차도 거대한 실행 파일로 바뀝니다.

나는 작은 프로그램을 작성했는데, 그것은 (GHC로) 7MB를 확장하는 바이너리로 컴파일되었습니다!

작은 하스켈 프로그램도 거대한 바이너리로 컴파일되는 원인은 무엇입니까?

이것을 줄이기 위해 무엇을 할 수 있습니까?


2
그냥 벗겨 보셨나요?
Fred Foo

21
strip바이너리 에서 프로그램 을 실행하여 기호 테이블을 제거하십시오.
Fred Foo

1
@ tm1rbt : 실행 strip test. 이 명령은 프로그램에서 일부 디버그 정보를 제거하고 더 작게 만듭니다.
fuz

8
여담으로 3 차원 수학 라이브러리에서 데이터 유형은 성능 향상을 위해 강화해야한다 : data M3 = M3 !V3 !V3 !V3data V3 = V3 !Float !Float !Float. 함께 컴파일 ghc -O2 -funbox-strict-fields.
Don Stewart

8
이 게시물은 meta에 대해 설명합니다 .
Patrick Hofman 2014 년

답변:


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는 C 및 Haskell 라이브러리의 동적 연결에 대한 지원을 얻었습니다 . 대부분의 배포판은 이제 Haskell 라이브러리의 동적 연결을 지원하기 위해 빌드 된 GHC 버전을 배포합니다. 공유 된 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...

그리고, voilà!

$ 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 파일을 얻을 수 있으며, 이는 정적으로 링크 된 라이브러리의 크기를 더욱 줄일 수 있습니다. -split-objs를 사용하여 GHC를 빌드해야하는데, 일부 시스템에서는이를 잊어 버립니다.


7
Mac에서 ghc에 도착하기 때문에 동적 연결은 언제입니까?
Carter Tazio Schonwald

1
... cabal install기본적으로 설치된 바이너리를 제거 하지 않습니까?
hvr

1
Windows에서 그렇게하면 결과 파일을 실행할 수 없게되는 것 같습니다. libHSrts-ghc7.0.3.dll 누락에 대해 불평합니다
is7s

3
이 바이너리가이 절차 후에 다른 Linux 시스템에서 작동합니까?
アレックス

1
2011 년부터 OP 안녕하세요! 나는 미래에서 왔으며 Ubuntu 16.04의 pandoc 실행 파일이 50MB 뚱뚱하고 packages.ubuntu.com/zesty/pandoc 기반으로 변경되지 않을 것이라고 말할 수 있습니다 . 가까운 미래의 자신과 다른 사람들에게 보내는 메시지 : 패키지 관리자에게 연락하여 enable-shared고려 되었는지 물어 보십시오. launchpad.net/ubuntu/+source/pandoc/+bugs
스테판 구리 콘

11

Haskell은 기본적으로 정적 링크를 사용합니다. 즉, OpenGL에 대한 전체 바인딩이 프로그램에 복사됩니다. 크기가 크기 때문에 프로그램이 불필요하게 부풀려집니다. 기본적으로 활성화되어 있지는 않지만 동적 연결을 사용하여이 문제를 해결할 수 있습니다.


5
이 문제를 해결하기 위해 라이브러리를 동적으로 연결할 수 있습니다. 기본값이 무엇인지가 왜 중요한지 잘 모르겠지만 플래그는 충분히 간단합니다.
Thomas M. DuBuisson

4
문제는 "공유하려는 모든 라이브러리를 함께 빌드해야합니다 --enabled-shared"라는 것입니다. 따라서 Haskell 플랫폼에 빌드 된 라이브러리가 함께 제공되는 --enabled shared경우 기본 라이브러리를 다시 컴파일 하지 않아도 되므로 매우 고통 스러울 수 있습니다.
nponeccop
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.