Skip to content

Commit

Permalink
doc: dune pkg tutorial
Browse files Browse the repository at this point in the history
Signed-off-by: Marek Kubica <marek@tarides.com>
  • Loading branch information
Leonidas-from-XIV committed Sep 18, 2024
1 parent 3f31387 commit 3b4a0e6
Show file tree
Hide file tree
Showing 15 changed files with 427 additions and 0 deletions.
141 changes: 141 additions & 0 deletions doc/tutorials/dune-package-management/dependencies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# Managing dependencies

The OCaml ecosystem has a wealth of third-party packages that are available for
use. In this section we will look into how to use them with Dune.

## Adding dependencies

Much like in regular projects to add a library we need to add a dependency to
it. For simplicity we'll use the popular `fmt` library as an example, but any
library on the OPAM repository can be used.

First we update the `dune-project` file to add a dependeny on the OPAM package.

::::{dropdown} `dune-project`
:icon: file-code

:::{literalinclude} dependencies/dune-project
:language: dune
:emphasize-lines: 8
:::

::::

After this change to our project dependencies, we need to re-lock dependencies
to update our lock directory with the new packages.

```sh
$ dune pkg lock
Solution for dune.lock:
- base-unix.base
- fmt.0.9.0
- ocaml.5.2.0
- ocaml-base-compiler.5.2.0
- ocaml-config.3
- ocamlbuild.0.15.0+dune
- ocamlfind.1.9.6+dune
- topkg.1.0.7
```

You can see a lot of new dependencies, among these `fmt`.

:::{note}
The list of packages being output includes all dependencies of your project,
including transitive dependencies.
:::

This will take care of installing the dependencies, but we still need to add it to
our build as a library, as usual:

::::{dropdown} `dune`
:icon: file-code

:::{literalinclude} dependencies/dune
:language: dune
:emphasize-lines: 3
:::

Adding a library dependency to our `dune` file as usual via the `libraries`
stanza.

::::

This will allow us to use `Fmt` in our OCaml code.

::::{dropdown} `test.ml`
:icon: file-code

:::{literalinclude} dependencies/test.ml
:language: ocaml
:emphasize-lines: 4
:::

We update the code to define an `Fmt.t` pretty printer for the list of strings
and then print the value.

::::

To build it we just call `build` again.

```sh
$ dune build
```

which will download and install the new dependencies and build our project as
before.

As we see, the code works and uses `fmt` to do the prettyprinting:

```sh
$ dune exec ./test.exe
Hello, OCaml, Rust!
```

### Dependency constraints

Packages are often only compatible with some versions of dependencies. To
specify a version range you can use the regular Dune dependency syntax that is
used for OPAM dependencies in the `dune-project` file.

::::{dropdown} `dune-project`
:icon: file-code

:::{literalinclude} dependencies/constraints
:language: dune
:emphasize-lines: 7-8
:::

::::

This will ensure that the `fmt` package to be installed will be compatible with
our request. These constraints will be taken into account the next time the
package is locked:

```sh
$ dune pkg lock
Solution for dune.lock:
- base-unix.base
- fmt.0.9.0
- ocaml.5.2.0
- ocaml-base-compiler.5.2.0
- ocaml-config.3
- ocamlbuild.0.15.0+dune
- ocamlfind.1.9.6+dune
- topkg.1.0.7
```

The version of `fmt` picked is indeed between `0.6` and `1.0`.

## Removing dependencies

Given all dependencies are defined in the `dune-project` file, removing a
dependency means to remove the dependency from the `depends` field of your
`dune-project` and relocking the project.

The new lock directory will not depend on the package anymore and in future
builds the package will not be accessible as `library` anymore.

:::{note}
The removed dependency might still be part of the lock directory if some other
dependency of your project depends on it.
:::
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
(lang dune 3.17)
(name test)

(package
(name test)
(depends
(ocaml (>= 4.14))
(fmt (and (>= 0.6) (< 1.0)))))
3 changes: 3 additions & 0 deletions doc/tutorials/dune-package-management/dependencies/dune
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(executable
(public_name test)
(libraries fmt))
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
(lang dune 3.17)
(name test)

