opam 2.0 tips
This blog post looks back on some of the improvements in opam 2.0, and gives tips on the new workflows available.
Package development environment management
Opam 2.0 has been vastly improved to handle locally defined packages. Assuming
you have a project ~/projects/foo
, defining two packages foo-lib
and
foo-bin
, you would have:
~/projects/foo
|-- foo-lib.opam
|-- foo-bin.opam
`-- src/ ...
(See also about computed dependency constraints for handling multiple package definitions with mutual constraints)
Automatic pinning
The underlying mechanism is the same, but this is an interface improvement that
replaces most of the opam 1.2 workflows based on opam pin
.
The usual commands (install
, upgrade
, remove
, etc.) have been extended to
support specifying a directory as argument. So when working on project foo
,
just write:
cd ~/projects/foo
opam install .
and both foo-lib
and foo-bin
will get automatically pinned to the current
directory (using git if your project is versioned), and installed. You may
prefer to use:
opam install . --deps-only
to just get the package dependencies ready before you start hacking on it.
See below for details on how to reproduce a
build environment more precisely. Note that opam depext .
will not work at the
moment, which will be fixed in the next release when the external dependency
handling is integrated (opam will still list you the proper packages to install
for your OS upon failure).
If your project is versioned and you made changes, remember to either commit, or
add --working-dir
so that your uncommitted changes are taken into account.
Local switches
Opam 2.0 introduced a new feature called "local switches". This section explains what it is about, why, when and how to use them.
Opam switches allow to maintain several separate development environments, each with its own set of packages installed. This is particularly useful when you need different OCaml versions, or for working on projects with different dependency sets.
It can sometimes become tedious, though, to manage, or remember what switch to use with what project. Here is where "local switches" come in handy.
How local switches are handled
A local switch is simply stored inside a _opam/
directory, and will be
selected automatically by opam whenever your current directory is below its
parent directory.
NOTE: it's highly recommended that you enable the new shell hooks when using local switches. Just run
opam init --enable-shell-hook
: this will make sure your PATH is always set for the proper switch.You will otherwise need to keep remembering to run
eval $(opam env)
every time youcd
to a directory containing a local switch. See also how to display the current switch in your prompt
For example, if you have ~/projects/foo/_opam
, the switch will be selected
whenever in project foo
, allowing you to tailor what it has installed for the
needs of your project.
If you remove the switch dir, or your whole project, opam will forget about it transparently. Be careful not to move it around, though, as some packages still contain hardcoded paths and don't handle relocation well (we're working on that).
Creating a local switch
This can generally start with:
cd ~/projects/foo
opam switch create . --deps-only
Local switch handles are just their path, instead of a raw name. Additionally,
the above will detect package definitions present in ~/projects/foo
, pick a
compatible version of OCaml (if you didn't explicitely mention any), and
automatically install all the local package dependencies.
Without --deps-only
, the packages themselves would also get installed in the
local switch.
Using an existing switch
If you just want an already existing switch to be selected automatically,
without recompiling one for each project, you can use opam switch link
:
cd ~/projects/bar
opam switch link 4.07.1
will make sure that switch 4.07.1
is chosen whenever you are in project bar
.
You could even link to ../foo
here, to share foo
's local switch between the
two projects.
Reproducing build environments
Pinnings
If your package depends on development versions of some dependencies (e.g. you had to push a fix upstream), add to your opam file:
depends: [ "some-package" ] # Remember that pin-depends are depends too
pin-depends: [
[ "some-package.version" "git+https://gitfoo.com/blob.git#mybranch" ]
]
This will have no effect when your package is published in a repository, but
when it gets pinned to its dev version, opam will first make sure to pin
some-package
to the given URL.
Lock-files
Dependency contraints are sometimes too wide, and you don't want to explore all the versions of your dependencies while developing. For this reason, you may want to reproduce a known-working set of dependencies. If you use:
opam lock .
opam will check what version of the dependencies are installed in your current
switch, and explicit them in *.opam.locked
files. opam lock
is a plugin at
the moment, but will get automatically installed when needed.
Then, assuming you checked these files into version control, any user can do
opam install . --deps-only --locked
to instruct opam to reproduce the same build environment (the --locked
option
is also available to opam switch create
, to make things easier).
The generated lock-files will also contain added constraints to reproduce the
presence/absence of optional dependencies, and reproduce the appropriate
dependency pins using pin-depends
. Add the --direct-only
option if you don't
want to enforce the versions of all recursive dependencies, but only direct
ones.
About OCamlPro:
OCamlPro is a R&D lab founded in 2011, with the mission to help industrial users benefit from experts with a state-of-the-art knowledge of programming languages theory and practice.
- We provide audit, support, custom developer tools and training for both the most modern languages, such as Rust, Wasm and OCaml, and for legacy languages, such as COBOL or even home-made domain-specific languages;
- We design, create and implement software with great added-value for our clients. High complexity is not a problem for our PhD-level experts. For example, we helped the French Income Tax Administration re-adapt and improve their internally kept M language, we designed a DSL to model and express revenue streams in the Cinema Industry, codename Niagara, and we also developed the prototype of the Tezos proof-of-stake blockchain from 2014 to 2018.
- We have a long history of creating open-source projects, such as the Opam package manager, the LearnOCaml web platform, and contributing to other ones, such as the Flambda optimizing compiler, or the GnuCOBOL compiler.
- We are also experts of Formal Methods, developing tools such as our SMT Solver Alt-Ergo (check our Alt-Ergo Users' Club) and using them to prove safety or security properties of programs.
Please reach out, we'll be delighted to discuss your challenges: contact@ocamlpro.com or book a quick discussion.
Most Recent Articles
2024
- opam 2.3.0 release!
- Optimisation de Geneweb, 1er logiciel français de Généalogie depuis près de 30 ans
- Alt-Ergo 2.6 is Out!
- Flambda2 Ep. 3: Speculative Inlining
- opam 2.2.0 release!
- Flambda2 Ep. 2: Loopifying Tail-Recursive Functions
- Fixing and Optimizing the GnuCOBOL Preprocessor
- OCaml Backtraces on Uncaught Exceptions
- Opam 102: Pinning Packages
- Flambda2 Ep. 1: Foundational Design Decisions
- Behind the Scenes of the OCaml Optimising Compiler Flambda2: Introduction and Roadmap
- Lean 4: When Sound Programs become a Choice
- Opam 101: The First Steps
2023
- Maturing Learn-OCaml to version 1.0: Gateway to the OCaml World
- The latest release of Alt-Ergo version 2.5.1 is out, with improved SMT-LIB and bitvector support!
- 2022 at OCamlPro
- Autofonce, GNU Autotests Revisited
- Sub-single-instruction Peano to machine integer conversion
- Statically guaranteeing security properties on Java bytecode: Paper presentation at VMCAI 23
- Release of ocplib-simplex, version 0.5