Project Configuration
package.json
esy knows how to build your package and its dependencies by looking at the
package.json file at the root of the project.
Because esy needs more information about the project, it extends package.json
with the following fields:
esy.buildesy.buildDevesy.installesy.buildsInSourceesy.exportedEnvesy.buildEnvesy.opamRepositoriesscriptsdependenciesdevDependenciesresolutions
Specify Build & Install Commands
The crucial pieces of configuration are esy.build and esy.install keys, they
specify how to build and install built artifacts.
esy.build
Describe how your package's default targets should be built when package is being used as a dependency.
For example, for a dune based package you'd want to call dune build
command.
{
"esy": {
"build": [
"dune build -p #{self.name}",
]
}
}
esy variable substitution syntax can be used to declare build commands.
esy.buildDev
Describe how your package's default targets should be built when package is being developed. This is only used for the root package of an esy project.
The main difference with esy.build is that commands declared in esy.buildDev
have access to "devDependencies".
For example, for a dune based package you'd want
to call dune build command.
{
"esy": {
"buildDev": [
"refmterr dune build --root . --only-packages #{self.name}",
]
},
"devDependencies": {
"refmterr": "*",
...
}
}
Note that we use refmterr command which is declared in "devDependencies"
section.
esy variable substitution syntax can be used to declare build commands.
If no esy.buildDev is defined then esy.build is used instead.
esy.install (optional)
By default esy will look for a single *.install file in the project root and
will transfer all files mentioned there into #{self.install} directory.
This follows the convention of opam and plays well with dune (which produces
*.install files by default).
But some projects can have special requirements:
-
Some have multiple
*.installfiles and want to install artifacts only from some of them. -
Some might require custom commands to be executed (for example
make install).
There's esy.install config key which allows to specify a set of commands which
should move built artifacts to #{self.install} location.
{
"esy": {
"build": [...],
"install": [
"dune install --prefix=#{self.install}"
]
}
}
esy variable substitution syntax can be used to declare install commands.
Enforcing Out Of Source Builds
esy requires packages to be built "out of source".
It allows esy to separate source code from built artifacts and thus reuse the same source code location between several sandboxes.
esy.buildsInSource
Because not every project's build system is designed in a way which allows "out
of source" builds esy has special settings esy.buildsInSource which provide
a useful workaround.
There are three modes which are controlled by esy.buildsInSource config key:
{
"esy": {
"build": [...],
"install": [...],
"buildsInSource": "_build" | false | true,
}
}
Each mode changes how esy executes build commands. This is how those modes work:
-
"_build"Build commands can place artifacts inside the
_builddirectory of the project's root ($cur__root/_buildin terms of esy build environment).This is what dune or ocamlbuild (in its default configuration) users should be using as this matches those build systems' conventions.
-
false(default if key is omitted)Build commands should use
$cur__target_diras the build directory. -
trueProjects are allowed to place build artifacts anywhere in their source tree, but not outside of their source tree. Otherwise, esy will defensively copy project's root into
$cur__target_dirand run build commands from there.This is the mode which should be used as the last resort as it degrades performance of the builds greatly by placing correctness as a priority.
Exported Environment
Packages can configure how they contribute to the environment of the packages which depend on them.
esy.exportedEnv
To add a new environment variable to the esy build
environment packages could specify esy.exportedEnv config
key:
{
"name": "mylib",
"esy": {
...,
"exportedEnv": {
"CAML_LD_LIBRARY_PATH": {
"val": "#{mylib.lib : $CAML_LD_LIBRARY_PATH}",
"scope": "global"
}
}
}
}
In the example above, the configuration exports (in this specific case it
re-exports it) an environment variable called $CAML_LD_LIBRARY_PATH by
appending $mylib__lib to its previous value.
Note the usage of esy variable substitution
syntax to define the value of the
$CAML_LD_LIBRARY_PATH variable.
Multiple opam repositories
esy.opamRepositories
If you wish to provide an overlay of packages, maybe because you
patched a package and your changes haven't been merged yet, you can do
so, by specifying your opam repository in addition to the upstream, in
the opamRepositories field.
Example
{
"esy":
"opamRepositories": [
{
"type": "remote",
"location": "https://github.com/ocaml/opam-repository.git"
},
{
"type": "remote",
"location": "https://github.com/ocaml/opam-repository-archive.git"
}
]
}
The git URLs can also have a branch name at the end.
{
"esy":
"opamRepositories": [
{
"type": "remote",
"location": "https://github.com/ocaml/opam-repository.git#master"
},
{
"type": "remote",
"location": "https://github.com/ocaml/opam-repository-archive.git#main#main"
}
]
}
Build Environment
Packages can configure their own build environment.
Note that build environment doesn't propagate to dependencies, only current package's build process can access it.
esy.buildEnv
To add a new environment variable to the build environment of the current
package there's esy.buildEnv config key:
{
"name": "mylib",
"esy": {
...,
"buildEnv": {
"DUNE_BUILD_DIR": "#{self.target_dir}"
}
}
}
Note the usage of esy variable substitution
syntax to define the value of the
$DUNE_BUILD_DIR variable.
Example: dune (jbuilder)
This is how it looks for a dune (formely jbuilder) based project:
{
"name": "my-dune-project",
"version": "1.0.0",
"esy": {
"build": ["dune build"],
"buildEnv": {"DUNE_BUILD_DIR": "#{self.target_dir}"}
},
"dependencies": {
"@opam/dune": "*",
"ocaml": "*"
}
}
Specify dependencies
dependencies
This works similar to npm or yarn standard
dependenciesconfiguration.
To define a set of dependencies of the package specify them in dependencies
key inside package.json.
"dependencies": {
"refmterr": "^3.1.7",
"@esy-ocaml/reason": "^3.0.0"
}
We refer to the npm documentation on dependencies for the
syntax of possible package constraints.
As esy allows to work with packages hosted on opam repository it extends npm's
standard mechanism with a special handling of @opam/* scope:
-
Any scoped package
@opam/PKGrefers to an opam packsagePKG. -
Any constraint for a scoped package
@opam/PKGis a constraint against opam versions.
devDependencies
This works similar to npm or yarn standard
devDependenciesconfiguration.
devDependencies works similar to dependencies but they are only handled for
the root package and override the constraints found in dependencies key.
resolutions
It's sometimes necessary to override the package version determined by the
solver. In such a case, use resolutions field in the package.json.
"resolutions": {
"@opam/menhir": "20171013"
}
Resolutions are only valid in the current project and are not exported.
This feature works similar to yarn's Selective dependency resolutions
but nested patterns (which contain ** or * are not supported).
Project Specific Commands
scripts
Similar to npm and yarn, esy supports custom project specific commands via
scripts section inside package.json.
"scripts": {
"build-dev": "esy build dune build --dev",
"test": "dune runtest",
}
The example above defines two new commands.
The command esy build-dev is configured to be a shortcut for the following
invocation:
esy build dune build
While the command esy test is defined to be a shortcut for:
esy dune runtest
For non-interactive (ie. when used in scripts), to ensure forward compatiblity, we encourage a more verbose
esy run-script build-dev and esy run-script test. Explicitly specifying
run-script prevents clashes with subcommands that we add in future.
Note that if a command in scripts is not prefixed with the esy command then it's made to automatically execute inside the Command Environment.