Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 017d26f

Browse files
committedJan 25, 2021
Toggle interface generation with (executables_implicit_empty_intf)
Signed-off-by: Craig Ferguson <me@craigfe.io>
1 parent b9082b7 commit 017d26f

File tree

13 files changed

+64
-23
lines changed

13 files changed

+64
-23
lines changed
 

‎doc/dune-files.rst

+22-6
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,24 @@ Starting from dune 2.0, dune mangles compilation units of executables by
9191
default. However, this can still be turned off using ``(wrapped_executables
9292
false)``
9393

94+
.. _executables_implicit_empty_intf:
95+
96+
executables_implicit_empty_intf
97+
-------------------------------
98+
99+
By default, executables defined via ``(executables(s) ...)`` or ``(test(s)
100+
...)`` stanzas are compiled with the interface file provided (e.g. ``.mli`` or
101+
``rei``). Since these modules cannot be used as library dependencies, it's
102+
common to give them empty interface files to strengthen the compiler's ability
103+
to detect unused values in these modules.
104+
105+
Starting from dune 2.8, an option is available to automatically generate empty
106+
interface files for executables and tests that don't already have them:
107+
108+
.. code:: scheme
109+
110+
(executables_implicit_empty_intf true)
111+
94112
.. _explicit-js-mode:
95113

96114
explicit_js_mode
@@ -633,9 +651,8 @@ binary at the same place as where ``ocamlc`` was found.
633651
Executables can also be linked as object or shared object files. See
634652
`linking modes`_ for more information.
635653

636-
Starting from dune 2.8, executable modules without interface files (e.g. `.mli`,
637-
`.rei`) are compiled against empty interfaces in order to improve dead code
638-
detection.
654+
Starting from dune 2.8, it's possible to automatically generate empty interface
655+
files for executables. See `executables_implicit_empty_intf`_.
639656

640657
``<optional-fields>`` are:
641658

@@ -1348,9 +1365,8 @@ running dune runtest you can use the following stanza:
13481365
(libraries alcotest mylib)
13491366
(action (run %{test} -e)))
13501367
1351-
Starting from dune 2.8, test modules without interface files (e.g. `.mli`,
1352-
`.rei`) are compiled against empty interfaces in order to improve dead code
1353-
detection.
1368+
Starting from dune 2.8, it's possible to automatically generate empty interface
1369+
files for test executables. See `executables_implicit_empty_intf`_.
13541370

13551371
test
13561372
----

‎src/dune_engine/dune_project.ml

+20
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ type t =
159159
; parsing_context : Univ_map.t
160160
; implicit_transitive_deps : bool
161161
; wrapped_executables : bool
162+
; executables_implicit_empty_intf : bool
162163
; dune_version : Dune_lang.Syntax.Version.t
163164
; generate_opam_files : bool
164165
; use_standard_c_and_cxx_flags : bool option
@@ -210,6 +211,7 @@ let to_dyn
210211
; packages
211212
; implicit_transitive_deps
212213
; wrapped_executables
214+
; executables_implicit_empty_intf
213215
; dune_version
214216
; generate_opam_files
215217
; use_standard_c_and_cxx_flags
@@ -232,6 +234,7 @@ let to_dyn
232234
(Package.Name.Map.to_list packages) )
233235
; ("implicit_transitive_deps", bool implicit_transitive_deps)
234236
; ("wrapped_executables", bool wrapped_executables)
237+
; ("executables_implicit_empty_intf", bool executables_implicit_empty_intf)
235238
; ("dune_version", Dune_lang.Syntax.Version.to_dyn dune_version)
236239
; ("generate_opam_files", bool generate_opam_files)
237240
; ("use_standard_c_and_cxx_flags", option bool use_standard_c_and_cxx_flags)
@@ -550,6 +553,9 @@ let implicit_transitive_deps_default ~lang:_ = true
550553
let wrapped_executables_default ~(lang : Lang.Instance.t) =
551554
lang.version >= (2, 0)
552555

556+
let executables_implicit_empty_intf_default ~(lang : Lang.Instance.t) =
557+
lang.version >= (3, 0)
558+
553559
let strict_package_deps_default ~(lang : Lang.Instance.t) =
554560
lang.version >= (3, 0)
555561

@@ -593,6 +599,9 @@ let infer ~dir packages =
593599
in
594600
let implicit_transitive_deps = implicit_transitive_deps_default ~lang in
595601
let wrapped_executables = wrapped_executables_default ~lang in
602+
let executables_implicit_empty_intf =
603+
executables_implicit_empty_intf_default ~lang
604+
in
596605
let explicit_js_mode = explicit_js_mode_default ~lang in
597606
let strict_package_deps = strict_package_deps_default ~lang in
598607
let root = dir in
@@ -604,6 +613,7 @@ let infer ~dir packages =
604613
; version = None
605614
; implicit_transitive_deps
606615
; wrapped_executables
616+
; executables_implicit_empty_intf
607617
; stanza_parser
608618
; project_file
609619
; extension_args
@@ -695,6 +705,9 @@ let parse ~dir ~lang ~opam_packages ~file ~dir_status =
695705
"It is useless since the Merlin configurations are not ambiguous \
696706
anymore."
697707
loc lang.syntax (2, 8) ~what:"This field"
708+
and+ executables_implicit_empty_intf =
709+
field_o_b "executables_implicit_empty_intf"
710+
~check:(Dune_lang.Syntax.since Stanza.syntax (2, 8))
698711
and+ () = Dune_lang.Versioned_file.no_more_lang
699712
and+ generate_opam_files =
700713
field_o_b "generate_opam_files"
@@ -805,6 +818,10 @@ let parse ~dir ~lang ~opam_packages ~file ~dir_status =
805818
Option.value wrapped_executables
806819
~default:(wrapped_executables_default ~lang)
807820
in
821+
let executables_implicit_empty_intf =
822+
Option.value executables_implicit_empty_intf
823+
~default:(executables_implicit_empty_intf_default ~lang)
824+
in
808825
let strict_package_deps =
809826
Option.value strict_package_deps
810827
~default:(strict_package_deps_default ~lang)
@@ -864,6 +881,7 @@ let parse ~dir ~lang ~opam_packages ~file ~dir_status =
864881
; parsing_context
865882
; implicit_transitive_deps
866883
; wrapped_executables
884+
; executables_implicit_empty_intf
867885
; dune_version
868886
; generate_opam_files
869887
; use_standard_c_and_cxx_flags
@@ -913,6 +931,8 @@ let set_parsing_context t parser =
913931

