# Connection between libraries in Opam, Dune, and Findlib

**URL:** <https://discuss.ocaml.org/t/connection-between-libraries-in-opam-dune-and-findlib/2536>\
**Category:** Learning\
**Tags:** opam, dune\
**Created:** [September 9, 2018, 8:38am UTC](https://discuss.ocaml.org/t/connection-between-libraries-in-opam-dune-and-findlib/2536 "2018-09-09T08:38:37Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![lindig](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/lindig/32/532_2.png) [@lindig](https://discuss.ocaml.org/u/lindig)\
**Post date:** [September 9, 2018, 8:38am UTC](https://discuss.ocaml.org/t/connection-between-libraries-in-opam-dune-and-findlib/2536/1 "2018-09-09T08:38:37Z")

</div>

I would like to understand the connection between libraries and packages better and would be interested in plans to close the gap between them.

Dune knows which OCaml libraries to make available during compilation of a project and it can report them with `dune external-lib-deps` globally or per package (`-p`) for a source tree. The names it reports can be fed to `ocamlfind query` to locate them. However, the names only approximate the corresponding Opam packages. For example, `threads` belongs to Opam package `base-threads`. So the connection between a library and the Opam package that installs it is not obvious (to me). Is there a way to establish a connection or plans to establish it? For example, could the META file for a library optionally name the Opam package that installed it?

Addendum. These recent discussions seem to be relevant:

- [RFC dune-package files](https://github.com/ocaml/dune/issues/1206)
- [RFC generating opam files](https://github.com/ocaml/dune/issues/1190)

---

<div class="post-metadata">

**Author:** ![emillon](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/emillon/32/1206_2.png) [@emillon](https://discuss.ocaml.org/u/emillon)\
**Post date:** [September 10, 2018, 7:29am UTC](https://discuss.ocaml.org/t/connection-between-libraries-in-opam-dune-and-findlib/2536/2 "2018-09-10T07:29:42Z")

</div>

Hi,

In `dune` files, everything that is in `(libraries ...)` refers to findlib names. That is the same as what as in `package(...)` in `_tags` with `ocamlbuild`.

This does not always involve `findlib`: within a project, `dune` will be able to resolve libraries by itself, for example when linking your test suite against your lib.

Strictly speaking, the library names (for `findlib`) and opam package names are not related. For packages using `topkg` or calling `ocamlfind install` directly, it is up to the package author to specify the exposed modules, the library name, and the package name.

Base libraries in particular do not use strictly the same name. That is also the case in some common libraries: for example the `ounit` package exposes a `oUnit` library which has a `OUnit2` module.

`dune` is a bit less flexible: the library name is always the same as the package name. That is derived from the `(public_name)`.

`opam` used to have some support for exposing the mapping between libraries and packages: [findlib files](https://github.com/ocaml/opam/issues/2948). It seems that it does not exist anymore though.

To avoid the confusion, the best practice these days is to make packages expose a single library, which exposes a single module, all named the same (that’s what you get when using `dune` with the default `(wrapped true)` mode).

---

<div class="post-metadata">

**Author:** ![lindig](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/lindig/32/532_2.png) [@lindig](https://discuss.ocaml.org/u/lindig)\
**Post date:** [September 10, 2018, 4:05pm UTC](https://discuss.ocaml.org/t/connection-between-libraries-in-opam-dune-and-findlib/2536/3 "2018-09-10T16:05:09Z")

</div>

In summary, I’d say the situation is more confusing (for historical reasons) than one would like and hence the efforts to streamline this by Dune potentially generating Opam files.

---

<div class="post-metadata">

**Author:** ![emillon](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/emillon/32/1206_2.png) [@emillon](https://discuss.ocaml.org/u/emillon)\
**Post date:** [September 10, 2018, 4:28pm UTC](https://discuss.ocaml.org/t/connection-between-libraries-in-opam-dune-and-findlib/2536/4 "2018-09-10T16:28:48Z")

</div>

I’d say that dune already keeps this difference manageable by enforcing a 1-1 mapping between opam packages and findlib libraries. Generating opam files might help, but in the linked proposal the dependencies in `dune-project` are opam names so this is a purely syntactic generation (at least for now).

---

<div class="post-metadata">

**Author:** ![lindig](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/lindig/32/532_2.png) [@lindig](https://discuss.ocaml.org/u/lindig)\
**Post date:** [September 11, 2018, 8:12am UTC](https://discuss.ocaml.org/t/connection-between-libraries-in-opam-dune-and-findlib/2536/5 "2018-09-11T08:12:44Z")

</div>

Dune complains when a library is known to findlib and used in code but not imported by a `jbuild` file. But it does not notice when a library that is used is not mentioned in the corresponding Opam file and hence available only by accident.

---

<div class="post-metadata">

**Author:** ![Leonidas](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/leonidas/32/4039_2.png) [@Leonidas](https://discuss.ocaml.org/u/Leonidas)\
**Post date:** [September 11, 2018, 8:20am UTC](https://discuss.ocaml.org/t/connection-between-libraries-in-opam-dune-and-findlib/2536/6 "2018-09-11T08:20:02Z")

</div>

This is true. As a stopgap solution I recommend using clean switches per project and only install packages via dependencies declared in the `opam` file and avoiding to call `opam install …` directly.

---

<div class="post-metadata">

**Author:** ![jeremiedimino](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/jeremiedimino/32/699_2.png) [@jeremiedimino](https://discuss.ocaml.org/u/jeremiedimino)\
**Post date:** [September 11, 2018, 8:53am UTC](https://discuss.ocaml.org/t/connection-between-libraries-in-opam-dune-and-findlib/2536/7 "2018-09-11T08:53:44Z")

</div>

Dune should have enough information so that it could warn when a dependency is missing in an opam file. However, opam files are complicated to interpret. Putting the information in the `dune-project` file should help with implementing these checks.

Currently, the solution @Leonidas suggests is indeed the safest one.

---

<div class="post-metadata">

**Author:** ![RogerT](https://avatars.discourse-cdn.com/v4/letter/r/5f8ce5/32.png) [@RogerT](https://discuss.ocaml.org/u/RogerT)\
**Post date:** [September 25, 2018, 8:53pm UTC](https://discuss.ocaml.org/t/connection-between-libraries-in-opam-dune-and-findlib/2536/8 "2018-09-25T20:53:16Z")

</div>

Thanks for this wise recommendation that gives us light (and hope!)

Can you detail a little bit about how to do that?

Currently I’m using opam for installing packages “as recommended in all tutorials” (opam install \<package\>).  
And also dune for building (so I know the syntax of a dune file).  
Is the opam file you mention like the one detailed here? [https://opam.ocaml.org/doc/Tricks.html#Provide-a-set-of-packages-for-a-group-of-users-to-install](https://opam.ocaml.org/doc/Tricks.html#Provide-a-set-of-packages-for-a-group-of-users-to-install)?

Do I need to use opam 2.0 to create “one clean switch per project” ? (I’ve just upgraded this afternoon, assuming it makes possible to create one switch per project/program - and possibly several switch with the same compiler - )

And which command is required to get the packages/libraries available (for coding and for compilation)? Or maybe dune simply does the job? (I can spend some time in the opam documentation but this point should be obvious for you)

Also, can you explain clearly and exhaustively what is a package and what is a library?  
See example from @emillon:

> the `ounit` package exposes a `oUnit` library which has a `OUnit2` module

AFAIK what is an (Ocaml) module is clear for me: a Foo module can be represented by a file foo.ml ; a Bar module car be related to a Bar module declaration ( module Bar : BAR = struct … end ) inside the the foo.ml file of a Foo module, and accessed by Foo.Bar .

Thanks

**EDIT:**  
I’ve read some opam documentation, especially [http://opam.ocaml.org/doc/Manual.html#Local-configuration-files](http://opam.ocaml.org/doc/Manual.html#Local-configuration-files).  
I upgraded to opam 2.0.0.  
I did

```auto
$ mkdir ~/project ; cd project/
$ opam switch create ./ ocaml-base-compiler.4.06.1

```

> \<\>\<\> Error report \<\>\<\>\<\>\<\>\<\>\<\>\<\>\<\>\<\>\<\>\<\>\<\>\<\>\<\>\<\>\<\>\<\>\<\>\<\>\<\>\<\>\<\>\<\>\<\>\<\>\<\>\<\>\<\>\<\>\<\>\<\>  
> ┌─ The following actions failed  
> │ λ build ocaml-base-compiler 4.06.1  
> └─  
> ┌─ The following changes have been performed (the rest was aborted)  
> │ ∗ install base-bigarray base  
> │ ∗ install base-threads base  
> │ ∗ install base-unix base  
> └─

Inspired by [https://github.com/ocaml/opam-repository/issues/12050](https://github.com/ocaml/opam-repository/issues/12050) I tried with 4.02.3 but got the same error message.  
Opam 2.0.0 has [just been released last week](https://opam.ocaml.org/blog/opam-2-0-0/) and there may be some traps.

This opam local repository setup should be obvious for you. What do you recommend?

**EDIT2:**  
I did again:  
`$ opam install opam-devel`  
and I got a clear message from opam that I didn’t have before (but thanks for that!):

> # The ‘bwrap’ command was not found. Install ‘bubblewrap’ on your system, or  
> # disable sandboxing in ~/.opam/config at your own risk.

So I did the following that solved my opam 2.0.0 installation issue (if it may help s.o.):  
`$ sudo apt-get install bubblewrap`

Then I did:  
`~/project$ opam switch create ./ ocaml-base-compiler.4.06.1`

> Done.  
> \<\>\<\> (All…) installed successfully \<\>\<\>\<\>\<\>\<\>

And it seems that I have now a local repository switch for _project_.  
As _opam switch_ documentation tells:  
`$ opam switch create --help`

> DESCRIPTION  
> …  
> When creating a directory switch, if package definitions are found locally, the user is automatically prompted to install them after the switch is created unless --no-install is specified.

Now, to follow @Leonidas recommendation, I understand that I “just” need to write a file ~/project/opam and redo  
`~/project$ opam switch create ./ ocaml-base-compiler.4.06.1`  
“to get prompted to install them after the switch is created”.

I hope these details could be helpful for other people in my situation.

---

<div class="post-metadata">

**Author:** ![emillon](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/emillon/32/1206_2.png) [@emillon](https://discuss.ocaml.org/u/emillon)\
**Post date:** [September 26, 2018, 7:40am UTC](https://discuss.ocaml.org/t/connection-between-libraries-in-opam-dune-and-findlib/2536/9 "2018-09-26T07:40:28Z")

</div>

> [@RogerT](#):
>
> Also, can you explain clearly and exhaustively what is a package and what is a library?

It is confusing indeed. In a nutshell, modules are an OCaml abstraction, libraries are a findlib abstraction, and packages are an opam abstraction.

Modules: you got this. They are the larger unit of code in OCaml. They can contain types, values, exceptions, other modules, etc. You can define one using `module M = struct ... end` and everytime you compile a file named `foo.ml`, its contents correspond to the body of the module `Foo`.

Libraries: as you may have noticed, when you run the ocaml compiler, it creates some binary files, like cmi (compiled version of .mli), cmo (bytecode version of .ml), or cmx (native version of .ml). These files can be linked into an application. That’s how you get separate compilation of third party code (Core or Containers is not rebuilt every time you build your application). To link them with an application, these files need to be given a global name: this is the role of findlib. The name is their library name. This step is comparable to storing a `.a` file in a global directory.

Packages: libraries are a useful abstraction, but they’re not the whole story. Suppose I have an application that requires Containers. What is Containers? Where do I get it? How do I build it? Do I need some other packages to do so? This is the role of opam and packages. An opam package is a source tarball and a metadata file with all that info. The opam program can interpret it to install dependencies for a piece of software (executable or library), build it, and install it. In the case of a library, opam will install cmi, cmx etc files into the correct directory so that it can be found (via findlib) by other pieces of code.

Hope that helps. Let me know if I should expand on some parts!

---

<div class="post-metadata">

**Author:** ![perry](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/perry/32/518_2.png) [@perry](https://discuss.ocaml.org/u/perry)\
**Post date:** [September 26, 2018, 10:13am UTC](https://discuss.ocaml.org/t/connection-between-libraries-in-opam-dune-and-findlib/2536/10 "2018-09-26T10:13:46Z")

</div>

This should be a FAQ answer on OCamlverse.

---

<div class="post-metadata">

**Author:** ![sean](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/sean/32/981_2.png) [@sean](https://discuss.ocaml.org/u/sean)\
**Post date:** [February 18, 2019, 2:08pm UTC](https://discuss.ocaml.org/t/connection-between-libraries-in-opam-dune-and-findlib/2536/11 "2019-02-18T14:08:04Z")

</div>

> [@lindig](#):
>
> hence the efforts to streamline this by Dune potentially generating Opam files.

Are the efforts for this going forward?

> [@Leonidas](#):
>
> As a stopgap solution I recommend using clean switches per project and only install packages via dependencies declared in the `opam` file and avoiding to call `opam install …` directly.

Is there a document somewhere that says how to set up a new project like this? We’re starting one and everyone is just installing project dependencies with a bash script right now, but it would be nice to have a way to pin dependency versions (maybe with the .opam file, and then use opam to install dependencies even as we use dune to build?). Any tips or links here appreciated!

---

<div class="post-metadata">

**Author:** ![Leonidas](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/leonidas/32/4039_2.png) [@Leonidas](https://discuss.ocaml.org/u/Leonidas)\
**Post date:** [February 19, 2019, 9:01am UTC](https://discuss.ocaml.org/t/connection-between-libraries-in-opam-dune-and-findlib/2536/12 "2019-02-19T09:01:09Z")

</div>

> [@sean](#):
>
> Is there a document somewhere that says how to set up a new project like this?

```sh
git checkout …
cd project
opam switch create ./ ocaml-base-compiler.4.07.1

```

Will create a switch and automatically install all the dependencies declared in the opam file in the right versions.
