N.B. These notes date back to before the name change to Rocq.
The following is a grab bag of tips on developing Rocq itself, from writing plugins for it to modifying the trusted kernel.
Further references:
- Installation guide
- Beginner’s guide to hacking Coq
- Development tutorial
- Make installation instructions
- Developer Makefile
- Debugging Coq
- Style guide
- Coq source description
- Other development resources
Setup
For writing OCaml in VSCode, use the OCaml and Reason IDE plugin by Darin Morrison.
$ sudo apt install opam # OCaml package manager
$ opam init && opam switch create ocaml-base-compiler # OCaml compiler
$ opam install ocamlfind zarith ounit merlin user-setup # OCaml libraries
$ opam user-setup install # configuring Merlin
$ ./configure -profile devel -warn-error no # local binaries, disable errorfying warnings
$ make coqbinaries # make native code toplevel
$ make byte # make bytecode toplevel
$ make coqocaml # make all OCaml code
$ make init # make Init libraries
$ make coqlib # make all Coq libraries
$ make theories/<PATH>/<FILE>.vo # make a specific library
Debugging
Printing
let open Format in
let open Pp in
let msg : string = ... in
let cstr : Constr.constr = ... in
(* See Pp.mli for more handy dandy pretty printers *)
let prs : Pp.t list = [str msg; spc (); Constr.debug_print cstr; fnl ()] in
(* Print to file *)
let oc = open_out_gen [Open_append; Open_creat] 0o666 "out.txt" in
let fmt = formatter_of_out_channel oc in
pp_with fmt @@ seq prs;
pp_print_flush fmt ();
close_out oc;
(* Print to stdout *)
pp_with std_formatter @@ seq prs;
From toplevel
bin/coqtop
(native code) orbin/coqtop.byte
(bytecode)Drop.
#use “base_include”;;
(basic printing) or#use “include”;;
(pretty printing)#trace Module.function;;
go();;
- Run Coq code in prompt;
Ctrl-d
to exit
Using ocamldebug
dev/ocamldebug-coq bin/coqtop.byte
source db
(optionally load printers)break @ Module 123
to set breakpoint at line 123 inmodule.ml
run
, then run Coq code in prompt- Useful commands (see OCaml manual for more):
s
: Step into functionn
: Next functionp var
: Print variablevar
li
: Print surrounding lines
Unit tests
Test template
open Utest
let log_out_ch = open_log_out_ch __FILE__
let test1 = mk_{eq, bool}_test "<NAME>" "<DESC>" ...
...
let testn = ...
let tests = [test1;...;testn]
let _ = run_tests __FILE__ log_out_ch tests
Running tests
$ make bin/coqtop bin/coqide
$ cd test-suite
$ make unit-tests/<DIR>/*.ml.log # run tests in `unit-tests/<DIR>`
$ make unit-tests/**/*.ml.log # run all unit tests
$ make summary # print list of tests that were run
$ make report PRINT_LOGS=1 # print test failures
Plugins
$ ./configure -profile devel # make sure *.cma files will be built
$ make byte
$ bin/coqtop.byte
> Declare ML Module "example_plugin". # load plugin
plugins/example/example.mlg
{
open Example
...
}
DECLARE PLUGIN "example_plugin"
VERNAC COMMAND EXTEND CommandName CLASSIFIED AS SIDEFF
| [ "Set" "Flag" ] -> { set_flag true }
END
VERNAC COMMAND EXTEND CommandName CLASSIFIED AS QUERY
| [ "Print" "Stuff" ] -> { print_stuff () }
END
plugins/example/example.ml(i)
let set_flag b = ...
let print_stuff () = ...
val set_flag b : bool -> unit
val print_stuff : unit -> unit
plugins/example/example_plugin.mlpack
Example
G_example
Relevant modules for typing
Constr
constr
: Main AST of Coq core (“constructions”)mk*
,is*
,dest*
: Create/test membership/destructconstr
compare_head_gen_leq_with
: Subtyping and alpha equivalence of termsconstr_ord_int
: Total ordering with alpha equivalence (unrelated to subtyping)
Typeops
execute
: Main type inference algorithminfer*
: Entry points to type inferencecheck_cast
: Entry point to subtyping (i.e.conv
)
CClosure
fconstr
: Frozen version ofConstr.constr
for closures
Reduction
eqappr
: Subtyping onfterm
, similar toConstr.compare_head_gen_leq_with
(probably)
Other modules
Term
: Contains functions for making and decomposing lambdas, products, aritiesTerm_typing
: Main caller ofTypeops
functionsUniv
: Type universesuGraph
: Specialization of acyclic graphs to universe levels for constraint solving
Other
- If the dependencies of
kernel/declarations.ml
are changed, e.g. adding a new field to a variant inConstr.constr
, changes may be needed inchecker/values.ml
, e.g. inValues.v_constr
. Failure to make the necessary changes may result in mysterious segfaults. - Changes to
Constr.constr
also need to be reflected inConstr.hash*
.