Skip to content

Commit 7447fe0

Browse files
authored
Merge branch 'main' into ps/branch/refactor__move_bin_describe_ml_to_bin_describe_
2 parents def9d80 + de87591 commit 7447fe0

File tree

24 files changed

+284
-89
lines changed

24 files changed

+284
-89
lines changed

CHANGES.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ Unreleased
3333
- Respect `-p` / `--only-packages` for `melange.emit` artifacts (#7849,
3434
@anmonteiro)
3535

36+
- Fix scanning of Coq installed files (@ejgallego, reported by
37+
@palmskog, #7895 , fixes #7893)
38+
3639
3.8.1 (2023-06-05)
3740
------------------
3841

otherlibs/stdune/src/table.mli

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,9 @@ val filteri_inplace : ('a, 'b) t -> f:(key:'a -> data:'b -> bool) -> unit
5959
val length : (_, _) t -> int
6060

6161
module Multi : sig
62-
type ('k, 'v) t
62+
type ('k, 'v) t := ('k, 'v list) t
6363

6464
val cons : ('k, 'v) t -> 'k -> 'v -> unit
6565

6666
val find : ('k, 'v) t -> 'k -> 'v list
6767
end
68-
with type ('k, 'v) t := ('k, 'v list) t

otherlibs/stdune/src/type_eq.mli

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ val cast : ('a, 'b) t -> 'a -> 'b
88
at runtime if two identifiers are equal, and if so to get a proof of
99
equality of their types. *)
1010
module Id : sig
11-
type ('a, 'b) eq
11+
type ('a, 'b) eq := ('a, 'b) t
1212

1313
type 'a t
1414

@@ -20,4 +20,3 @@ module Id : sig
2020

2121
val same : 'a t -> 'b t -> ('a, 'b) eq option
2222
end
23-
with type ('a, 'b) eq := ('a, 'b) t

src/dune_rules/coq/coq_lib.ml

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ and Legacy : sig
152152
; implicit : bool (* Only useful for the stdlib *)
153153
; installed_root : Path.t (* ; libraries : (Loc.t * Lib.t) list Resolve.t *)
154154
; vo : Path.t list
155-
; cmxs : Path.t list
155+
; cmxs_directories : Path.t list
156156
}
157157

158158
val to_dyn : t -> Dyn.t
@@ -171,27 +171,24 @@ end = struct
171171
; implicit : bool (* Only useful for the stdlib *)
172172
; installed_root : Path.t (* ; libraries : (Loc.t * Lib.t) list Resolve.t *)
173173
; vo : Path.t list
174-
; cmxs : Path.t list
174+
; cmxs_directories : Path.t list
175175
}
176176

177-
let to_dyn { boot_id; id; implicit; installed_root; vo; cmxs } =
177+
let to_dyn { boot_id; id; implicit; installed_root; vo; cmxs_directories } =
178178
Dyn.record
179179
[ ("boot_id", Dyn.option Id.to_dyn boot_id)
180180
; ("id", Id.to_dyn id)
181181
; ("implicit", Dyn.bool implicit)
182182
; ("installed_root", Path.to_dyn installed_root)
183183
; ("vo", Dyn.list Path.to_dyn vo)
184-
; ("cmxs", Dyn.list Path.to_dyn cmxs)
185-
(* ; ( "libraries" *)
186-
(* , Resolve.to_dyn (Dyn.list (Dyn.pair Loc.to_dyn Lib.to_dyn)) libraries *)
187-
(* ) *)
184+
; ("cmxs_directories", Dyn.list Path.to_dyn cmxs_directories)
188185
]
189186

190187
let implicit t = t.implicit
191188

192189
let installed_root t = t.installed_root
193190

194-
let cmxs_directories t = t.cmxs
191+
let cmxs_directories t = t.cmxs_directories
195192

196193
let vo t = t.vo
197194
end
@@ -504,16 +501,17 @@ module DB = struct
504501
let create_from_stanza coq_db db dir stanza =
505502
Memo.exec memo (coq_db, db, dir, stanza)
506503

