[解決済み] GHCでコンパイルした小さなHaskellプログラムを巨大なバイナリにする
質問
どんなに小さなHaskellプログラムでも、巨大な実行ファイルになってしまいます。
私は小さなプログラムを書きましたが、(GHCで)コンパイルされたバイナリは7MBにもなりました。
小さなHaskellのプログラムでも、巨大なバイナリにコンパイルされてしまう原因は何なのでしょうか?
これを減らすためにできることがあるとすれば、それは何でしょうか?
どのように解決するのですか?
何が起こっているのか、試してみましょう。
$ 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
できることは2つ。
記号の除去
簡単な解決策:バイナリを取り除く。
$ strip A
$ du -hs A
5.8M A
ストリップはオブジェクトファイルからシンボルを削除します。それらは一般にデバッグのためにのみ必要とされます。
動的にリンクされたHaskellライブラリ
より最近では、GHCは以下のものをサポートするようになりました。 のダイナミックリンクをサポートしました。 . ほとんどのディストロでは、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 => ...
最後のポイントとして、静的リンクのみのシステムでも を使用することができます。 を使えば、トップレベル関数ごとに 1 つの .o ファイルを取得でき、静的にリンクされたライブラリのサイズをさらに小さくできます。これは、GHC を -split-objs をオンにしてビルドする必要がありますが、システムによってはそれを忘れているものもあります。
関連
-
[解決済み] Haskell - Ord aの型は何を意味するのでしょうか?
-
[解決済み] モナドはエンドファンクタのカテゴリではただのモノイドですが、何か問題でも?
-
[解決済み] .の違いは何ですか?(ドット)と$(ドルマーク)の違いは何ですか?
-
[解決済み】テンプレートHaskellで関連する型の同義語を取得する
-
[解決済み] GHCはなぜこんなに大きいのか/大きいのか?
-
[解決済み】Haskellの入門編
-
[解決済み】Haskell/GHCの`forall`キーワードは何をするのですか?
-
[解決済み] Haskellプログラムにおけるガベージコレクションの一時停止時間の削減
-
[解決済み] Haskellでグラフはどのように表現するのか?
-
[解決済み] GHCでコンパイルした小さなHaskellプログラムを巨大なバイナリにする
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] Haskellです。パターンでのパースエラー
-
[解決済み] Haskell タプルをリスト化する?
-
[解決済み] Hindley-Milnerのどの部分が理解できないのでしょうか?
-
[解決済み] Haskellで大規模設計?[クローズド]
-
[解決済み] フリーモナドとは何ですか?
-
[解決済み] IntとIntegerの違いは何ですか?
-
[解決済み] Haskellにはなぜ "data "と "newtype "があるのですか?重複] [重複] [重複
-
[解決済み] 制約条件付き特殊化
-
[解決済み] Haskellでメモ化?
-
[解決済み] HaskellとF#の主な違いは何ですか?[クローズド]