下载 Dune
opam install dune
创建项目
dune init project <project-name>
如果创建成功,有
Success: initialized project component named <project-name>
得到如下的一个文件结构
project_name/
├── dune-project
├── test
│ ├── dune
│ └── test_project_name.ml
├── lib
│ └── dune
├── bin
│ ├── dune
│ └── main.ml
└── project_name.opam
/lib
lib
里存放编写的库 library(可以看作是一组模块 module 的集合),比如我有如下的一个 module MyModule
:
(* MyModule.ml *)
type t = int listlet init n = List.init n (fun i -> i)let print l = List.iter print_int l
把它放在 lib
下后修改 /lib/dune
文件如下:
(library(name my_project)(modules MyModule))
在 /bin/main.ml
下可以这么调用:
let lst = My_project.MyModule.init 10let () = My_project.MyModule.print lst
library 描述文件 stanza 的格式如下:
(library(name <library-name>)<optional-fields>)
<library-name>
指库 library 的名字,在上面的例子中,<library-name>
是 my_project
,那么在 /bin/main.ml
中就是用 My_project
去调用它内部的模块。
<optional-fields>
有很多可选项,包括:
-
(modules <modules>)
规定哪些模块 module 被包括在这个库 library 之中,使用 Ordered Set Language 来描述 -
(libraries <libraries-dependencies>)
决定了库 library 的依赖
/bin
/bin
存放可运行的 .ml
代码文件,关于 module
的调用方式见上文,使用 dune exec <project_name>
在终端中执行代码,上面的例子的运行结果如下:
dune exec my_project ─╯
Hello, World!
0123456789
如果想要引入外部库,可以修改 /bin/dune
,以使用 lwt 库为例:
(executable(public_name myproject)(name main)(libraries myproject lwt.unix))
(* main.ml *)let lst = Myproject.MyModule.init 10let () = Myproject.MyModule.print lst;Lwt_main.run (Lwt_io.printf "Hello, world!\n")
再次调用 dune exec
可以发现其正常工作
dune-project
dune-project 是描述工程 project 的元数据文件,以我刚刚建立的工程为例:
(lang dune 3.6) ; dune 的版本(name my_project) ; 工程名(generate_opam_files true)(source(github username/reponame))(authors "Author Name") ; 作者(maintainers "Maintainer Name") ; 拥有者(license LICENSE) (documentation https://url/to/documentation)(package(name my_project)(synopsis "A short synopsis")(description "A longer description")(depends ocaml dune)(tags(topics "to describe" your project))); See the complete stanza docs at https://dune.readthedocs.io/en/stable/dune-files.html#dune-project
构建测试
根据 github 更新时间来看,推荐使用 QCheck 或者 ppx_inline_test
使用 QCheck 构建随机单元测试
Cornell cs3110 的课程中使用的是 QCheck,在我的 docker 容器上不是很能正确安装
一直报错 Curl failed
原因是 seq
这个依赖对应的地址没能被正确 dns 解析,把 dns 服务器地址改为 8.8.8.8 之后问题被修复( 有点难绷
QCheck 文档
使用 QCheck 的例子如下:
#require "qcheck"(* [rev] is a function that reverses a list. For example, [rev [1;2;3]] is [3;2;1]. *)
let rev lst = List.rev lst(* QCheck *)
let test =QCheck.Test.make ~count:1000 ~name:"test_rev"QCheck.(list small_nat)(fun l -> rev l = l);;(* we can check right now the property... *)
QCheck_runner.run_tests [test];;
#require "qcheck"let leap_year year =if year mod 400 = 0 then trueelse if year mod 100 = 0 then falseelse year mod 4 = 0let test =QCheck.Test.make ~count:1000 ~name:"test_leap_year_and_mod_4"QCheck.(small_nat)(fun year -> leap_year year = (year mod 4 = 0));;QCheck_runner.run_tests [test]
集成到 Dune 中:
(executable(public_name myproject)(name main)(libraries myproject lwt.unix qcheck))
使用 OUnit2 测试套件
(施工中)