Tutorial

Getting started

With Cmdliner your tool's main function evaluates a command.

A command is a value of type Cmdliner.Cmd.t which gathers a command name and a term of type Cmdliner.Term.t. A term is an expression to be evaluated. The type parameter of the term (and the command) indicates the type of the result of the evaluation.

One way to create terms is by lifting regular OCaml values with Cmdliner.Term.const. Terms can be applied to terms evaluating to functional values with Cmdliner.Term.($).

For example, in a revolt.ml file, for the function:

let revolt () = print_endline "Revolt!"

the term :

open Cmdliner

let revolt_t = Term.(const revolt $ const ())

is a term that evaluates to the result (and effect) of the revolt function. This term can be attached to a command:

let cmd = Cmd.v (Cmd.info "revolt") revolt_t

and evaluated with Cmdliner.Cmd.eval:

let () = exit (Cmd.eval cmd)

This defines a command line tool named "revolt" (this name will be used in error reporting and documentation generation), without command line arguments, that just prints "Revolt!" on stdout.

> ocamlfind ocamlopt -linkpkg -package cmdliner -o revolt revolt.ml
> ./revolt
Revolt!

The combinators in the Cmdliner.Arg module allow to extract command line arguments as terms. These terms can then be applied to lifted OCaml functions to be evaluated.

Terms corresponding to command line argument data that are part of a term evaluation implicitly define a command line syntax. We show this on an concrete example.

In a chorus.ml file, consider the chorus function that prints repeatedly a given message :

let chorus count msg = for i = 1 to count do print_endline msg done

we want to make it available from the command line with the synopsis:

chorus [-c COUNT | --count=COUNT] [MSG]

where COUNT defaults to 10 and MSG defaults to "Revolt!". We first define a term corresponding to the --count option:

let count =
  let doc = "Repeat the message $(docv) times." in
  Arg.(value & opt int 10 & info ["c"; "count"] ~docv:"COUNT" ~doc)

This says that count is a term that evaluates to the value of an optional argument of type int that defaults to 10 if unspecified and whose option name is either -c or --count. The arguments doc and docv are used to generate the option's man page information.

The term for the positional argument MSG is:

let msg =
  let env =
    let doc = "Overrides the default message to print." in
    Cmd.Env.info "CHORUS_MSG" ~doc
  in
  let doc = "The message to print." in
  Arg.(value & pos 0 string "Revolt!" & info [] ~env ~docv:"MSG" ~doc)

which says that msg is a term whose value is the positional argument at index 0 of type string and defaults to "Revolt!" or the value of the environment variable CHORUS_MSG if the argument is unspecified on the command line. Here again doc and docv are used for the man page information.

The term for executing chorus with these command line arguments is :

let chorus_t = Term.(const chorus $ count $ msg)

We are now ready to define the main function of our tool:

let cmd =
  let doc = "print a customizable message repeatedly" in
  let man = [
    `S Manpage.s_bugs;
    `P "Email bug reports to <bugs@example.org>." ]
  in
  let info = Cmd.info "chorus" ~version:"%‌%VERSION%%" ~doc ~man in
  Cmd.v info chorus_t

let main () = exit (Cmd.eval cmd)
let () = main ()

The info value created with Cmdliner.Cmd.info gives more information about the term we execute and is used to generate the tool's man page. Since we provided a ~version string, the tool will automatically respond to the --version option by printing this string.

A tool using Cmdliner.Cmd.eval always responds to the --help option by showing the tool's man page generated using the information you provided with Cmdliner.Cmd.info and Cmdliner.Arg.info. Here is the output generated by our example:

> ocamlfind ocamlopt -linkpkg -package cmdliner -o chorus chorus.ml
> ./chorus --help
NAME
       chorus - Print a customizable message repeatedly

SYNOPSIS
       chorus [--count=COUNT] [OPTION]… [MSG]

ARGUMENTS
       MSG (absent=Revolt! or CHORUS_MSG env)
           The message to print.

OPTIONS
       -c COUNT, --count=COUNT (absent=10)
           Repeat the message COUNT times.

COMMON OPTIONS
       --help[=FMT] (default=auto)
           Show this help in format FMT. The value FMT must be one of auto,
           pager, groff or plain. With auto, the format is pager or plain
           whenever the TERM env var is dumb or undefined.

       --version
           Show version information.

EXIT STATUS
       chorus exits with the following status:

       0   on success.

       123 on indiscriminate errors reported on standard error.

       124 on command line parsing errors.

       125 on unexpected internal errors (bugs).

ENVIRONMENT
       These environment variables affect the execution of chorus:

       CHORUS_MSG
           Overrides the default message to print.

BUGS
       Email bug reports to <bugs@example.org>.

If a pager is available, this output is written to a pager. This help is also available in plain text or in the groff man page format by invoking the program with the option --help=plain or --help=groff.

For examples of more complex command line definitions look and run the examples.

Sub commands

Cmdliner also provides support for programs like git that have sub commands each with their own command line syntax and manual:

tool [COMMAND]… [OPTION]… ARG…

These sub commands are defined by grouping them under a parent command via the Cmdliner.Cmd.group function.