Skip to content

Commit

Permalink
[Doc] Add explanation for sites in its own file
Browse files Browse the repository at this point in the history
Signed-off-by: François Bobot <[email protected]>
  • Loading branch information
bobot committed Sep 16, 2020
1 parent 356537e commit a006ade
Show file tree
Hide file tree
Showing 5 changed files with 225 additions and 88 deletions.
85 changes: 0 additions & 85 deletions doc/advanced-topics.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,91 +57,6 @@ set of predicates:
it is linked as part of a driver or meant to add a ``-ppx`` argument
to the compiler, choose the former behavior

.. _plugins:

Plugins and dynamic loading of packages
========================================

Dune allows to define and load plugins without having to deal with specific
compilation, installation directories, dependencies or the module `Dynlink`.
Here we show an example of an executable which can be extended using plugins,
and the definition of one plugin in another package.

Example
-------

Main executable (C)
^^^^^^^^^^^^^^^^^^^^^

- ``dune-project`` file:

.. code:: scheme
(lang dune 2.8)
(name c)
(package (name c) (sites (lib plugins)))
- ``dune`` file:

.. code:: scheme
(executable
(public_name c)
(modules sites c)
(libraries c.register dune-site dune-site.plugins))
(library
(public_name c.register)
(name c_register)
(modules c_register))
(generate_module (module sites) (plugins (c plugins)))
- The module ``c_register.ml`` of the library ``c.register``:

.. code:: ocaml
let todo = Queue.create ()
- The code of the exectuable ``c.ml``:

.. code:: ocaml
(* load all the available plugins *)
let () = Sites.Plugins.Plugins.load_all ()
(* Execute the code registered by the plugins *)
let () = Queue.iter (fun f -> f ()) !C_register.todo
One plugin (B)
^^^^^^^^^^^^^^

- ``dune-project`` file:

.. code:: scheme
(lang dune 2.8)
(name b)
- ``dune`` file:

.. code:: scheme
(library
(public_name b)
(libraries c.register))
(plugin
(name b)
(libraries b)
(site (c plugins)))
- The code of the plugin ``b.ml``:

.. code:: ocaml
let () = Queue.add (fun () -> print_endline "B is doing something") C_register.todo

Dynamic loading of packages with findlib
========================================
Expand Down
4 changes: 1 addition & 3 deletions doc/concepts.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1048,8 +1048,6 @@ the installation directory is either guessed or can be manually
specified by the user. This is described more in detail in the last
section of this page.

.. _sites:

Sites of a package
------------------

Expand All @@ -1058,7 +1056,7 @@ could be hard to find. Moreover some packages could add resources to another
package, for example in the case of plugins. These location are called sites in
dune. One package can define them. During execution one site corresponds to a
list of directories. They are like layers, the first directories have an higher
priority.
priority. Examples and precisions are available at :ref:`sites`.


Libraries
Expand Down
3 changes: 3 additions & 0 deletions doc/dune-files.rst
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,9 @@ It contains the following fields:
<url>)``, ``(documentation <url>)`` are the same (and take precedence over)
the corresponding global fields. These fields are available since Dune 2.0.

- ``(sites (<section> <name>) ...)`` define a site named ``<name>`` in the
section ``<section>``.

Adding libraries to different packages is done via ``public_name`` field. See
:ref:`library` section for details.

Expand Down
1 change: 1 addition & 0 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Welcome to dune's documentation!
foreign-code
documentation
jsoo
sites
opam
variants
formatting
Expand Down
220 changes: 220 additions & 0 deletions doc/sites.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
.. _sites:

*****************
How to load additional files at runtime
*****************

Sites
=====

Sites are a way for a package to define particular sub-directories in a :ref:`section<install>`
(``lib``, ``share``, ``etc``, ... ) directory. The main difficulty is that those directories
are not at the same location at different time:

- When the package is available locally, the location is inside ``_build``
- When the package is installed, the location is inside the install prefix
- If a local package want to install files to the site of another installed
package the location is at the same time in ``_build`` and in the install prefix
of the second package.

With the last example we see that the location of a site is not always uniq but
could be layers of directories: ``["dir1";"dir2"]``. So a lookup must first look
into "dir1", then into "dir2".

Defining a site
---------------

A site is defined a package :ref:`package` in the ``dune-project`` file.

.. code:: scheme
(lang gune 2.8)
(name mygui)
(package (name mygui) (sites (share themes)))
Adding files to a site
----------------------


