Skip to content

Commit a061aa4

Browse files
committed
Don't treat toolchains like packages in Pkg_rules
Previously toolchains were treated as special packages by the package rules logic. This change removes toolchains from the package dependency graph used by package rules (but not from any other part of dune such as the solver or lockfiles). This separation lets us remove a bunch of special treatment for packages that contain toolchains. Signed-off-by: Stephen Sherratt <[email protected]>
1 parent 155e349 commit a061aa4

File tree

3 files changed

+100
-149
lines changed

3 files changed

+100
-149
lines changed

src/dune_pkg/toolchain.ml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ module Compiler_package = struct
9797
:: ([ "ocaml-system"; "ocaml-variants" ] |> List.map ~f:Package_name.of_string)
9898
;;
9999

100+
let is_compiler_package_by_name name =
101+
List.exists ~f:(Package_name.equal name) package_names
102+
;;
103+
100104
let constraint_ =
101105
let open Dune_lang in
102106
let constraint_ =

src/dune_pkg/toolchain.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ module Compiler_package : sig
88
used instead. *)
99
val package_names : Package_name.t list
1010

11+
val is_compiler_package_by_name : Package_name.t -> bool
12+
1113
(** Constraint to apply to the dependency solver to guarantee a
1214
solution that's includes a version of a compiler package that's
1315
supported by dune toolchains. *)

src/dune_rules/pkg_rules.ml

Lines changed: 94 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ module Value_list_env = struct
152152

153153
let parse_strings s = Bin.parse s |> List.map ~f:(fun s -> Value.String s)
154154
let of_env env : t = Env.to_map env |> Env.Map.map ~f:parse_strings
155+
let global () = of_env (Global.env ())
155156

156157
(* Concatenate a list of values in the style of lists found in
157158
environment variables, such as PATH *)
@@ -264,6 +265,7 @@ module Pkg = struct
264265
; build_command : Build_command.t option
265266
; install_command : Dune_lang.Action.t option
266267
; depends : t list
268+
; toolchain_depends : Dune_pkg.Toolchain.Version.t list
267269
; info : Pkg_info.t
268270
; paths : Paths.t
269271
; files_dir : Path.Build.t
@@ -355,38 +357,11 @@ module Pkg = struct
355357
List.fold_left t.exported_env ~init:env ~f:Env_update.set)
356358
;;
357359

358-
let name_is_compiler name =
359-
List.exists
360-
~f:(Dune_pkg.Package_name.equal name)
361-
Dune_pkg.Toolchain.Compiler_package.package_names
362-
;;
363-
364-
let is_compiler t = name_is_compiler t.info.name
365-
366-
(* If this package is a compiler whose version is supported by dune
367-
toolchains then returns the toolchain version, otherwise returns
368-
None. *)
369-
let as_compiler_with_version_in_toolchain_dir t =
370-
if is_compiler t
371-
then Dune_pkg.Toolchain.Version.of_package_version t.info.version
372-
else None
373-
;;
374-
375-
let is_compiler_with_version_in_toolchain_dir t =
376-
Option.is_some (as_compiler_with_version_in_toolchain_dir t)
377-
;;
378-
379360
(* Returns the version of the compiler toolchain dependen on by this
380361
package if any. *)
381362
let compiler_toolchain_version t =
382-
let module Toolchain = Dune_pkg.Toolchain in
383-
if is_compiler t
384-
then Toolchain.Version.of_package_version t.info.version
385-
else
386-
List.find_map (deps_closure t) ~f:(fun pkg ->
387-
if is_compiler pkg
388-
then Toolchain.Version.of_package_version pkg.info.version
389-
else None)
363+
List.find_map (deps_closure t) ~f:(fun { toolchain_depends; _ } ->
364+
List.hd_opt toolchain_depends)
390365
;;
391366

392367
(* If there is a compiler package in the dependency closure of this
@@ -434,8 +409,6 @@ module Pkg = struct
434409
programs or build tools (e.g. NixOS). *)
435410
Value_list_env.extend_concat_path (Value_list_env.of_env (Global.env ())) package_env
436411
;;
437-
438-
let exported_env t = Value_list_env.to_env @@ exported_value_env t
439412
end
440413

441414
module Pkg_installed = struct
@@ -1099,30 +1072,19 @@ module Action_expander = struct
10991072
;;
11001073

