Skip to content

Commit ae776d3

Browse files
authored
feat: %{cmt} and %{cmti} artifact variables (#12634)
* feat: %{cmt} and %{cmti} artifact variables Signed-off-by: Ali Caglayan <[email protected]> * refactor: inline Cm_kind.Dict usage Signed-off-by: Ali Caglayan <[email protected]> * Revert "refactor: inline Cm_kind.Dict usage" This reverts commit 7604432. Signed-off-by: Rudi Grinberg <[email protected]> * fix: punt on all the refactoring Signed-off-by: Rudi Grinberg <[email protected]> --------- Signed-off-by: Ali Caglayan <[email protected]> Signed-off-by: Rudi Grinberg <[email protected]>
1 parent 8329919 commit ae776d3

File tree

7 files changed

+241
-19
lines changed

7 files changed

+241
-19
lines changed

doc/advanced/variables-artifacts.rst

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,18 @@ interpreted relative to the current directory:
2323
``<path>`` should be the name of a module as specified in a ``(modules)``
2424
field.
2525

26-
- ``cma:<path>`` and ``cmxa:<path>`` expands to the corresponding
27-
artifact's path for the library specified by ``<path>``. The basename of ``<path>``
26+
- ``cma:<path>`` and ``cmxa:<path>`` expands to the corresponding artifact's
27+
path for the library specified by ``<path>``. The basename of ``<path>``
2828
should be the name of the library as specified in the ``(name)`` field of a
2929
``library`` stanza (*not* its public name).
3030

31+
- ``cmt:<path>`` and ``cmti:<path>`` expand to the corresponding compiled
32+
annotation files for the module specified by ``<path>``. These files contain
33+
the typed abstract syntax tree with precise location information and type
34+
annotations, generated with the ``-bin-annot`` flag. They are particularly
35+
useful for IDE tools to provide tooltips and type information.
36+
37+
.. versionadded:: 3.21
38+
3139
In each case, the expansion of the variable is a path pointing inside the build
3240
context (i.e., ``_build/<context>``).

doc/changes/added/12634.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
- Add support for `%{cmt:...}` and `%{cmti:...}` variables to reference
2+
compiled annotation files (.cmt and .cmti) containing typed abstract syntax
3+
trees with location and type information. (#12634, grants #12633, @Alizter)

src/dune_lang/pform.ml

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -219,32 +219,60 @@ end
219219
module Artifact = struct
220220
open Ocaml
221221

222+
type mod_ =
223+
| Cm_kind of Ocaml.Cm_kind.t
224+
| Cmt
225+
| Cmti
226+
227+
let dyn_of_mod_ =
228+
let open Dyn in
229+
function
230+
| Cm_kind x -> Ocaml.Cm_kind.to_dyn x
231+
| Cmt -> variant "Cmt" []
232+
| Cmti -> variant "Cmti" []
233+
;;
234+
222235
type t =
223-
| Mod of Cm_kind.t
236+
| Mod of mod_
224237
| Lib of Mode.t
225238

239+
let compare_mod x y =
240+
match x, y with
241+
| Cm_kind x, Cm_kind y -> Ocaml.Cm_kind.compare x y
242+
| Cm_kind _, _ -> Lt
243+
| _, Cm_kind _ -> Gt
244+
| Cmt, Cmt -> Eq
245+
| Cmt, _ -> Lt
246+
| _, Cmt -> Gt
247+
| Cmti, Cmti -> Eq
248+
;;
249+
226250
let compare x y =
227251
match x, y with
228-
| Mod x, Mod y -> Cm_kind.compare x y
252+
| Mod x, Mod y -> compare_mod x y
229253
| Mod _, _ -> Lt
230254
| _, Mod _ -> Gt
231255
| Lib x, Lib y -> Mode.compare x y
232256
;;
233257

234258
let ext = function
235-
| Mod cm_kind -> Cm_kind.ext cm_kind
259+
| Mod Cmt -> ".cmt"
260+
| Mod Cmti -> ".cmti"
261+
| Mod (Cm_kind cm_kind) -> Cm_kind.ext cm_kind
236262
| Lib mode -> Mode.compiled_lib_ext mode
237263
;;
238264

239265
let all =
240-
List.map ~f:(fun kind -> Mod kind) Cm_kind.all
241-
@ List.map ~f:(fun mode -> Lib mode) Mode.all
266+
Mod Cmt
267+
:: Mod Cmti
268+
:: (List.map ~f:(fun kind -> Mod (Cm_kind kind)) Cm_kind.all
269+
@ List.map ~f:(fun mode -> Lib mode) Mode.all)
242270
;;
243271

244272
let to_dyn a =
245273
let open Dyn in
246274
match a with
247-
| Mod cm_kind -> variant "Mod" [ Cm_kind.to_dyn cm_kind ]
275+
| Mod cm_kind -> variant "Mod" [ dyn_of_mod_ cm_kind ]
248276
| Lib mode -> variant "Lib" [ Mode.to_dyn mode ]
249277
;;
250278
end
@@ -610,7 +638,13 @@ module Env = struct
610638
let macros =
611639
let macro (x : Macro.t) = No_info x in
612640
let artifact x =
613-
String.drop (Artifact.ext x) 1, since ~version:(2, 0) (Macro.Artifact x)
641+
let name = String.drop (Artifact.ext x) 1 in
642+
let version =
643+
match x with
644+
| Mod Cmt | Mod Cmti -> 3, 21
645+
| _ -> 2, 0
646+
in
647+
name, since ~version (Macro.Artifact x)
614648
in
615649
String.Map.of_list_exn
616650
([ "exe", macro Exe

src/dune_lang/pform.mli

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,13 @@ module Var : sig
101101
end
102102

103103
module Artifact : sig
104+
type mod_ =
105+
| Cm_kind of Ocaml.Cm_kind.t
106+
| Cmt
107+
| Cmti
108+
104109
type t =
105-
| Mod of Ocaml.Cm_kind.t
110+
| Mod of mod_
106111
| Lib of Ocaml.Mode.t
107112

108113
val compare : t -> t -> Ordering.t

src/dune_rules/expander.ml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,12 @@ let expand_artifact ~source t artifact arg =
191191
(match Artifacts_obj.lookup_module artifacts name with
192192
| None -> does_not_exist ~what:"Module" (Module_name.to_string name)
193193
| Some (t, m) ->
194-
(match Obj_dir.Module.cm_file t m ~kind:(Ocaml kind) with
194+
(match
195+
match kind with
196+
| Cm_kind kind -> Obj_dir.Module.cm_file t m ~kind:(Ocaml kind)
197+
| Cmt -> Obj_dir.Module.cmt_file t m ~cm_kind:(Ocaml Cmi) ~ml_kind:Impl
198+
| Cmti -> Some (Obj_dir.Module.cmti_file t m ~cm_kind:(Ocaml Cmi))
199+
with
195200
| None -> Action_builder.return [ Value.String "" ]
196201
| Some path -> dep (Path.build path)))
197202
| Lib mode ->

src/ocaml/cm_kind.ml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ let choose cmi cmo cmx = function
2727
let ext = choose ".cmi" ".cmo" ".cmx"
2828
let source = choose Ml_kind.Intf Impl Impl
2929

30+
let to_dyn =
31+
let open Dyn in
32+
function
33+
| Cmi -> variant "cmi" []
34+
| Cmo -> variant "cmo" []
35+
| Cmx -> variant "cmx" []
36+
;;
37+
3038
module Dict = struct
3139
type 'a t =
3240
{ cmi : 'a
@@ -43,11 +51,3 @@ module Dict = struct
4351
let of_func f = { cmi = f ~cm_kind:Cmi; cmo = f ~cm_kind:Cmo; cmx = f ~cm_kind:Cmx }
4452
let make_all x = { cmi = x; cmo = x; cmx = x }
4553
end
46-
47-
let to_dyn =
48-
let open Dyn in
49-
function
50-
| Cmi -> variant "cmi" []
51-
| Cmo -> variant "cmo" []
52-
| Cmx -> variant "cmx" []
53-
;;
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
Test that %{cmt:...} and %{cmti:...} variables work correctly.
2+
3+
$ cat > dune-project <<EOF
4+
> (lang dune 3.20)
5+
> EOF
6+
7+
Create a library with both .ml and .mli files:
8+
9+
$ cat > mylib.mli <<EOF
10+
> val hello : string
11+
> EOF
12+
13+
$ cat > mylib.ml <<EOF
14+
> let hello = "world"
15+
> EOF
16+
17+
$ cat > dune <<EOF
18+
> (library
19+
> (name mylib))
20+
>
21+
> (rule
22+
> (alias show-cmt)
23+
> (deps %{cmt:mylib})
24+
> (action
25+
> (echo "cmt file: %{cmt:mylib}\n")))
26+
>
27+
> (rule
28+
> (alias show-cmti)
29+
> (deps %{cmti:mylib})
30+
> (action
31+
> (echo "cmti file: %{cmti:mylib}\n")))
32+
> EOF
33+
34+
This feature is guarded behind dune lang 3.21:
35+
36+
$ dune build @show-cmt @show-cmti
37+
File "dune", line 6, characters 7-19:
38+
6 | (deps %{cmt:mylib})
39+
^^^^^^^^^^^^
40+
Error: %{cmt:..} is only available since version 3.21 of the dune language.
41+
Please update your dune-project file to have (lang dune 3.21).
42+
[1]
43+
44+
$ cat > dune-project <<EOF
45+
> (lang dune 3.21)
46+
> EOF
47+
48+
Build and check that cmt and cmti files are found:
49+
50+
$ dune build @show-cmt
51+
cmt file: .mylib.objs/byte/mylib.cmt
52+
53+
$ dune build @show-cmti
54+
cmti file: .mylib.objs/byte/mylib.cmti
55+
56+
Test with a module that has only implementation (no interface):
57+
58+
$ cat > only_impl.ml <<EOF
59+
> let x = 42
60+
> EOF
61+
62+
$ cat >> dune <<EOF
63+
> (rule
64+
> (alias show-impl-only-cmt)
65+
> (deps %{cmt:only_impl})
66+
> (action
67+
> (echo "impl-only cmt: %{cmt:only_impl}\n")))
68+
>
69+
> (rule
70+
> (alias show-impl-only-cmti)
71+
> (deps %{cmti:only_impl})
72+
> (action
73+
> (echo "impl-only cmti: %{cmti:only_impl}\n")))
74+
> EOF
75+
76+
$ dune build @show-impl-only-cmt
77+
impl-only cmt: .mylib.objs/byte/mylib__Only_impl.cmt
78+
79+
$ dune build @show-impl-only-cmti
80+
impl-only cmti: .mylib.objs/byte/mylib__Only_impl.cmt
81+
82+
Test with a module that has only interface (no implementation):
83+
84+
$ cat > only_intf.mli <<EOF
85+
> val y : int
86+
> EOF
87+
88+
$ cat > dune <<EOF
89+
> (library
90+
> (name mylib)
91+
> (modules_without_implementation only_intf))
92+
>
93+
> (rule
94+
> (alias show-intf-only-cmt)
95+
> (deps %{cmt:only_intf})
96+
> (action
97+
> (echo "intf-only cmt: %{cmt:only_intf}\n")))
98+
>
99+
> (rule
100+
> (alias show-intf-only-cmti)
101+
> (deps %{cmti:only_intf})
102+
> (action
103+
> (echo "intf-only cmti: %{cmti:only_intf}\n")))
104+
> EOF
105+
106+
$ dune build @show-intf-only-cmt
107+
Error: No rule found for .
108+
-> required by alias show-intf-only-cmt in dune:5
109+
[1]
110+
111+
$ dune build @show-intf-only-cmti
112+
intf-only cmti: .mylib.objs/byte/mylib__Only_intf.cmti
113+
114+
Test error when module does not exist:
115+
116+
$ cat >> dune <<EOF
117+
> (alias
118+
> (name test-nonexistent)
119+
> (deps %{cmt:nonexistent}))
120+
> EOF
121+
122+
$ dune build @test-nonexistent
123+
File "dune", line 18, characters 7-25:
124+
18 | (deps %{cmt:nonexistent}))
125+
^^^^^^^^^^^^^^^^^^
126+
Error: Module Nonexistent does not exist.
127+
[1]
128+
129+
Test with native-only library (bytecode disabled):
130+
131+
$ cat > native_lib.ml <<EOF
132+
> let z = 100
133+
> EOF
134+
135+
$ cat > dune <<EOF
136+
> (library
137+
> (name native_lib)
138+
> (modules native_lib)
139+
> (modes native))
140+
>
141+
> (rule
142+
> (alias show-native-cmt)
143+
> (deps %{cmt:native_lib})
144+
> (action
145+
> (echo "native-lib cmt: %{cmt:native_lib}\n")))
146+
> EOF
147+
148+
$ dune build @show-native-cmt --display short
149+
ocamlc .native_lib.objs/byte/native_lib.{cmi,cmo,cmt}
150+
native-lib cmt: .native_lib.objs/byte/native_lib.cmt
151+
152+
$ cat > native_lib.mli <<EOF
153+
> val z : int
154+
> EOF
155+
156+
$ cat >> dune <<EOF
157+
> (rule
158+
> (alias show-native-cmti)
159+
> (deps %{cmti:native_lib})
160+
> (action
161+
> (echo "native-lib cmti: %{cmti:native_lib}\n")))
162+
> EOF
163+
164+
$ dune build @show-native-cmti --display short
165+
ocamlc .native_lib.objs/byte/native_lib.{cmi,cmti}
166+
native-lib cmti: .native_lib.objs/byte/native_lib.cmti
167+

0 commit comments

Comments
 (0)