Common Lisp から、 NCURSES を触りたくなった。早速、Quicklisp で、 cl-charms をインストールしてみよう:
* (ql:quickload "cl-charms") To load "cl-charms": Load 2 ASDF systems: alexandria cffi Install 1 Quicklisp release: cl-charms ; Fetching #<URL "http://beta.quicklisp.org/archive/cl-charms/2014-03-16/cl-charms-20140316-git.tgz"> ; 10.48KB ================================================== 10,735 bytes in 0.00 seconds (0.00KB/sec) ; Loading "cl-charms" [package cl-charms]........................ debugger invoked on a LOAD-FOREIGN-LIBRARY-ERROR in thread #<THREAD "initial thread" RUNNING {1002998ED3}>: Unable to load foreign library (LIBCURSES). Error opening shared object "libncursesw.so": /usr/lib/x86_64-linux-gnu/libncursesw.so: ファイルが小さすぎます. Type HELP for debugger help, or (SB-EXT:QUIT) to exit from SBCL.
あらら、何らかのエラーが出て、インストールに失敗してしまった。何ともは や
もしかしたら、 CFFI がなんかやってるのだろうか?じゃあ、 UFFI を使う、 cl-ncurses を使ってみよう。
* (ql:quickload "cl-ncurses") To load "cl-ncurses": Load 1 ASDF system: uffi Install 1 Quicklisp release: cl-ncurses ; Fetching #<URL "http://beta.quicklisp.org/archive/cl-ncurses/2010-10-06/cl-ncurses_0.1.4.tgz"> ; 23.05KB ================================================== 23,603 bytes in 0.17 seconds (134.01KB/sec) ; Loading "cl-ncurses" [package cl-ncurses].............................. ............. ("cl-ncurses") *
なにやらインストールできたようなので、ロードしてみる:
* (require :cl-ncurses) WARNING: Unable to load ncurses. NIL *
だめだ! 結局ライブラリのロードに失敗している。
Google 大先生にお問い合わせしてみると、すぐに回避方法が見つかる。 http://stackoverflow.com/questions/17416504/unable-to-load-libncurses-with-uffi
以下のようにリンクを張ることで、正常にインストールとロードができる。
sudo ln -s /lib/x86_64-linux-gnu/libncurses.so.5.9 /usr/lib/libncurses.so
sudo ln -s /lib/x86_64-linux-gnu/libncursesw.so.5.9 /usr/lib/libncursesw.so
これらを行うことで、 cl-charms も cl-ncurses も正常にインストールするこ とが出来た。
回避策はさておき、問題の原因を調べてみる。まず、エラーメッセージには、 こう書いてあった:
Error opening shared object "libncursesw.so": /usr/lib/x86_64-linux-gnu/libncursesw.so: ファイルが小さすぎます.
これだけ見ると、 libncursesw.so が壊れているように見える。しかし、C で 適当に ncurses 使うプログラムを書き、 libncursesw をリンクしてみた所、 普通に実行することが出来た。ならば、ファイルが破損しているわけではない ようだ。
じゃあ、上記ファイルは何者なのか?
hoge:~$ file /usr/lib/x86_64-linux-gnu/libncursesw.so /usr/lib/x86_64-linux-gnu/libncursesw.so: ASCII text
ASCII text ? 共有オブジェクトではないのか?
覗いてみよう:
hoge:~$ cat /usr/lib/x86_64-linux-gnu/libncursesw.so INPUT(libncursesw.so.5 -ltinfo)
これは一体・・?
僕の大予想は、以下のようなもの:
- apt-get 視点では、 libncurses は正しくインストールされている。
- おそらく、 Ubuntu Linux 搭載の 素敵なリンカ は、上記のASCII textを 解釈して、 いい感じにリンク してくれる。 C 言語のプログラムでは、 そのリンカを通すので、問題なかった。
- おそらく、 SBCL か、 Common Lisp の CFFI, UFFI のどちらかが、上記の ASCII text を解釈できない。そのため、 libncurses.so をロードする時点 で弾かれてしまう。
上記 2. と 3. は予想にすぎない。暇があったら調べてみようと思う。
上で現れた謎の ASCII text は、 GNU ld の使用するリンカスクリプトである。 何らかの理由で、 ncurses はリンカスクリプトの現れる形式でインストールさ れるようだ。
当然だが、これは ELF バイナリ等ではないため、それのためのローダでは読み
とれない。 dlopen(3)
でも読めないようだ。
共有オブジェクトのロードは、当然ながら Lisp 処理系依存である。 SBCL で
は、 SB-ALIEN:LOAD-SHARED-OBJECT
関数で実装されており、これは最終的に
dlopen(3)
を呼んでロードしている。
上記の通り、 dlopen(3)
は、リンカスクリプトを読めない。そのため、リン
カスクリプトを読む必要があるライブラリのロードは失敗してしまうのである。
偉大なる Google 先生にお伺いをたてたところ、 Lisp じゃない処理系でのバグ レポートが見つかった:
- GHC (Haskell)
- https://ghc.haskell.org/trac/ghc/ticket/2615
- Parrot (perl)
- http://www.parrot.org/scratch/general-handling-linker-scripts-reached-dlopen
GHC のものは、なんと 自前でリンカスクリプトを読む という力技。こういう ことになるのかなあ。
GHC 7.8.1 は、 system linker を使ってリンクしてるらしい。
https://ghc.haskell.org/trac/ghc/wiki/DynamicGhcPrograms
これだな。