This commit is contained in:
swrup 2025-11-11 02:07:51 +01:00
parent aa2ff7b2f0
commit 2f3113f55d
11742 changed files with 1223940 additions and 0 deletions

View file

@ -0,0 +1,140 @@
# 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 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.
::::{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 relock dependencies
to update our lock directory with the new packages.
```
$ 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 via the `libraries` stanza.
::::
This will allow us to use the `Fmt` module 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 use it to print the value.
::::
To build it we just call `build` again.
```
$ 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 pretty-printing:
```
$ dune exec ./test.exe
Hello, OCaml, Rust!
```
### Dependency Constraints
Packages are often only compatible with some versions of dependencies. To
specify a version range, use the regular Dune dependency syntax
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 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:
```
$ 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.
:::

View file

@ -0,0 +1,8 @@
(lang dune 3.17)
(name test)
(package
(name test)
(depends
(ocaml (>= 4.14))
(fmt (and (>= 0.6) (< 1.0)))))

View file

@ -0,0 +1,3 @@
(executable
(public_name test)
(libraries fmt))

View file

@ -0,0 +1,8 @@
(lang dune 3.17)
(name test)
(package
(name test)
(depends
(ocaml (>= 4.14))
fmt))

View file

@ -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

View file

@ -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
:::

View file

@ -0,0 +1,55 @@
# Pinning Projects
When Dune is looking up packages to lock, it uses the (pre)configured OCaml
package repositories. However it is also possible to manually specify the
sources of packages; for example, if the package is not released in a package
repository. 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,12
:::
This will create a pin on the `fmt` package and use the specified Git
repository URL to retrieve the sources. For more information refer to {doc}`the
pin stanza reference </reference/dune-project/pin>`.
Don't forget to remove the version constraints from `fmt` in the list of
dependencies.
::::
The next time the package is locked, Dune will use this repository instead of
the information from the selected package repositories.
```
$ 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
```
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
Hello, OCaml, Rust!
```

View file

@ -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))

View file

@ -0,0 +1,56 @@
# Custom Repositories
By default when locking package versions, 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 repository with patched software to allow usage in Dune at
[ocaml-dune/opam-overlays](https://github.com/ocaml-dune/opam-overlays)
To change the presets, 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
:::
::::
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
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:
```
$ 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.
:::{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.
:::

View file

@ -0,0 +1,8 @@
(lang dune 3.17)
(lock_dir
(repositories overlay specific-upstream))
(repository
(name specific-upstream)
(url "git+https://github.com/ocaml/opam-repository.git#00ac3727bc4ac0eabd3c89e69c1660d6b63a3d48"))

View file

@ -0,0 +1,120 @@
# Setting Up Package Management With Dune
The idea of package management with Dune has been as unobtrusive as
possible. Thus most projects can easily be built with just the minimum of
changes.
In this tutorial we will create a simple project to use the integrated package
management feature for the very first time.
## Declare Dependencies
The best way to work with the package management is to declare your
dependencies in the `dune-project` file.
::::{dropdown} `dune-project`
:icon: file-code
:::{literalinclude} setup/dune-project
:language: dune
:emphasize-lines: 6-7
:::
We define a project called `test` and declare that to build it we need an OCaml
compiler that is at least version 4.14.
This is exactly the same information that is used to generate opam files using
the `generate_opam_files` stanza as described in
{doc}`/howto/opam-file-generation`.
::::
::::{dropdown} `test.ml`
:icon: file-code
:::{literalinclude} setup/test.ml
:language: ocaml
:::
To show that the build works, this simple program will be built and executed.
::::
::::{dropdown} `dune`
:icon: file-code
:::{literalinclude} setup/dune
:language: dune
:::
To declare our module an executable we need a little bit of configuration, so we
just define the module as an executable.
::::
After our project skeleton is set up, we can proceed to the next step.
## Locking Dependencies
After declaring the dependencies, you will need to tell Dune which package
versions to use for your project. This is done by creating a lock directory.
This is easily done with a new Dune command:
```
$ dune pkg lock
Solution for dune.lock:
- ocaml.5.2.0
- ocaml-base-compiler.5.2.0
- ocaml-config.3
```
This will update all the required opam repositories, use the newest version of
each and try to find a set of packages and versions that satisfy the
constraints that your project dependencies declare.
:::{note}
The versions that get locked might be different from this tutorial, as we only
specified the lower bound of `ocaml`; barring any additional configuration, Dune
will pick the newest possible version for each dependency.
:::
## Build Project
To build the project, you can just use the regular Dune commands.
```sh
dune build
```
This will download, build, and install all your locked dependencies and then use
those to build your project. This means that the first time building it will take
longer than usual, as the dependencies need to be built first. Subsequent
builds where all dependencies have been built before will be just as fast as
before.
We can show that the package has been built successfully and works as expected:
```
$ dune exec ./test.exe
Hello, OCaml, Rust!
```
:::{note}
If you want to only build and fetch the project dependencies, you can use
the `@pkg-install` alias like so
```shell
$ dune build @pkg-install
```
See {doc}`/reference/aliases/pkg-install` for more information.
:::
## Conclusion
In this section we learned how to set up a Dune project that picks a compiler
and installs it without the need for any additional tooling.
In the next section {doc}`dependencies` we will look on how to add third party
dependencies.

View file

@ -0,0 +1,2 @@
(executable
(public_name test))

View file

@ -0,0 +1,7 @@
(lang dune 3.17)
(name test)
(package
(name test)
(depends
(ocaml (>= 4.14))))

View file

@ -0,0 +1,5 @@
let langs = ["OCaml"; "Rust"]
let () =
let s = String.concat ", " langs in
Format.printf "Hello, %s!\n" s