Skip to content
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

Dunify #598

Draft
wants to merge 10 commits into
base: master
Choose a base branch
from
Draft

Dunify #598

wants to merge 10 commits into from

Conversation

chrismamo1
Copy link

@chrismamo1 chrismamo1 commented Apr 12, 2019

Eliom now compiles in ~17s on my machine, whereas the master branch takes up to 100s.

This also factors the eliom PPX into a separate package, although I suspect it would be possible to avoid doing that.

It also completely removes the syntax package, which I believe is necessary as dune actively discourages camlp4 use. This will break ocsigen-start, since that still relies on Macaque's camlp4 extension, so it cannot use PPX.

Copy link
Member

@Drup Drup left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see you managed to go forward quite a bit, impressive!

First off, You have lot's of code changes that are due to two things: warnings fixes due to dune's settings, and OMPification of the ppxs. I suggest you pull those out and submit them in separate PRs, so that we can merge them (they are much simpler in nature) and clean up the current PR.

Now, about the core of the PR: Your solution is to segregate shared, client, server and eliom files each in their own folder/library, and enforce some dependency order between them. The goal of eliom is precisely not to organize libraries like that, but to organize them by topic, regardless of where the modules are located. If we want to truly be able to build eliom libraries correctly, we need to have libraries where all kind of files live, and have proper handling of dependencies. Of course, this doesn't prevent to merge an initial dunification which we can refine later (when dune has proper support, for instance).