(package
(name test)
(depends
(ocaml (>= 4.14))
fmt))
5 changes: 5 additions & 0 deletions doc/tutorials/dune-package-management/dependencies/test.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
let langs = ["OCaml"; "Rust"]

let () =
let pp_langs = Fmt.(list ~sep:(any ", ") string) in
Format.printf "Hello, %a!\n" pp_langs langs
27 changes: 27 additions & 0 deletions doc/tutorials/dune-package-management/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
author: Marek Kubica
---

OCaml Package Management with Dune
==================================

:::{warning}
Dune Package Management is not final yet and details are still subject to
change.
:::

In this tutorial we will be looking at how to use Dune for managing project
dependencies. This enables users to install the compiler as well as third-party
dependencies using a single tool which takes care of building code and
dependencies.

To get started you only need Dune. Head to {doc}`setup` to begin the setup.

:::{toctree}
:hidden:
:maxdepth: 1
setup
dependencies
pinning
repos
:::
38 changes: 38 additions & 0 deletions doc/tutorials/dune-package-management/pinning.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Pinning projects

When Dune is looking up packages it uses OPAM repository to look up packages.
But in cases where e.g. the package is not released it is also possible to
specify the source of the packages directory. This is called `pinning`.

## Installing packages from a pin

To pin a package, a new `pin` has to be declared in the `dune-project` file.

::::{dropdown} `dune-project`
:icon: file-code

:::{literalinclude} pinning/dune-project
:language: dune
:emphasize-lines: 4-6
:::

This will create a pin on the `fmt` name and use the specified Git repository
URL to retrieve the sources.

::::

The next time the package is locked, Dune will use this repository instead of
the information from OPAM repository.

```sh
$ dune pkg lock
TODO
```

The next build will check out the sources from that repository instead of
downloading the release tarball:

```sh
$ dune exec ./test.exe
TODO
```
12 changes: 12 additions & 0 deletions doc/tutorials/dune-package-management/pinning/dune-project
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
(lang dune 3.17)
(name test)

(pin
(url "git+https://github.com/dbuenzli/fmt.git")
(package (name fmt)))

(package
(name test)
(depends
(ocaml (>= 4.14))
fmt))
53 changes: 53 additions & 0 deletions doc/tutorials/dune-package-management/repos.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
## Custom repositories

In normal usage Dune looks up packages from two sources:

1. The upstream, community maintained OPAM repository at
[ocaml/opam-repository](https://github.com/ocaml/opam-repository) for most
packages
2. An overlay OPAM repository with patched software to allow usage in Dune at
[ocaml-dune/opam-overlays](https://github.com/ocaml-dune/opam-overlays)

This list is built-in but can be configured. To change the repositories to be
used the `dune-workspace` file has to be edited (and created if it didn't
exist):

::::{dropdown} `dune-workspace`
:icon: file-code

:::{literalinclude} repos/dune-workspace
:language: dune
:::

::::

The `repository` stanza defines a new repository `specific-upstream` with an
URL. In this case we want to select a specific revision of the OPAM repository,
instead of always using the most recent one.

The `lock_dir` stanza defines the configuration for a specific lock directory;
amongst others it specifies the repositories to be used for the lock directory.

When relocking the dependencies, the list of packages that are found as
dependencies changes accordingly:

```sh
$ dune pkg lock
Solution for dune.lock:
- base-unix.base
- fmt.0.9.0
- ocaml.5.0.0
- ocaml-base-compiler.5.0.0
- ocaml-config.3
- ocamlbuild.0.15.0+dune
- ocamlfind.1.9.6+dune
- topkg.1.0.
```

Compared to before, the version of the OCaml compiler is older.

:::{note}
This feature can also be used to make sure the locked dependencies are
reproducible, as fixing all the package repository versions will lead to
equivalent locking results.
:::
8 changes: 8 additions & 0 deletions doc/tutorials/dune-package-management/repos/dune-workspace
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
(lang dune 3.17)

(lock_dir
(repositories overlay specific-upstream))

(repository
(name specific-upstream)
(source "git+https://github.com/ocaml/opam-repository.git#00ac3727bc4ac0eabd3c89e69c1660d6b63a3d48"))
Loading

0 comments on commit 3b4a0e6

Please sign in to comment.