************
Other topics
************

This section describes some details of dune for advanced users.

META file generation
====================

Dune uses ``META`` files from the `findlib library
manager <http://projects.camlcity.org/projects/findlib.html>`__ in order
to interoperate with the rest of the world when installing libraries. It
is able to generate them automatically. However, for the rare cases
where you would need a specific ``META`` file, or to ease the transition
of a project to dune, it is allowed to write/generate a specific
one.

In order to do that, write or setup a rule to generate a
``META.<package>.template`` file in the same directory as the
``<package>.opam`` file. Dune will generate a ``META.<package>``
file from the ``META.<package>.template`` file by replacing lines of
the form ``# DUNE_GEN`` by the contents of the ``META`` it would
normally generate.

For instance if you want to extend the ``META`` file generated by
dune you can write the following ``META.foo.template`` file:

.. code::

   # DUNE_GEN
   blah = "..."

Findlib integration
===================

Dune uses ``META`` files to support external libraries. However, it
doesn't export the full power of findlib to the user, and especially
it doesn't let the user specify *predicates*.

The reason for this limitation is that so far they haven't been
needed, and adding full support for them would complicate things quite
a lot. In particular, complex ``META`` files are often hand-written and
the various features they offer are only available once the package is
installed, which goes against the root ideas dune is built on.

In practice, dune interprets ``META`` files assuming the following
set of predicates:

- ``mt``: what this means is that using a library that can be used
  with or without threads with dune will force the threaded
  version

- ``mt_posix``: forces the use of posix threads rather than VM
  threads. VM threads are deprecated and are likely to go away soon

- ``ppx_driver``: when a library acts differently depending on whether
  it is linked as part of a driver or meant to add a ``-ppx`` argument
  to the compiler, choose the former behavior


Dynamic loading of packages with findlib
========================================

The preferred way for new development is to use :ref:`plugins`.

Dune supports the ``findlib.dynload`` package from `findlib
<http://projects.camlcity.org/projects/findlib.html>`_ that enables
dynamically loading packages and their dependencies (using the OCaml Dynlink module).
So adding the ability for an application to have plugins just requires to add
``findlib.dynload`` to the set of library dependencies:

.. code:: scheme

    (library
      (name mytool)
      (public_name mytool)
      (modules ...)
    )

    (executable
      (name main)
      (public_name mytool)
      (libraries mytool findlib.dynload)
      (modules ...)
    )


Then you could use in your application ``Fl_dynload.load_packages l``
that will load the list ``l`` of packages. The packages are loaded
only once. So trying to load a package statically linked does nothing.

A plugin creator just need to link to your library:

.. code:: scheme

    (library
      (name mytool_plugin_a)
      (public_name mytool-plugin-a)
      (libraries mytool)
    )

By choosing some naming convention, for example all the plugins of
``mytool`` should start with ``mytool-plugin-``. You can automatically
load all the plugins installed for your tool by listing the existing packages:

.. code:: ocaml

    let () = Findlib.init ()
    let () =
      let pkgs = Fl_package_base.list_packages () in
      let pkgs =
        List.filter
          (fun pkg -> 14 <= String.length pkg && String.sub pkg 0 14 = "mytool-plugin-")
          pkgs
      in
      Fl_dynload.load_packages pkgs

Classical ppx
=============

*classical ppx* refers to running ppx using the -ppx compiler option, which is
composed using Findlib. Even though this is useful to run some (usually old)
ppx's which don't support drivers, dune does not support preprocessing with
ppx this way. but a workaround exists using the `ppxfind
<https://github.com/diml/ppxfind>`_ tool.

Profiling dune
==============

If ``--trace-file FILE`` is passed, dune will write detailed data about internal
operations, such as the timing of commands that are run by dune.

The format is compatible with `Catapult trace-viewer`_. In particular, these
files can be loaded into Chromium's ``chrome://tracing``. Note that the exact
format is subject to change between versions.

.. _Catapult trace-viewer: https://github.com/catapult-project/catapult/blob/master/tracing/README.md

.. _package-version:

Package version
===============

Dune determine the version of a package by looking at the ``version``
field in the :ref:`package stanza <package>`. If the version field is
not set, it looks at the toplevel ``version`` field in the
``dune-project`` field. If neither are set, dune assume that we are in
development mode and reads the version from the VCS if any. The way it
obtains the version from the VCS in described in :ref:`the build-info
section <build-info>`.

When installing the files of a package on the system, dune
automatically inserts the package version into various metadata files
such as ``META`` and ``dune-package`` files.

.. _ocaml-syntax:

OCaml syntax
============

If a ``dune`` file starts with ``(* -*- tuareg -*- *)``, then it is
interpreted as an OCaml script that generates the ``dune`` file as described
in the rest of this section. The code in the script will have access to a
`Jbuild_plugin
<https://github.com/ocaml/dune/blob/master/plugin/jbuild_plugin.mli>`__
module containing details about the build context it is executed in.

The OCaml syntax gives you an escape hatch for when the S-expression
syntax is not enough. It is not clear whether the OCaml syntax will be
supported in the long term as it doesn't work well with incremental
builds. It is possible that it will be replaced by just an ``include``
stanza where one can include a generated file.

Consequently **you must not** build complex systems based on it.

.. _variables-for-artifacts:

Variables for artifacts
-----------------------

For specific situations where one needs to refer to individual compilation
artifacts, special variables (see :ref:`variables`) are provided so that the
user does not need to be aware of the particular naming conventions or directory
layout implemented by ``dune``.

These variables can appear wherever a :ref:`deps-field` is expected and also
inside :ref:`user-actions`. When used inside :ref:`user-actions`, they
implicitly declare a dependency on the corresponding artifact.

The variables have the form ``%{<ext>:<path>}``, where ``<path>`` is
interpreted relative to the current directory:

- ``cmo:<path>``, ``cmx:<path>``, ``cmi:<path>`` expand to the path of the
  corresponding artifact for the module specified by ``<path>``. The basename of
  ``<path>`` should be the name of a module as specified in a ``(modules)``
  field.

- ``cma:<path>``, ``cmxa:<path>`` expands to the path of the corresponding
  artifact for the library specified by ``<path>``. The basename of ``<path>``
  should be the name of the library as specified in the ``(name)`` field of a
  ``library`` stanza (*not* its public name).

In each case, the expansion of the variable is a path pointing inside the build
context (i.e. ``_build/<context>``).

Building an ad-hoc ``.cmxs``
----------------------------

In the model exposed by ``dune``, a ``.cmxs`` target is created for each
library.  However, the ``.cmxs`` format itself is more flexible than that and is
capable to containing arbitrary ``.cmxa`` and ``.cmx`` files.

For the specific cases where this extra flexibility is needed, one can use
:ref:`variables-for-artifacts` to write explicit rules to build ``.cmxs`` files
not associated to any library.

Below is an example where we build ``my.cmxs`` containing ``foo.cmxa`` and
``d.cmx``. Note how we use a :ref:`library` stanza to set up the compilation of
``d.cmx``.

.. code:: lisp

    (library
     (name foo)
     (modules a b c))

    (library
     (name dummy)
     (modules d))

    (rule
     (targets my.cmxs)
     (action (run %{ocamlopt} -shared -o %{targets} %{cmxa:foo} %{cmx:d})))
