This commit is contained in:
parent
aa2ff7b2f0
commit
2f3113f55d
11742 changed files with 1223940 additions and 0 deletions
152
unikernel/duniverse/dune_/doc/concepts/dependency-spec.rst
Normal file
152
unikernel/duniverse/dune_/doc/concepts/dependency-spec.rst
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
Dependency Specification
|
||||
========================
|
||||
|
||||
.. TODO(diataxis)
|
||||
- reference - dependency spec
|
||||
- reference - globbing
|
||||
|
||||
Dependencies in ``dune`` files can be specified using one of the following:
|
||||
|
||||
.. _source_tree:
|
||||
|
||||
- ``(:name <dependencies>)`` will bind the list of dependencies to the
|
||||
``name`` variable. This variable will be available as ``%{name}`` in actions.
|
||||
- ``(file <filename>)``, or simply ``<filename>``, depend on this file.
|
||||
- ``(alias <alias-name>)`` depends on the construction of this alias. For
|
||||
instance: ``(alias src/runtest)``.
|
||||
- ``(alias_rec <alias-name>)`` depends on the construction of this
|
||||
alias recursively in all children directories wherever it is
|
||||
defined. For instance: ``(alias_rec src/runtest)`` might depend on
|
||||
``(alias src/runtest)``, ``(alias src/foo/bar/runtest)``, etc.
|
||||
- ``(glob_files <glob>)`` depends on all files matched by ``<glob>``. See the
|
||||
:ref:`glob <glob>` for details.
|
||||
- ``(glob_files_rec <glob>)`` is the recursive version of
|
||||
``(glob_files <glob>)``. See the :ref:`glob <glob>` for details.
|
||||
- ``(source_tree <dir>)`` depends on all source files in the subtree with root
|
||||
``<dir>``.
|
||||
- ``(universe)`` depends on everything in the universe. This is for
|
||||
cases where dependencies are too hard to specify. Note that Dune
|
||||
will not be able to cache the result of actions that depend on the
|
||||
universe. In any case, this is only for dependencies in the
|
||||
:term:`installed world`. You must still specify all dependencies that come
|
||||
from the workspace.
|
||||
- ``(package <pkg>)`` depends on all files installed by ``<package>``, as well
|
||||
as on the transitive package dependencies of ``<package>``. This can be used
|
||||
to test a command against the files that will be installed.
|
||||
- ``(env_var <var>)`` depends on the value of the environment variable ``<var>``.
|
||||
If this variable becomes set, becomes unset, or changes value, the target
|
||||
will be rebuilt.
|
||||
- ``(sandbox <config>)`` requires a particular sandboxing configuration.
|
||||
``<config>`` can be one (or many) of:
|
||||
|
||||
- ``always``: the action requires a clean environment
|
||||
- ``none``: the action must run in the build directory
|
||||
- ``preserve_file_kind``: the action needs the files it reads to look
|
||||
like normal files (so Dune won't use symlinks for sandboxing)
|
||||
- ``(include <file>)`` read the s-expression in ``<file>`` and interpret it as
|
||||
additional dependencies. The s-expression is expected to be a list of the
|
||||
same constructs enumerated here.
|
||||
|
||||
In all these cases, the argument supports :doc:`variables`.
|
||||
|
||||
Named Dependencies
|
||||
------------------
|
||||
|
||||
Dune allows a user to organize dependency lists by naming them. The user is
|
||||
allowed to assign a group of dependencies a name that can later be referred to
|
||||
in actions (like the ``%{deps}``, ``%{target}``, and ``%{targets}`` built in variables).
|
||||
|
||||
One instance where this is useful is for naming globs. Here's an
|
||||
example of an imaginary bundle command:
|
||||
|
||||
.. code:: dune
|
||||
|
||||
(rule
|
||||
(target archive.tar)
|
||||
(deps
|
||||
index.html
|
||||
(:css (glob_files *.css))
|
||||
(:js foo.js bar.js)
|
||||
(:img (glob_files *.png) (glob_files *.jpg)))
|
||||
(action
|
||||
(run %{bin:bundle} index.html -css %{css} -js %{js} -img %{img} -o %{target})))
|
||||
|
||||
Note that a named dependency list can also include unnamed
|
||||
dependencies (like ``index.html`` in the example above). Also, such
|
||||
user defined names will shadow build in variables, so
|
||||
``(:workspace_root x)`` will shadow the built-in ``%{workspace_root}``
|
||||
variable.
|
||||
|
||||
.. _glob:
|
||||
|
||||
Glob
|
||||
----
|
||||
|
||||
You can use globs to declare dependencies on a set of files. Note that globs
|
||||
will match files that exist in the source tree as well as buildable targets, so
|
||||
for instance you can depend on ``*.cmi``.
|
||||
|
||||
Dune supports globbing files in a single directory via ``(glob_files
|
||||
...)`` and, starting with Dune 3.0, in all subdirectories recursively via ``(glob_files_rec
|
||||
...)``. The glob is interpreted as follows:
|
||||
|
||||
- anything before the last ``/`` is taken as a literal path
|
||||
- anything after the last ``/``, or everything if the glob contains no ``/``, is
|
||||
interpreted using the glob syntax
|
||||
|
||||
Absolute paths are permitted in the ``(glob_files ...)`` term only. It's an error to pass
|
||||
an absolute path (i.e., a path beginning with a ``/``) to ``(glob_files_rec ...)```.
|
||||
|
||||
The glob syntax is interpreted as follows:
|
||||
|
||||
- ``\<char>`` matches exactly ``<char>``, even if it's a special character
|
||||
(``*``, ``?``, ...).
|
||||
- ``*`` matches any sequence of characters, except if it comes first, in which
|
||||
case it matches any character that is not ``.`` followed by anything.
|
||||
- ``**`` matches any character that is not ``.`` followed by anything, except if
|
||||
it comes first, in which case it matches anything.
|
||||
- ``?`` matches any single character.
|
||||
- ``[<set>]`` matches any character that is part of ``<set>``.
|
||||
- ``[!<set>]`` matches any character that is not part of ``<set>``.
|
||||
- ``{<glob1>,<glob2>,...,<globn>}`` matches any string that is matched by one of
|
||||
``<glob1>``, ``<glob2>``, etc.
|
||||
|
||||
.. list-table:: Glob syntax examples
|
||||
:header-rows: 1
|
||||
|
||||
* - Syntax
|
||||
- Files matched
|
||||
- Files not matched
|
||||
* - ``x``
|
||||
- ``x``
|
||||
- ``y``
|
||||
* - ``\*``
|
||||
- ``*``
|
||||
- ``x``
|
||||
* - ``file*.txt``
|
||||
- ``file1.txt``, ``file2.txt``
|
||||
- ``f.txt``
|
||||
* - ``*.txt``
|
||||
- ``f.txt``
|
||||
- ``.hidden.txt``
|
||||
* - ``a**``
|
||||
- ``aml``
|
||||
- ``a.ml``
|
||||
* - ``**``
|
||||
- ``a/b``, ``a.b``
|
||||
- (none)
|
||||
* - ``a?.txt``
|
||||
- ``a1.txt``, ``a2.txt``
|
||||
- ``b1.txt``, ``a10.txt``
|
||||
* - ``f[xyz].txt``
|
||||
- ``fx.txt``, ``fy.txt``, ``fz.txt``
|
||||
- ``f2.txt``, ``f.txt``
|
||||
* - ``f[!xyz].txt``
|
||||
- ``f2.txt``, ``fa.txt``
|
||||
- ``fx.txt``, ``f.txt``
|
||||
* - ``a.{ml,mli}``
|
||||
- ``a.ml``, ``a.mli``
|
||||
- ``a.txt``, ``b.ml``
|
||||
* - ``../a.{ml,mli}``
|
||||
- ``../a.ml``, ``../a.mli``
|
||||
- ``a.ml``
|
||||
53
unikernel/duniverse/dune_/doc/concepts/locks.rst
Normal file
53
unikernel/duniverse/dune_/doc/concepts/locks.rst
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
Locks
|
||||
=====
|
||||
|
||||
.. TODO(diataxis)
|
||||
- howto: testing in general (note about concurrency)
|
||||
- reference: locks
|
||||
|
||||
Given two rules that are independent, Dune will assume that their
|
||||
associated actions can be run concurrently. Two rules are considered
|
||||
independent if neither of them depend on the other, either directly or
|
||||
through a chain of dependencies. This basic assumption allows Dune to
|
||||
parallelize the build.
|
||||
|
||||
However, it is sometimes the case that two independent rules cannot be
|
||||
executed concurrently. For instance, this can happen for more
|
||||
complicated tests. In order to prevent Dune from running the
|
||||
actions at the same time, you can specify that both actions take the
|
||||
same lock:
|
||||
|
||||
.. code:: dune
|
||||
|
||||
(rule
|
||||
(alias runtest)
|
||||
(deps foo)
|
||||
(locks m)
|
||||
(action (run test.exe %{deps})))
|
||||
|
||||
(alias
|
||||
(rule runtest)
|
||||
(deps bar)
|
||||
(locks m)
|
||||
(action (run test.exe %{deps})))
|
||||
|
||||
Dune will make sure that the executions of ``test.exe foo`` and
|
||||
``test.exe bar`` are serialized.
|
||||
|
||||
Although they don't live in the filesystem, lock names are interpreted as file
|
||||
names. So for instance, ``(with-lock m ...)`` in ``src/dune`` and ``(with-lock
|
||||
../src/m)`` in ``test/dune`` refer to the same lock.
|
||||
|
||||
Note also that locks are per build context. So if your workspace has two build
|
||||
contexts setup, the same rule might still be executed concurrently between the
|
||||
two build contexts. If you want a lock that is global to all build contexts,
|
||||
simply use an absolute filename:
|
||||
|
||||
.. code:: dune
|
||||
|
||||
(rule
|
||||
(alias runtest)
|
||||
(deps foo)
|
||||
(locks /tcp-port/1042)
|
||||
(action (run test.exe %{deps})))
|
||||
|
||||
22
unikernel/duniverse/dune_/doc/concepts/ocaml-flags.rst
Normal file
22
unikernel/duniverse/dune_/doc/concepts/ocaml-flags.rst
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
OCaml Flags
|
||||
===========
|
||||
|
||||
In ``library``, ``executable``, ``executables``, and ``env`` stanzas,
|
||||
you can specify OCaml compilation flags using the following fields:
|
||||
|
||||
- ``(flags <flags>)`` to specify flags passed to both ``ocamlc`` and
|
||||
``ocamlopt``
|
||||
- ``(ocamlc_flags <flags>)`` to specify flags passed to ``ocamlc`` only
|
||||
- ``(ocamlopt_flags <flags>)`` to specify flags passed to ``ocamlopt`` only
|
||||
|
||||
For all these fields, ``<flags>`` is specified in the
|
||||
:doc:`../reference/ordered-set-language`.
|
||||
These fields all support ``(:include ...)`` forms.
|
||||
|
||||
The default value for ``(flags ...)`` is taken from the environment,
|
||||
as a result it's recommended to write ``(flags ...)`` fields as
|
||||
follows:
|
||||
|
||||
.. code:: dune
|
||||
|
||||
(flags (:standard <my options>))
|
||||
147
unikernel/duniverse/dune_/doc/concepts/package-spec.rst
Normal file
147
unikernel/duniverse/dune_/doc/concepts/package-spec.rst
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
Package Specification
|
||||
=====================
|
||||
|
||||
.. TODO(diataxis)
|
||||
- reference: packages
|
||||
- howto: preparing an opam package
|
||||
- tutorial: from zero to opam
|
||||
|
||||
Installation is the process of copying freshly built libraries,
|
||||
binaries, and other files from the build directory to the system. Dune
|
||||
offers two ways of doing this: via opam or directly via the ``install``
|
||||
command. In particular, the installation model implemented by Dune
|
||||
was copied from opam. Opam is the standard OCaml package manager.
|
||||
|
||||
In both cases, Dune only know how to install whole packages. A
|
||||
package being a collection of executables, libraries, and other files.
|
||||
In this section, we'll describe how to define a package, how to
|
||||
"attach" various elements to it, and how to proceed with installing it
|
||||
on the system.
|
||||
|
||||
.. _declaring-a-package:
|
||||
|
||||
Declaring a Package
|
||||
-------------------
|
||||
|
||||
To declare a package, simply add a ``package`` stanza to your
|
||||
``dune-project`` file:
|
||||
|
||||
.. code:: dune
|
||||
|
||||
(package
|
||||
(name mypackage)
|
||||
(synopsis "My first Dune package!")
|
||||
(description "\| This is my first attempt at creating
|
||||
"\| a project with Dune.
|
||||
))
|
||||
|
||||
Once you have done this, Dune will know about the package named
|
||||
``mypackage`` and you will be able to attach various elements to it.
|
||||
The ``package`` stanza accepts more fields, such as dependencies.
|
||||
|
||||
Note that package names are in a global namespace, so the name you choose must
|
||||
be universally unique. In particular, package managers never allow users to
|
||||
release two packages with the same name.
|
||||
|
||||
.. TODO: describe this more in details
|
||||
|
||||
In older projects using Dune, packages were defined by manually writing a file
|
||||
called ``<package-name>.opam`` at the root of the project. However, it's not
|
||||
recommended to use this method in new projects, as we expect to deprecate it in
|
||||
the future. The right way to define a package is with a ``package`` stanza in
|
||||
the ``dune-project`` file.
|
||||
|
||||
See :doc:`../howto/opam-file-generation` for instructions on configuring Dune
|
||||
to automatically generate ``.opam`` files based on the ``package`` stanzas.
|
||||
|
||||
Attaching Elements to a Package
|
||||
-------------------------------
|
||||
|
||||
Attaching an element to a package means declaring to Dune that this
|
||||
element is part of the said package. The method to attach an element
|
||||
to a package depends on the kind of the element. In this subsection,
|
||||
we will go through the various kinds of elements and describe how to
|
||||
attach each of them to a package.
|
||||
|
||||
In the rest of this section, ``<prefix>`` refers to the directory in
|
||||
which the user chooses to install packages. When installing via opam,
|
||||
it's opam that sets this directory. When calling ``dune install``,
|
||||
the installation directory is either guessed or can be manually
|
||||
specified by the user. Defaults directories which replace guessing
|
||||
can be set during the compilation of dune.
|
||||
|
||||
Sites of a Package
|
||||
------------------
|
||||
|
||||
When packages need additional resources outside their binary, their location
|
||||
could be hard to find. Moreover, some packages could add resources to another
|
||||
package, e.g., in the case of plugins. These locations are called sites in
|
||||
Dune. One package can define them. During execution, one site corresponds to a
|
||||
list of directories. They are like layers, and the first directories have a higher
|
||||
priority. Examples and precisions are available at :ref:`sites`.
|
||||
|
||||
|
||||
Libraries
|
||||
^^^^^^^^^
|
||||
|
||||
In order to attach a library to a package, merely add a
|
||||
``public_name`` field to your library. This is the name that external
|
||||
users of your libraries must use in order to refer to it. Dune
|
||||
requires that a library's public name is either the name of the
|
||||
package it is part of or start with the package name followed by a dot
|
||||
character.
|
||||
|
||||
For instance:
|
||||
|
||||
.. code:: dune
|
||||
|
||||
(library
|
||||
(name mylib)
|
||||
(public_name mypackage.mylib))
|
||||
|
||||
After you have added a public name to a library, Dune will know to
|
||||
install it as part of the package it is attached to. Dune installs
|
||||
the library files in a directory ``<prefix>/lib/<package-name>``.
|
||||
|
||||
If the library name contains dots, the full directory in which the
|
||||
library files are installed is ``lib/<comp1>/<comp2/.../<compn>``,
|
||||
where ``<comp1>``, ``<comp2>``, ... ``<compn>`` are the dot-separated
|
||||
component of the public library name. By definition, ``<comp1>`` is
|
||||
always the package name.
|
||||
|
||||
Executables
|
||||
^^^^^^^^^^^
|
||||
|
||||
Similar to libraries, to attach an executable to a package simply
|
||||
add a ``public_name`` field to your ``executable`` stanza or a
|
||||
``public_names`` field for ``executables`` stanzas. Designate this
|
||||
name to match the available executables through the installed ``PATH``
|
||||
(i.e., the name users must type in their shell to execute
|
||||
the program), because Dune cannot guess an executable's relevant package
|
||||
from its public name. It's also necessary to add a ``package`` field
|
||||
unless the project contains a single package, in which case the executable
|
||||
will be attached to this package.
|
||||
|
||||
For instance:
|
||||
|
||||
.. code:: dune
|
||||
|
||||
(executable
|
||||
(name main)
|
||||
(public_name myprog)
|
||||
(package mypackage))
|
||||
|
||||
Once ``mypackage`` is installed on the system, the user will be able
|
||||
to type the following in their shell:
|
||||
|
||||
.. code:: console
|
||||
|
||||
$ myprog
|
||||
|
||||
to execute the program.
|
||||
|
||||
Other Files
|
||||
^^^^^^^^^^^
|
||||
|
||||
For all other kinds of elements, you must attach them manually via
|
||||
an :doc:`/reference/dune/install` stanza.
|
||||
109
unikernel/duniverse/dune_/doc/concepts/promotion.rst
Normal file
109
unikernel/duniverse/dune_/doc/concepts/promotion.rst
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
Diffing and Promotion
|
||||
=====================
|
||||
|
||||
You can use Diffing and Promotion flows to compare the outputs of your build in
|
||||
the build directory with the source tree and/or copy the result of the rules
|
||||
into your source tree to store the changes.
|
||||
|
||||
Diffing
|
||||
=======
|
||||
|
||||
You can use the ``(diff <file1> <file2>)`` directive in a rule to compare
|
||||
its output with the version in your source tree. It is useful when
|
||||
your tests produce a file output and you want to make sure that output has
|
||||
not changed.
|
||||
|
||||
.. TODO(diataxis)
|
||||
- howto: diffing and promotion
|
||||
- reference: diffing
|
||||
|
||||
``(diff <file1> <file2>)`` is very similar to ``(run diff <file1>
|
||||
<file2>)``. In particular it behaves in the same way:
|
||||
|
||||
- When ``<file1>`` and ``<file2>`` are equal, it does nothing.
|
||||
- When they are not, the differences are shown and the action fails.
|
||||
|
||||
However, it is different for the following reason:
|
||||
|
||||
- The exact command used for diff files can be configured via the
|
||||
``--diff-command`` command line argument. Note that it's only
|
||||
called when the files are not byte equals
|
||||
|
||||
- By default, it will use ``patdiff`` if it is installed. ``patdiff``
|
||||
is a better diffing program. You can install it via opam with:
|
||||
|
||||
.. code:: console
|
||||
|
||||
$ opam install patdiff
|
||||
|
||||
- On Windows, both ``(diff a b)`` and ``(diff? a b)`` normalize
|
||||
end-of-line characters before comparing the files.
|
||||
|
||||
- Since ``(diff a b)`` is a built-in action, Dune knows that ``a``
|
||||
and ``b`` are needed, so you don't need to specify them
|
||||
explicitly as dependencies.
|
||||
|
||||
- You can use ``(diff? a b)`` after a command that might or might not
|
||||
produce ``b``, for cases where commands optionally produce a
|
||||
*corrected* file
|
||||
|
||||
- If ``<file1>`` doesn't exist, it will compare with the empty file.
|
||||
|
||||
- It allows promotion. See below.
|
||||
|
||||
Note that ``(cmp a b)`` does no end-of-line normalization and doesn't
|
||||
print a diff when the files differ. ``cmp`` is meant to be used with
|
||||
binary files.
|
||||
|
||||
Promotion
|
||||
=========
|
||||
|
||||
Promotion relates to copying the output of a Dune rule to your source tree.
|
||||
Common uses include updating rule output after a failed diff (e.g., from a
|
||||
test) or committing output to source control to cut down on dependencies
|
||||
during packaging.
|
||||
|
||||
Promoting Test or Rule Output After Diffing
|
||||
-------------------------------------------
|
||||
|
||||
Whenever an action ``(diff <file1> <file2>)`` or ``(diff? <file1>
|
||||
<file2>)`` fails because the two files are different, Dune allows
|
||||
you to promote ``<file2>`` as ``<file1>`` if ``<file1>`` is a source
|
||||
file and ``<file2>`` is a generated file.
|
||||
|
||||
More precisely, let's consider the following Dune file:
|
||||
|
||||
.. code:: dune
|
||||
|
||||
(rule
|
||||
(with-stdout-to data.out (run ./test.exe)))
|
||||
|
||||
(rule
|
||||
(alias runtest)
|
||||
(action (diff data.expected data.out)))
|
||||
|
||||
Where ``data.expected`` is a file committed in the source
|
||||
repository. You can use the following workflow to update your test:
|
||||
|
||||
- Update the code of your test.
|
||||
- Run ``dune runtest``. The diff action will fail and a diff will
|
||||
be printed.
|
||||
- Check the diff to make sure it's what you expect. This diff can be displayed
|
||||
again by running ``dune promotion diff``.
|
||||
- Run ``dune promote``. This will copy the generated ``data.out``
|
||||
file to ``data.expected`` directly in the source tree.
|
||||
|
||||
You can also use ``dune runtest --auto-promote``, which will
|
||||
automatically do the promotion.
|
||||
|
||||
Automatically Promoting Rule Output Into the Source Tree
|
||||
--------------------------------------------------------
|
||||
|
||||
Dune rules support a ``(mode promote)`` directive that will automatically
|
||||
copy their output into your source tree. This approach suits, for example, code
|
||||
documentation generation flows where output needs to be committed to source
|
||||
code control to enable easier browsing, or eliminate dependencies on a code
|
||||
generation step during opam package installation.
|
||||
|
||||
More information, including customising when the source is copied, can be found
|
||||
in :doc:`../reference/dune/rule`.
|
||||
76
unikernel/duniverse/dune_/doc/concepts/sandboxing.rst
Normal file
76
unikernel/duniverse/dune_/doc/concepts/sandboxing.rst
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
Sandboxing
|
||||
==========
|
||||
|
||||
.. TODO(diataxis)
|
||||
- explanation: sandboxing
|
||||
- reference: sandboxing
|
||||
|
||||
The user actions that run external commands (``run``, ``bash``, ``system``)
|
||||
are opaque to Dune, so Dune has to rely on manual specification of dependencies
|
||||
and targets. One problem with manual specification is that it's error-prone.
|
||||
It's often hard to know in advance what files the command will read,
|
||||
and knowing a correct set of dependencies is very important for build
|
||||
reproducibility and incremental build correctness.
|
||||
|
||||
To help with this problem Dune supports sandboxing.
|
||||
An idealized view of sandboxing is that it runs the action in an environment
|
||||
where it can't access anything except for its declared dependencies.
|
||||
|
||||
In practice, we have to make compromises and have some trade-offs between
|
||||
simplicity, information leakage, performance, and portability.
|
||||
|
||||
The way sandboxing is currently implemented is that for each sandboxed action
|
||||
we build a separate directory tree (sandbox directory) that mirrors the build
|
||||
directory, filtering it to only contain the files that were declared as
|
||||
dependencies. We run the action in that directory, and then we copy
|
||||
the targets back to the build directory.
|
||||
|
||||
You can configure Dune to use sandboxing modes ``symlink``, ``hardlink``, or
|
||||
``copy``, which determine how the individual files are populated (they will be
|
||||
symlinked, hardlinked, or copied into the sandbox directory).
|
||||
|
||||
This approach is very simple and portable, but that comes with
|
||||
certain limitations:
|
||||
|
||||
- The actions in the sandbox can use absolute paths to refer to anywhere outside
|
||||
the sandbox. This means that only dependencies on relative paths in the build
|
||||
tree can be enforced/detected by sandboxing.
|
||||
- The sandboxed actions still run with full permissions of Dune itself, so
|
||||
sandboxing is not a security feature. It won't prevent network access either.
|
||||
- We don't erase the environment variables of the sandboxed
|
||||
commands. This is something we want to change.
|
||||
- Performance impact is usually small, but it can get noticeable for
|
||||
fast actions with very large sets of dependencies.
|
||||
|
||||
Per-Action Sandboxing Configuration
|
||||
-----------------------------------
|
||||
|
||||
Some actions may rely on sandboxing to work correctly.
|
||||
For example, an action may need the input directory to contain nothing
|
||||
except the input files, or the action might create temporary files that
|
||||
break other build actions.
|
||||
|
||||
Some other actions may refuse to work with Sandboxing. For example,
|
||||
if they rely on absolute path to the build directory staying fixed,
|
||||
or if they deliberately use some files without declaring dependencies
|
||||
(this is usually a very bad idea, by the way).
|
||||
|
||||
Generally it's better to improve the action so it works with or without
|
||||
sandboxing (especially with), but sometimes you just can't do that.
|
||||
|
||||
Things like this can be described using the "sandbox" field in the dependency
|
||||
specification language (see :doc:`dependency-spec`).
|
||||
|
||||
Global Sandboxing Configuration
|
||||
-------------------------------
|
||||
|
||||
Dune always respects per-action sandboxing specification.
|
||||
You can configure it globally to prefer a certain sandboxing mode if
|
||||
the action allows it.
|
||||
|
||||
This is controlled by:
|
||||
|
||||
- ``dune --sandbox <...>`` CLI flag (see ``man dune-build``)
|
||||
- ``DUNE_SANDBOX`` environment (see ``man dune-build``)
|
||||
- ``(sandboxing_preference ..)`` field in the configuration file (see ``man
|
||||
dune-config``)
|
||||
241
unikernel/duniverse/dune_/doc/concepts/variables.rst
Normal file
241
unikernel/duniverse/dune_/doc/concepts/variables.rst
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
Variables
|
||||
=========
|
||||
|
||||
.. TODO(diataxis)
|
||||
- reference: variables
|
||||
- explanation: rule loading
|
||||
|
||||
Some fields can contains variables that are expanded by Dune.
|
||||
The syntax of variables is as follows:
|
||||
|
||||
.. code::
|
||||
|
||||
%{var}
|
||||
|
||||
or, for more complex forms that take an argument:
|
||||
|
||||
.. code::
|
||||
|
||||
%{fun:arg}
|
||||
|
||||
In order to write a plain ``%{``, you need to write ``\%{`` in a
|
||||
string.
|
||||
|
||||
Dune supports the following variables:
|
||||
|
||||
- ``project_root`` is the root of the current project. It is typically the root
|
||||
of your project, and as long as you have a ``dune-project`` file there,
|
||||
``project_root`` is independent of the workspace configuration.
|
||||
- ``workspace_root`` is the root of the current workspace. Note that
|
||||
the value of ``workspace_root`` isn't constant and depends on
|
||||
whether your project is vendored or not.
|
||||
- ``cc`` is the C compiler command line (list made of the compiler
|
||||
name followed by its flags) that will be used to compile foreign code. For
|
||||
more details about its content, please see :doc:`/reference/foreign-flags`.
|
||||
- ``cxx`` is the C++ compiler command line being used in the
|
||||
current build context.
|
||||
- ``ocaml_bin`` is the path where ``ocamlc`` lives.
|
||||
- ``ocaml`` is the ``ocaml`` binary.
|
||||
- ``ocamlc`` is the ``ocamlc`` binary.
|
||||
- ``ocamlopt`` is the ``ocamlopt`` binary.
|
||||
- ``ocaml_version`` is the version of the compiler used in the
|
||||
current build context.
|
||||
- ``ocaml_where`` is the output of ``ocamlc -where``.
|
||||
- ``arch_sixtyfour`` is ``true`` if using a compiler that targets a
|
||||
64-bit architecture and ``false`` otherwise.
|
||||
- ``null`` is ``/dev/null`` on Unix or ``nul`` on Windows.
|
||||
- ``ext_obj``, ``ext_asm``, ``ext_lib``, ``ext_dll``, and ``ext_exe``
|
||||
are the file extensions used for various artifacts.
|
||||
- ``ext_plugin`` is ``.cmxs`` if ``natdynlink`` is supported and
|
||||
``.cma`` otherwise.
|
||||
- ``ocaml-config:v`` is for every variable ``v`` in the output of
|
||||
``ocamlc -config``. Note that Dune processes the output
|
||||
of ``ocamlc -config`` in order to make it a bit more stable across
|
||||
versions, so the exact set of variables accessible this way might
|
||||
not be exactly the same as what you can see in the output of
|
||||
``ocamlc -config``. In particular, variables added in new OCaml versions
|
||||
need to be registered in Dune before they can be used.
|
||||
- ``profile`` is the profile selected via ``--profile``.
|
||||
- ``context_name`` is the name of the context (``default``, or defined in the
|
||||
workspace file)
|
||||
- ``os_type`` is the type of the OS the build is targeting. This is
|
||||
the same as ``ocaml-config:os_type``.
|
||||
- ``architecture`` is the type of the architecture the build is targeting. This
|
||||
is the same as ``ocaml-config:architecture``.
|
||||
- ``model`` is the type of the CPU the build is targeting. This is
|
||||
the same as ``ocaml-config:model``.
|
||||
- ``system`` is the name of the OS the build is targeting. This is the same as
|
||||
``ocaml-config:system``.
|
||||
- ``ignoring_promoted_rules`` is ``true`` if
|
||||
``--ignore-promoted-rules`` was passed on the command line and
|
||||
``false`` otherwise.
|
||||
- ``<ext>:<path>`` where ``<ext>`` is one of ``cmo``, ``cmi``, ``cma``,
|
||||
``cmx``, or ``cmxa``. See :ref:`variables-for-artifacts`.
|
||||
- ``env:<var>=<default`` expands to the value of the environment
|
||||
variable ``<var>``, or ``<default>`` if it does not exist.
|
||||
For example, ``%{env:BIN=/usr/bin}``.
|
||||
Available since Dune 1.4.0.
|
||||
- There are some Coq-specific variables detailed in :ref:`coq-variables`.
|
||||
|
||||
In addition, ``(action ...)`` fields support the following special variables:
|
||||
|
||||
- ``target`` expands to the one target.
|
||||
- ``targets`` expands to the list of target.
|
||||
- ``deps`` expands to the list of dependencies.
|
||||
- ``^`` expands to the list of dependencies, separated by spaces.
|
||||
- ``dep:<path>`` expands to ``<path>`` (and adds ``<path>`` as a dependency of
|
||||
the action).
|
||||
- ``exe:<path>`` is the same as ``<path>``, except when cross-compiling, in
|
||||
which case it will expand to ``<path>`` from the host build context.
|
||||
- ``bin:<program>`` expands ``<path>`` to ``program``. If ``program``
|
||||
is installed by a workspace package (see :doc:`/reference/dune/install`
|
||||
stanzas), the locally built binary will be used, otherwise it will be
|
||||
searched in the ``<path>`` of the current build context. Note that ``(run
|
||||
%{bin:program} ...)`` and ``(run program ...)`` behave in the same way.
|
||||
``%{bin:...}`` is only necessary when you are using ``(bash ...)`` or
|
||||
``(system ...)``.
|
||||
- ``bin-available:<program>`` expands to ``true`` or ``false``, depending
|
||||
on whether ``<program>`` is available or not.
|
||||
- ``file-available:<path>`` expands to ``true`` or ``false``, depending on
|
||||
whether the file at ``<path>`` is available in the current workspace.
|
||||
- ``lib:<public-library-name>:<file>`` expands to the file's installation path
|
||||
``<file>`` in the library ``<public-library-name>``. If
|
||||
``<public-library-name>`` is available in the current workspace, the local
|
||||
file will be used, otherwise the one from the :term:`installed world` will be
|
||||
used.
|
||||
- ``lib-private:<library-name>:<file>`` expands to the file's build path
|
||||
``<file>`` in the library ``<library-name>``. Both public and private library
|
||||
names are allowed as long as they refer to libraries within the same project.
|
||||
- ``libexec:<public-library-name>:<file>`` is the same as ``lib:...``, except
|
||||
when cross-compiling, in which case it will expand to the file from the host
|
||||
build context.
|
||||
- ``libexec-private:<library-name>:<file>`` is the same as ``lib-private:...``
|
||||
except when cross-compiling, in which case it will expand to the file from the
|
||||
host build context.
|
||||
- ``lib-available:<library-name>`` expands to ``true`` or ``false`` depending on
|
||||
whether the library is available or not. A library is available if at least
|
||||
one of the following conditions holds:
|
||||
|
||||
- It's part the :term:`installed world`.
|
||||
- It's available locally and is not optional.
|
||||
- It's available locally, and all its library dependencies are
|
||||
available.
|
||||
|
||||
- ``version:<package>`` expands to the version of the given
|
||||
package. Packages defined in the current scope have priority over the
|
||||
public packages. Public packages that don't install any libraries
|
||||
will not be detected. How Dune determines the version
|
||||
of a package is described :doc:`here <../advanced/package-version>`.
|
||||
- ``read:<path>`` expands to the contents of the given file.
|
||||
- ``read-lines:<path>`` expands to the list of lines in the given
|
||||
file.
|
||||
- ``read-strings:<path>`` expands to the list of lines in the given
|
||||
file, unescaped using OCaml lexical convention.
|
||||
|
||||
The ``%{<kind>:...}`` forms are what allows you to write custom rules that work
|
||||
transparently, whether things are installed or not.
|
||||
|
||||
Note that aliases are ignored by ``%{deps}``
|
||||
|
||||
The intent of this last form is to reliably read a list of strings
|
||||
generated by an OCaml program via:
|
||||
|
||||
.. code:: ocaml
|
||||
|
||||
List.iter (fun s -> print_string (String.escaped s)) l
|
||||
|
||||
#. Dealing with circular dependencies introduced by variables
|
||||
|
||||
If you ever see Dune reporting a dependency cycle that involves a
|
||||
variable such as `%{read:<path>}`, try to move `<path>` to a different
|
||||
directory.
|
||||
|
||||
The reason you might see such dependency cycle is because Dune is
|
||||
trying to evaluate the `%{read:<path>}` too early. For instance, let's
|
||||
consider the following example:
|
||||
|
||||
.. code:: dune
|
||||
|
||||
(rule
|
||||
(targets x)
|
||||
(enabled_if %{read:y})
|
||||
(action ...))
|
||||
|
||||
(rule
|
||||
(with-stdout-to y (...)))
|
||||
|
||||
When Dune loads and interprets this file, it decides whether the
|
||||
first rule is enabled by evaluating ``%{read:y}``. To
|
||||
evaluate ``%{read:y}``, it must build ``y``. To build ``y``, it must
|
||||
figure out the build rule that produces ``y``, and in order to do that, it must
|
||||
first load and evaluate the above ``dune`` file. You can see how this
|
||||
creates a cycle.
|
||||
|
||||
Some cycles might be more complex. In any case, when you see such an
|
||||
error, the easiest thing to do is move the file that's being read
|
||||
to a different directory, preferably a standalone one. You can use the
|
||||
:doc:`/reference/dune/subdir` stanza to keep the logic self-contained in
|
||||
the same ``dune`` file:
|
||||
|
||||
.. code:: dune
|
||||
|
||||
(rule
|
||||
(targets x)
|
||||
(enabled_if %{read:dir-for-y/y})
|
||||
(action ...))
|
||||
|
||||
(subdir
|
||||
dir-for-y
|
||||
(rule
|
||||
(with-stdout-to y (...))))
|
||||
|
||||
Expansion of Lists
|
||||
------------------
|
||||
|
||||
Forms that expand to a list of items, such as ``%{cc}``, ``%{deps}``,
|
||||
``%{targets}``, or ``%{read-lines:...}``, are suitable to be used in
|
||||
``(run <prog> <arguments>)``. For instance in:
|
||||
|
||||
.. code:: dune
|
||||
|
||||
(run foo %{deps})
|
||||
|
||||
If there are two dependencies, ``a`` and ``b``, the produced command
|
||||
will be equivalent to the shell command:
|
||||
|
||||
.. code:: console
|
||||
|
||||
$ foo "a" "b"
|
||||
|
||||
If you want both dependencies to be passed as a single argument,
|
||||
you must quote the variable:
|
||||
|
||||
.. code:: dune
|
||||
|
||||
(run foo "%{deps}")
|
||||
|
||||
which is equivalent to the following shell command:
|
||||
|
||||
.. code:: console
|
||||
|
||||
$ foo "a b"
|
||||
|
||||
(The items of the list are concatenated with space.)
|
||||
Please note: since ``%{deps}`` is a list of items, the first one may be
|
||||
used as a program name. For instance:
|
||||
|
||||
.. code:: dune
|
||||
|
||||
(rule
|
||||
(targets result.txt)
|
||||
(deps foo.exe (glob_files *.txt))
|
||||
(action (run %{deps})))
|
||||
|
||||
Here is another example:
|
||||
|
||||
.. code:: dune
|
||||
|
||||
(rule
|
||||
(target foo.exe)
|
||||
(deps foo.c)
|
||||
(action (run %{cc} -o %{target} %{deps} -lfoolib)))
|
||||
Loading…
Add table
Add a link
Reference in a new issue