507-
(* XXX: Memoize? This is pretty cheap so not sure worth the cost *)
504+
(* XXX: Memoize? This is pretty cheap so not sure worth the cost,
505+
still called too much I have observed, suspicious! *)
508506
let create_from_coqpath ~boot_id cp =
509507
let name = Coq_path.name cp in
510508
let installed_root = Coq_path.path cp in
511509
let implicit = Coq_path.stdlib cp in
512-
let cmxs = Coq_path.cmxs cp in
510+
let cmxs_directories = Coq_path.cmxs_directories cp in
513511
let vo = Coq_path.vo cp in
514512
let id = Id.create ~path:installed_root ~name:(Loc.none, name) in
515513
Resolve.Memo.return
516-
{ Legacy.boot_id; id; implicit; installed_root; vo; cmxs }
514+
{ Legacy.boot_id; id; implicit; installed_root; vo; cmxs_directories }
517515

518516
module Resolve_result_no_redirect = struct
519517
(** In our second iteration, we remove all the redirects *)

src/dune_rules/coq/coq_lib.mli

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,22 @@ end
1717
module Legacy : sig
1818
type t
1919

20+
(** For each legacy library, we need two pieces of data:
21+
22+
- the list of [.vo] files, this is because we need to make the call to
23+
[coqdep] depend on it. If due to external action the list of these files
24+
changes, coqdep must be re-run. Note that coqdep sometimes checks for
25+
[.vo] files and sometimes for [.v] files, which is messy (in principle
26+
only checks for [.v] files when compiling the stdlib using make, but
27+
YMMV with coqdep code).
28+
29+
In the case of a [Dune.t] lib, this list is obtained from the [src_root],
30+
via [Dir_contents.coq], maybe we should move that function here and make
31+
it common.
32+
33+
- the list of directories containing [.cmxs] files, so we can add them to
34+
the loadpath as Coq does for all [user-contrib] *)
35+
2036
(** List of vo files *)
2137
val vo : t -> Path.t list
2238

src/dune_rules/coq/coq_path.ml

Lines changed: 94 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ type t =
1212
; path : Path.t
1313
; vo : Path.t list
1414
; cmxs : Path.t list
15+
; cmxs_directories : Path.t list
1516
; stdlib : bool
1617
}
1718

@@ -23,6 +24,8 @@ let vo t = t.vo
2324

2425
let cmxs t = t.cmxs
2526

27+
let cmxs_directories t = t.cmxs_directories
28+
2629
let stdlib t = t.stdlib
2730

2831
let config_path_exn coq_config key =
@@ -48,98 +51,136 @@ let config_path ~default coq_config key =
4851
(* This should never happen *)
4952
Code_error.raise "key is not a path" [ (key, Coq_config.Value.to_dyn path) ]
5053

51-
let stdlib_plugins_dir path =
52-
let open Memo.O in
53-
let path = Path.relative path "plugins" in
54-
let* dir_contents =
55-
Fs_memo.dir_contents (Path.as_outside_build_dir_exn path)
56-
in
57-
match dir_contents with
58-
| Error _ -> Memo.return []
59-
| Ok dir_contents ->
60-
let f (d, kind) =
61-
match kind with
62-
| File_kind.S_DIR | S_LNK -> Some (Path.relative path d)
63-
| _ -> None
64-
in
65-
Memo.return
66-
(List.filter_map ~f (Fs_cache.Dir_contents.to_list dir_contents))
67-
68-
let build_user_contrib ~cmxs ~vo ~subpath ~name =
69-
let path = subpath in
70-
{ name; path; cmxs; vo; stdlib = false }
54+
let build_user_contrib ~cmxs ~cmxs_directories ~vo ~path ~name =
55+
{ name; path; cmxs; cmxs_directories; vo; stdlib = false }
7156

7257
(* Scanning todos: blacklist? *)
73-
let scan_vo_cmxs ~path dir_contents =
58+
let scan_vo_cmxs ~dir dir_contents =
7459
let f (d, kind) =
7560
match kind with
76-
(* Skip some directories as Coq does, for now '-' and '.' *)
61+
(* Skip some files as Coq does, for now files with '-' *)
7762
| _ when String.contains d '-' -> List.Skip
78-
| _ when String.contains d '.' -> Skip
7963
| (File_kind.S_REG | S_LNK) when Filename.check_suffix d ".cmxs" ->
80-
Left (Path.relative path d)
64+
Left (Path.relative dir d)
8165
| (File_kind.S_REG | S_LNK) when Filename.check_suffix d ".vo" ->
82-
Right (Path.relative path d)
66+
Right (Path.relative dir d)
8367
| _ -> Skip
8468
in
8569
List.filter_partition_map ~f dir_contents
8670

