Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 76 additions & 47 deletions doc/tutorials/dune-package-management/dependencies.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ Much like in regular projects, to add a library we need to add a dependency to
it. For simplicity we will use the popular `fmt` library as an example, but any
package from the [package repository](https://ocaml.org/packages) can be used.

First we update the `dune-project` file to add a dependency on the opam package.
To do so we update the `dune-project` file to add a dependency on the opam
package.

::::{dropdown} `dune-project`
:icon: file-code
Expand All @@ -19,33 +20,27 @@ First we update the `dune-project` file to add a dependency on the opam package.
:emphasize-lines: 8
:::

Here we define the OPAM packages that we want to use, along with the version
constraints these dependencies should adhere to.

::::

After this change to our project dependencies, we need to relock dependencies
to update our lock directory with the new packages.
::::{dropdown} `dune-workspace`
:icon: file-code

```
$ 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
```
:::{literalinclude} dependencies/dune-workspace
:language: dune
:emphasize-lines: 2
:::

You can see a lot of new dependencies, among these `fmt`.
In this file we direct Dune to enable package management in the current
workspace. The `pkg` stanza configures Dune to manage the declared dependencies
automatically.

:::{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:
This configuration 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
Expand All @@ -55,11 +50,12 @@ our build as a library as usual:
:emphasize-lines: 3
:::

Adding a library dependency to our `dune` file via the `libraries` stanza.
Adding a library dependency to our `dune` file via the `libraries` stanza. This
is unchanged from the usual Dune workflow.

::::

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

::::{dropdown} `test.ml`
:icon: file-code
Expand All @@ -80,8 +76,34 @@ To build it we just call `build` again.
$ dune build
```

which will download and install the new dependencies and build our project as
before.
Dune will notice that the project depends on new packages. Thus it will re-run
the internal dependency solver to find a solution for the set of packages to
use. It will then use this new solution to download, build and install these
dependencies automatically.

We can check the build log in `_build/log` and see the packages that the Dune
solver has selected:

```
...
# Dependency solution for
# _build/.sandbox/<sandbox-hash>/_private/default/.lock/dune.lock:
# - base-unix.base
# - fmt.0.11.0
# - ocaml.5.4.0
# - ocaml-base-compiler.5.4.0
# - ocaml-compiler.5.4.0
# - ocaml-config.3
# - ocamlbuild.0.16.1+dune
# - ocamlfind.1.9.8+dune
# - topkg.1.1.1
...
```

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

As we see, the code works and uses `fmt` to do the pretty-printing:

Expand All @@ -106,35 +128,42 @@ used for opam dependencies in the `dune-project` file.

::::

This ensures the `fmt` package to install will be compatible with
our request. These constraints will be taken into account the next time the
package is locked:
This change ensures the `fmt` package to install will be compatible with our
request. These constraints will be taken into account the next time the build
system is ran.

```
$ 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
```sh
dune build
```

The version of `fmt` picked is indeed between `0.6` and `1.0`.
Checking `_build/log` again reveals that our change was taken into account:

```
...
# Dependency solution for
# _build/.sandbox/<sandbox-hash>/_private/default/.lock/dune.lock:
# - base-unix.base
# - fmt.0.9.0
# - ocaml.5.4.0
# - ocaml-base-compiler.5.4.0
# - ocaml-compiler.5.4.0
# - ocaml-config.3
# - ocamlbuild.0.16.1+dune
# - ocamlfind.1.9.8+dune
# - topkg.1.1.1
...
```

## 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.
dependency just means to remove the dependency from the `depends` field of your
`dune-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.
From then on the project 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.
The removed dependency might still be accessible if some other dependency of
your project depends on it, thus if it is a transitive dependency.
:::
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
(lang dune 3.21)
(pkg enabled)
1 change: 1 addition & 0 deletions doc/tutorials/dune-package-management/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ setup
dependencies
pinning
repos
locking
:::
42 changes: 42 additions & 0 deletions doc/tutorials/dune-package-management/locking.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Locking Your Dependencies

In the default use-case Dune will automatically determine which packages to
install, by reading the package constrains, determining compatible versions and
installing the dependencies automatically.

For many projects this is a good and acceptable behavior as users often want to
use new versions of their dependencies. However some projects might want to
keep a fixed set of (transitive) dependencies that is only updated manually.

## Create a lock directory manually

If a lock directory exists in the source, Dune will use that to fix the exact
version and source of dependencies. The default name of said lock directory is
`dune.lock`. Lock directories are created with:

```
$ dune pkg lock
Solution for dune.lock:
- ocaml.5.2.0
- ocaml-base-compiler.5.2.0
- ocaml-config.3
```

Whenever Dune encounters a `dune.lock` folder, it will use the set of
dependencies defined in the lock. It contains all the metadata about package
names and versions, their dependencies and source locations that are necessary
to build the project's dependencies.

On the next build, Dune will read the stored solver solution from the
`dune.lock` directory, download and build the dependencies and then continue on
building the project as usual.

The lock directory will not be updated until `dune pkg lock` is rerun.

:::{note}
This approach is similar to using `opam switch export --full --freeze` to
export the configuration of a switch.
:::

Deleting the lock directory will cause Dune to fall back to automatically
determining dependency versions via the declared package constraints.
39 changes: 24 additions & 15 deletions doc/tutorials/dune-package-management/pinning.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,28 +26,37 @@ dependencies.

::::

The next time the package is locked, Dune will use this repository instead of
the information from the selected package repositories.
The next time the project is built, Dune will use this repository instead of
the information from the selected package repositories. Thus the `fmt` package
will be built from the source in the specified Git repository rather than from
the source tarball released in the `opam-repository`.

```sh
dune build
```
$ dune pkg lock
Solution for dune.lock:
- base-unix.base
- fmt.dev
- 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.7

will find a new solution, quoting `_build/log`:

```
...

# Dependency solution for
# _build/.sandbox/<sandbox-hash>/_private/default/.lock/dune.lock:
# - base-unix.base
# - fmt.dev
# - ocaml.5.4.0
# - ocaml-base-compiler.5.4.0
# - ocaml-compiler.5.4.0
# - ocaml-config.3
# - ocamlbuild.0.16.1+dune
# - ocamlfind.1.9.8+dune
# - topkg.1.1.1
...
```

Unlike previously, the version of the `fmt` library that is picked is `dev`, to
signify a development version.

The next time the project is built, the `fmt` package will be built from the
source in the specified Git repository rather than from the source tarball
released in the `opam-repository`.

```
$ dune exec ./test.exe
Expand Down
48 changes: 32 additions & 16 deletions doc/tutorials/dune-package-management/repos.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,40 +17,56 @@ if it didn't exist):

:::{literalinclude} repos/dune-workspace
:language: dune
:emphasize-lines: 5-6,8-10
:::

::::

In this case, we want to select a specific revision of the community repository
instead of always using the most recent one as it would do by default. We
define a new repository and configure the lock directory to use this
define a new repository and configure the Dune solver to use this
repository.

For more information about the stanzas refer to the {doc}`repositories stanza
</reference/dune-workspace/repository>` as well as the {doc}`lock_dir stanza
</reference/dune-workspace/lock_dir>`.

When relocking the dependencies, the list of packages that are found as
dependencies changes accordingly:
The next time the build system is run, instead of using the default
repositories at their newest versions, the solver will check out the configured
repositories at the defined revisions. These will then be used to determine the
new solution, which will get used for downloading and building the
dependencies.

```sh
dune build
```
$ 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 OCaml compiler version is older, which shows
that we did indeed pick an older version of the package repository for locking.
will thus log a new solution in `_build/log`. Note that a lot of package
versions are different, as the state of the opam-repository is frozen at the
specific commit:

```
...
# Dependency solution for
# _build/.sandbox/<sandbox-hash>/_private/default/.lock/dune.lock:
# - base-unix.base
# - fmt.0.9.0
# - ocaml.5.0.0
# - ocaml-base-compiler.5.0.0
# - ocaml-config.3
# - ocamlbuild.0.16.1+dune
# - ocamlfind.1.9.8+dune
# - topkg.1.0.7
...
```

:::{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.
:::

:::{seealso}
{doc}`/tutorials/dune-package-management/locking`
More information how to keep package versions locked.
:::
4 changes: 3 additions & 1 deletion doc/tutorials/dune-package-management/repos/dune-workspace
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
(lang dune 3.17)
(lang dune 3.21)

(pkg enabled)

(lock_dir
(repositories overlay specific-upstream))
Expand Down
Loading
Loading