使用 Dune 编译和调试 OCaml 代码

下载 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 list

let 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 10

let () = 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 10

let () = 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 true
  else if year mod 100 = 0 then false
  else year mod 4 = 0

let 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 测试套件

(施工中)

posted @ 2024-10-06 21:36  sysss  阅读(20)  评论(0编辑  收藏  举报