More concretely:

  • I do not see calls to the type ppx, how does that work ?
  • you renamed *.eliom[i] files in eliom/*.ml[i]. This doesn't seem necessary.
  • You currently suppose that we have two building scheme, one for client and one for server. This is not the case with my new implementation. It would be nicer to only suppose you have one build scheme that output 2 things (and which happens to call 2 ppxs currently). This would provide a better way forward.

@@ -46,6 +46,7 @@ let consume (t,u) s =
| Lwt.Sleep -> Lwt.wakeup_exn u e;
| _ -> ());
[%lwt raise ( e)]
[@ocaml.warning "-22"]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure you can just turn those into Lwt.raise, and get rid of the extension node.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change was made to satisfy Dune's default settings, which are very strict on compiler warnings. As per your suggestion, I've pulled it out of the PR.

src/ppx/.merlin Outdated
S /home/chrismamo1/.opam/default/lib/result
S .
FLG -ppx '/home/chrismamo1/Documents/work/BeSport/pgocaml-ppx-porting/eliom/_build/default/.ppx/1f6b9d3f3f2366a895b212642c81f26e/ppx.exe --as-ppx --cookie '\''library-name="ppx"'\'''
FLG -w @a-4-29-40-41-42-44-45-48-58-59-60-40 -strict-sequence -strict-formats -short-paths -keep-locs
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should just drop the merlin file, since they are dune-generated.

@@ -315,7 +312,6 @@ module type Pass = sig
val client_sig: signature_item -> signature_item list
val server_sig: signature_item -> signature_item list

(** How to handle "[%client ...]" and "[%shared ...]" expr. *)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you removing comments?!

... x ...
]
]
*)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

| "", false -> ()
| _, true -> Location.raise_errorf ~loc:Location.(in_file !input_name)
"Wrong arguments:@ %s" (String.concat " " (Array.to_list Sys.argv))
| x, _ -> Mli.type_file := Some x
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you are already using Arg, you should use the ~args argument of Migrate_parsetree_driver.register.

k
| _ ->
failwith "non_attached_info"
.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Beware, this restrict to fairly recent OCaml versions.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change was made to satisfy Dune's default settings, which are very strict on compiler warnings. As per your suggestion, I've pulled it out of the PR.

John Christopher McAlpine added 7 commits April 15, 2019 11:33
move *.client.ml* and *.server.ml* lib files into their respective directories

move *.shared.ml* files into shared directory and add symlinks

refactor the ppx to support standalone and factor .eliom files back out

actually compile things

fix building multiple tools

delete ppx

use external ppx tools

fix a dependency issue and update some possibly-obsolete package names

create eliomopt alias
@chrismamo1
Copy link
Author

@Drup thank you very much for the input.

I've pulled all the compiler warning fixes out, and will submit a new PR once this one has been dealt with.

For simplicity reasons, I think it would be best to pull the PPX and Camlp4 rewriters into separate opam packages, with eliom itself depending on the PPX package.

As for your specific concerns:

  • I do not see calls to the type ppx, how does that work ?

    I'm also unsure about this. I'm able to build ocsigen-toolkit and ocsigen-start with the library as-is, which I honestly didn't expect to work precisely because I've done nothing to handle the generation of .type_mli files within eliom, and I'm a bit unsure of what I could concretely do with those.

  • you renamed .eliom[i] files in eliom/.ml[i]. This doesn't seem necessary.

    I've undone this.

  • You currently suppose that we have two building scheme, one for client and one for server. This is not the case with my new implementation. It would be nicer to only suppose you have one build scheme that output 2 things (and which happens to call 2 ppxs currently). This would provide a better way forward.

    I'm not sure what you're talking about when you mention your new implementation. Are you referring to DO NOT MERGE: Compiling Eliom with the new compiler #459 ?

@Drup
Copy link
Member

Drup commented Apr 16, 2019

For simplicity reasons, I think it would be best to pull the PPX and Camlp4 rewriters into separate opam packages, with eliom itself depending on the PPX package.

Agreed, but keep everything in this repository for now. Dune works particularly well for this, and opam support it just fine. And please don't push things to the opam repository before it's discussed and we have reached a stable solution. In particular it's completely unacceptable to have some eliom packages pointing to github repositories that are not under the ocsigen umbrella.

I'm also unsure about this. I'm able to build ocsigen-toolkit and ocsigen-start with the library as-is, which I honestly didn't expect to work precisely because I've done nothing to handle the generation of .type_mli files within eliom, and I'm a bit unsure of what I could concretely do with those.

If the typing files are not available, the typing is basically ignored. This is wrong as it means injections and fragments are unchecked and makes eliom's typing completely useless. Arguably, it should lead to an error, but unfortunately it currently doesn't. The fact that eliom code compiles is not sufficient to assert that eliom works. You also need wrong code to fail. :)

I'm not sure what you're talking about when you mention your new implementation. Are you referring to #459 ?

Yes.

@rgrinberg
Copy link

@chrismamo1 are you still working on this?

@chrismamo1
Copy link
Author

@chrismamo1 are you still working on this?

Not actively, no.

@rgrinberg
Copy link

I see. I was wondering if you were interested in upstreaming eliom support in dune itself. It would be nice if people didn't have to manually write eliom/eliomi rules :)

@paurkedal
Copy link
Contributor

I think dune support would be a tremendous help. Judging from my own experience, using manual rules is infeasible. Just getting it to compile is straight forward, but getting the dependencies right for server-client type-checking is tricky. That also means adding dune support may be less straight forward than one would think. I hope that doesn't sound too scary. Someone correct my if I'm wrong, but the rough approach to compiling an Eliom applications is:

  • Build dependencies separately for server and client side, these need to be included in the ruleset somehow.
  • Build the server side as a library using eliom.ppx.server, both native and bytecode are supported by the OCSIGEN server.
  • Build once again in the server side environment using eliom.ppx.type and -infer the result to produce mli files for parts shared with the client.
  • Build the client side bytecode using the eliom.ppx.client, which for each compilation unit will use the corresponding inferred mli file from the server side for the additional type-checking.
  • The bytecode can then be compiled to JavaScript with the built-in js_of_ocaml rule.

We should take advantage of the dependencies in the first step to parallelize across the succeeding steps. Note that a client side compilation unit will depend on the corresponding server side inferred type in addition to the regular dependencies, and the inferred type may have it's own dependencies on the server side.

One thing we need to consider is that client-side must have a different build directory from the server side since the module names of the compilation units overlap.

@rgrinberg
Copy link

@paurkedal Indeed that sounds involved. It seems like you know quite a bit of what's required. If you're interested, I can help you understand the require parts of dune needed to implement this feature.

One thing we need to consider is that client-side must have a different build directory from the server side since the module names of the compilation units overlap.

That would be a good first step to look into in dune.

@paurkedal
Copy link
Contributor

@rgrinberg I would like to take you up on that offer in a couple of months when I have more time to spare, but just to get the thoughts going:

We could try to generalize dune to support eliom-style flows or we could make a specialised rule. I think the latter is most realistic given how I understand the dune design as an end-user. Keeping all sources in a single directory for server and client is encouraged, using .client.ml, .server.ml, and .shared.ml for non-eliom files, so the application is best declared in a single dune file. Since it makes no sense to only build one side of an eliom application and since the parts have non-trivial inter-dependencies, I think the best option is to also use a single stanza. Not to get into details about syntax, a flattered stanza might that look like

(eliom_application
 (name ...) (public_name ...)
 (eliom_modules ...) (shared_modules ...) (client_modules ...) (server_modules ...)
 (shared_libraries ...) (client_libraries ...) (server_libraries ...)
 (shared_flags ...) (client_flags ...) (server_flags ...)
 (shared_preprocess ...) (client_preprocess ...) (server_proprocess ...)
 ...)

but we could also make server library and client executable nested with shared properties factored up.

Next, it would also be good to support building Eliom libraries, which would consist of two libraries, a server and client, where the latter is bytecode only. Otherwise the same logic regarding inferred mli files, PPXes, and dependencies applies.

@rgrinberg
Copy link

What about eliom libraries? Isn't it possible to define a library with client & server side components?

@paurkedal
Copy link
Contributor

Yes, I think an (eliom_library ...) stanza would be quite similar. The public names would by convention be foo.server and foo.client. (Also for the application I assumed above that the library and executable names would be inferred from the declared names.)

@rgrinberg
Copy link

I see. I wonder if it's simpler to just an eliom field to existing stanzas. I'd prefer to introduce new stanza only if some existing fields of library or executable don't apply to eliom.

@paurkedal
Copy link
Contributor

paurkedal commented Aug 20, 2020

But note that there is a tight relation between the client and server side, both since declarations of modules and library dependencies will overlap (i.e. the (shared_* ...) and (eliom_* ...) will be the common case) and due to tight dependencies from servers side to client side.

@clembu
Copy link
Contributor

clembu commented Aug 21, 2020

I imagine support for an (eliom (server_libraries ...) (client_libraries ...) (server_flags ...) .....) stanza for both executables and library stanzas would be better than brand new top-level stanzas.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants