Repository navigation
3.25.0~alpha0 no longer exports OCAMLPATH to actions #16617
Description
3.25.0~alpha0 no longer exports OCAMLPATH to actions, breaking opam install -t for packages whose tests find themselves through findlib.
Up to 3.24, every action dune runs gets OCAMLPATH=<root>/_build/install/<context>/lib (plus the other install roots) from make_root_env in src/dune_rules/super_context.ml. In 3.25.0~alpha0 that is gone: #14373 replaced it with a per-action layout that is only set up for actions declaring (deps (package ...)). A one-rule project shows the difference:
(rule (alias runtest) (action (system "echo OCAMLPATH=${OCAMLPATH:-unset}")))
dune 3.24.2: OCAMLPATH=/tmp/e/_build/install/default/lib
dune 3.25.0~alpha0: OCAMLPATH=unset
A number of released packages rely on the old behaviour, because their tests reach for the package by name rather than through dune: ocamlfind query, #require in an mdx block, a nested dune build of a scratch project inside a cram test, or loading a stub library through CAML_LD_LIBRARY_PATH. Under 3.24 those resolve to the package being built. Under the alpha they resolve only to an installed copy, so a fresh opam install -t fails:
docker run --rm -it ocaml/opam:debian-13-ocaml-5.5
sudo ln -sf /usr/bin/opam-dev /usr/bin/opam && opam init --reinit -ni
opam install dune.3.24.2
opam install -t hxd.0.5.0 # passes
opam install -t GT.0.5.5 # passes
opam install -t bogue.20260208 # passesTrying the same with dune.3.25.0~alpha0
docker run --rm -it ocaml/opam:debian-13-ocaml-5.5
sudo ln -sf /usr/bin/opam-dev /usr/bin/opam && opam init --reinit -ni
opam repo add dune-alpha https://github.com/ocaml/opam-repository.git#refs/pull/30850/head
opam install dune.3.25.0~alpha0
opam install -t hxd.0.5.0 # Error: Library "hxd.string" not found (nested dune build in a cram test)
opam install -t GT.0.5.5 # No such package: GT (mdx #require)
opam install -t bogue.20260208 # ocamlfind: Package `bogue' not found (ocamlfind query at test time)Each of these passes again under the alpha if the package was installed first and then rebuilt with opam reinstall -t, because opam builds before it removes and the test finds the old install. That is why the reverse dependency run on ocaml/opam-repository#30850 reported them green: opam-repo-ci installs each dependent without tests and then reinstalls it with tests, so the package is always present while its tests run. Building with-tests in a fresh switch finds 88 failing jobs across bogue (13 versions), hxd (9), flint, GT, ostap, embedded_ocaml_templates, ocaml-index and topup, on their current releases as well as older ones.
Activity
shonfeder commentedon Oct 17, 2026
Thanks to initial triage and analysis by @Alizter, our current inclination is to
understand this as a result of improved build hygiene, resulting from the elimination of
dependency ambiguity as part of #14432
We believe all these cases of build failures detected by day10 are actually misconfigurations of the build, but I'll present a catalogue here of the failure cases to confirm.
(Thanks to a quick chat with @Alizter, today, I removed some nonsense I asked
here due to having my wires crossed.)
shonfeder commentedon Oct 20, 2026
hxd:
Fails on running tests
Fixed with
The cram test in
lib.tincludes the generation of a libraries that has a library dependency onhxd.string, and this assumes that the package is installed in the context of the test.shonfeder commentedon Oct 20, 2026
GT:
Errors
sfubu@counteragent:~/Repos/GT$ dune build File "camlp5/dune", lines 122-136, characters 0-316: 122 | (rule 123 | (targets pp5+gt+o.byte) 124 | (deps pa_gt.cma) ..... 134 | %{deps} 135 | -o 136 | %{targets}))) ocamlfind: Package `GT.common' not found Maybe an error? Command exited with code 2 File "camlp5/dune", lines 108-120, characters 0-270: 108 | (rule 109 | (targets pp5+gt+o.exe) 110 | (deps pa_gt.cmxa) ..... 118 | %{deps} 119 | -o 120 | %{targets}))) ocamlfind: Package `GT.common' not found Maybe an error? Command exited with code 2 sfubu@counteragent:~/Repos/GT$ dune test File "dune", lines 6-9, characters 0-64: 6 | (mdx 7 | (files index.mld README.md) 8 | (package GT) 9 | (libraries GT)) Got an error while evaluating: --- #require "GT";; --- No such package: GT File "index.mld", line 1, characters 0-0: diff --git a/_build/default/index.mld b/_build/default/.mdx/index.mld.corrected index 0bf157c13..cd54eff33 100644 --- a/_build/default/index.mld +++ b/_build/default/.mdx/index.mld.corrected @@ -20,8 +20,11 @@ Findlib has been successfully loaded. Additional directives: - : unit = () # #require "GT";; +No such package: GT # #require "GT.syntax.all";; +No such package: GT.syntax.all # #require "GT.ppx_all";; +No such package: GT.ppx_all ]} The `deriving` specification will generate @@ -32,49 +35,13 @@ The `deriving` specification will generate {@ocaml[ # type 'a list = Nil | Cons of 'a * 'a list [@@deriving gt ~options:{fmt; show}];; type 'a list = Nil | Cons of 'a * 'a list -class virtual ['ia, 'a, 'sa, 'inh, 'extra, 'syn] list_t : - object - method virtual c_Cons : 'inh -> 'extra -> 'a -> 'a list -> 'syn - method virtual c_Nil : 'inh -> 'extra -> 'syn - end -val gcata_list : - ('a, 'typ0__003_, 'b, 'c, 'typ0__003_ list, 'd) #list_t -> - 'c -> 'typ0__003_ list -> 'd = <fun> -class ['a, 'b] show_list_t : - (unit -> 'a -> string) -> - (unit -> 'a list -> string) -> - object - constraint 'b = 'a list - method c_Cons : unit -> 'a list -> 'a -> 'a list -> string - method c_Nil : unit -> 'a list -> string - end -class ['a, 'b] fmt_list_t : - (Format.formatter -> 'a -> unit) -> - (Format.formatter -> 'a list -> unit) -> - object - constraint 'b = 'a list - method c_Cons : Format.formatter -> 'a list -> 'a -> 'a list -> unit - method c_Nil : Format.formatter -> 'a list -> unit - end -val fmt_list : - (Format.formatter -> 'a -> unit) -> Format.formatter -> 'a list -> unit = - <fun> -val list : - (('a, 'b, 'c, 'd, 'b list, 'e) #list_t -> 'd -> 'b list -> 'e, - < fmt : (Format.formatter -> 'f -> unit) -> - Format.formatter -> 'f list -> unit; - show : ('g -> string) -> 'g list -> string >, - (('h -> 'i list -> 'j) -> ('k, 'i, 'l, 'h, 'i list, 'j) #list_t) -> - 'h -> 'i list -> 'j) - GT.t = {GT.gcata = <fun>; plugins = <obj>; fix = <fun>} -val show_list : ('a -> string) -> 'a list -> string = <fun> ]} {@ocaml[ # Format.printf "%a\n%!" (fmt_list Format.pp_print_int) (Cons(1, Nil));; -Cons (1, Nil) -- : unit = () +Line 1, characters 25-33: +Error: Unbound value fmt_list ]} @@ -105,28 +72,6 @@ type expr = | Mul of expr * expr | Int of int | Var of string -class virtual ['inh, 'extra, 'syn] expr_t : - object - method virtual c_Add : 'inh -> 'extra -> expr -> expr -> 'syn - method virtual c_Int : 'inh -> 'extra -> int -> 'syn - method virtual c_Mul : 'inh -> 'extra -> expr -> expr -> 'syn - method virtual c_Var : 'inh -> 'extra -> string -> 'syn - end -val gcata_expr : ('a, expr, 'b) #expr_t -> 'a -> expr -> 'b = <fun> -class ['a] show_expr_t : - (unit -> expr -> string) -> - object - constraint 'a = expr - method c_Add : unit -> expr -> expr -> expr -> string - method c_Int : unit -> expr -> int -> string - method c_Mul : unit -> expr -> expr -> expr -> string - method c_Var : unit -> expr -> string -> string - end -val expr : - (('a, expr, 'b) #expr_t -> 'a -> expr -> 'b, < show : expr -> string >, - (('c -> expr -> 'd) -> ('c, expr, 'd) #expr_t) -> 'c -> expr -> 'd) - GT.t = {GT.gcata = <fun>; plugins = <obj>; fix = <fun>} -val show_expr : expr -> string = <fun> ]} For mutually recursive type declarations add decoration only to the last type @@ -140,7 +85,11 @@ In our framework (at least by now) all transformations are expressed by the foll {@ocaml[ fun tr_obj init value -> GT.transform(t) tr_obj init value -]} +][ +{err@mdx-error[ +Line 1, characters 41-42: +Error: Unbound value t +]err}]} or more precisely @@ -174,20 +123,16 @@ For example, if we are not satisfied by the "default" behavior of "show", we can inherit [_] show_expr_t fself method c_Var _ _ s = s end;; -class show' : - (unit -> expr -> string) -> - object - method c_Add : unit -> expr -> expr -> expr -> string - method c_Int : unit -> expr -> int -> string - method c_Mul : unit -> expr -> expr -> expr -> string - method c_Var : unit -> expr -> string -> string - end +Line 2, characters 12-27: +Error: Unbound class show_expr_t ]} {@ocaml[ # GT.transform expr (new show') () (Mul (Var "a", Add (Int 1, Var "b"))) -- : string = "Mul (a, Add (Int (1), b))" +Line 1, characters 14-18: +Error: Unbound value expr +Hint: Did you mean exp? ]} Now the result is @@ -207,17 +152,14 @@ If we still not satisfied with the result, we can further proceed with fixing th inherit show' fself method c_Int _ _ i = string_of_int i end;; -class show'' : - (unit -> expr -> string) -> - object - method c_Add : unit -> expr -> expr -> expr -> string - method c_Int : unit -> expr -> int -> string - method c_Mul : unit -> expr -> expr -> expr -> string - method c_Var : unit -> expr -> string -> string - end +Line 2, characters 13-18: +Error: Unbound class show' +Hint: Did you mean show''? # GT.transform(expr) (new show'') () (Mul (Var "a", Add (Int 1, Var "b"))) -- : string = "Mul (a, Add (1, b))" +Line 1, characters 14-18: +Error: Unbound value expr +Hint: Did you mean exp? ]} In the next step we're going to switch to infix representation of operators; @@ -231,17 +173,14 @@ Fortunately, this is easy: method c_Add () _ x y = fself () x ^ " + " ^ fself () y method c_Mul () _ x y = fself () x ^ " * " ^ fself () y end -class show''' : - (unit -> expr -> string) -> - object - method c_Add : unit -> expr -> expr -> expr -> string - method c_Int : unit -> expr -> int -> string - method c_Mul : unit -> expr -> expr -> expr -> string - method c_Var : unit -> expr -> string -> string - end +Line 2, characters 13-19: +Error: Unbound class show'' +Hint: Did you mean show'''? # GT.transform(expr) (new show''') () (Mul (Var "a", Add (Int 1, Var "b"))) -- : string = "a * 1 + b" +Line 1, characters 14-18: +Error: Unbound value expr +Hint: Did you mean exp? ]} Method "`c_Add`" takes four arguments: @@ -270,14 +209,9 @@ Finally, we may want to provide a complete infix representation (including a min method c_Mul _ _ x y = enclose "*" 2 x y method c_Add _ _ x y = enclose "+" 1 x y end;; -class show4 : - (unit -> expr -> string) -> - object - method c_Add : unit -> expr -> expr -> expr -> string - method c_Int : unit -> expr -> int -> string - method c_Mul : unit -> expr -> expr -> expr -> string - method c_Var : unit -> expr -> string -> string - end +Line 13, characters 15-22: +Error: Unbound class show''' +Hint: Did you mean show4? ]} On the final note for this example we point out that all these flavors of "show" transformation coexist simultaneously; any of them can be used as a starting point for further adjustments. @@ -295,39 +229,6 @@ type expr = | Mul of expr * expr | Int of int | Var of string -class virtual ['inh, 'extra, 'syn] expr_t : - object - method virtual c_Add : 'inh -> 'extra -> expr -> expr -> 'syn - method virtual c_Int : 'inh -> 'extra -> int -> 'syn - method virtual c_Mul : 'inh -> 'extra -> expr -> expr -> 'syn - method virtual c_Var : 'inh -> 'extra -> string -> 'syn - end -val gcata_expr : ('a, expr, 'b) #expr_t -> 'a -> expr -> 'b = <fun> -class ['syn, 'a] foldl_expr_t : - ('syn -> expr -> 'syn) -> - object - constraint 'a = expr - method c_Add : 'syn -> expr -> expr -> expr -> 'syn - method c_Int : 'syn -> expr -> int -> 'syn - method c_Mul : 'syn -> expr -> expr -> expr -> 'syn - method c_Var : 'syn -> expr -> string -> 'syn - end -val foldl_expr : 'a -> expr -> 'a = <fun> -class ['a] show_expr_t : - (unit -> expr -> string) -> - object - constraint 'a = expr - method c_Add : unit -> expr -> expr -> expr -> string - method c_Int : unit -> expr -> int -> string - method c_Mul : unit -> expr -> expr -> expr -> string - method c_Var : unit -> expr -> string -> string - end -val expr : - (('a, expr, 'b) #expr_t -> 'a -> expr -> 'b, - < foldl : 'c -> expr -> 'c; show : expr -> string >, - (('d -> expr -> 'e) -> ('d, expr, 'e) #expr_t) -> 'd -> expr -> 'e) - GT.t = {GT.gcata = <fun>; plugins = <obj>; fix = <fun>} -val show_expr : expr -> string = <fun> ]} With this plugin enabled we can easily express what we want: @@ -341,17 +242,13 @@ With this plugin enabled we can easily express what we want: inherit [S.t,_] foldl_expr_t fself method c_Var s _ x = S.add x s end -class vars : - (S.t -> expr -> S.t) -> - object - method c_Add : S.t -> expr -> expr -> expr -> S.t - method c_Int : S.t -> expr -> int -> S.t - method c_Mul : S.t -> expr -> expr -> expr -> S.t - method c_Var : S.t -> expr -> string -> S.t - end +Line 2, characters 13-33: +Error: Unbound class foldl_expr_t # let vars e = S.elements (GT.transform(expr) (new vars) S.empty e) -val vars : expr -> string list/2 = <fun> +Line 1, characters 39-43: +Error: Unbound value expr +Hint: Did you mean exp? ]} In the default version, [ foldl_expr_t ] is generated in such a way that inherited attribute value (in out case of type [S.t]) is simply threaded through all nodes of the data structure. This behavior as such gives us nothing; however we can redefine the "interesting case" (variable occurrence) to take this occurrence into account. @@ -366,14 +263,8 @@ The next example - expression evaluator - demonstrates the case when we implemen method c_Add s _ x y = fself s x + fself s y method c_Mul s _ x y = fself s x * fself s y end;; -class eval : - ((string -> int) -> expr -> int) -> - object - method c_Add : (string -> int) -> int -> expr -> expr -> int - method c_Int : (string -> int) -> int -> int -> int - method c_Mul : (string -> int) -> int -> expr -> expr -> int - method c_Var : (string -> int) -> int -> string -> int - end +Line 2, characters 13-43: +Error: Unbound class expr_t ]} Since we develop a new transformation, we have to take care of types for inherited and synthesized attributes (when we're extending the existing classes these types are already taken care of). Since our evaluator needs a state to bind variables, the type of inherited attribute is "`string -> int`" and the type of synthesized attribute is just "`int`". The implementations of methods are straightforward. @@ -391,50 +282,6 @@ type expr = | Mul of expr * expr | Int of int | Var of string -class virtual ['inh, 'extra, 'syn] expr_t : - object - method virtual c_Add : 'inh -> 'extra -> expr -> expr -> 'syn - method virtual c_Int : 'inh -> 'extra -> int -> 'syn - method virtual c_Mul : 'inh -> 'extra -> expr -> expr -> 'syn - method virtual c_Var : 'inh -> 'extra -> string -> 'syn - end -val gcata_expr : ('a, expr, 'b) #expr_t -> 'a -> expr -> 'b = <fun> -class ['a, 'b] gmap_expr_t : - (unit -> expr -> expr) -> - object - constraint 'a = expr - constraint 'b = expr - method c_Add : unit -> expr -> expr -> expr -> expr - method c_Int : unit -> expr -> int -> expr - method c_Mul : unit -> expr -> expr -> expr -> expr - method c_Var : unit -> expr -> string -> expr - end -class ['syn, 'a] foldl_expr_t : - ('syn -> expr -> 'syn) -> - object - constraint 'a = expr - method c_Add : 'syn -> expr -> expr -> expr -> 'syn - method c_Int : 'syn -> expr -> int -> 'syn - method c_Mul : 'syn -> expr -> expr -> expr -> 'syn - method c_Var : 'syn -> expr -> string -> 'syn - end -val foldl_expr : 'a -> expr -> 'a = <fun> -class ['a] show_expr_t : - (unit -> expr -> string) -> - object - constraint 'a = expr - method c_Add : unit -> expr -> expr -> expr -> string - method c_Int : unit -> expr -> int -> string - method c_Mul : unit -> expr -> expr -> expr -> string - method c_Var : unit -> expr -> string -> string - end -val expr : - (('a, expr, 'b) #expr_t -> 'a -> expr -> 'b, - < foldl : 'c -> expr -> 'c; gmap : expr -> expr; show : expr -> string >, - (('d -> expr -> 'e) -> ('d, expr, 'e) #expr_t) -> 'd -> expr -> 'e) - GT.t = {GT.gcata = <fun>; plugins = <obj>; fix = <fun>} -val gmap_expr : expr -> expr = <fun> -val show_expr : expr -> string = <fun> ]} In the first iteration we simplify additions by performing constant calculations; we also "normalize" additions in such a way, that if it has one constant operand, then this operand occupies "left" position. The normalization makes it possible to take into account the associativity of addition: @@ -454,14 +301,8 @@ In the first iteration we simplify additions by performing constant calculations inherit [_,_] gmap_expr_t fself method c_Add _ _ x y = fself () x + fself () y end -class simplify_add : - (unit -> expr -> expr) -> - object - method c_Add : unit -> expr -> expr -> expr -> expr - method c_Int : unit -> expr -> int -> expr - method c_Mul : unit -> expr -> expr -> expr -> expr - method c_Var : unit -> expr -> string -> expr - end +Line 12, characters 15-32: +Error: Unbound class gmap_expr_t ]} As we can see, we again concentrated only on the "interesting case"; the implementation of infix "`+`" may look cumbersome, but this is an essential part of the transformation. @@ -483,7 +324,12 @@ Equally, we can handle the simplification of multiplication: inherit simplify_add fself method c_Mul _ _ x y = fself () x * fself () y end -]} +][ +{err@mdx-error[ +Line 12, characters 16-28: +Error: Unbound class simplify_add +Hint: Did you mean simplify_mul? +]err}]} The class "`simplify_mul`" implements a decent simplifier; however, it overlooks the following equalities: "0*x=0", "0+x=x", and "1*x=x". These cases can be easily integrated into existing implementation: @@ -500,14 +346,9 @@ The class "`simplify_mul`" implements a decent simplifier; however, it overlooks | Mul (Int 0, _) -> Int 0 | x -> x end;; -class simplify_all : - (unit -> expr -> expr) -> - object - method c_Add : unit -> expr -> expr -> expr -> expr - method c_Int : unit -> expr -> int -> expr - method c_Mul : unit -> expr -> expr -> expr -> expr - method c_Var : unit -> expr -> string -> expr - end +Line 2, characters 13-25: +Error: Unbound class simplify_mul +Hint: Did you mean simplify_all? ]} The interesting part of this implementation is an explicit utilization of a superclass' methods.Fix
shonfeder commentedon Oct 20, 2026
bogue
The claude-reported error is a bit misleading here. Running a local build, we get the following (with output trimmed to what is strictly relevant):
When running the opam install command in a docker container, as reported, it is true that the line
ocamlfind: Packagebogue' not found` occurs, but this is downstream of the relevant fatal error:Which is also due to the invalid
DIRconfiguration."A diff shows the one-rule fix":
shonfeder commentedon Oct 20, 2026
The following packages will need upper bounds added on test running in the opam repo:
shonfeder commentedon Oct 20, 2026
Submitted all upstream fixes and added needed bounds on the opam repo.