mte/unikernel/duniverse/dune_/doc/reference/actions/index.rst

121 lines
3 KiB
ReStructuredText
Raw Normal View History

2025-11-11 02:07:51 +01:00
Actions
=======
.. highlight:: dune
``(action ...)`` fields describe user actions.
User actions are always run from the same subdirectory of the current build
context as the ``dune`` file they are defined in, so for instance, an action defined
in ``src/foo/dune`` will be run from ``$build/<context>/src/foo``.
The argument of ``(action ...)`` fields is a small DSL that's interpreted by
Dune directly and doesn't require an external shell. All atoms in the DSL
support :doc:`/concepts/variables`. Moreover, you don't need to specify
dependencies explicitly for the special ``%{<kind>:...}`` forms; these are
recognized and automatically handled by Dune.
The DSL is currently quite limited, so if you want to do something complicated,
it's recommended to write a small OCaml program and use the DSL to invoke it.
You can use `shexp <https://github.com/janestreet/shexp>`__ to write portable
scripts or :ref:`configurator` for configuration related tasks. You can also
use :ref:`dune-action-plugin` to express program dependencies directly in the
source code.
The following constructions are available:
.. grid:: 1 1 2 2
.. grid-item::
.. toctree::
:caption: Running commands
run
system
bash
dynamic-run
chdir
setenv
with-accepted-exit-codes
.. grid-item::
.. toctree::
:caption: Input and output
echo
with-outputs-to
with-stdin-from
ignore-outputs
cat
copy
copy#
write-file
pipe-outputs
format-dune-file
.. grid-item::
.. toctree::
:caption: Comparing files
diff
diffq
cmp
.. grid-item::
.. toctree::
:caption: Control structures
progn
concurrent
no-infer
Note: expansion of the special ``%{<kind>:...}`` is done relative to the current
working directory of the DSL being executed. So for instance, if you
have this action in a ``src/foo/dune``:
.. code:: dune
(action (chdir ../../.. (echo %{dep:dune})))
Then ``%{dep:dune}`` will expand to ``src/foo/dune``. When you run various
tools, they often use the filename given on the command line in error messages.
As a result, if you execute the command from the original directory, it will
only see the basename.
To understand why this is important, let's consider this ``dune`` file living in
``src/foo``::
(rule
(target blah.ml)
(deps blah.mll)
(action
(run ocamllex -o %{target} %{deps})))
Here the command that will be executed is:
.. code:: console
$ ocamllex -o blah.ml blah.mll
And it will be executed in ``_build/<context>/src/foo``. As a result, if there
is an error in the generated ``blah.ml`` file, it will be reported as:
::
File "blah.ml", line 42, characters 5-10:
Error: ...
Which can be a problem, as your editor might think that ``blah.ml`` is at the root
of your project. Instead, this is a better way to write it::
(rule
(target blah.ml)
(deps blah.mll)
(action
(chdir %{workspace_root}
(run ocamllex -o %{target} %{deps}))))