This commit is contained in:
swrup 2025-11-11 02:07:51 +01:00
parent aa2ff7b2f0
commit 2f3113f55d
11742 changed files with 1223940 additions and 0 deletions

View file

@ -0,0 +1,3 @@
(cram
(applies_to envs-and-contexts)
(deps ${bin:opam}))

View file

@ -0,0 +1,27 @@
Current directory (and also current env) can affect an expander,
and expander is in turn used to expand things in env.
Given that we only have a few string_with_vars in env, a reasonable
example is hard to come up with, but here is a contrived one.
$ echo '(lang dune 2.0)' > dune-project
$ cat > dune <<EOF
> (env
> (_
> (ocamlc_flags "%{inline_tests}")))
> EOF
$ dune printenv --root . . --field ocamlc_flags
(ocamlc_flags (enabled))
$ echo '(lang dune 2.0)' > dune-project
$ cat > dune <<EOF
> (env
> (_
> (ocamlc_flags "%{inline_tests}")
> (inline_tests ignored)))
> EOF
$ dune printenv --root . . --field ocamlc_flags
(ocamlc_flags (ignored))

View file

@ -0,0 +1,3 @@
(env
(_
(flags (:include flags))))

View file

@ -0,0 +1 @@
(lang dune 1.4)

View file

@ -0,0 +1 @@
-from-included-file

View file

@ -0,0 +1,7 @@
Reproduction case for #1508: make sure that paths in `env` stanzas are
interpreted relative to the directory of the `env` stanza.
$ dune printenv . --field flags
(flags (-from-included-file))
$ dune printenv src --field flags
(flags (-from-included-file))

View file

@ -0,0 +1,74 @@
Test that we can control generation of cmt files using (cmt_annot ...) field in (env ...).
$ cat >dune-project <<EOF
> (lang dune 3.8)
> (package (name pub))
> (package (name pub2))
> EOF
$ mkdir -p priv/priv2 pub/pub2 priv/proj
$ touch main.ml priv/priv.ml priv/priv2/priv2.ml pub/pub.ml pub/pub2/pub2.ml priv/proj/proj.ml
$ cat >dune <<EOF
> (library (name main))
> EOF
$ cat >priv/dune <<EOF
> (env (_ (bin_annot false)))
> (library (name priv))
> EOF
$ cat >priv/priv2/dune <<EOF
> (env (_ (bin_annot true)))
> (library (name priv2))
> EOF
We also check that public libraries work: the first should be installed without
any cmt file...
$ cat >pub/dune <<EOF
> (env (_ (bin_annot false)))
> (library (public_name pub))
> EOF
... and the second one _with_ cmt files.
$ cat >pub/pub2/dune <<EOF
> (env (_ (bin_annot true)))
> (library (public_name pub2))
> EOF
$ cat >priv/proj/dune-project <<EOF
> (lang dune 3.8)
> EOF
$ cat >priv/proj/dune <<EOF
> (library (name proj))
> EOF
$ dune build
Note that "pub" does not appear in the list (as we disabled cmt files for it).
$ find _build -name '*.cmt*' | sort
_build/default/.main.objs/byte/main.cmt
_build/default/priv/priv2/.priv2.objs/byte/priv2.cmt
_build/default/priv/proj/.proj.objs/byte/proj.cmt
_build/default/pub/pub2/.pub2.objs/byte/pub2.cmt
_build/install/default/lib/pub2/pub2.cmt
The next test shows that workspace env settings are used as fallback if a
project does not specify the option explicitly.
$ cat >dune-workspace <<EOF
> (lang dune 3.8)
> (env (_ (bin_annot false)))
> EOF
$ dune build
$ find _build -name '*.cmt*' | sort
_build/default/priv/priv2/.priv2.objs/byte/priv2.cmt
_build/default/pub/pub2/.pub2.objs/byte/pub2.cmt
_build/install/default/lib/pub2/pub2.cmt

View file

