diff --git a/doc/tutorials/index.md b/doc/tutorials/index.md index 1c6322e96cb..844a35b7fbe 100644 --- a/doc/tutorials/index.md +++ b/doc/tutorials/index.md @@ -8,4 +8,5 @@ These tutorials are hands-on lessons to learn about Dune. developing-with-dune/index dune-package-management/index +oxcaml-parameterized-library/index ::: diff --git a/doc/tutorials/oxcaml-parameterized-library/implement.md b/doc/tutorials/oxcaml-parameterized-library/implement.md new file mode 100644 index 00000000000..7107aa3f590 --- /dev/null +++ b/doc/tutorials/oxcaml-parameterized-library/implement.md @@ -0,0 +1,119 @@ +# Implement a Library Parameter + +Now we have our parameter, we have our interface. In this section, we will +focus on how to write a library that implements our parameter. + +## Structure Our Project + +As we did for the `parameter`, we are going to add a new directory in our +structure under `lib/`. We create a directory `impl/` under `lib/`. At the root +of the directory, we can run: + +```{code-block} shell +mkdir -p lib/impl +``` + +## Creating an Implementation + +As for the parameter, we start with our `lib/impl/dune` + +:::{literalinclude} implement/lib/impl/dune +:language: dune +::: + +To create an implementation, we write two files: +- The first one is `lib/impl/impl.ml`. It contains the implementation. +- The second one is `lib/impl/impl.mli`. It contains the interface of the implementation. + + +We define an additional `create` function to send our element in the abstract +type. Our project now implements a parameter. + +:::{literalinclude} implement/lib/impl/impl.mli +:language: ocaml +::: + +To have an abstract interface, we define an `mli` file. + +:::{literalinclude} implement/lib/impl/impl.ml +:language: ocaml +::: + + +## Conclusion + +In this section you have learned to implement a parameter. We have added the +following files: + +::::{dropdown} `lib/impl/dune` +:icon: file-code + +:::{literalinclude} implement/lib/impl/dune +:language: dune +::: +:::: + +::::{dropdown} `lib/impl/impl.ml` +:icon: file-code + +:::{literalinclude} implement/lib/impl/impl.ml +:language: ocaml +::: +:::: + +::::{dropdown} `lib/impl/impl.mli` +:icon: file-code + +:::{literalinclude} implement/lib/impl/impl.mli +:language: ocaml +::: +:::: + +You should also have the previous files: + +::::{dropdown} `dune-project` +:icon: file-code + +:::{literalinclude} implement/dune-project +:language: dune +::: +:::: + +::::{dropdown} `test/dune` +:icon: file-code + +:::{literalinclude} implement/test/dune +:language: dune +::: +:::: + +:::: + +::::{dropdown} `test/simple.t` +:icon: file-code + +:::{literalinclude} implement/test/simple.t +:language: dune +::: +:::: + +::::{dropdown} `lib/param/dune` +:icon: file-code + +:::{literalinclude} implement/lib/param/dune +:language: dune +::: +:::: + +::::{dropdown} `lib/param/param.mli` +:icon: file-code + +:::{literalinclude} implement/lib/param/param.mli +:language: ocaml +::: +:::: + +:::: + +In the next section, we will see how we write a library parameterized by our +parameter. diff --git a/doc/tutorials/oxcaml-parameterized-library/implement/dune-project b/doc/tutorials/oxcaml-parameterized-library/implement/dune-project new file mode 100644 index 00000000000..ca4150f22d3 --- /dev/null +++ b/doc/tutorials/oxcaml-parameterized-library/implement/dune-project @@ -0,0 +1,4 @@ +(lang dune 3.20) +(using oxcaml 0.1) + +(package (name param)) diff --git a/doc/tutorials/oxcaml-parameterized-library/implement/lib/impl/dune b/doc/tutorials/oxcaml-parameterized-library/implement/lib/impl/dune new file mode 100644 index 00000000000..7f456382fea --- /dev/null +++ b/doc/tutorials/oxcaml-parameterized-library/implement/lib/impl/dune @@ -0,0 +1,3 @@ +(library + (name impl) + (implement param)) diff --git a/doc/tutorials/oxcaml-parameterized-library/implement/lib/impl/impl.ml b/doc/tutorials/oxcaml-parameterized-library/implement/lib/impl/impl.ml new file mode 100644 index 00000000000..971aaeb0868 --- /dev/null +++ b/doc/tutorials/oxcaml-parameterized-library/implement/lib/impl/impl.ml @@ -0,0 +1,5 @@ +type t = int + +let create t = t + +let compare = Int.compare diff --git a/doc/tutorials/oxcaml-parameterized-library/implement/lib/impl/impl.mli b/doc/tutorials/oxcaml-parameterized-library/implement/lib/impl/impl.mli new file mode 100644 index 00000000000..5e1efb844fb --- /dev/null +++ b/doc/tutorials/oxcaml-parameterized-library/implement/lib/impl/impl.mli @@ -0,0 +1,3 @@ +type t +val create : int -> t +val compare: t -> t -> int diff --git a/doc/tutorials/oxcaml-parameterized-library/implement/lib/param/dune b/doc/tutorials/oxcaml-parameterized-library/implement/lib/param/dune new file mode 100644 index 00000000000..4d2405a6fdd --- /dev/null +++ b/doc/tutorials/oxcaml-parameterized-library/implement/lib/param/dune @@ -0,0 +1,2 @@ +(library_parameter + (public_name param)) diff --git a/doc/tutorials/oxcaml-parameterized-library/implement/lib/param/param.mli b/doc/tutorials/oxcaml-parameterized-library/implement/lib/param/param.mli new file mode 100644 index 00000000000..ce52b0d7c1a --- /dev/null +++ b/doc/tutorials/oxcaml-parameterized-library/implement/lib/param/param.mli @@ -0,0 +1,2 @@ +type t +val compare: t -> t -> int diff --git a/doc/tutorials/oxcaml-parameterized-library/implement/test/dune b/doc/tutorials/oxcaml-parameterized-library/implement/test/dune new file mode 100644 index 00000000000..da0be2eb9b0 --- /dev/null +++ b/doc/tutorials/oxcaml-parameterized-library/implement/test/dune @@ -0,0 +1,3 @@ +(cram + (applies_to :whole_subtree) + (enabled_if %{oxcaml_supported})) diff --git a/doc/tutorials/oxcaml-parameterized-library/implement/test/simple.t b/doc/tutorials/oxcaml-parameterized-library/implement/test/simple.t new file mode 100644 index 00000000000..23175439e97 --- /dev/null +++ b/doc/tutorials/oxcaml-parameterized-library/implement/test/simple.t @@ -0,0 +1,4 @@ +This test shows the behavior of the program and ensures it does not have +regression. + + $ dune build diff --git a/doc/tutorials/oxcaml-parameterized-library/index.md b/doc/tutorials/oxcaml-parameterized-library/index.md new file mode 100644 index 00000000000..adb73d307ef --- /dev/null +++ b/doc/tutorials/oxcaml-parameterized-library/index.md @@ -0,0 +1,38 @@ +--- +author: Etienne Marais +--- + +OxCaml Parameterized Library With Dune +====================================== + +:::{warning} +Parameterized libraries are a feature only supported by the OxCaml branch of +the OCaml compiler. You need to install this version of the compiler to use it +within Dune. This feature should currently be considered as not stable. +::: + +This tutorial explains how to create a parameterized library in Dune. +Parameterized library in Dune are a concept similar to +{doc}`/virtual-libraries`. Parameterized libraries are the formalization within +the compiler of virtual libraries.A parameterized library is conceptually +equivalent to a functor. For more detailled explanation, see (TODO @maiste: +link to explanation). + +By the end of the tutorial, you will know: +- how to create a library parameter, +- how to implement a library parameter, +- how to parameterize a library with a library parameter, +- how to instantiate a parameterized library with a a parameter implementation. + +To get started make sure you have [oxcaml](https://oxcaml.org/) available in +your path and let's {doc}`setup` our project. + +:::{toctree} +:hidden: +:maxdepth: 1 +setup +parameter +implement +parameterized_by +instantiate +::: diff --git a/doc/tutorials/oxcaml-parameterized-library/instantiate.md b/doc/tutorials/oxcaml-parameterized-library/instantiate.md new file mode 100644 index 00000000000..c58e22cac97 --- /dev/null +++ b/doc/tutorials/oxcaml-parameterized-library/instantiate.md @@ -0,0 +1,3 @@ +# Instantiate a Parameterized Library + +TODO @maiste: instantiate the parameterized library with the implementation. diff --git a/doc/tutorials/oxcaml-parameterized-library/parameter.md b/doc/tutorials/oxcaml-parameterized-library/parameter.md new file mode 100644 index 00000000000..9e3ad651270 --- /dev/null +++ b/doc/tutorials/oxcaml-parameterized-library/parameter.md @@ -0,0 +1,101 @@ +# Create a Library Parameter + +In this section, we are going to learn how to write a +{doc}`/reference/dune/library_parameter` + +## Declaring a parameter + +We can either declare our parameter as private or public in Dune. In our case, +we are going to declare it as a public parameter. Indeed, Dune doesn't build +unecessary targets. It means it won't build anything that is not needed. In our +case, it would mean our parameter wouldn't get built until we use it. Making it +public informs Dune it is mandatory to build the target. + +To build our parameter we are going to use the +{doc}`/reference/dune/library_parameter` stanza. + +First, we need to create the directory where we are going to host our +parameter. At the root of our project, we create a `lib/` directory where we +are going to host the code. Inside the `lib/` directory, we create a `param/` +directory to host our parameter. We do this in a single command to save +instructions. + +```{code-block} shell +mkdir -p lib/param +``` + +In `lib/param/`, we create a new `dune` file: + +:::{literalinclude} parameter/lib/param/dune +:language: dune +::: +:::: + +The `library_parameter` stanza takes care of the parameter generation under the +hood. It calls the OxCaml compiler with the correct compiler options and flags. + +Still in `lib/param/`, we create the interface for our future libraries in `param.mli`: + +:::{literalinclude} parameter/lib/param/param.mli +:language: ocaml +::: +:::: + +This interface is what our implementation library will need to provide and the +interface of our future parameterized library. + +## Conclusion + +We have learned how to declare a parameter using Dune with its interface. + +Your directory should now contains two additional files: + +::::{dropdown} `lib/param/dune` +:icon: file-code + +:::{literalinclude} parameter/lib/param/dune +:language: dune +::: +:::: + +::::{dropdown} `lib/param/param.mli` +:icon: file-code + +:::{literalinclude} parameter/lib/param/param.mli +:language: ocaml +::: +:::: + +:::: + +The file from the previous should be in the following state: + +::::{dropdown} `dune-project` +:icon: file-code + +:::{literalinclude} parameter/dune-project +:language: dune +::: +:::: + +::::{dropdown} `test/dune` +:icon: file-code + +:::{literalinclude} parameter/test/dune +:language: dune +::: +:::: + +:::: + +::::{dropdown} `test/simple.t` +:icon: file-code + +:::{literalinclude} parameter/test/simple.t +:language: dune +::: +:::: + +In the next part, we are going to learn how to write the implementation of our +parameter. + diff --git a/doc/tutorials/oxcaml-parameterized-library/parameter/dune-project b/doc/tutorials/oxcaml-parameterized-library/parameter/dune-project new file mode 100644 index 00000000000..ca4150f22d3 --- /dev/null +++ b/doc/tutorials/oxcaml-parameterized-library/parameter/dune-project @@ -0,0 +1,4 @@ +(lang dune 3.20) +(using oxcaml 0.1) + +(package (name param)) diff --git a/doc/tutorials/oxcaml-parameterized-library/parameter/lib/param/dune b/doc/tutorials/oxcaml-parameterized-library/parameter/lib/param/dune new file mode 100644 index 00000000000..4d2405a6fdd --- /dev/null +++ b/doc/tutorials/oxcaml-parameterized-library/parameter/lib/param/dune @@ -0,0 +1,2 @@ +(library_parameter + (public_name param)) diff --git a/doc/tutorials/oxcaml-parameterized-library/parameter/lib/param/param.mli b/doc/tutorials/oxcaml-parameterized-library/parameter/lib/param/param.mli new file mode 100644 index 00000000000..ce52b0d7c1a --- /dev/null +++ b/doc/tutorials/oxcaml-parameterized-library/parameter/lib/param/param.mli @@ -0,0 +1,2 @@ +type t +val compare: t -> t -> int diff --git a/doc/tutorials/oxcaml-parameterized-library/parameter/test/dune b/doc/tutorials/oxcaml-parameterized-library/parameter/test/dune new file mode 100644 index 00000000000..da0be2eb9b0 --- /dev/null +++ b/doc/tutorials/oxcaml-parameterized-library/parameter/test/dune @@ -0,0 +1,3 @@ +(cram + (applies_to :whole_subtree) + (enabled_if %{oxcaml_supported})) diff --git a/doc/tutorials/oxcaml-parameterized-library/parameter/test/simple.t b/doc/tutorials/oxcaml-parameterized-library/parameter/test/simple.t new file mode 100644 index 00000000000..23175439e97 --- /dev/null +++ b/doc/tutorials/oxcaml-parameterized-library/parameter/test/simple.t @@ -0,0 +1,4 @@ +This test shows the behavior of the program and ensures it does not have +regression. + + $ dune build diff --git a/doc/tutorials/oxcaml-parameterized-library/parameterized_by.md b/doc/tutorials/oxcaml-parameterized-library/parameterized_by.md new file mode 100644 index 00000000000..160377ab0cc --- /dev/null +++ b/doc/tutorials/oxcaml-parameterized-library/parameterized_by.md @@ -0,0 +1,3 @@ +# Parameterized a Library + +TODO @maiste: Create a library using the parameter. diff --git a/doc/tutorials/oxcaml-parameterized-library/parameters_field/a/a.mli b/doc/tutorials/oxcaml-parameterized-library/parameters_field/a/a.mli new file mode 100644 index 00000000000..d457bb75239 --- /dev/null +++ b/doc/tutorials/oxcaml-parameterized-library/parameters_field/a/a.mli @@ -0,0 +1 @@ +val foo : string diff --git a/doc/tutorials/oxcaml-parameterized-library/parameters_field/a/dune b/doc/tutorials/oxcaml-parameterized-library/parameters_field/a/dune new file mode 100644 index 00000000000..2993e2ce519 --- /dev/null +++ b/doc/tutorials/oxcaml-parameterized-library/parameters_field/a/dune @@ -0,0 +1 @@ +(library_parameter (public_name param.a) (name a)) diff --git a/doc/tutorials/oxcaml-parameterized-library/parameters_field/b/b.mli b/doc/tutorials/oxcaml-parameterized-library/parameters_field/b/b.mli new file mode 100644 index 00000000000..46253bca69d --- /dev/null +++ b/doc/tutorials/oxcaml-parameterized-library/parameters_field/b/b.mli @@ -0,0 +1 @@ +val bar : string \ No newline at end of file diff --git a/doc/tutorials/oxcaml-parameterized-library/parameters_field/b/dune b/doc/tutorials/oxcaml-parameterized-library/parameters_field/b/dune new file mode 100644 index 00000000000..9d4d0e72d17 --- /dev/null +++ b/doc/tutorials/oxcaml-parameterized-library/parameters_field/b/dune @@ -0,0 +1 @@ +(library_parameter (name b)) \ No newline at end of file diff --git a/doc/tutorials/oxcaml-parameterized-library/parameters_field/dune b/doc/tutorials/oxcaml-parameterized-library/parameters_field/dune new file mode 100644 index 00000000000..44ba11e0f06 --- /dev/null +++ b/doc/tutorials/oxcaml-parameterized-library/parameters_field/dune @@ -0,0 +1 @@ +(library (name parameterised) (parameters param.a b)) \ No newline at end of file diff --git a/doc/tutorials/oxcaml-parameterized-library/parameters_field/p.ml b/doc/tutorials/oxcaml-parameterized-library/parameters_field/p.ml new file mode 100644 index 00000000000..7489d0e6f28 --- /dev/null +++ b/doc/tutorials/oxcaml-parameterized-library/parameters_field/p.ml @@ -0,0 +1 @@ +let test () = print_endline A.foo \ No newline at end of file diff --git a/doc/tutorials/oxcaml-parameterized-library/setup.md b/doc/tutorials/oxcaml-parameterized-library/setup.md new file mode 100644 index 00000000000..e2725e83b30 --- /dev/null +++ b/doc/tutorials/oxcaml-parameterized-library/setup.md @@ -0,0 +1,106 @@ +# Setting Up The Project Structure + +Parameterized libraries only work with a compiler supporting parameterized +libraries. Currently, only OxCaml supports this feature. Follow [the +instructions](https://oxcaml.org/get-oxcaml/) to get the OxCaml version of the +compiler. + +Once that is done, we will create a simple project structure that we will grow +during the tutorial. + +## Setting a Simple Project + +We create a `dune-project` file using the `3.20` version (or a higher version) +of the language, as OxCaml support is available only from version `3.20` +onwards: + +:::{literalinclude} setup/dune-project +:language: dune +::: + +:::{important} +It is mandatory to add the `oxcaml` extension. It allows dune to use the +stanzas and fields specific to OxCaml +::: + +And... This is it! We have our basic structure to be able to build the project. + +## Adding a basic test + +Now we have our base, we want to add a simple test and make sure the test only +runs when the OxCaml compiler is available. We are going to use +{doc}`/reference/cram` to verify the program behaves as we expect. + +First, we create a test directory to store our tests: + +```{code-block} shell +mkdir test +``` + +Inside our `test/` directory, we add our `dune` file with all the information +required to build the directory: + +:::{literalinclude} setup/test/dune +:language: dune +:emphasize-lines: 3 +::: + +Let's analyze the content of the `dune` file. We declare add a +{doc}`/reference/dune/cram` stanza. Then we declare we want the stanza to apply +to the entire subtree of our `test/` directory. The highlighted part tells Dune +to only execute the cram test when OxCaml is supported. Again, this variable is +only available because we set the `oxcaml` extension. + +Afterward, we create a `simple.t` file where we store our first test. The test +consists on building the project and make sure it compiles. + +:::{literalinclude} setup/test/simple.t +:language: cram +::: + +As the test succeeds, the test command should output nothing: +```{code-block} shell +dune test +echo "$?" +# 0 +``` + +## Conclusion + +In this part of the tutorial, we have seen how to create a project where we +enable support for OxCaml. We have also learnt how to create a simple test +suite, and only run it when OxCaml is available. + +Your directory should be in the following state after the tutorial. + +::::{dropdown} `dune-project` +:icon: file-code + +:::{literalinclude} setup/dune-project +:language: dune +::: +:::: + +::::{dropdown} `test/dune` +:icon: file-code + +:::{literalinclude} setup/test/dune +:language: dune +::: +:::: + +:::: + +::::{dropdown} `test/simple.t` +:icon: file-code + +:::{literalinclude} setup/test/simple.t +:language: dune +::: +:::: + +:::: + + +In the next part of the tutorial, we are going to explore how to write a +`library_parameter`. diff --git a/doc/tutorials/oxcaml-parameterized-library/setup/dune-project b/doc/tutorials/oxcaml-parameterized-library/setup/dune-project new file mode 100644 index 00000000000..e7dc57572bd --- /dev/null +++ b/doc/tutorials/oxcaml-parameterized-library/setup/dune-project @@ -0,0 +1,2 @@ +(lang dune 3.20) +(using oxcaml 0.1) diff --git a/doc/tutorials/oxcaml-parameterized-library/setup/test/dune b/doc/tutorials/oxcaml-parameterized-library/setup/test/dune new file mode 100644 index 00000000000..da0be2eb9b0 --- /dev/null +++ b/doc/tutorials/oxcaml-parameterized-library/setup/test/dune @@ -0,0 +1,3 @@ +(cram + (applies_to :whole_subtree) + (enabled_if %{oxcaml_supported})) diff --git a/doc/tutorials/oxcaml-parameterized-library/setup/test/simple.t b/doc/tutorials/oxcaml-parameterized-library/setup/test/simple.t new file mode 100644 index 00000000000..23175439e97 --- /dev/null +++ b/doc/tutorials/oxcaml-parameterized-library/setup/test/simple.t @@ -0,0 +1,4 @@ +This test shows the behavior of the program and ensures it does not have +regression. + + $ dune build