8771
(* Note this will only work for absolute paths *)
8872
let retrieve_vo_cmxs cps =
89-
(List.concat_map ~f:cmxs cps, List.concat_map ~f:vo cps)
73+
( List.concat_map ~f:cmxs cps
74+
, List.concat_map ~f:cmxs_directories cps
75+
, List.concat_map ~f:vo cps )
76+
77+
module Scan_action = struct
78+
type ('prefix, 'res) t =
79+
dir:Path.t
80+
-> prefix:'prefix
81+
-> subresults:'res list
82+
-> (Filename.t * File_kind.t) list
83+
-> 'res list Memo.t
84+
end
85+
86+
(** [scan_path ~f ~acc ~prefix ~dir dir_contents] Given
87+
[f ~dir
88+
~prefix ~subresults dir_contents], [scan_path] will call [f]
89+
forall the subdirs of [dir] with [dir] set to the subpath, [prefix] set to
90+
[acc prefix d] for each subdirectory [d] and [subresults] the results of the
91+
scanning of children directories *)
92+
let rec scan_path ~(f : ('prefix, 'res) Scan_action.t) ~acc ~prefix ~dir
93+
dir_contents : 'a list Memo.t =
94+
let open Memo.O in
95+
let f (d, kind) =
96+
match kind with
97+
(* We skip directories starting by . , this is mainly to avoid
98+
.coq-native *)
99+
| (File_kind.S_DIR | S_LNK) when d.[0] = '.' -> Memo.return []
100+
(* Need to check the link resolves to a directory! *)
101+
| File_kind.S_DIR | S_LNK -> (
102+
let dir = Path.relative dir d in
103+
let* dir_contents =
104+
Fs_memo.dir_contents (Path.as_outside_build_dir_exn dir)
105+
in
106+
match dir_contents with
107+
| Error _ -> Memo.return []
108+
| Ok dir_contents ->
109+
let dir_contents = Fs_cache.Dir_contents.to_list dir_contents in
110+
let prefix = acc prefix d in
111+
let* subresults = scan_path ~f ~acc ~prefix ~dir dir_contents in
112+
f ~dir ~prefix ~subresults dir_contents)
113+
| _ -> Memo.return []
114+
in
115+
Memo.List.concat_map ~f dir_contents
90116

91-
(** [scan_user_path ~prefix path] Note that we already have very similar
92-
functionality in [Dir_status] *)
93-
let rec scan_path ~f ~acc ~prefix path : 'a list Memo.t =
117+
let scan_path ~f ~acc ~prefix dir =
94118
let open Memo.O in
95119
let* dir_contents =
96-
Fs_memo.dir_contents (Path.as_outside_build_dir_exn path)
120+
Fs_memo.dir_contents (Path.as_outside_build_dir_exn dir)
97121
in
98122
match dir_contents with
99123
| Error _ -> Memo.return []
100124
| Ok dir_contents ->
101125
let dir_contents = Fs_cache.Dir_contents.to_list dir_contents in
102-
let f (d, kind) =
103-
match kind with
104-
| File_kind.S_DIR | S_LNK ->
105-
let subpath = Path.relative path d in
106-
let prefix = acc prefix d in
107-
let* subpaths = scan_path ~f ~acc ~prefix subpath in
108-
f ~path ~prefix ~subpath ~subpaths dir_contents
109-
| _ -> Memo.return []
126+
scan_path ~f ~acc ~prefix ~dir dir_contents
127+
128+
(** Scan the plugins in stdlib, returns list of cmxs + list of directories with
129+
cmxs *)
130+
let scan_stdlib_plugins coqcorelib : (Path.t list * Path.t) list Memo.t =
131+
let f ~dir ~prefix:() ~subresults dir_contents =
132+
let cmxs, _ = scan_vo_cmxs ~dir dir_contents in
133+
let res =
134+
match cmxs with
135+
| [] -> subresults
136+
| _ :: _ -> (cmxs, dir) :: subresults
110137
in
111-
Memo.List.concat_map ~f dir_contents
112-
113-
let scan_user_path path =
114-
let f ~path ~prefix ~subpath ~subpaths dir_contents =
115-
let cmxs, vo = scan_vo_cmxs ~path dir_contents in
116-
let cmxs_r, vo_r = retrieve_vo_cmxs subpaths in
117-
let cmxs, vo = (cmxs @ cmxs_r, vo @ vo_r) in
118-
Memo.return (build_user_contrib ~cmxs ~vo ~subpath ~name:prefix :: subpaths)
138+
Memo.return res
139+
in
140+
let pluginsdir = Path.relative coqcorelib "plugins" in
141+
let acc _ _ = () in
142+
scan_path ~f ~acc ~prefix:() pluginsdir
143+
144+
(** [scan_user_path path] Note that we already have very similar functionality
145+
in [Dir_status] *)
146+
let scan_user_path root_path =
147+
let f ~dir ~prefix ~subresults dir_contents =
148+
let cmxs, vo = scan_vo_cmxs ~dir dir_contents in
149+
let cmxs_directories = if not (List.is_empty cmxs) then [ dir ] else [] in
150+
let cmxs_r, cdir_r, vo_r = retrieve_vo_cmxs subresults in
151+
let cmxs, cmxs_directories, vo =
152+
(cmxs @ cmxs_r, cmxs_directories @ cdir_r, vo @ vo_r)
153+
in
154+
Memo.return
155+
(build_user_contrib ~cmxs ~cmxs_directories ~vo ~path:dir ~name:prefix
156+
:: subresults)
119157
in
120-
scan_path path ~f ~acc:Coq_lib_name.append ~prefix:Coq_lib_name.empty
158+
scan_path ~f ~acc:Coq_lib_name.append ~prefix:Coq_lib_name.empty root_path
121159

122-
let scan_vo path =
123-
let f ~path ~prefix:_ ~subpath:_ ~subpaths dir_contents =
124-
let _, vo = scan_vo_cmxs ~path dir_contents in
125-
Memo.return (vo @ subpaths)
160+
let scan_vo root_path =
161+
let f ~dir ~prefix:() ~subresults dir_contents =
162+
let _, vo = scan_vo_cmxs ~dir dir_contents in
163+
Memo.return (vo @ subresults)
126164
in
127165
let acc _ _ = () in
128-
scan_path path ~f ~acc ~prefix:()
166+
scan_path ~f ~acc ~prefix:() root_path
129167

130168
let of_coq_install coqc =
131169
let open Memo.O in
132170
let* coq_config = Coq_config.make ~coqc:(Ok coqc) in
133171
(* Now we query for coqlib *)
134172
let coqlib_path = config_path_exn coq_config "coqlib" in
135173
let coqcorelib = config_path coq_config "coqcorelib" ~default:coqlib_path in
136-
let* cmxs = stdlib_plugins_dir coqcorelib in
174+
let* stdlib_plugs = scan_stdlib_plugins coqcorelib in
137175
let* vo = scan_vo coqlib_path in
176+
let cmxs, cmxs_directories = List.split stdlib_plugs in
177+
let cmxs = List.concat cmxs in
138178
let stdlib =
139179
{ name = Coq_lib_name.stdlib
140180
; path = Path.relative coqlib_path "theories"
141181
; vo
142182
; cmxs
183+
; cmxs_directories
143184
; stdlib = true
144185
}
145186
in

src/dune_rules/coq/coq_path.mli

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,21 @@ val name : t -> Coq_lib_name.t
1818

1919
val path : t -> Path.t
2020

21+
(** List of .vo files in a path *)
2122
val vo : t -> Path.t list
2223

24+
(** Unused for now, maybe be useful for coqdep -modules *)
2325
val cmxs : t -> Path.t list
2426

27+
(** List of directories that contain .cmxs files and thus need to be passed to
28+
Coq using -I *)
29+
val cmxs_directories : t -> Path.t list
30+
31+
(** Does the path correspond to Coq's stdlib? *)
2532
val stdlib : t -> bool
2633

34+
(** Build list of Coq paths from a Coq install ([COQLIB] and [coqc -config]) *)
2735
val of_coq_install : Context.t -> t list Memo.t
2836

29-
(** *)
37+
(** Build list of Coq paths from [COQPATH] variable *)
3038
val of_env : Env.t -> t list Memo.t
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
Test for https://github.com/ocaml/dune/issues/7893
2+
When using an installed theory with plugins, things should work fine.
3+
4+
$ dune build --root to_install @all
5+
Entering directory 'to_install'
6+
Hello
7+
Leaving directory 'to_install'
8+
$ dune install --root to_install --prefix=$PWD
9+
10+
We now build the normal theory, and should work
11+
12+
$ COQPATH=$PWD/lib/coq/user-contrib dune build --root user @all
13+
Entering directory 'user'
14+
Hello
15+
Leaving directory 'user'
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
(lang dune 3.8)
2+
(using coq 0.8)
3+
4+
(package (name global))
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
(library
2+
(name plugin)
3+
(public_name global.plugin))

0 commit comments

Comments
 (0)