-
Notifications
You must be signed in to change notification settings - Fork 413
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
jbuild plugins #56
Comments
I had a discussion with @lpw25 about the subject of jbuilder plugins and he has We extend the notion of plugins to be dynlinked libaries rather than just
This would be the registration and plugin api: module V1 : sig
type 'a context =
| Sexp : Sexp.t context
| Ordered_set_lang : Ordered_set_lang.t context
| Rules : Rules.t context
type handler = {
handle : 'a. 'a context -> Sexp.t -> 'a;
}
val interpret_set : Sexp.t -> Ordered_set_lang.t
val interpret_sexp : Sexp.t -> Sexp.t
val interpret_rules : Sexp.t -> Rules.t
val register_extension : string -> (Version.t -> handler) -> unit
end The idea is that everyone one of the types in context has a jbuilder function
As an example, here's how a simplified library stanza would be implemented as a module Jbuilder = Jbuilder.V1
type lib = ...
let add_name : string -> lib -> lib = ...
let add_flags : Jbuilder.Ordered_set_lang.t -> lib -> lib = ...
let rules_for_lib : lib -> Jbuilder.Rules.t = ...
let handle_library_arg acc arg =
match Jbuilder.interpret_sexp arg with
| Atom "name" :: Atom name -> add_name name acc
| Atom "flags" :: List flags -> add_flags (Jbuilder.interpret_set flags) acc
| sexp -> Jbuilder.Error.unexpectd sexp "library stanza"
let rules_handler sexp =
match sexp with
| Atom "library" :: args ->
let lib = List.fold_left handle_library_arg empty_lib in
rules_for_lib lib
| ...
let handler (type a) (context : a Jbuilder.context) sexp : a =
match context with
| Rules -> rules_handler sexp
| ...
let () = Jbuilder.register_extension "jbuild" (fun _version -> { handler }) You would import jbuild plugins with a stanza like:
The first plugin listed will handle stanzas of the form This is important because we'd like to statically know which plugins are going Any library will be usable as a plugin, without any prior declaration. This is |
Well, that's more a discussion about the technical API. For me the first question is the following: when you write Another thing to discuss is that if we make the system too generalist, jbuild files are essentially going to become blackboxes, and we won't even be able to lint them without building a lot of stuff. Relying entirely on dynlink is a bit annoying as well. The question of plugins is a bit complicated if we want to get it right, I think we should have another brainstorming session about it. |
You don't need to intepret all jbuild files -- you only need to interpret the ones needed for building foo. Now you don't know which ones those are in advance, but you just assume that the things using
That's going to be true not matter how you approach plugins -- you can't lint things using plugins without building the plugin. But clearly most jbuilds will just use the builtin "jbuild" language and can be linted without building anything. |
To me this boils down to two choices: whether plugins and libraries should live in the same namespace. There are benefit to both approaches but one is clearly simpler than the other. And if we start with separate namespaces, we can always migrate to a single namespace latter. So we should discuss all this a bit more before starting the work on plugins.
Not necessarily, the current syntax could be entirely described using a static DSL, and we could require plugins to do the same. Maybe that's not worth it, but I think we should discuss it before we commit to one particular solution. |
Well, that's more a discussion about the technical API. For me the first
question is the following: when you write (run foo), foo is looked in the
workspace and for that you need to interpret all jbuild files. If plugins
are arbitrary libraries, you need to build them to interpret jbuild files,
and to build them you need to interpret jbuild files, you see the issue...
Is the issue that we'll need to refactor our code a lot to be able to do
this? Because I think that with our restriction of jbuild files declaring
the plugins upfront, it's not really a problem. We might have to be careful
to make sure that plugins don't generate new library stanzas for example.
But that doesn't seem too bad.
Another thing to discuss is that if we make the system too generalist,
jbuild files are essentially going to become blackboxes, and we won't even
be able to lint them without building a lot of stuff.
On the other hand, I can think of a few places where we'll be able to get
rid of ocaml syntax with the help of plugins. This is a net win imo, and
means that even a flawed plugin system is better than no plugin system at
all.
The question of plugins is a bit complicated if we want to get it right, I
think we should have another brainstorming session about it.
Yes, that would be a good idea. I'd like to hear some input from all the
maintainers before proceeding.
… |
To me this boils down to two choices: whether plugins and libraries should
live in the same namespace. There are benefit to both approaches but one is
clearly simpler than the other. And if we start with separate namespaces,
we can always migrate to a single namespace latter. So we should discuss
all this a bit more before starting the work on plugins.
Would you mind elaborating this problem a bit? I'm not sure what is a
namespace in this context for example.
… |
If we have only one namespace then plugins can be used inside normal libraries and normal libraries can use plugins if they want to. If we have two namespaces, normal libraries cannot use plugins and plugins cannot use normal libraries. Plugins can only use other plugins. For instance, you could imagine that all plugins live under |
OK, I see. Thanks.
Aren't plugins unusable without dynlink in either situation? How does the absence of dynlink simplify things between these different universe assumptions. Also, about from your original comment in this issue:
Could you explain why that is necessary for jenga integration? Would it still be necessary for dynlink based plugins. Finally (apologies for the barrage of questions), would we still want to implement plugins as in the original proposal (executables) alongside this new proposal? |
With the two separate namespaces, the workflow is as follow:
step 2 can be done either with dynlink, by dynlinking a cmxs into the running jbuilder, or by linking a new jbuilder binary with the plugins statically linked in and chaining the execution to this new binary. The two code paths are similar, so it's simple to support both. With a single namespace it is more complicated if you don't have dynlink.
I don't remember the details off-hand, but no, let's not go in all directions. Plugins as libraries is a better model, so we should only support that. |
One possibility to get the separate namespaces but still make it easy to use plugins from ocamlfind/opam is to split the namespace with a prefix or suffix. So e.g. every library called |
It would be good to ensure that we don't require natdynlink support to use a native-code jbuilder out of the box. The link-executable-and-exec will work on non-natdynlink platforms as well. Once we have that, what are the benefits of maintaining a dynlink codepath at all? Once the executable is linked, it will be faster for subsequent runs than a repeated dynlink on every build. |
We now have a fresh plugin proposal #1855 that makes this one obsolete |
It is currently impossible for users to extend the jbuild syntax. The ml syntax offers an escape hatch but you have to switch the whole file. One possible way to allow this would be:
where
foo
would be a command that would take the S-expression<arg>
on stdin and output some jbuild syntax on stdout, which would be more or less inlined in the file. Possibly it could use a different version of the spec.For that to work well with the jenga integration, the command would have to output what files it reads and globs it evaluates.
The text was updated successfully, but these errors were encountered: