Skip to content

Commit bb0a0c1

Browse files
committed
add: build_if in test stanza
Fixes #6938 The semantics of `(enabled_if)` in `(test)` can be confusing: `(test)` can be seen as the combination of `(executable)` and a `(rule (alias runtest))`; but `(enabled_if)` actually only controls the "running" part, not the "building" one. This adds a new `(build_if)` field in `(test)`. When it evaluates to false, the test stanza is bypassed (no build is attempted). Signed-off-by: Etienne Millon <[email protected]>
1 parent bd1193d commit bb0a0c1

File tree

10 files changed

+197
-30
lines changed

10 files changed

+197
-30
lines changed

CHANGES.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ Unreleased
3030
- Switch back to threaded console for all systems; fix unresponsive console on
3131
Windows (#7906, @nojb)
3232

33+
- Add `(build_if)` to the `(test)` stanza. When it evaluates to false, the
34+
executable is not built. (#7899, fixes #6938, @emillon)
35+
3336
3.8.1 (2023-06-05)
3437
------------------
3538

doc/stanzas/test.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ In particular, all fields except for ``public_names`` are supported from the
3737
:ref:`executables stanza <shared-exe-fields>`. Alias fields apart from ``name``
3838
are allowed.
3939

40+
The ``(enabled_if)`` field has special semantics: when present, it only applies
41+
to running the tests. The test executable is always built by default.
42+
If you need to restrict building the test executable, use ``(build_if)`` instead.
43+
4044
By default, the test binaries are run without options. The ``action`` field can
4145
override the test binary invocation, i.e., if you're using Alcotest and wish to
4246
see all the test failures on the standard output. When running Dune ``runtest``

src/dune_rules/dune_file.ml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1905,6 +1905,7 @@ module Tests = struct
19051905
; package : Package.t option
19061906
; deps : Dep_conf.t Bindings.t
19071907
; enabled_if : Blang.t
1908+
; build_if : Blang.t
19081909
; action : Dune_lang.Action.t option
19091910
}
19101911

@@ -1936,6 +1937,10 @@ module Tests = struct
19361937
(Dune_lang.Syntax.since Stanza.syntax (2, 0)
19371938
>>> repeat (located Lib_name.decode))
19381939
~default:[]
1940+
and+ build_if =
1941+
field "build_if" ~default:Blang.true_
1942+
(Syntax.since Stanza.syntax (3, 9)
1943+
>>> Enabled_if.decode_value ~allowed_vars:Any ())
19391944
in
19401945
{ exes =
19411946
{ Executables.link_flags
@@ -1957,6 +1962,7 @@ module Tests = struct
19571962
; package
19581963
; deps
19591964
; enabled_if
1965+
; build_if
19601966
; action
19611967
}))
19621968

src/dune_rules/dune_file.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,7 @@ module Tests : sig
359359
; package : Package.t option
360360
; deps : Dep_conf.t Bindings.t
361361
; enabled_if : Blang.t
362+
; build_if : Blang.t
362363
; action : Dune_lang.Action.t option
363364
}
364365
end

src/dune_rules/enabled_if.ml

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -40,30 +40,31 @@ let emit_warning allowed_vars is_error var =
4040
(Dune_lang.Template.Pform.name var)
4141
]
4242

43-
let decode ~allowed_vars ?(is_error = true) ~since () =
44-
let decode =
45-
match allowed_vars with
46-
| Any -> Blang.decode
47-
| Only allowed_vars ->
48-
Blang.decode_manually (fun env var ->
49-
match Dune_lang.Template.Pform.payload var with
50-
| Some _ ->
43+
let decode_value ~allowed_vars ?(is_error = true) () =
44+
match allowed_vars with
45+
| Any -> Blang.decode
46+
| Only allowed_vars ->
47+
Blang.decode_manually (fun env var ->
48+
match Dune_lang.Template.Pform.payload var with
49+
| Some _ ->
50+
emit_warning allowed_vars is_error var;
51+
Pform.Env.parse env var
52+
| None -> (
53+
let name = Dune_lang.Template.Pform.name var in
54+
match List.assoc allowed_vars name with
55+
| None ->
5156
emit_warning allowed_vars is_error var;
5257
Pform.Env.parse env var
53-
| None -> (
54-
let name = Dune_lang.Template.Pform.name var in
55-
match List.assoc allowed_vars name with
56-
| None ->
57-
emit_warning allowed_vars is_error var;
58-
Pform.Env.parse env var
59-
| Some min_ver ->
60-
let current_ver = Pform.Env.syntax_version env in
61-
if min_ver > current_ver then
62-
let loc = Dune_lang.Template.Pform.loc var in
63-
let what = Dune_lang.Template.Pform.describe var in
64-
Dune_lang.Syntax.Error.since loc Stanza.syntax min_ver ~what
65-
else Pform.Env.unsafe_parse_without_checking_version env var))
66-
in
58+
| Some min_ver ->
59+
let current_ver = Pform.Env.syntax_version env in
60+
if min_ver > current_ver then
61+
let loc = Dune_lang.Template.Pform.loc var in
62+
let what = Dune_lang.Template.Pform.describe var in
63+
Dune_lang.Syntax.Error.since loc Stanza.syntax min_ver ~what
64+
else Pform.Env.unsafe_parse_without_checking_version env var))
65+
66+
let decode ~allowed_vars ?is_error ~since () =
67+
let decode = decode_value ?is_error ~allowed_vars () in
6768
let decode =
6869
match since with
6970
| None -> decode

src/dune_rules/enabled_if.mli

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,9 @@ val decode :
1212
-> since:Dune_lang.Syntax.Version.t option
1313
-> unit
1414
-> Blang.t Dune_lang.Decoder.fields_parser
15+
16+
val decode_value :
17+
allowed_vars:allowed_vars
18+
-> ?is_error:bool
19+
-> unit
20+
-> Blang.t Dune_lang.Decoder.t

src/dune_rules/gen_rules.ml

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,14 +110,17 @@ end = struct
110110
let+ () = Simple_rules.alias sctx alias ~dir ~expander in
111111
empty_none
112112
| Tests tests ->
113-
let+ cctx, merlin =
114-
Test_rules.rules tests ~sctx ~dir ~scope ~expander ~dir_contents
115-
in
116-
{ merlin = Some merlin
117-
; cctx = Some (tests.exes.buildable.loc, cctx)
118-
; js = None
119-
; source_dirs = None
120-
}
113+
let* enabled = Expander.eval_blang expander tests.build_if in
114+
if enabled then
115+
let+ cctx, merlin =
116+
Test_rules.rules tests ~sctx ~dir ~scope ~expander ~dir_contents
117+
in
118+
{ merlin = Some merlin
119+
; cctx = Some (tests.exes.buildable.loc, cctx)
120+
; js = None
121+
; source_dirs = None
122+
}
123+
else Memo.return empty_none
121124
| Copy_files { files = glob; _ } ->
122125
let* source_dirs =
123126
let loc = String_with_vars.loc glob in
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
enabled_if has a limitation: it attempts building even if enabled_if evaluates to false.
2+
3+
$ cat > dune-project << EOF
4+
> (lang dune 3.9)
5+
> EOF
6+
7+
$ cat > dune << EOF
8+
> (test
9+
> (name t)
10+
> (enabled_if %{env:ENABLED=false}))
11+
> EOF
12+
13+
$ touch t.ml
14+
15+
We test the various combinations:
16+
17+
$ test_one () {
18+
> dune clean
19+
> output=$( dune build "$1" --display short 2>&1 )
20+
> echo When building $1 with ENABLED=${ENABLED:-unset}:
21+
> if echo $output|grep -q ocamlopt ; then
22+
> echo ' build was done: YES'
23+
> else
24+
> echo ' build was done: NO'
25+
> fi
26+
> if echo $output|grep -q "alias runtest" ; then
27+
> echo ' test did run: YES'
28+
> else
29+
> echo ' test did run: NO'
30+
> fi
31+
> }
32+
33+
$ test_all () {
34+
> test_one @all
35+
> test_one @runtest
36+
> ENABLED=true test_one @all
37+
> ENABLED=true test_one @runtest
38+
> }
39+
40+
$ test_all
41+
When building @all with ENABLED=unset:
42+
build was done: YES
43+
test did run: NO
44+
When building @runtest with ENABLED=unset:
45+
build was done: NO
46+
test did run: NO
47+
When building @all with ENABLED=true:
48+
build was done: YES
49+
test did run: NO
50+
When building @runtest with ENABLED=true:
51+
build was done: YES
52+
test did run: YES
53+
54+
Now with build_if:
55+
56+
$ cat > dune << EOF
57+
> (test
58+
> (name t)
59+
> (build_if %{env:ENABLED=false}))
60+
> EOF
61+
62+
Notice that in the first case, nothing is done at all:
63+
64+
$ test_all
65+
When building @all with ENABLED=unset:
66+
build was done: NO
67+
test did run: NO
68+
When building @runtest with ENABLED=unset:
69+
build was done: NO
70+
test did run: NO
71+
When building @all with ENABLED=true:
72+
build was done: YES
73+
test did run: NO
74+
When building @runtest with ENABLED=true:
75+
build was done: YES
76+
test did run: YES
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
build_if is compatible with package.
2+
3+
This is important to test because in that case, (test) can not be split into two stanzas:
4+
5+
$ cat > dune-project << EOF
6+
> (lang dune 3.9)
7+
>
8+
> (package (name a) (allow_empty))
9+
> EOF
10+
11+
$ cat > dune << EOF
12+
> (test
13+
> (name t)
14+
> (package a)
15+
> (build_if %{env:ENABLED=false}))
16+
> EOF
17+
18+
$ touch t.ml
19+
20+
$ dune runtest
21+
22+
If we try to split it we get an error:
23+
24+
$ cat > dune << EOF
25+
> (executable
26+
> (name t)
27+
> (package a)
28+
> (enabled_if %{env:ENABLED=false}))
29+
>
30+
> (rule
31+
> (alias runtest)
32+
> (action (run ./t.exe))
33+
> (package a)
34+
> (enabled_if %{env:ENABLED=false}))
35+
> EOF
36+
37+
$ dune runtest
38+
File "dune", line 3, characters 1-12:
39+
3 | (package a)
40+
^^^^^^^^^^^
41+
Error: This field is useless without a (public_name ...) field.
42+
[1]
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
$ cat > dune-project << EOF
2+
> (lang dune 3.8)
3+
> EOF
4+
5+
$ cat > dune << EOF
6+
> (test
7+
> (name t)
8+
> (build_if true))
9+
> EOF
10+
11+
$ touch t.ml
12+
13+
$ dune build
14+
File "dune", line 3, characters 1-16:
15+
3 | (build_if true))
16+
^^^^^^^^^^^^^^^
17+
Error: 'build_if' is only available since version 3.9 of the dune language.
18+
Please update your dune-project file to have (lang dune 3.9).
19+
[1]
20+
21+
$ cat > dune-project << EOF
22+
> (lang dune 3.9)
23+
> EOF
24+
25+
$ dune build

0 commit comments

Comments
 (0)