blog.anqou.net
rss
author
tags

Dune ファイルを OCaml で動的に生成する

Dune は OCaml 用のビルドシステムで、現在のデファクトスタンダードです。Dune の設定ファイルは dune というファイル名で配置され、中には S 式を書くことになっています。Dune の設定は結構リッチな仕様になっていて、enabled_if などを使い条件を指定することもできます。以下は拙作のプログラムから引っ張ってきた dune ファイルの例です:

; コメントもかける
(library
 (name fsnotify_linux)
 (implements fsnotify)
 (preprocess
  (pps lwt_ppx ppx_deriving.make ppx_deriving.show ppx_yojson_conv))
 (libraries inotify.lwt)
 (enabled_if
  (= %{system} linux)))

しかしいくらリッチとは言っても、複雑な設定を書こうとすると力不足であるときもあります。そのような場合に備えて、Dune には OCaml でスクリプティングする機能(OCaml Syntax)が備わっています。この機能を使うと Dune ファイルを OCaml コードで動的に生成することができます。すぐ後に引用するように、この機能は facebook/flow でビルド環境に応じて inotify 相当のライブラリを使い分けるために実際に使われています。

さて OCaml Syntax の使い方ですが、なんと dune ファイルの先頭に Emacs 用のマジックコメントを書くと使えるようになるという仕様になっています(引用元):

(* -*- tuareg -*- *)

let () =
  (* https://github.com/ocaml/ocaml/blob/36c163248d77e7df0803c1e9893ad01948846081/asmcomp/x86_proc.ml#L40-L59 *)
  let system = List.assoc "system" Jbuild_plugin.V1.ocamlc_config in
  let fsnotify_impl = match system with
  | "macosx" -> Some "fsnotify_Darwin"
  | "linux" -> Some "fsnotify_Linux"
  | "cygwin"
  | "mingw64"
  | "win64" -> Some "fsnotify_Windows"
  | _ -> None
  in
  match fsnotify_impl with
  | None -> Jbuild_plugin.V1.send ""
  | Some fsnotify_impl -> Printf.ksprintf Jbuild_plugin.V1.send "\

(library
  (name fsnotify)
  (wrapped false)
  (libraries %s))
" fsnotify_impl

ちなみに tuareg は OCaml 用の Emacs Major Mode を提供するソフトウェアで、Emacs で OCaml を書いている人にはデファクトスタンダードです[1]。ソフトウェア的には Dune となんの関係もなはずの tuareg のマジックコメントを書くと Dune の挙動が変わるという良くわからない仕様になっています。

詳細は Dune のドキュメントを参照してください。ちなみに公式ドキュメント的にもこれは “escape hatch” だと明記されているので、使わないに越したことはなさそうです。

The OCaml syntax gives you an escape hatch for when the S-expression syntax is not enough.

注釈

  1. 自分は (Neo)Vim 派なのでほとんど使ったことがなく、詳しくないです。