Proposal for Dune Plugins #8707
Replies: 7 comments 7 replies
-
Thanks for the interesting and well thought out proposal. Some things are not too different from the various discussions about plugins the team had over the years. I'm going to point a few instances where I think this proposal deviates from dune's normal design patterns or fails to address important (IMHO) use cases.
Finally, you've already pointed this out as a concern, but we need a naming scheme that allows dune to go from a plugin name to the package where this plugin must exist. Without this convention, we won't have effective lazy loading. |
Beta Was this translation helpful? Give feedback.
-
Thanks for the proposal! I have a few comments/questions. Firstly I want to discus the ux of declaring that a project uses a plugin. Consider this example:
The main confusion I have about this as a user is that the plugin is enabled for the entire project but the package implementing the plugin is listed in the dependencies of a specific package. My first question would be what is the behaviour if As you mentioned, we could have dune automatically add dependencies to packages when it sees that they use a plugin and use a naming scheme like An alternative might be to add a keyword for running arbitrary executables (installed from dependencies) that implement the plugin protocol. E.g.
Before evaluating rules dune would expand all the Regarding the matter of generating dune syntax of the appropriate version, @rgrinberg what do you think about making a library to help with this sort of thing, where users could construct typed ASTs and then convert them into sexps compatible with a given version of lang dune? |
Beta Was this translation helpful? Give feedback.
-
Haven't received any feedback about (Provide a way to call dune programatically #8638) but it's conceptually fixing the same extensibility problem. The design of a plugin system is indeed a little tricky, allowing a free-form for users might eventually expose easier what are the limits where users are trying to push Also, both "features" can co-exist. If it's an idea that it's worth pursuing I might have time to create a proper RFC for this. |
Beta Was this translation helpful? Give feedback.
-
Thanks for the updated proposal. One point I would disagree with is that using RPC is going to be overkill for the first version. If we're going introduce a library for plugin authors, we might as well make this library handle communicating with dune using the existing RPC mechanism. This is an already working building block we can just use, so it will simplify the implementation of a library we already plan to introduce. Not to mention that it will make it far simpler to evolve things. The rest of your proposal seems fine to me. I'm still a bit uneasy about the naming scheme to accommodate lazy loading. Another option is to just to make users write the package name from which a plugin must come from in their project file. In any case, I think this proposal is good enough to start gathering feedback from the rest of the interested parties. I will ask in the dev channel to comment. |
Beta Was this translation helpful? Give feedback.
-
@nojb could you have a look at this proposal? It's aimed at helping out power users of dune that would like to do something more complicated than generating dune files. I imagine that it might be of use to you. |
Beta Was this translation helpful? Give feedback.
-
I got around to reading the proposal, sorry for the lag. Thanks @jonahbeckford for putting it forward. The main idea that I am drawing from the proposal is that of having executables that can act as "stanza generators" for Dune. This idea seems useful. However, my feeling is that it would be good to start with small steps that would get us closer to the goal, without necessarily starting to work on the whole proposal at once. We could, for example, proceed as follows:
Just my 2c, not opposed to other approaches :) What do you think @jonahbeckford? Cheers. |
Beta Was this translation helpful? Give feedback.
-
I think you created an iterative task list compatible with the overall goal. And as a bonus the complexity of achieving dynamic includes is reduced. I'm quite fine with that obviously. The only specific concern I have is that it would be nice to not introduce concepts that are temporary and have to be deprecated later ... From a broader perspective, I'm not entirely sure the task list gets the core problem (
I mentioned earlier that I already wrote one; it might have gotten lost in the noise. https://v3.ocaml.org/p/dkml-dune-dsl/latest. I use it heavily in DkCoder (meta build system on top of Dune) and a few other things much earlier than that. |
Beta Was this translation helpful? Give feedback.
-
Dune Plugins
Problem
Given there is a limited set of core Dune developers, it may take years for new tooling to be integrated into Dune.
Terms
(lang dune 3.8)
(foo.bar) (baz.wonky)
High Level Requirements
Implicit Proposal through Examples
Capnp Code Generation
More Terms:
What? Tooling to generate
.ml
files from Capn' Proto.capnp
schemas.Generalizes to? Any tool that generates
.ml
,.mli
,.mll
,.mly
and/or.mld
fromanother type of file.
Without this proposal, a Dune user would add a Capn' Proto generated
.ml
and.mli
files by using the following Dune stanzas (confer: https://github.com/capnproto/capnp-ocaml/tree/v3.6.0/src/examples/1) in herdune
file:and in her
dune-project
file:and manually compile and install the C++ executable
capnp
using instructions on https://github.com/capnproto/capnproto.With this proposal, a Dune user would instead write in her
dune
fileand in her
dune-project
file:The
capnp.generate
plugin author would be responsible for:dune-capnp.0.1.0
which installs the executabledune-capnp.exe
into the opam switch and queryable from findlib. An ordinarydune-project
based package can trivially do this, but nothing precludes non-Dune based packages that conform to findlib.dune-capnp.exe translate-sexp
EACH TIME Dune encounters(capnp.generate ...)
. The functional specification is:The standard input will be the contents of the Dune stanza:
Dune has a set of exclusions that must be respected by the plugin; the
(source (project_pwd (files ...) (dirs ...)))
captures that. In additionthe plugin only has read-only access to source files in the current directory (
project_pwd
).The
(context)
is the currently active build context. Any files in<project_root>/plugins/capnp
generated by thedune-capnp.exe initial-sexp
command (which will be documented further below) will be available todune-capnp.exe translate-sexp
.The
(input)
contains location information for error reporting, and the raw text of the sexp to be translated. It is raw text so that whitespace is preserved for error reporting.The arguments will be:
argv[0] = dune-capnp.exe
argv[1] = translate-sexp
argv[2] = generate
. This is from(capnp.generate ...)
.argv[3] = --plugin-version=0.1
. This is from(using capnp 0.1)
.argv[4] = --dune-lang=4.0
. This is from(lang dune 4.0)
.argv[5] = --protocol=1
. See the Formal Proposal.The standard output (the response of
dune-capnp.exe
) will be of the form:The response will either have an
(error)
or it will have an(output)
, but not both.Because the plugin needs a C executable
capnp
in the PATH only during the build, thecapnp.generate
plugin author will also be responsible for:dune-capnp.exe initial-sexp
ONCE, regardless of the number of occurrences of(capnp.generate ...)
. The functional specification is:The standard input will be the contents of the Dune stanza:
The
(contexts)
contain the one or more build contexts. Each field in a build context comes from the publicly declared Dune Variables; they are not all listed here for brevity's sake.The arguments will be:
argv[0] = dune-capnp.exe
argv[1] = initial-sexp
argv[3] = --plugin-version=0.1
. This is from(using capnp 0.1)
.argv[2] = --dune-lang=4.0
. This is from(lang dune 4.0)
.argv[3] = --protocol=1
. See the Formal Proposal.The standard output (the response of
dune-capnp.exe
) will take the form:The response will either have an
(error)
or it will have an(output)
, but not both.vcpkg C Library Dependency Injection
More Terms:
vcpkg: A popular C package manager; there are others. https://vcpkg.io/
Dune Configurator: A Dune library that lets a Dune project (typically)
Those sexp files can then be used in Dune clauses throughout the Dune project.
https://dune.readthedocs.io/en/stable/dune-libs.html#configurator
dependency injection: A pattern where dependencies are given to an entity (ex. a Dune project). The pattern constrasts with an entity instantiating or discovering its own dependencies (ex. Dune Configurator).
What? Tooling to inject C flags and linker flags for a C library from a Dune workspace into Dune projects, especially into child (vendored) Dune projects.
Generalizes to? The obvious narrow extension is to any C dependency injector tool. But more generally any tool that needs access to the cross-compiling context or source code files.
Without this proposal,
The maintainer of the OCaml
sqlite
package (an arbitrary example) would write code that uses the Dune Configurator to discover where the C librarylibsqlite3
was located. The maintainer would be able to find sqlite3 throughpkg-config
on Unix systems if it were pre-installed.; file: dune (executable (name discover) (libraries dune-configurator)) (rule (targets sqlite3.loc cflags.sexp clibs.sexp) (action (run ./discover.exe))) (library (name sqlite3) (foreign_stubs (language c) (names caml_sqlite3_stubs.c) (flags (:include (cflags.sexp)))) (c_library_flags (:include (clibs.sexp))))
The Dune user of the
sqlite3
package would write ...Everything in the following list increases the difficulty:
luv
package does this)sqlite3
working on Windows and other systems that don't have a system package managersqlite3
working withdune build -x
cross-compilationWith this proposal,
The maintainer of the
sqlite3
would write:to make:
lib/libsqlite3.a
andlib/libsqlite3.so
available if the Dune workspace supports vcpkgpkg-config --libs sqlite3
(ex.-lsqlite3
) if the Dune workspace does not support vcpkgThe maintainer would also write:
; file: dune (library (name sqlite3) (foreign_stubs (language c) (names caml_sqlite3_stubs.c) (flags (:include (%{project_root}/c_inject.sqlite3.cflags.sexp)))) (foreign_archives (:include (%{project_root}/c_inject.sqlite3.archives.sexp))) (c_library_flags (:include (%{project_root}/c_inject.sqlite3.clibs.sexp))))
The
c_inject
plugin author's responsibility would be to create the sexp files%{project_root}/c_inject.<name>.{cflags,archives,clibs}.sexp
.The Dune user of the
sqlite3
package would write ...A
vcpkg.json
file for making the sqlite3 libraries with the specified sqlite3 features enabled available in either Dune's "default" context (if no cross-compiling) or in Dune's cross-compiling context (if there is only one cross-compiling context):A
vcpkg-host.json
file making the sqlite3 executable:And the other files:
Formal Proposal
(<macroname> ...)
stanza with the expansion of the Dune macro(name1.name2 ...)
Dune stanza in adune
file where the head of the stanza contains a dot (ex.capnp.generate
) is a Dune macro call implemented in a Dune plugin executable nameddune-<name1>.exe
.dune-<name1>.exe
with argumentstranslate-sexp <name2> --protocol=1 --dune-lang-VERSION
. The Implicit Proposal specifies thetranslate-sexp
sub-command.(A.B ...)
, Dune will call theinitial-sexp --protocol=1 --dune-lang-VERSION
subcommand and inject its standard output in thedune-project
directory scope. The Implicit Proposal specifies theinitial-sexp
sub-command.13
is reserved to communicate that--protocol=N
is not supported by the Dune plugin. An optimized Protocol 2 may be written at a future date which uses the Dune RPC protocol. Of course that is overkill in the early stages of authoring a Dune plugin. Dune should try the highest protocol it supports, and if it gets exit code13
it should downgrade the protocol number until it no longer receives exit code13
.initial-sexp
andtranslate-sexp <name2>
output of a Dune plugin<name1>
:(lang dune VERSION)
where VERSION is passed in the option--dune-lang=VERSION
.(foo.bar ...)
may emit(baz.wonky ...)
, wherefoo
is one plugin andbaz
is another plugin. That is, Dune plugins are context-independent in their inputs to satisfy high level requirement H1 but may be context-dependent in their outputs.Artifacts
(lang dune VERSION)
. That library must be usable in non-Dune build systems to satisfy high level requirement H2, and ideally would be owned by the Dune team. I have a library that might be a starting point: https://v3.ocaml.org/p/dkml-dune-dsl/latest/README.md.html.Beta Was this translation helpful? Give feedback.
All reactions