OCamlのプロジェクトをduneを使って管理してみる。

Duneとは

Dune は OCaml 用のビルドシステムです。 似たようなものにoasisと言うのもありますが、こちらの方が新しくて簡単らしいです。

インストール

OPAMが入っている前提でいきます。

opam install dune

インストールができたらバージョンを確認してみます。

dune --version
2.5.1

執筆時点では、2.5.1がインストールされました。

プロジェクトを作成する

早速プロジェクトを作成していきます。
myprojectと言うプロジェクトを作成してみます。

dune init project myproject

これを実行すると、以下のようなファイル群が作成されます。

myproject
├── bin
│   ├── dune
│   └── main.ml
├── lib
│   └── dune
├── myproject.opam
└── test
    ├── dune
    └── myproject.ml

各ディレクトリに入っているduneファイルが設定ファイルになります。

binが実行ファイル、libがライブラリ、testがテスト用のディレクトリです。

コマンドのproject部分をexecutable, test, libraryにするとそれそれ単体で作成することもできます。

ビルドしてみる

プロジェクトが作成できたら、まずはビルドしてみます。

dune build

すると_buildと言うディレクトリとdune-projectと言うファイルができるはずです。

_buildにはビルドした生成物が入っています。

dune-projectはプロジェクト全体の設定を記述するファイルです。

プロジェクト全体の情報を記述する

dune-projectはの中身は初期状態だと以下のようになっていると思います。

(lang dune 2.5)
(name myproject)

ここにプロジェクトの情報を記述していきます。
(記述しなくても普通にビルドは通るので飛ばしてもOK)

(lang dune 2.5)
(name myproject)
(version 0.0.0)
(generate_opam_files true)

(source (github username/myproject))
(license MIT)
(authors "author<email@email.com>" "author2<email2@email.com>")
(maintainers "author<email@email.com>")

(package
 (name myproject)
 (synopsis "Short description")
 (description "Long description")
 (depends
  (ounit :with-test)
  (dune (> 1.5))))

(generate_opam_files true)を設定してパッケージに関する情報を記述すると次にビルドされたときに<project_name>.opamが自動生成されます。

上記の例では、依存関係にounitduen自身を指定してみました。

duneファイルの中身を記述する

それぞれのディレクトリに入っているduneファイルに情報を追加していきます。
bin/dune

(executable
 (public_name myproject)
 (name main)
 (libraries myproject))

初期状態だとこんな感じだと思います。
(executableがこのディレクトリないのファイルが実行ファイルとしてコンパイルされることを示します。

(public_name myproject)duneコマンドで指定する際の名称です。

(name main)と設定してあればmain.mlがエントリーポイントになります。

(libraries myproject)部分が、依存するライブラリです。
プロジェクトで依存するライブラリがあればここに追加していきます。
(libraries deplib1 deplib2)みたいな感じです。

後述する、libディレクトリのライブラリの名称をmylibに変更するので(libraries 部分を書き換えます。

(executable
 (public_name myproject)
 (name main)
 (libraries mylib))

lib/duneの初期状態

(library
 (name myproject))

(library部分がこのディレクトリの中身がライブラリ(モジュール)であることを示します。
(name myproject)部分がエントリーポイント(モジュール名)になります。

依存するライブラリがあれば先ほどと同様に(libraries を書き加えます。

(name )部分をmylibに書き換えます。
mylib.mlがモジュールになります。
外から利用する場合はMylib.~~みたいな形で使えます。

(library
 (name mylib))

**test/duneの初期状態 **

(test
 (name myproject))

(test部分がこのディレクトリないのファイルがテストであることを示します。
(name myproject)部分でテストの際のエントリーポイントを指定します。

(name \test)に変更してエントリーポイントをtest.mlとかにするとわかりやすいかと思います。

ここにounitを追加してみます。

(test
 (name myproject_test)
 (libraries oUnit))

あとは、ごく簡単な実行の仕方の紹介です。

実行してみる

dune exec

を実行するとbinディレクトリの中身がコンパイルされて実行されます。

main.mlを編集していなければ、Hello, Worldが表示されると思います。

テストを実行する

dune runtest

を実行するとtestディレクトリの中身がコンパイルされてテストが実行されます。

ビルドキャッシュを削除する

ビルドキャッシュとは言っても_buildを消すだけです。

dune clean

最後に

以上、簡単にOCamlのビルドシステムのduneを試してみました。

参考

https://dune.build/ https://qiita.com/keigoi/items/a68298fcd39322004fed