@ -0,0 +1,11 @@
(env
(_
(binaries ./foo/foo.exe)))
(alias
(name default)
(action (run %{exe:foo.exe})))
(alias
(name default)
(action (run %{bin:foo})))

View file

@ -0,0 +1 @@
(lang dune 1.8)

View file

@ -0,0 +1 @@
(executable (name foo))

View file

@ -0,0 +1 @@
print_endline "this is foo.exe"

View file

@ -0,0 +1,8 @@
%{exe:foo.exe} should not be veisible if foo.exe is added to PATH via the
binaries stanza. %{bin:foo} is visible on the other hand.
$ dune build
this is foo.exe
Error: No rule found for foo.exe
-> required by %{exe:foo.exe} at dune:7
-> required by alias default in dune:5
[1]

View file

@ -0,0 +1,3 @@
(alias
(name default)
(deps (alias_rec runtest)))

View file

@ -0,0 +1 @@
(lang dune 1.8)

View file

@ -0,0 +1 @@
(executable (name priv))

View file

@ -0,0 +1,22 @@
let count_segments s ~segment =
s
|> String.split_on_char '/'
|> List.filter (fun part -> String.equal part segment)
|> List.length
let is_in_inner_build_dir s =
count_segments ~segment:"_build" s = 2
let () =
let name = Filename.basename Sys.argv.(0) in
Printf.printf "Executing priv as %s\n" name;
let path =
match Sys.getenv "PATH" with
| exception Not_found -> "<empty>"
| s ->
s
|> String.split_on_char ':'
|> List.filter is_in_inner_build_dir
|> String.concat "\n\t"
in
Printf.printf "PATH:\n\t%s\n" path

View file

@ -0,0 +1,17 @@
Nest env binaries
$ dune build
Executing priv as priv
PATH:
$TESTCASE_ROOT/_build/default/using-priv/nested/.bin
$TESTCASE_ROOT/_build/default/using-priv/.bin
$TESTCASE_ROOT/_build/install/default/bin
Executing priv as priv-renamed
PATH:
$TESTCASE_ROOT/_build/default/using-priv/nested/.bin
$TESTCASE_ROOT/_build/default/using-priv/.bin
$TESTCASE_ROOT/_build/install/default/bin
Executing priv as priv-renamed-nested
PATH:
$TESTCASE_ROOT/_build/default/using-priv/nested/.bin
$TESTCASE_ROOT/_build/default/using-priv/.bin
$TESTCASE_ROOT/_build/install/default/bin

View file

@ -0,0 +1,5 @@
(env
(_
(binaries
../priv/priv.exe
(../priv/priv.exe as priv-renamed))))

View file

@ -0,0 +1,12 @@
(env
(_
(binaries
(../../priv/priv.exe as priv-renamed-nested))))
(alias
(name runtest)
(action
(progn
(run priv)
(run priv-renamed)
(run priv-renamed-nested))))

View file

@ -0,0 +1,4 @@
(alias
(name default)
(deps (alias_rec runtest))
(action (run foo)))

View file

@ -0,0 +1 @@
(executable (name priv))

View file

@ -0,0 +1 @@
print_endline "private binary"

View file

@ -0,0 +1 @@
(executable (public_name foo))

View file

@ -0,0 +1 @@
print_endline "public binary"

View file

@ -0,0 +1,5 @@
Override public binary in env
$ dune build
private binary
public binary

View file

@ -0,0 +1,7 @@
(env
(_
(binaries (../priv/priv.exe as foo))))
(alias
(name runtest)
(action (run foo)))

View file

@ -0,0 +1,3 @@
(alias
(name default)
(deps (alias_rec runtest)))

View file

@ -0,0 +1 @@
(executable (name priv))

View file

@ -0,0 +1,22 @@
let count_segments s ~segment =
s
|> String.split_on_char '/'
|> List.filter (fun part -> String.equal part segment)
|> List.length
let is_in_inner_build_dir s =
count_segments ~segment:"_build" s = 2
let () =
let name = Filename.basename Sys.argv.(0) in
Printf.printf "Executing priv as %s\n" name;
let path =
match Sys.getenv "PATH" with
| exception Not_found -> "<empty>"
| s ->
s
|> String.split_on_char ':'
|> List.filter is_in_inner_build_dir
|> String.concat "\n\t"
in
Printf.printf "PATH:\n\t%s\n" path

View file

@ -0,0 +1,11 @@
Basic test that we can use private binaries as public ones
$ dune build
Executing priv as priv
PATH:
$TESTCASE_ROOT/_build/default/using-priv/.bin
$TESTCASE_ROOT/_build/install/default/bin
Executing priv as priv-renamed
PATH:
$TESTCASE_ROOT/_build/default/using-priv/.bin
$TESTCASE_ROOT/_build/install/default/bin

View file

@ -0,0 +1,12 @@
(env
(_
(binaries
../priv/priv.exe
(../priv/priv.exe as priv-renamed))))
(alias
(name runtest)
(action
(progn
(run priv)
(run priv-renamed))))

View file

@ -0,0 +1,4 @@
(env
(default
(c_flags "in bin")
(cxx_flags "in bin")))

View file

@ -0,0 +1,4 @@
(env
(default
(c_flags ":standard + in .")
(cxx_flags ":standard + in .")))

View file

@ -0,0 +1 @@
(lang dune 1.7)

View file

@ -0,0 +1,26 @@
$ alias dune_printenv="dune printenv --profile default --field c_flags --field cxx_flags"
$ dune_printenv .
(c_flags (":standard + in ."))
(cxx_flags (":standard + in ."))
$ dune_printenv src
(c_flags
(":standard + in ." ":standard + in src"))
(cxx_flags
(":standard + in ." ":standard + in src"))
$ dune_printenv bin
(c_flags ("in bin"))
(cxx_flags ("in bin"))
$ dune_printenv run
(c_flags (-DTEST_C))
(cxx_flags (-DTEST_CPP))
$ dune exec --profile default ./run/foo.exe
TEST_C defined.
$ dune exec --profile default ./run/bar.exe
TEST_CPP defined.

View file

@ -0,0 +1,11 @@
#include <stdio.h>
int main(int argc, char ** argv){
#ifdef TEST_CPP
printf("TEST_CPP defined.\n");
return 0;
#else
printf("TEST_CPP not defined.\n");
return 1;
#endif
}

View file

@ -0,0 +1,15 @@
(env
(default
(c_flags "-DTEST_C")
(cxx_flags "-DTEST_CPP")))
(rule
(targets foo.exe)
(deps foo.c)
(action (run %{cc} -o %{targets} %{deps})))
(rule
(targets bar.exe)
(deps bar.cpp)
(action (run %{cxx} -o %{targets} %{deps})))

View file

@ -0,0 +1,11 @@
#include <stdio.h>
int main(int argc, char ** argv){
#ifdef TEST_C
printf("TEST_C defined.\n");
return 0;
#else
printf("TEST_C not defined.\n");
return 1;
#endif
}

View file

@ -0,0 +1,4 @@
(env
(default
(c_flags :standard ":standard + in src")
(cxx_flags :standard ":standard + in src")))

View file

@ -0,0 +1,8 @@
(env
(_
(env-vars
(DUNE_FOO PASS))))
(alias
(name default)
(deps (alias_rec runtest)))

View file

@ -0,0 +1,3 @@
env vars set in env should be visible to all subdirs
$ dune build
PASS

View file

@ -0,0 +1,3 @@
(alias
(name runtest)
(action (echo %{env:DUNE_FOO=FAIL})))

View file

@ -0,0 +1,15 @@
(env
(_
(env-vars
(DUNE_FOO -principal))))
(executable
(flags %{env:DUNE_FOO=-BREAK})
(name foo))
(alias
(name default)
(action
(progn
(echo "var visible from dune: %{env:DUNE_FOO=absent}\n")
(run ./foo.exe))))

View file

@ -0,0 +1,4 @@
Printf.printf "DUNE_FOO: %s\n%!"
(match Sys.getenv "DUNE_FOO" with
| s -> s
| exception Not_found -> "<not found>");;