11011074
let build_command context (pkg : Pkg.t) =
1102-
if Pkg.is_compiler_with_version_in_toolchain_dir pkg
1103-
then
1104-
(* Ignore the build command of compiler packages supported by
1105-
dune toolchains. *)
1106-
None
1107-
else
1108-
Option.map pkg.build_command ~f:(function
1109-
| Action action -> expand context pkg action
1110-
| Dune ->
1111-
(* CR-rgrinberg: respect [dune subst] settings. *)
1112-
Command.run_dyn_prog
1113-
(Action_builder.of_memo (dune_exe context))
1114-
~dir:(Path.build pkg.paths.source_dir)
1115-
[ A "build"; A "-p"; A (Package.Name.to_string pkg.info.name) ]
1116-
|> Memo.return)
1075+
Option.map pkg.build_command ~f:(function
1076+
| Action action -> expand context pkg action
1077+
| Dune ->
1078+
(* CR-rgrinberg: respect [dune subst] settings. *)
1079+
Command.run_dyn_prog
1080+
(Action_builder.of_memo (dune_exe context))
1081+
~dir:(Path.build pkg.paths.source_dir)
1082+
[ A "build"; A "-p"; A (Package.Name.to_string pkg.info.name) ]
1083+
|> Memo.return)
11171084
;;
11181085

11191086
let install_command context (pkg : Pkg.t) =
1120-
if Pkg.is_compiler_with_version_in_toolchain_dir pkg
1121-
then
1122-
(* Ignore the install command of compiler packages supported by
1123-
dune toolchains. *)
1124-
None
1125-
else Option.map pkg.install_command ~f:(fun action -> expand context pkg action)
1087+
Option.map pkg.install_command ~f:(fun action -> expand context pkg action)
11261088
;;
11271089

11281090
let exported_env (expander : Expander.t) (env : _ Env_update.t) =
@@ -1158,7 +1120,11 @@ module rec Resolve : sig
11581120
: DB.t
11591121
-> Context_name.t
11601122
-> Loc.t * Package.Name.t
1161-
-> [ `Inside_lock_dir of Pkg.t | `System_provided ] Memo.t
1123+
-> [ `Inside_lock_dir of Pkg.t
1124+
| `System_provided
1125+
| `Toolchain of Dune_pkg.Toolchain.Version.t
1126+
]
1127+
Memo.t
11621128
end = struct
11631129
open Resolve
11641130

@@ -1167,38 +1133,47 @@ end = struct
11671133
| None -> Memo.return None
11681134
| Some { Lock_dir.Pkg.build_command; install_command; depends; info; exported_env } ->
11691135
assert (Package.Name.equal name info.name);
1170-
let* depends =
1171-
Memo.parallel_map depends ~f:(fun name ->
1172-
resolve db ctx name
1173-
>>| function
1174-
| `Inside_lock_dir pkg -> Some pkg
1175-
| `System_provided -> None)
1176-
>>| List.filter_opt
1177-
and+ files_dir =
1178-
let+ lock_dir = Lock_dir.get_path ctx >>| Option.value_exn in
1179-
Path.Build.append_source
1180-
(Context_name.build_dir ctx)
1181-
(Dune_pkg.Lock_dir.Pkg.files_dir info.name ~lock_dir)
1182-
in
1183-
let id = Pkg.Id.gen () in
1184-
let paths = Paths.make name ctx in
1185-
let t =
1186-
{ Pkg.id
1187-
; build_command
1188-
; install_command
1189-
; depends
1190-
; paths
1191-
; info
1192-
; files_dir
1193-
; exported_env = []
1194-
}
1195-
in
1196-
let+ exported_env =
1197-
let* expander = Action_expander.expander ctx t in
1198-
Memo.parallel_map exported_env ~f:(Action_expander.exported_env expander)
1136+
let is_toolchain_package =
1137+
Dune_pkg.Toolchain.Compiler_package.is_compiler_package_by_name name
11991138
in
1200-
t.exported_env <- exported_env;
1201-
Some t
1139+
(match Dune_pkg.Toolchain.Version.of_package_version info.version with
1140+
| Some package_version when is_toolchain_package ->
1141+
Memo.return (Some (`Toolchain package_version))
1142+
| _ ->
1143+
let* depends, toolchain_depends =
1144+
Memo.parallel_map depends ~f:(fun name ->
1145+
resolve db ctx name
1146+
>>| function
1147+
| `Inside_lock_dir pkg -> List.Left pkg
1148+
| `Toolchain toolchain_version -> Right toolchain_version
1149+
| `System_provided -> Skip)
1150+
>>| List.filter_partition_map ~f:Fun.id
1151+
and+ files_dir =
1152+
let+ lock_dir = Lock_dir.get_path ctx >>| Option.value_exn in
1153+
Path.Build.append_source
1154+
(Context_name.build_dir ctx)
1155+
(Dune_pkg.Lock_dir.Pkg.files_dir info.name ~lock_dir)
1156+
in
1157+
let id = Pkg.Id.gen () in
1158+
let paths = Paths.make name ctx in
1159+
let t =
1160+
{ Pkg.id
1161+
; build_command
1162+
; install_command
1163+
; depends
1164+
; toolchain_depends
1165+
; paths
1166+
; info
1167+
; files_dir
1168+
; exported_env = []
1169+
}
1170+
in
1171+
let+ exported_env =
1172+
let* expander = Action_expander.expander ctx t in
1173+
Memo.parallel_map exported_env ~f:(Action_expander.exported_env expander)
1174+
in
1175+
t.exported_env <- exported_env;
1176+
Some (`Inside_lock_dir t))
12021177
;;
12031178

