2015年3月25日水曜日

[windows][haskell] bzlibパッケージ利用時にHSbzlib-0.5.0.5.o: unknown symbol `fileno'となる問題の対処

Haskellでは、bzip2で圧縮されたデータを解凍(もちろん逆に圧縮も)できるbzlibパッケージが提供されています。

ところが、自分の環境(Windows 8.1+Haslell Platform 2014.2.0.0)でbzlibパッケージをインポートするサンプルプログラムをビルド・実行しようとすると、以下のようなエラーになってしまいました。
> runghc examples/bunzip2.hs       
bunzipz2.hs: C:\Users\XXX\AppData\Roaming\cabal\x86_64-windows-ghc-7.8.3\bzlib-0.5.0.5\HSbzlib-0.5.0.5.o: unknown symbol `fileno'                      
bunzip2.hs: bunzip2.hs: unable to load package `bzlib-0.5.0.5'            

ネット上の情報を漁ってみたのですが同じ問題に遭遇している人はいなさそう・・・。ということで、自力で調べてみました。以下、分かったことと回避方法をまとめておきます。


問題の原因:

  • 詳細は「調査の内容」に記しましたが、bzlibが内部で呼び出しているfileno()とfdopen()が定義されているmingwのlibmoldname.aがリンクされないのが原因のようです。

問題の回避方法

  • libmoldname.aをリンクする修正が正しいのですが、その方法が分からなかったため、bzlibのコードに手をいれてileno()とfdopen()を呼ばないバージョンをビルドし、それで正規のパッケージを置き換えることで、bzlibが利用できるようになりました。以下、その手順です。
    1. cabalのpackageがダウンロードされているディレクトリに移動する
    2. % cd C:\Users\XXX\AppData\Roaming\cabal\packages\hackage.haskell.org\bzlib\0.5.0.5
      
    3. bzlib-0.5.0.5.tar.gzを展開する
    4. % tar xzf bzlib-0.5.0.5.tar.gz
      
    5. このパッチをDLしてbzlib.patchという名前で保存し、適用する
    6. % patch -p1 < bzlib.patch
      
    7. パッチを含んだアーカイブでオリジナルのbzlib-0.5.0.5.tar.gzを置き換える
    8. % tar czf bzlib-0.5.0.5.tar.gz bzlib-0.5.0.5/
      
    9. bzlibパッケージをreinstallする
    10. % cabal install bzlib --reinstall
      

調査の内容:

  • 自分の環境にcygwinとHaskell付属のmingwの両方が存在しているが原因かと思ったがそうではないらしい。
    • mingwのライブラリにもfilenoがちゃんと用意されている。
    • mingw環境においてここのfilenoのサンプルがビルドでき、動作しているため
      • > gcc fileno.cpp
  • mingw環境の確認
    • filenoを利用するC言語版サンプルをビルドしてmapファイルを出力したところ、filenoはlibmoldname.aというライブラリの定義をリンクしていることが分かった。
      • gcc -Wl,-Map=a.map -g fileno.cpp
      •  .text          0x0000000000402c10        0x8 c:/program files/haskell platform/2014.2.0.0/mingw/bin/../lib/gcc/x86_64-w64-mingw32/4.6.3/../../../../x86_64-w64-mingw32/lib/../lib/libmoldname.a(dnvzs00026.o)
                        0x0000000000402c10                fileno
        
  • bzlib-0.5.0.5をローカル環境でビルドしてその内容を確認
    • filenoがunknown symbolとなっているのは以下の2つのオブジェクトファイル
      • bzlib-0.5.0.5/dist/build/cbits/bzlib.o
      • bzlib-0.5.0.5/dist/build/cbits/HSbzlib-0.5.0.5.o
    • 上記オブジェクトファイルで同じくunknown symbolになっているfopen, fread, fwrite, fcloseといった関数はlibmoldname.aとは別のlibmsvcrt.aにアーカイブされている。
      • a.mapより
      •  .text          0x0000000000402c70        0x8 c:/program files/haskell platform/2014.2.0.0/mingw/bin/../lib/gcc/x86_64-w64-mingw32/4.6.3/../../../../x86_64-w64-mingw32/lib/../lib/libmsvcrt.a(dnhvs00971.o)
                        0x0000000000402c70                fopen
         .text          0x0000000000402c78        0x8 c:/program files/haskell platform/2014.2.0.0/mingw/bin/../lib/gcc/x86_64-w64-mingw32/4.6.3/../../../../x86_64-w64-mingw32/lib/../lib/libmsvcrt.a(dnhvs00979.o)
                        0x0000000000402c78                fread
        
        
  • windows版のみcabal buildでパッケージをビルドする際に、filenoの解決に必要なlibmoldname.aのリンクが漏れているのでは?
    • 試しに、libmoldname.aを削除してcabal buildをビルドしてみたところ、リンクエラーになりました。ということは、パッケージビルド時にはlibmoldname.aをリンクしようとしていることになります。・・・ハズレ。
    • Resolving dependencies...
      Configuring bzlib-0.5.0.5...
      Building bzlib-0.5.0.5...
      Preprocessing library bzlib-0.5.0.5...
      c:/program files/haskell platform/2014.2.0.0/mingw/bin/../lib/gcc/x86_64-w64-mingw32/4.6.3/../../../../x86_64-w64-mingw32/bin/ld.exe: cannot find -lmoldname
      c:/program files/haskell platform/2014.2.0.0/mingw/bin/../lib/gcc/x86_64-w64-mingw32/4.6.3/../../../../x86_64-w64-mingw32/bin/ld.exe: cannot find -lmoldname
      collect2: ld returned 1 exit status
      linking dist\build\Codec\Compression\BZip\Stream_hsc_make.o failed (exit code 1)
      
      command was: C:\Program Files\Haskell Platform\2014.2.0.0\mingw\bin\gcc.exe dist\build\Codec\Compression\BZip\Stream_hsc_make.o dist\build\Codec\Compression\BZip\Stream_hsc_utils.o -o dist\build\Codec\Compression\BZip\Stream_hsc_make.exe -LC:\Users\XXX\AppData\Roaming\cabal\x86_64-windows-ghc-7.8.3\bytestring-0.10.4.1 -LC:\Program Files\Haskell Platform\2014.2.0.0\lib\deepseq-1.3.0.2 -LC:\Program Files\Haskell Platform\2014.2.0.0\lib\array-0.5.0.0 -LC:\Program Files\Haskell Platform\2014.2.0.0\lib\base-4.7.0.1 -lwsock32 -luser32 -lshell32 -LC:\Program Files\Haskell Platform\2014.2.0.0\lib\integer-gmp-0.5.1.0 -LC:\Program Files\Haskell Platform\2014.2.0.0\lib\ghc-prim-0.3.1.0 -LC:\Program Files\Haskell Platform\2014.2.0.0\lib/rts-1.0 -lm -lwsock32 -lgdi32 -lwinmm
      
  • パッケージビルド時ではなく、パッケージを利用するコードをコンパイルして実行ファイルを生成するときにlibmodulename.aがリンクされていないようです。
    • これはどこの設定に書かれているのか・・・?
      
      

備考:

  • 冒頭に書いたとおり、本来ならば適切にlibmoldname.aをリンクするように修正するのが正しい解決方法なのですが、bzlibパッケージの中にそのような見つからず、どこを変えれば良いか分かりませんでした・・・。orz 。どこを修正すればリンクライブラリを追加できるか知っている方、是非ご教示ください。 m(_ _)m 
  • unknown symbolとなるfilenoとfdopenはbzlib-0.5.0.5/cbits/bzlib.cの中で呼び出しています。コードを確認したところどちらも環境によってはundefされており、呼び出さなくても問題はないことを確認しました。
  • なお、Linux, Mac環境上ではこの問題は発生しません。問題なく利用できています。

参考:

0 件のコメント:

コメントを投稿