File: dune.mld

package info (click to toggle)
ocaml-odoc 2.1.1%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 6,744 kB
  • sloc: ml: 37,049; makefile: 124; sh: 79
file content (139 lines) | stat: -rw-r--r-- 4,405 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
{0 Dune and odoc}

{1:using_dune Using Dune}

To create docs with [odoc] and Dune is straightforward, but there is an important
point to know: Dune only creates docs for {e public packages}, so you will need
a [(public_name ...)] stanza in your libraries and a corresponding [lib.opam]
file in the root of your project.

The following files are a simple example:

- [dune-project]
{[
(lang dune 2.0)
]}
- [dune]
{[
(library
  (public_name lib))
]}
- [a.ml]
{[
(** Module A *)

type t = int (** My type *)
]}
- [lib.opam] - this file need only {e exist}, i.e., [touch lib.opam] is sufficient.

Dune creates the docs for these with this command:

{[
$ dune build @doc
]}

and the results will be in [_build/default/_doc/_html/].

{1:library_wrapping Dune's Library Wrapping}

Dune has a feature whereby a library may be exposed under a single top-level
module. This makes use of an OCaml feature where the use of the compiler
flag [-no-alias-deps] is used to avoid introducing dependencies between
compilation units.

We aim to reduce the potential name clashes of modules by
only exposing one main module for library users to use,
encapsulating all other modules as submodules, while
still retaining the usual way of writing OCaml code with one module per
file. These individual files are still compiled, and installed, and
available in the global namespace, but their names are prefixed with
the library's name in order to reduce the possibility of clashes. These
prefixed modules are not intended to be used directly, so
Dune includes canonical tags for these modules for [odoc] to
ensure they don't 'leak' into the documentation.

{1 Example}

Given two modules: [A] and [B], with [B] referencing types declared in module
[A]:

{[
(** Module A *)
type t
]}

{[
(** Module B *)
type t = A.t
]}

If these modules are to become part of a library called [Lib], then Dune will
compile these two as if their names were [Lib__A] and [Lib__B] and also 
create a file [lib.ml] containing the following:

{[
(** @canonical Lib.A *)
module A = Lib__A

(** @canonical Lib.B *)
module B = Lib__B
]}

This will be the one module intended to be used directly by
the library's users. This module is in fact compiled {e first}, using the
compiler flag [--no-alias-deps], which allows it to be compiled without requiring
[Lib__A] and [Lib__B] to be compiled first.

Dune will then compile [a.ml] and [b.ml], in that order, but ask the compiler to
name them [Lib__A] and [Lib__B]. It also 'opens' the module [Lib], which is what
allows [B] to refer to [A.t]. 

When [odoc] is used to produce documentation for this, firstly all modules are
compiled, but only one module is considered to be visible: [Lib]. All others
have double underscores meaning they are hidden. Only the non-hidden module
[Lib] is linked, and during this process, the
the modules [A] and [B] are expanded because they are aliases of hidden
modules. All references to [Lib__A] and [Lib__B] are replaced with the canonical
paths [Lib.A] and [Lib.B], so in this way odoc presents the library as entirely
contained within the module [Lib].

{2 Hand-Written Top-Level Module}

In some cases it's desirable to hand-write the top-level library module. This
is usually done because some of the modules within the library are intended to
be internal only and not exposed. Dune will notice that a module exists with
the name of the library ([lib.ml] in this case), so instead it will create the
file [lib__.ml]. The contents of this are identical to the previous section, 
with aliases for all modules. The canonical tags on the aliases are, as before,
to [Lib.A] and [Lib.B]. These are references to module aliases that should be
present in [lib.ml]. If these are {e not} there, [odoc] won't be able to
resolve the canonical references, and any items from these modules that are
exposed elsewhere will be hidden. If the items are type aliases they can be
replaced, but otherwise they'll be rendered as unresolved links.

For example, consider the following module structure. First, the module [Unexposed]
in file [unexposed.mli]:

{[
(** Unexposed module *)

type t
]}

The module [Wrapping], in file [wrapping.mli]:

{[
(** Example of Dune's wrapping *)

type t = Unexposed.t

val f : Unexposed.t
]}

and the library module that only exposes the module [Wrapping]:

{[
module Wrapping = Wrapping
]}

This structure is rendered {{!Odoc_examples.Wrapping}here}.