12041179
let resolve =
@@ -1224,7 +1199,7 @@ end = struct
12241199
else
12251200
Memo.exec memo (db, ctx, name)
12261201
>>| function
1227-
| Some s -> `Inside_lock_dir s
1202+
| Some s -> s
12281203
| None ->
12291204
User_error.raise
12301205
~loc
@@ -1557,52 +1532,13 @@ let rule ?loc { Action_builder.With_targets.build; targets } =
15571532
Rule.make ~info:(Rule.Info.of_loc_opt loc) ~targets build |> Rules.Produce.rule
15581533
;;
15591534

1560-
(* Action which creates a fake package source in place of a compiler
1561-
package for use when a compiler from the toolchains directory will be
1562-
used instead of taking the compiler from a regular opam package. *)
1563-
let make_dummy_compiler_package_source (pkg : Pkg.t) version target =
1564-
Action.progn
1565-
[ Action.mkdir target
1566-
; Action.with_stdout_to
1567-
(Path.Build.relative target "debug_hint.txt")
1568-
(Action.echo
1569-
[ sprintf
1570-
"This file was created as a hint to people debugging issues with dune \
1571-
package management.\n\
1572-
This project attempted to download and build the compiler package: %s.%s\n\
1573-
Instead of using the complier package, dune is using the compiler \
1574-
toolchain installed at: %s"
1575-
(Dune_pkg.Package_name.to_string pkg.info.name)
1576-
(Dune_pkg.Package_version.to_string pkg.info.version)
1577-
(Dune_pkg.Toolchain.Version.toolchain_dir version
1578-
|> Path.Outside_build_dir.to_string)
1579-
])
1580-
; (* TODO: it doesn't seem like it should be necessary to generate
1581-
this file but without it dune complains *)
1582-
Action.with_stdout_to
1583-
(Path.Build.relative target "config.cache")
1584-
(Action.echo
1585-
[ "Dummy file created to placate dune's package installation rules. See the \
1586-
debug_hint.txt file for more information."
1587-
])
1588-
]
1589-
|> Action.Full.make
1590-
|> Action_builder.With_targets.return
1591-
|> Action_builder.With_targets.add_directories ~directory_targets:[ target ]
1592-
;;
1593-
15941535
let source_rules (pkg : Pkg.t) =
15951536
let+ source_deps, copy_rules =
15961537
match pkg.info.source with
15971538
| None -> Memo.return (Dep.Set.empty, [])
15981539
| Some (Fetch { url = (loc, _) as url; checksum }) ->
15991540
let fetch =
1600-
match Pkg.as_compiler_with_version_in_toolchain_dir pkg with
1601-
| Some version ->
1602-
(* Don't download the source of compiler packages supported
1603-
by dune toolchains. *)
1604-
make_dummy_compiler_package_source pkg version pkg.paths.source_dir
1605-
| None -> Fetch_rules.fetch ~target:pkg.paths.source_dir `Directory url checksum
1541+
Fetch_rules.fetch ~target:pkg.paths.source_dir `Directory url checksum
16061542
in
16071543
Memo.return (Dep.Set.of_files [ Path.build pkg.paths.source_dir ], [ loc, fetch ])
16081544
| Some (External_copy (loc, source_root)) ->
@@ -1638,8 +1574,9 @@ let source_rules (pkg : Pkg.t) =
16381574

16391575
module Compiler_dependency = struct
16401576
type t =
1577+
| Toolchain of Dune_pkg.Toolchain.Version.t
16411578
(* The lockdir specifies a compiler dependency as a package. *)
1642-
| Pkg of Pkg.t
1579+
| Inside_lock_dir of Pkg.t
16431580
(* The lockdir specifies that the system compiler toolchain will
16441581
be used rather than one managed by dune. *)
16451582
| System_provided
@@ -1658,35 +1595,34 @@ module Compiler_dependency = struct
16581595
| Some ocaml ->
16591596
let+ toolchain_pkg = Resolve.resolve db context ocaml in
16601597
(match toolchain_pkg with
1598+
| `Toolchain toolchain_version -> Toolchain toolchain_version
16611599
| `System_provided -> System_provided
1662-
| `Inside_lock_dir pkg -> Pkg pkg)
1600+
| `Inside_lock_dir pkg -> Inside_lock_dir pkg)
16631601
;;
16641602

16651603
let toolchain_version = function
1604+
| Toolchain toolchain_version -> Some toolchain_version
1605+
| Inside_lock_dir pkg ->
1606+
let module Toolchain = Dune_pkg.Toolchain in
1607+
User_warning.emit
1608+
~hints:
1609+
[ Pp.textf
1610+
"Supported versions of the compiler toolchain are: %s"
1611+
(List.map Toolchain.Version.all ~f:Toolchain.Version.to_string
1612+
|> String.enumerate_and)
1613+
]
1614+
[ Pp.textf
1615+
"Project depends on version %s of the compiler toolchain, which is not \
1616+
supported by dune. Dune will attempt to use a compiler toolchain from your \
1617+
PATH."
1618+
(Package_version.to_string pkg.info.version)
1619+
];
1620+
None
16661621
| System_provided ->
16671622
(* In this case it's expected that the user have the compiler
16681623
toolchain in their PATH already *)
16691624
None
16701625
| No_compiler_dependency -> Some Dune_pkg.Toolchain.Version.latest
1671-
| Pkg pkg ->
1672-
let module Toolchain = Dune_pkg.Toolchain in
1673-
let toolchain_version_opt = Toolchain.Version.of_package_version pkg.info.version in
1674-
if Option.is_none toolchain_version_opt
1675-
then
1676-
User_warning.emit
1677-
~hints:
1678-
[ Pp.textf
1679-
"Supported versions of the compiler toolchain are: %s"
1680-
(List.map Toolchain.Version.all ~f:Toolchain.Version.to_string
1681-
|> String.enumerate_and)
1682-
]
1683-
[ Pp.textf
1684-
"Project depends on version %s of the compiler toolchain, which is not \
1685-
supported by dune. Dune will attempt to use a compiler toolchain from \
1686-
your PATH."
1687-
(Package_version.to_string pkg.info.version)
1688-
];
1689-
toolchain_version_opt
16901626
;;
16911627

16921628
let toolchain_version_ensure_installed t =
@@ -1821,6 +1757,13 @@ let setup_package_rules context ~dir ~pkg_name : Gen_rules.result Memo.t =
18211757
Resolve.resolve db context (Loc.none, name)
18221758
>>| function
18231759
| `Inside_lock_dir pkg -> pkg
1760+
| `Toolchain _ ->
1761+
User_error.raise
1762+
(* TODO loc, toolchain info *)
1763+
[ Pp.textf
1764+
"There are no rules for %S because it's provided by the toolchain"
1765+
(Package.Name.to_string name)
1766+
]
18241767
| `System_provided ->
18251768
User_error.raise
18261769
(* TODO loc *)
@@ -1870,7 +1813,9 @@ let ocaml_toolchain context =
18701813
| Some toolchain_version ->
18711814
let env =
18721815
match compiler_dependency with
1873-
| Pkg pkg -> Env.extend_env (Global.env ()) (Pkg.exported_env pkg)
1816+
| Toolchain toolchain_version ->
1817+
Value_list_env.(
1818+
add_toolchain_bin_dir_to_path (global ()) toolchain_version |> to_env)
18741819
| _ -> Global.env ()
18751820
in
18761821
Ocaml_toolchain.of_toolchain_version toolchain_version context env >>| Option.some
@@ -1884,7 +1829,7 @@ let all_packages context =
18841829
Resolve.resolve db context (Loc.none, package)
18851830
>>| function
18861831
| `Inside_lock_dir pkg -> Some pkg
1887-
| `System_provided -> None)
1832+
| `System_provided | `Toolchain _ -> None)
18881833
>>| List.filter_opt
18891834
>>| Pkg.top_closure
18901835
;;
@@ -1938,7 +1883,7 @@ let find_package ctx pkg =
19381883
let* db = DB.get ctx in
19391884
Resolve.resolve db ctx (Loc.none, pkg)
19401885
>>| (function
1941-
| `System_provided -> Action_builder.return ()
1886+
| `System_provided | `Toolchain _ -> Action_builder.return ()
19421887
| `Inside_lock_dir pkg ->
19431888
let open Action_builder.O in
19441889
let+ _cookie = (Pkg_installed.of_paths pkg.paths).cookie in

0 commit comments

Comments
 (0)