2022/07/13

「Real World OCaml」のForeign Function Interfaceの章にて

ctypesおよびctypes-foreignのインストールに関して

「Real World OCaml」(以下RWO)に書かれている通りにやってみると、私の場合エラーが発生しました。OSはManjaro Linuxです。conf-pkg-config.2のビルドで失敗したようです。

どうやら私のマシンにはpkg-configが入っていないので、このエラーが発生したようです。

Manjaroではpkgconfという名前でライブラリが提供されているようなので、そちらをダウンロードし、再びインストールを試みたところ、うまくいきました。

もし、同じようなエラーが発生している方がいらっしゃいましたら、pkg-configの有無をチェックしてみてください。

またRWOでは以下のように書かれていますが、


$ utop
# #require "ctypes-foreign" ;;

これもうまくいきません。これはctypes-foreignctypes.foreignにすると解決します。

Let's Ncurses

では、NcursesでHello worldを表示してみましょう。

まず作業ディレクトリを作ります。私はncurという名前のディレクトリを作成しました。そして、その中にdune、dune-project、ncurses.ml、ncur.mlの4つのファイルを作成します。ディレクトリは以下のようになっています。


ncur/
    dune
    dune-project
    ncurses.ml
    ncur.ml

dune-projectには以下のように書いておきます。


(lang dune 3.0)

duneはRWOではctypes-foreignとなっていますが、以下のように書きます。


(executable
  (name ncur)
  (libraries ctypes.foreign)
  (flags :standard -cclib -lncurses))

そしてncurses.mlはRWOのまま以下のように書きます。


open Ctypes

type window = unit ptr

let window : window typ = ptr void

open Foreign

let initscr = foreign "initscr" (void @-> returning window)

let newwin = foreign "newwin" (int @-> int @-> int @-> int @-> returning window)

let endwin = foreign "endwin" (void @-> returning void)

let refresh = foreign "refresh" (void @-> returning void)

let wrefresh = foreign "wrefresh" (window @-> returning void)

let addstr = foreign "addstr" (string @-> returning void)

let mvwaddch = foreign "mvwaddch" (window @-> int @-> int @-> char @-> returning void)

let mvwaddstr = foreign "mvwaddstr" (window @-> int @-> int @-> string @-> returning void)

let box = foreign "box" (window @-> char @-> char @-> returning void)

let cbreak = foreign "cbreak" (void @-> returning int)

最後にncur.mlはRWOどおりに以下のように書きます。


open Ncurses

let () =
  let main_window = initscr () in
  ignore(cbreak ());
  let small_window = newwin 10 10 5 5 in
  mvwaddstr main_window 1 2 "Hello";
  mvwaddstr small_window 2 2 "world";
  box small_window '\000' '\000';
  refresh ();
  Unix.sleep 1;
  wrefresh small_window;
  Unix.sleep 5;
  endwin ()

これで完成です。

$ dune build ncur.exeでビルドして、$ dune exec ./ncur.exeで実行すれば、無事表示されます。

まとめ

RWOにおいては、ドキュメント通りやると、ところどころ上手く行かないところもあるようですが、ちょっとした修正で大体は機能します。