Login

opam

Add a version constraint to an opam install

$ opam install utop
...
<><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><>
⬇ retrieved lambda-term.3.3.3  (cached)
⬇ retrieved logs.0.9.0  (cached)
⬇ retrieved lwt.6.1.0  (cached)
⬇ retrieved lwt_react.1.2.0  (cached)
⬇ retrieved utop.2.16.0+ox  (cached)
[ERROR] The compilation of lwt.6.1.0 failed at "dune build -p lwt -j 15 @install".

#=== ERROR while compiling lwt.6.1.0 ==========================================#

On an old OxCaml, the new lwt 6 doesn't build, and naturally lwt isn't as aware of this OCaml fork. But you can just add constraints:

$ opam install utop 'lwt<6'
The following actions will be performed:
=== install 5 packages
  ∗ lambda-term 3.3.3     [required by utop]
  ∗ logs        0.9.0     [required by utop]
  ∗ lwt         5.9.2+ox
  ∗ lwt_react   1.2.0     [required by utop]
  ∗ utop        2.16.0+ox

Proceed with ∗ 5 installations? [Y/n] y

<><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><>
⬇ retrieved lambda-term.3.3.3  (cached)
⬇ retrieved logs.0.9.0  (cached)
⬇ retrieved lwt.5.9.2+ox  (cached)
⬇ retrieved lwt_react.1.2.0  (cached)
⬇ retrieved utop.2.16.0+ox  (cached)
∗ installed lwt.5.9.2+ox
∗ installed lwt_react.1.2.0
∗ installed logs.0.9.0
∗ installed lambda-term.3.3.3
∗ installed utop.2.16.0+ox
Done.

Recreate a switch with new ocaml-variants constraints

Get some useful lists.

$ opam list --installed --short --columns package | tee all-packages.list
$ opam list --installed --invariant --short --columns package | tee invariant-packages.list
$ opam list --installed --roots --short --columns package | tee root-packages.list
$ opam list --pinned --short --columns package,pin | tee pinned-packages.list

all-packages.list has a list of package names and version ($pkg.$vsn, same as wanted by opam install), and includes some packages that don't make sense to reinstall, e.g. base-unix.base, and dependencies that it would be better not to install directly (to not erase this distinction between roots and dependencies), and pinned packages that can't be reinstalled by only the name and version.

$ opam switch remove std
$ opam switch create std 5.4.1+options ocaml-option-fp ocaml-option-flambda

Then generate some opam commands to restore your environment, and run those.

#directory "+str"

#load "str.cma"

let pinned =
  let sep = Str.regexp " +" in
  In_channel.with_open_text "pinned-packages.list" (fun file ->
      In_channel.fold_lines
        (fun ht line ->
          match Str.split sep line with
          | [pkg; pin] ->
            Hashtbl.replace ht pkg pin;
            ht
          | _ -> failwith ("bad pinned package: " ^ line))
        (Hashtbl.create 0) file)

let invariants =
  In_channel.with_open_text "invariant-packages.list" (fun file ->
      In_channel.fold_lines
        (fun ht line ->
          Hashtbl.replace ht line ();
          ht)
        (Hashtbl.create 0) file)

let roots =
  In_channel.with_open_text "root-packages.list" (fun file ->
      In_channel.fold_lines
        (fun ht line ->
          if
            (not (Hashtbl.mem pinned line)) && not (Hashtbl.mem invariants line)
          then
            Hashtbl.replace ht line ();
          ht)
        (Hashtbl.create 0) file)

let () =
  Printf.printf "opam install %s\n"
    (Hashtbl.to_seq_keys roots |> List.of_seq |> String.concat " ");
  Hashtbl.iter
    (fun pkg pin -> Printf.printf "opam pin add %s %s\n" pkg pin)
    pinned