Project Description
Configuration files used by drom are in TOML syntax. See also Learn TOML in Y minutes for a very quick
introduction.
A project is composed of the project itself, and a set of packages
(libraries and executables), among which the main package shares the
same name as the project. An opam package is generated for
each package in the project.
The drom.toml Project File
To get a feeling of what is in this file, we can look at the one used for
drom itself:
[project]
drom-version = "0.1.0"
[project]
drom-version = "0.1.0"
[project]
authors = ["Fabrice Le Fessant <fabrice.le_fessant@origin-labs.com>", "Léo Andrès <leo.andres@ocamlpro.com>"]
copyright = "OCamlPro SAS & Origin Labs SAS"
edition = "4.10.0"
github-organization = "ocamlpro"
license = "LGPL2"
min-edition = "4.07.0"
mode = "binary"
name = "drom"
synopsis = "The drom tool is a wrapper over opam/dune in an attempt to provide a cargo-like user experience"
version = "0.2.0"
windows-ci = true
# keys that you could also define:
# build-profile = "...build-profile..."
# odoc-target = "...odoc-target..."
# sphinx-target = "...sphinx-target..."
# archive = "...archive..."
# dev-repo = "...dev-repo..."
# bug-reports = "...bug-reports..."
# doc-api = "...doc-api..."
# doc-gen = "...doc-gen..."
# homepage = "...homepage..."
[project]
description = """
The drom tool is a wrapper over opam/dune in an attempt to provide a cargo-like
user experience. It can be used to create full OCaml projects with
sphinx and odoc documentation. It has specific knowledge of Github and
will generate files for Github Actions CI and Github pages.
"""
[project]
skip = "sphinx/about.rst src/drom_lib/main.ml sphinx/index.rst CHANGES.md test/expect-tests/test.ml ocamlformat"
[dependencies]
[tools.ocamlformat]
for-test = true
[tools.odoc]
for-doc = true
[tools.ppx_expect]
for-test = true
[tools.ppx_inline_test]
for-test = true
[profile.dev]
ocaml-flags = "-w +a-4-40-41-42-44"
[profile.release]
ocaml-flags = "-w -a"
[project]
generators = ["ocamllex", "menhir"]
pack-modules = true
skip-dirs = ["drom-test"]
[[package]]
dir = "src/drom"
[[package]]
dir = "src/drom_lib"
Notice that every package contains only the directory where the
sources are located, in which drom expects to find a file package.toml describing the package itself.
The [project] table
This table describes the main project. For multi-package projects, these fields are used as default if the corresponding fields are not specified in sub-packages.
Here is a short description of the fields:
name: the name of the project and of its main package.version: the current version of the projectauthors: the list of authors of the project, to display in opam files and in the documentationcopyright: the name of the copyright holder for the projectedition: the version of OCaml to be used by default, when building locally or on the CIgithub-organization: the organization owning the project on Github. This field is used to compute the URLs for the documentation.kind: specify whether packages should be programs ("program") or libraries ("library") by default.license: the identifier of the license. See the section about licenses.dromknows a few license and may automatically generate the corresponding files.min-edition: the minimal version of OCaml with which the project can be built. The CI will start at least one job with this version.mode: the target of the compilation. It is either"binary"for an executable, orjavascriptfor a file generated byjs_of_ocaml.synopsis: a very short description of the project.opamrequires this field to start with an uppercase letter and not end with a dot.description: a long description of the project.pack-modules: a bool indicating whether modules should be packed.trueby default. It corresponds to thewrappedfield ofdune.
Some fields are computed automatically if github-organization
is specified, but can be overriden:
archive: the URL from where the sources can be downloaded. Can contain${version}instead of the version.dev-repo: the location of the VCS for the project. They are often specified withgit+https://.bug-reports: the URL where issues can be created.doc-api: the URL where the documentation of the API can be found.doc-gen: the URL where the general documentation can be found.homepage: the URL of the project main homepage
Another important field is the skip field:
skipcontains a space-separated list of files, that should not be modified anymore bydrom. By default,dromwill generate any missing file, and upgrade any file that was previously generated bydromand not modified since then.dromwill print a warning everytime it finds a modified file. This option can be used to avoid this warning, or to preventdromfrom recreating an unwanted file.dromgenerates a file_drom/maximum-skip-field.txtshowing all the values that can appear in this field.There is an exception for
drom.tomlandpackage.tomlfiles, that are only modified when the user configuration has been changed, a changing option passed todrom project, or the--upgradeoption to benefit from a more recent version ofdrom.skipcan also contains tags: such tags can be used to reference several files, related to the tag itself. For example, current skeletons use the following tags:code(source files),docs(documentation),sphinx(sphinx documentation),test(test files),github(github pages and workflows). More tags may be defined in the future.To detect modifications of its files,
dromgenerates a file .drom in the project. This file should be committed in the repository with the files, so thatdromcan always use it to detect changes.Every time
dromskips a file because it has been modified, it saves the new version in the_drom/skipped/directory.For example, if
dromoutputs:[...] Skipping modified file dune-project [...]
You can use the command:
$ diff dune-project _drom/skipped/dune-project
to see the differences. if the differences are meaningless, you may then decide to promote the new file by removing your file and restarting
drom.
The [dependencies] table
This section contains dependencies with their versions. These
dependencies are for libraries only, as they will be added in the
generated dune files.
For example:
ez_config = "0.1.0"
means that the project should be linked with ez_config with a
version compatible with 0.1.0. drom uses semantic
versioning, so it means version >= 0.1.0 and version <
1.0.0. If the version is not formatted as X.Y.Z, drom
will only generate a constraint version >= V.
Versions can also be specified with some other formats:
Following
opamconventions :">0.1.0"for exampleNo constraint specified, with the empty string
""Using the string
"version"meaning that the version of the dependency should be the same one as the package
It is possible to specify more information than the version, in which case the dependency object should be seen as a record containing the fields:
versionfor the version of the dependencylibnamefor the name of the dependency that should be used as a dependency indunefilesfor-testfor a boolean specifying if the dependency is only needed for tests (with-testinopamfiles)for-docfor a boolean specifying if the dependency is only needed for tests (with-docinopamfiles)
For example:
[dependencies]
ez-config = { version = "0.1.0", libname = "ez_config" }
or equivalently:
[dependencies.ez-config]
version = "0.1.0"
libanem = "ez_config"
meaning that the project depends on the opam package
ez-config, and that it should be linked with the corresponding
library ez_config.
The [tools] table
This section contains dependencies that will appear in the
opam files, but not as libraries in the dune files.
The [package] table
The package table has one entry per package (library or
program) included in the project. One of the packages must have the
same name as the project.
The most important field of the package description in the
drom.toml file is the dir field. drom expects
to find a package.toml file in that directory with more
information on the packages.
Yet, it is possible to inline these fields also in the
drom.toml file, but drom.toml will move them to their
package.toml file if you ask it to upgrade the file (using
drom project --upgrade). You can check the list of available
fields in the documentation of package.toml.
The [fields] table
The fields table contains fields that will be added to the
the dune-project file. There is two fields may be used :
dune-project-headerdune-project-trailer
The first one add verbatim content to the dune-project file, right
after the (lang dune X.Y) line. The second one add verbatim content
at the end of file.
Using those fields may be required when using very specific dune
build feature that are not handled by drom. For example, using
the parser generator menhir for non trivial cases will likely need
such tuning.
The package.toml Files
Every package source directory (as specified by the dir field
of each [[package]] entry in the drom.toml file) can
contain a package.toml file.
For example:
$ less src/drom_lib/package.toml
gen-version = "version.ml"
kind = "library"
name = "drom_lib"
pack-modules = true
[dependencies]
directories = "0.2"
ez_cmdliner = "0.1.0"
ez_config = "0.1.0"
ez_file = "0.2.0"
opam-file-format = "2.1.1"
toml = "5.0.0"
[fields]
dune-libraries = "bigarray"
The package fields
The following fields are allowed in a package definition:
dir: the directory of the package sources (defaults tosrc/${name}/dependencies: theopamlibrary dependencies of this packagegenerators: the list of program for which specificdunetargets should be generated. Defaults to an empty list, but the project can define its own list ([ "ocamllex" ; "ocamlyacc" ]by default). The generatormenhiris also available.gen-version: whether aversion.mlfile should be createdkind: the kind of the package (libraryorprogram)name: the name of the package (under which it will be published inopampack: if modules should be wrapped, the name of the wrapper module (defaults to the capitalized name of the library otherwise)skeleton: the skeleton to be used to generate the files of this project (defaults to"program"). See the section on skeletons for more info.tools: theopamtools dependencies of this package
The following fields are also allowed, and default to the project ones if not specified:
authors: the authors of the packagedescription: the full description of the packagemode: the mode of the package (binaryorjavascript)pack-modules: whether modules should be wrapped or notsynopsis: the one-line description of the packageversion: the version of this package
For menhir usage, you will find an optional [menhir] talbe,
with the following fields:
* version: the version of the menhir language configuration
* parser: a table with the following fields:
modules: an array of string with all your menhir modules
merge-into: an optional string for the name of the merged module, by default the last value in themodulesarray if not provided
tokens: an optional to add the--external-tokensflag
flags: an optional string array with menhir flags
infer: an optional boolean which adds the(infer <bool>)rule to thedunefile
tokens: an optional table that will add the –only-tokens flag to themenhirrule with the following fiels: *modules: a string array with all the modules to add to the rule *flags: an optional string array with all the flags to add to menhir
The [fields] table
Finally, there is a table [fields] within a
package. Currently, the following fields are used by skeletons:
dune-libraries: extra libraries that can be added in thelibrariesfield ofdune. Typically for internal libraries.dune-stanzas: extradunestanzas in the descriptiondune-trailer: a string that is added at the end of thedunefile.opam-trailer: a string that is added at the end of theopamfile for the package.
In skeletons, fields are referenced using parens (for example
!(dune-stanzas)).
The sites table
The sites table specifies the installation rules for the
project’s additionnal files. For each directories, a path is created
and made available for dynamic lookup through a generated module.
The predefined directories’ fields
There are several predefined directories in the sites table:
libbinsbintoplevelshareetcstublibsdocman
Each of these fields is an array of site specification which is a table with the following fields:
root: a boolean specifying if the directory is installed in the root prefix or in the package prefix. It has meaning only forlibandsharedirectories. Default isfalse.exec: a boolean specifying if the files are installed with the executable flag. It has meaning only forlibdirectory. Default isfalse.dir: the name of a custom site, if any.install: a list of installation specifications.
Each installation specification is a table with the following fields:
sourcedestinationrecursive
source is the source file or directory to install. It can be a glob
pattern like foo/*.js for instance. destination is the
destination file or directory. recursive says that source is
a directory and should be installed recursively.
For example:
[[sites.etc]]
[[sites.etc.install]]
source = "foo.conf"
# will install in <prefix>/etc/<package>/foo.conf
[[sites.share]]
root = true
dir = "www"
[[sites.share.install]]
source = "javascript"
destination = "js"
recursive = true
# will install the javascript directory is <prefix>/share/www/js
The name field
The various sites defined in the sites table are made available
at runtime through a generated module. The name of this module can be
specified with the name field. For example, if the previous
code was introduced by:
[sites]
name = "MySites"
This would generate a module MySites with the following signature:
module MySites : sig
module Sites : sig
val www : string list
end
end
where the www value is the list of files installed in it.
If not specified, the module is simply named Sites.
Warning
With the default name, the generated module will be Sites.Sites.
Warning
Only explicit custom sites are made available in the generated module.
Skeletons
drom generates most of the files using template files stored
in skeletons on which substitutions are applied.
There are two kinds of skeletons:
Project skeletons are used to create and update most of the files of the project, excluding package specific files.
Package skeletons are used to create and update package specific files, mostly
duneand sources files
When drom is called in a project, it generates a file
_drom/known-skeletons.txt listing all the skeletons it knows
about. Beware that, if you create a new skeleton, you will have to
share it for other users to be able to use drom on the project
to update generated files.
Project Skeletons
Default project skeletons are defined in the source tree in: https://github.com/OCamlPro/drom/tree/master/src/drom_lib/skeletons/projects
The following project skeletons are available by default:
The
virtualskeleton is for a “meta” project, i.e. a project containing other packages, but whose main package (with the name of the project) does not define a program or library. This skeleton can be seen as the root of the inheritance tree between project skeletons.Files:
$ drom new VIRTUAL --skeleton virtual └── VIRTUAL/ ├── .drom (drom state, do not edit) ├── .github/ │ └── workflows/ │ ├── doc-deploy.yml │ └── workflow.yml ├── .gitignore ├── .ocamlformat ├── .ocamlformat-ignore ├── .ocp-indent ├── CHANGES.md ├── LICENSE.md ├── Makefile ├── README.md ├── docs/ │ ├── README.txt │ ├── doc/ │ │ └── index.html │ ├── favicon.png │ ├── index.html │ ├── sphinx/ │ │ └── index.html │ └── style.css ├── drom.toml <────────── project config EDIT ! ├── dune ├── dune-project ├── sphinx/ │ ├── _static/ │ │ └── css/ │ │ └── fixes.css │ ├── about.rst │ ├── conf.py │ ├── index.rst │ ├── install.rst │ └── license.rst ├── src/ │ └── VIRTUAL/ │ └── package.toml <────────── package config EDIT ! └── test/ ├── expect-tests/ │ ├── dune │ └── test.ml ├── inline-tests/ │ ├── dune │ └── test.ml └── output-tests/ ├── dune ├── test1.expected ├── test2.expected └── test2.ml
Notice that there are no
.opamfile generated by default in thevirtualskeleton, until you add other packages usingdrom package XXX --new SKELETONThe
libraryskeleton contains only a library package. It inherits from thevirtualskeleton.Files:
$ drom new LIBRARY --skeleton library └── LIBRARY/ │ . (same as virtual ) . ├── LIBRARY.opam ├── src/ │ └── LIBRARY/ │ ├── dune │ ├── index.mld │ ├── main.ml │ ├── package.toml <────────── package config EDIT ! │ └── version.mlt └── test/ . . (same as virtual )
The
programskeleton contains both a library and a driver packages. It inherits from thevirtualskeleton. It is the default project skeleton used when nothing is specified.Files:
$ drom new PROGRAM --skeleton program └── PROGRAM/ │ . (same as virtual ) . ├── PROGRAM.opam ├── PROGRAM_lib.opam ├── src/ │ ├── PROGRAM/ │ │ ├── dune │ │ ├── index.mld │ │ ├── main.ml │ │ └── package.toml <────────── package config EDIT ! │ └── PROGRAM_lib/ │ ├── dune │ ├── index.mld │ ├── main.ml │ ├── package.toml <────────── package config EDIT ! │ └── version.mlt └── test/ . . (same as virtual )
The
mini-libskeleton contains a library package, with a minimal set of files (no test, no docs, etc.) (since version 0.2.2)Files:
$ drom new MINI-LIB --skeleton mini-lib └── MINI-LIB/ ├── .drom (drom state, do not edit) ├── .gitignore ├── CHANGES.md ├── LICENSE.md ├── MINI-LIB.opam ├── Makefile ├── README.md ├── drom.toml <────────── project config EDIT ! ├── dune ├── dune-project └── src/ └── MINI-LIB/ ├── dune ├── package.toml <────────── package config EDIT ! └── version.mlt
The
mini-prgskeleton contains a program package, with a minimal set of files (no test, no docs, etc.) (since version 0.2.2)Files:
$ drom new MINI-PRG --skeleton mini-prg └── MINI-PRG/ ├── .drom (drom state, do not edit) ├── .gitignore ├── CHANGES.md ├── LICENSE.md ├── MINI-PRG.opam ├── MINI-PRG_lib.opam ├── Makefile ├── README.md ├── drom.toml <────────── project config EDIT ! ├── dune ├── dune-project └── src/ ├── MINI-PRG/ │ ├── dune │ └── package.toml <────────── package config EDIT ! └── MINI-PRG_lib/ ├── dune ├── package.toml <────────── package config EDIT ! └── version.mlt
The
ppx_deriverskeleton contains a library package that defines a ppx_deriver, with a minimal example of code. (since version 0.2.2)Files:
$ drom new PPX_DERIVER --skeleton ppx_deriver └── PPX_DERIVER/ │ . (same as virtual ) . ├── PPX_DERIVER.opam ├── src/ │ └── PPX_DERIVER/ │ ├── dune │ ├── index.mld │ ├── main.ml │ ├── package.toml <────────── package config EDIT ! │ └── version.mlt └── test/ . . (same as virtual )
Package Skeletons
Default package skeletons are defined in the source tree in: https://github.com/OCamlPro/drom/tree/master/src/drom_lib/skeletons/packages
The following package skeletons are available by default:
The
virtualskeleton is an empty skeleton.The
libraryskeleton contains a simple library.The
programskeleton contains a simple program.The
driverskeleton contains a simple program that only calls the main entry point of an associated library.The
ppx_deriverskeleton contains a simple library that defines a ppx_deriver.
Note that the project program skeleton combines a
library package skeleton with a driver package
skeleton.
User-specified skeletons
Users can create their own skeletons. Check the documentation on Contributing Your Own Skeletons