Here the package ``mygui`` defines a sites named ``themes`` it will be located
in the section ``share``. This package can add files to this ``sites`` using the
:ref:`install stanza<install>`:

.. code:: scheme
(install
(section (site c themes))
(files
(layout.css as default/layout.css)
(ok.png as default/ok.png)
(ko.png as default/ko.png)
)
)
Another package ``mygui_material_theme`` can install files inside ``mygui`` directory for adding a new
theme. Inside the scope of ``mygui_material_theme`` the ``dune`` file:

.. code:: scheme
(install
(section (site c themes))
(files
(layout.css as material/layout.css)
(ok.png as material/ok.png)
(ko.png as material/ko.png)
)
)
The package ``mygui`` must be present in the workspace or installed.

Getting the locations of a site at runtime
------------------------------------------

The executable ``mygui`` will be able to get the locations of the ``themes``
site using the :ref:`generate module stanza<generate_module>`

.. code:: scheme
(executable
(name mygui)
(module mygui mysites)
)
(generate_module (name mysites) (sites c))
Then inside the ``mygui.ml`` module the locations can be recovered and used:

.. code:: ocaml
(** Locations of the site for the themes *)
let themes_locations : string list = Mysites.Sites.themes
(** Merge the content of the directories in [dirs] *)
let rec readdirs dirs =
List.concat
(List.map
(fun dir -> Array.to_list (Sys.readdir dir))
(List.filter Sys.file_exists dirs))
(** Get the lists of the available themes *)
let find_available_themes () : string list = lookup_dirs themes_locations
(** Lookup a file in the directories, priority on the first *)
let rec lookup_file filename = function
| [] -> raise Not_found
| dir::dirs ->
let filename' = Filename.concat dir filename in
if Sys.file_exists filename' then filename'
else lookup_file filename dirs
(** [lookup_theme_file theme file] get the [file] of the [theme] *)
let lookup_theme_file file theme =
lookup_file (Filename.concat theme file) themes_locations
let get_layout_css = lookup_theme_file "layout.css"
let get_ok_ico = lookup_theme_file "ok.png"
let get_ko_ico = lookup_theme_file "ko.png"
Tests
-----

During tests the files are copied into the sites through the dependency
``(package mygui)`` and ``(package mygui_material_theme)`` as for other files in
install stanza.


Installation
------------

Installation is done simply with ``dune install``, however if one want to
install this tool such as it is relocatable. One can use ``dune
install --relocatable --prefix $dir``. The files will be copied to the directory
``$dir`` but the binary ``$dir/bin/mygui`` will get the site location relatively
to its location. So even if the directory ``$dir`` is moved, ``themese_locations`` will
be correct.

.. _plugins:

Plugins and dynamic loading of packages
========================================

Dune allows to define and load plugins without having to deal with specific
compilation, installation directories, dependencies or the module `Dynlink`.
Here we show an example of an executable which can be extended using plugins,
and the definition of one plugin in another package.

Example
-------

Main executable (C)
^^^^^^^^^^^^^^^^^^^^^

- ``dune-project`` file:

.. code:: scheme
(lang dune 2.8)
(name c)
(package (name c) (sites (lib plugins)))
- ``dune`` file:

.. code:: scheme
(executable
(public_name c)
(modules sites c)
(libraries c.register dune-site dune-site.plugins))
(library
(public_name c.register)
(name c_register)
(modules c_register))
(generate_module (module sites) (plugins (c plugins)))
- The module ``c_register.ml`` of the library ``c.register``:

.. code:: ocaml
let todo = Queue.create ()
- The code of the exectuable ``c.ml``:

.. code:: ocaml
(* load all the available plugins *)
let () = Sites.Plugins.Plugins.load_all ()
(* Execute the code registered by the plugins *)
let () = Queue.iter (fun f -> f ()) !C_register.todo
One plugin (B)
^^^^^^^^^^^^^^

- ``dune-project`` file:

.. code:: scheme
(lang dune 2.8)
(name b)
- ``dune`` file:

.. code:: scheme
(library
(public_name b)
(libraries c.register))
(plugin
(name b)
(libraries b)
(site (c plugins)))
- The code of the plugin ``b.ml``:

.. code:: ocaml
let () = Queue.add (fun () -> print_endline "B is doing something") C_register.todo

0 comments on commit a006ade

Please sign in to comment.