914932
let wrapped_executables t = t.wrapped_executables
915933

934+
let executables_implicit_empty_intf t = t.executables_implicit_empty_intf
935+
916936
let () =
917937
let open Dune_lang.Decoder in
918938
Extension.register_simple Action_plugin.syntax (return []);

‎src/dune_engine/dune_project.mli

+2
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,8 @@ val dune_version : t -> Dune_lang.Syntax.Version.t
173173

174174
val wrapped_executables : t -> bool
175175

176+
val executables_implicit_empty_intf : t -> bool
177+
176178
val strict_package_deps : t -> bool
177179

178180
val cram : t -> bool

‎src/dune_rules/exe_rules.ml

+6-6
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,8 @@ let with_empty_intf ~sctx ~dir module_ =
102102
Super_context.add_rule sctx ~dir rule;
103103
Module.add_file module_ Ml_kind.Intf (Module.File.make Dialect.ocaml name)
104104

105-
let executables_rules ~sctx ~dune_version ~dir ~expander ~dir_contents ~scope
106-
~compile_info ~embed_in_plugin_libraries (exes : Dune_file.Executables.t) =
105+
let executables_rules ~sctx ~dir ~expander ~dir_contents ~scope ~compile_info
106+
~embed_in_plugin_libraries (exes : Dune_file.Executables.t) =
107107
(* Use "eobjs" rather than "objs" to avoid a potential conflict with a library
108108
of the same name *)
109109
let modules, obj_dir =
@@ -131,7 +131,8 @@ let executables_rules ~sctx ~dune_version ~dir ~expander ~dir_contents ~scope
131131
let name = Module.name m in
132132
let m = Pp_spec.pp_module_as pp name m in
133133
let add_empty_intf =
134-
dune_version >= (2, 8)
134+
let project = Scope.project scope in
135+
Dune_project.executables_implicit_empty_intf project
135136
&& List.mem name ~set:executable_names
136137
&& not (Module.has m ~ml_kind:Intf)
137138
in
@@ -218,9 +219,8 @@ let rules ~sctx ~dir ~dir_contents ~scope ~expander
218219
(exes : Dune_file.Executables.t) =
219220
let compile_info = compile_info ~scope exes in
220221
let f () =
221-
executables_rules exes ~sctx ~dune_version ~dir ~dir_contents ~scope
222-
~expander ~compile_info
223-
~embed_in_plugin_libraries:exes.embed_in_plugin_libraries
222+
executables_rules exes ~sctx ~dir ~dir_contents ~scope ~expander
223+
~compile_info ~embed_in_plugin_libraries:exes.embed_in_plugin_libraries
224224
in
225225
Buildable_rules.gen_select_rules sctx compile_info ~dir;
226226
Bootstrap_info.gen_rules sctx exes ~dir compile_info;

‎test/blackbox-tests/test-cases/implicit-empty-executables.t/run.t ‎test/blackbox-tests/test-cases/executables-implicit-empty-intf.t/run.t

+14-11
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
Executables with no corresponding `.mli` file will have one generated for them
22
by Dune:
33

4-
$ echo "(lang dune 2.8)" > dune-project
4+
$ cat >dune-project <<EOF
5+
> (lang dune 2.8)
6+
> (executables_implicit_empty_intf true)
7+
> EOF
8+
59
$ dune build ./bin/executable.exe
610
File "bin/executable.ml", line 1, characters 4-10:
711
1 | let unused = Dependency.a
@@ -25,20 +29,19 @@ as will test binaries:
2529
$ cat _build/default/test/test.mli
2630
(* Auto-generated by Dune *)
2731

28-
Empty `.mli` files are only generated when lang version >= 2.8:
29-
30-
$ dune clean
31-
$ echo "(lang dune 2.7)" > dune-project
32-
$ dune build ./bin/executable.exe
33-
$ dune runtest
34-
$ test ! -f _build/default/bin/executable.mli
35-
$ test ! -f _build/default/test/test.mli
36-
3732
If an executable already has an interface, it is preserved:
3833

3934
$ dune clean
40-
$ echo "(lang dune 2.8)" > dune-project
4135
$ dune build ./bin_with_intf/executable.exe
4236
$ cat _build/default/bin_with_intf/executable.mli
4337
val a : int
4438

39+
Generation of empty `.mli` files is disabled by default prior to lang 3.0:
40+
41+
$ dune clean
42+
$ echo >dune-project "(lang dune 2.8)"
43+
$ dune build ./bin/executable.exe
44+
$ dune runtest
45+
$ test ! -f _build/default/bin/executable.mli
46+
$ test ! -f _build/default/test/test.mli
47+

0 commit comments

Comments
 (0)
Please sign in to comment.