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//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 ``%{:...}`` 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 `__ 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 ``%{:...}`` 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//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}))))