View file

@ -0,0 +1,11 @@
env vars interpreted in various fields, such as flags
$ dune build --force
var visible from dune: -principal
DUNE_FOO: -principal
global vars are overridden
$ DUNE_FOO=blarg dune build --force
var visible from dune: -principal
DUNE_FOO: -principal

View file

@ -0,0 +1,9 @@
(env
(_
(env-vars
(DUNE_FOO foo-parent)
(DUNE_BAR bar-parent))))
(alias
(name default)
(deps (alias_rec runtest)))

View file

@ -0,0 +1,5 @@
proper inheritance chain of env stanzas
$ dune build
DUNE_FOO: foo-sub
DUNE_BAR: bar-parent

View file

@ -0,0 +1,9 @@
(env
(_
(env-vars
(DUNE_FOO foo-sub))))
(alias
(name runtest)
(action
(echo "DUNE_FOO: %{env:DUNE_FOO=unset}\nDUNE_BAR: %{env:DUNE_BAR=unset}")))

View file

@ -0,0 +1 @@
let () = print_endline "'A' was linked"

View file

@ -0,0 +1,4 @@
let () = print_endline "Starting main"
let _ = `no_reference_to_A

View file

@ -0,0 +1,16 @@
$ cat >> dune-project <<EOF
> (lang dune 3.0)
> EOF
$ cat >> dune << EOF
> (library (name a)(modules a))
> (executable (name main) (modules main) (libraries a))
> (env (linkall-profile (link_flags (:standard -linkall))))
> EOF
$ dune exec ./main.exe
Starting main
$ dune exec ./main.exe --profile linkall-profile
'A' was linked
Starting main

View file

@ -0,0 +1,5 @@
(env
(default
(flags "in bin")
(c_flags ())
(cxx_flags ())))

View file

@ -0,0 +1,5 @@
(env
(default
(flags :standard ":standard + in .")
(c_flags ())
(cxx_flags ())))

View file

@ -0,0 +1 @@
(lang dune 1.7)

View file

@ -0,0 +1,3 @@
#!/bin/bash
dune printenv $@

View file

@ -0,0 +1,34 @@
$ alias dune_printenv='dune printenv --profile default --field flags'
$ dune_printenv .
(flags
(-w -40 ":standard + in ."))
$ dune_printenv src
(flags
(-w -40 ":standard + in ." ":standard + in src"))
$ dune_printenv bin
(flags ("in bin"))
$ dune_printenv vendor
(flags
(-w -40 ":standard + in ."))
Vendored project without env customization, the global default should
apply:
$ dune_printenv vendor/without-env-customization
(flags
(-w -40))
Vendored project with env customization, the global default +
customization of vendored project should apply:
$ dune_printenv vendor/with-env-customization
(flags
(-w -40 ":standard + in vendor/with-env-customization"))
$ dune_printenv vendor/with-env-customization/src
(flags ("in vendor/with-env-customization/src"))

View file

@ -0,0 +1,5 @@
(env
(default
(flags :standard ":standard + in src")
(c_flags ())
(cxx_flags ())))

View file

@ -0,0 +1,5 @@
(env
(default
(flags :standard ":standard + in vendor/with-env-customization")
(c_flags ())
(cxx_flags ())))

View file

@ -0,0 +1,3 @@
(env
(default
(flags "in vendor/with-env-customization/src")))

View file

@ -0,0 +1,8 @@
let print_var k =
match Sys.getenv k with
| v -> Printf.printf "%s = %S\n" k v
| exception Not_found -> Printf.printf "%s is not set\n" k
let () =
print_var "X";
print_var "Y"

View file

@ -0,0 +1,11 @@
(executable
(name a))
(alias
(name without_dep)
(action (run ./a.exe)))
(alias
(name with_dep)
(deps (env_var X))
(action (run ./a.exe)))

View file

@ -0,0 +1 @@
(lang dune 1.1)

View file

@ -0,0 +1,21 @@
Aliases without a (env) dependency are not rebuilt when the environment
changes:
$ dune build @without_dep
X is not set
Y is not set
$ X=x dune build @without_dep
But if there is a dependency, the alias gets rebuilt:
$ dune build @with_dep
X is not set
Y is not set
$ X=x dune build @with_dep
X = "x"
Y is not set
This only happens for tracked variables:
$ dune build @with_dep
$ Y=y dune build @with_dep

View file

@ -0,0 +1,41 @@
$ cat > dune-project << EOF
> (lang dune 3.3)
> EOF
(env) is evaluated sequentially:
$ cat > dune << 'EOF'
> (rule
> (alias runtest)
> (action (system "echo $VAR")))
>
> (env
> (_ (env-vars (VAR default )))
> (dev (env-vars (VAR specific))))
> EOF
A warning is displayed when there are unreachable cases.
$ dune runtest
File "dune", lines 5-7, characters 0-71:
5 | (env
6 | (_ (env-vars (VAR default )))
7 | (dev (env-vars (VAR specific))))
Warning: This env stanza contains rules after a wildcard rule. These are
going to be ignored.
default
In 3.4, this warning becomes fatal.
$ cat > dune-project << EOF
> (lang dune 3.4)
> EOF
$ dune runtest
File "dune", lines 5-7, characters 0-71:
5 | (env
6 | (_ (env-vars (VAR default )))
7 | (dev (env-vars (VAR specific))))
Error: This env stanza contains rules after a wildcard rule. These are going
to be ignored.
[1]

View file

@ -0,0 +1,21 @@
(alias
(name echo1)
(action (echo %{env:DUNE_ENV_VAR=true})))
(alias
(name echo2)
(action
(progn
(echo "previous env: %{env:DUNE_ENV_VAR=unset}\n")
(setenv DUNE_ENV_VAR "set by setenv"
(echo "new env:%{env:DUNE_ENV_VAR=unset-by-env}")))))
(alias
(name enabled)
(enabled_if (= true %{env:DUNE_ENV_VAR=true}))
(action (echo "enabled!")))
(alias
(name disabled)
(enabled_if (= true %{env:DUNE_ENV_VAR=false}))
(action (echo "enabled!")))

View file

@ -0,0 +1,34 @@
Actually test that the environment changes are properly tracked, i.e. that
incrementality works properly, that (setenv ...) is taken into account, etc.
$ dune build @echo1
true
$ DUNE_ENV_VAR=true dune build @echo1
$ DUNE_ENV_VAR=false dune build @echo1
false
$ DUNE_ENV_VAR=false dune build @echo1
$ DUNE_ENV_VAR=true dune build @echo1
This test is broken because previous/new values should differ in these tests. In
the dune file, the environment variable ends up being set locally, but this
isn't reflected on a per action basis.
$ dune build @echo2
previous env: unset
new env:set by setenv
$ DUNE_ENV_VAR=true dune build @echo2
previous env: true
new env:set by setenv
$ DUNE_ENV_VAR=false dune build @echo2
previous env: false
new env:set by setenv
$ dune build @enabled
enabled!
$ DUNE_ENV_VAR=true dune build @enabled
$ DUNE_ENV_VAR=false dune build @enabled
$ dune build @disabled
$ DUNE_ENV_VAR=true dune build @disabled
enabled!
$ DUNE_ENV_VAR=false dune build @disabled

View file

@ -0,0 +1,3 @@
(alias
(name echo)
(action (echo %{env:DUNE_ENV_VAR})))

View file

@ -0,0 +1,16 @@
Make sure that we require a default value regardless of the context
$ dune build @echo
File "dune", line 3, characters 15-34:
3 | (action (echo %{env:DUNE_ENV_VAR})))
^^^^^^^^^^^^^^^^^^^
Error: %{env:..} must always come with a default value.
Hint: the syntax is %{env:VAR=DEFAULT-VALUE}
[1]
$ dune build @echo
File "dune", line 3, characters 15-34:
3 | (action (echo %{env:DUNE_ENV_VAR})))
^^^^^^^^^^^^^^^^^^^
Error: %{env:..} must always come with a default value.
Hint: the syntax is %{env:VAR=DEFAULT-VALUE}
[1]

View file

@ -0,0 +1,4 @@
(alias
(name echo)
(enabled_if (= true %{env:DUNE_ENV_VAR}))
(action (echo "enabled!")))

View file

@ -0,0 +1,7 @@
$ dune build @echo
File "dune", line 3, characters 21-40:
3 | (enabled_if (= true %{env:DUNE_ENV_VAR}))
^^^^^^^^^^^^^^^^^^^
Error: %{env:..} must always come with a default value.
Hint: the syntax is %{env:VAR=DEFAULT-VALUE}
[1]

View file

@ -0,0 +1,9 @@
(rule (with-stdout-to bar (echo "from bar")))
(alias
(name default)
(action
(progn
(echo "Initial value of %{env:DUNE_FOO=unset}\n")
(setenv DUNE_FOO XXXX (echo "Now set: %{env:DUNE_FOO=unset}\n"))
(setenv DUNE_FOO %{read:bar} (echo "From bar: %{env:DUNE_FOO=unset}\n")))))

View file

@ -0,0 +1,4 @@
$ dune build
Initial value of unset
Now set: XXXX
From bar: from bar

View file

@ -0,0 +1,7 @@
(lang dune 1.5)
(env
(_
(env-vars
(VARIABLE value1)
(VARIABLE value2))))

View file

@ -0,0 +1,8 @@
When a variable is repeated, an error message is displayed:
$ dune build
File "dune-workspace", lines 6-7, characters 3-41:
6 | (VARIABLE value1)
7 | (VARIABLE value2))))
Error: Variable VARIABLE is specified several times
[1]

View file

@ -0,0 +1,2 @@
(executable
(name printenv))

View file

@ -0,0 +1,15 @@
(lang dune 1.5)
(env
(_
(env-vars
(VARIABLE_FROM_WORKSPACE value1)
(VARIABLE_FROM_BOTH from_workspace))))
(context
(default
(env
(_
(env-vars
(VARIABLE_FROM_CONTEXT value2)
(VARIABLE_FROM_BOTH from_context))))))

View file

@ -0,0 +1,5 @@
let var_to_string k = try Sys.getenv k with Not_found -> "(unset)"
let print_var k = Printf.printf "%s=%s\n" k (var_to_string k)
let () = print_var Sys.argv.(1)

View file

@ -0,0 +1,17 @@
Environment variables defined in (env) are set during execution.
They can be set from the workspace:
$ dune exec ./printenv.exe VARIABLE_FROM_WORKSPACE
VARIABLE_FROM_WORKSPACE=value1
From a (context) stanza in the workspace:
$ dune exec ./printenv.exe VARIABLE_FROM_CONTEXT
VARIABLE_FROM_CONTEXT=value2
When a variable is set from both a context and a global one, the context one is
used.
$ dune exec ./printenv.exe VARIABLE_FROM_BOTH
VARIABLE_FROM_BOTH=from_workspace

View file

@ -0,0 +1 @@
(lang dune 1.1)

View file

@ -0,0 +1,10 @@
(lang dune 1.1)
(context (opam (switch default) (name dev) (profile dev) (merlin)))
(context (opam (switch default) (name release) (profile release)))
(env
(dev
(flags dev-flags))
(release
(flags release-flags)))

View file

@ -0,0 +1,27 @@
Regression test for https://github.com/ocaml/dune/issues/1016#issuecomment-411390740
$ dune printenv
Environment for context dev:
((flags (dev-flags))
(ocamlc_flags (-g))
(ocamlopt_flags (-g))
(c_flags
($flags))
(cxx_flags
($flags))
(menhir_flags ()))
Environment for context release:
((flags (release-flags))
(ocamlc_flags (-g))
(ocamlopt_flags (-g))
(c_flags
($flags))
(cxx_flags
($flags))
(menhir_flags ()))