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

melange: add runtime_deps field to library stanza #6643

Closed
wants to merge 15 commits into from

Conversation

jchavarri
Copy link
Collaborator

@jchavarri jchavarri commented Dec 6, 2022

Reuses the rules creation function from copy_rules.

One remaining question is about merlin integration. Dirs from copy_files stanzas are added to src_dirs here:

| Copy_files { files = glob; _ } ->
let* source_dirs =
let loc = String_with_vars.loc glob in
let+ src_glob = Expander.No_deps.expand_str expander glob in
if Filename.is_relative src_glob then
match Path.relative (Path.source src_dir) src_glob ~error_loc:loc with
| In_source_tree s -> Some (Path.Source.parent_exn s)
| In_build_dir _ | External _ -> None
else None
in
Memo.return { merlin = None; cctx = None; js = None; source_dirs }

However, in Melange case, these dirs will contain mostly assets that are needed at runtime. I can't think of any situations where they'd be needed at build time so I did not add any merlin-related functionality for this runtime_deps case.

@jchavarri jchavarri added the melange Melange rules and generator label Dec 6, 2022
@@ -131,6 +131,23 @@ end = struct
let f ~dir = Load.get sctx ~dir >>= artifacts in
Expander.set_lookup_ml_sources expander ~f

let buildable_files (buildable : Buildable.t) =
Copy link
Collaborator Author

@jchavarri jchavarri Dec 6, 2022

Choose a reason for hiding this comment

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

Nothing changes in this function, just moved from lines 166-179 below, to be able to split the Library and Executable cases.

let copy_files sctx ~dir ~expander ~src_dir (def : Copy_files.t) =
Expander.eval_blang expander def.enabled_if >>= function
| true -> copy_files sctx ~dir ~expander ~src_dir def
| false -> Memo.return Path.Set.empty

let extra_files_melange sctx ~dir ~expander ~src_dir files =
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I originally tried to create this function inside Melange_rules but got some cyclic dependency error:

Error: dependency cycle between modules in _build/default/src/dune_rules:
   Virtual_rules
-> Dir_contents
-> Compilation_context
-> Dir_contents

@jchavarri jchavarri changed the title melange: add extra_files field to library stanza melange: add extra_files field to library stanza Dec 6, 2022
@jchavarri
Copy link
Collaborator Author

I just remembered we discussed a couple of things:

  • @anmonteiro suggested to call the new field runtime_deps instead of extra_files
  • "Embed" the field inside modes, e.g. (modes (melange (runtime_deps foo.css))), to avoid ambiguous situations like OCaml libraries using the new field.

I will update the PR to apply both changes above, please hold on any reviews until then.

@anmonteiro
Copy link
Collaborator

Could adding extra files in modes conflict with equality in the Ordered Set Lang (#6611)?

@jchavarri
Copy link
Collaborator Author

Could adding extra files in modes conflict with equality in the Ordered Set Lang (#6611)?

Maybe. In any case, I took a stab at it and ultimately decided to leave the runtime deps as a separate field. Adding it inside modes caused a large amount of changes in Decoder.enum', the way modes is represented as a set later, and how the modes are decoded. In the end, the downsides of having a separate field are not that great: if some library has melange.runtime_deps and does not have melange mode, dune will just ignore the former, so I don't think it's a big deal.

This is ready to review now.

@jchavarri jchavarri changed the title melange: add extra_files field to library stanza melange: add runtime_deps field to library stanza Dec 8, 2022
@rgrinberg
Copy link
Member

suggested to call the new field runtime_deps instead of extra_files

It depends on when are these files being accessed. Are they being accessed at all by the compiler?

@rgrinberg
Copy link
Member

if some library has melange.runtime_deps and does not have melange mode, dune will just ignore the former, so I don't think it's a big deal.

Seems like it's worth it to add a TODO to make this an error in the future.

@jchavarri
Copy link
Collaborator Author

It depends on when are these files being accessed. Are they being accessed at all by the compiler?

These files are fonts, images and / or css stylesheets that are included in the resulting bundle. See for example https://webpack.js.org/guides/asset-management/.

I can't think of any examples where they would be accessed by the compiler.

@jchavarri
Copy link
Collaborator Author

Seems like it's worth it to add a TODO to make this an error in the future.

I was not sure how the TODO should be added (inline or new issue) so I went ahead and handled the error already as part of this PR: 7fc58cf.

@jchavarri jchavarri requested a review from rgrinberg December 12, 2022 11:47
"Library %S is using \"melange.runtime_deps\", but it \
is not a Melange library. To fix this error, you must \
add \"melange\" to \"modes\", or remove \
\"melange.runtime_deps\"."
Copy link
Member

Choose a reason for hiding this comment

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

I just checked the other errors in our code, and we don't quote field names. I'd drop the quotes here for the same reason. By the way, can this validation be moved to Dune_file? We should do it as early as possible.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I don't think there is a lot of consistency, there are cases without quotes, with single quotes and with double quotes.

Happy to unify them in another PR.

For now, removed the quotes in this case and moved to dune_file in 4a7e8b5.

let copy_files sctx ~dir ~expander ~src_dir (def : Copy_files.t) =
Expander.eval_blang expander def.enabled_if >>= function
| true -> copy_files sctx ~dir ~expander ~src_dir def
| false -> Memo.return Path.Set.empty

let melange_runtime_deps sctx ~dir ~expander ~src_dir files =
copy_files' sctx ~dir ~expander ~src_dir ~add_line_directive:false ~alias:None
Copy link
Member

Choose a reason for hiding this comment

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

Do you need the glob here? I don't see the glob functionality being tested anywhere.

Copy link
Collaborator Author

@jchavarri jchavarri Dec 12, 2022

Choose a reason for hiding this comment

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

I think the glob will be very useful to have, yes. I will add some tests to exercise the functionality.

While checking this, I realized a couple of things:

  • we want to allow multiple globs per field, e.g. (melange.runtime_deps assets/*.png fonts/file.ttf)
  • the current implementation is broken, the tests were only working by chance

I will update the PR with some improvements and fixes.

@jchavarri
Copy link
Collaborator Author

jchavarri commented Dec 13, 2022

@rgrinberg I tried to start adapting implementation to Melange specific case, which differs from original copy_files. In particular:

  • Honor the relative paths from original sources in the build targets paths
  • Prepend the target folder to those targets paths

For now I am hard-coding the target value, just to be able to test a simple case. But I am not able to make it work, as I get the following error:

$ dune build output/main.js
Error: Dependency cycle between:
Computing directory contents of _build/default
-> Evaluating predicate in directory _build/default/output/assets
-> Computing directory contents of _build/default
[1]

The issue seems to happen in this line:

let* files =
Build_system.eval_pred (File_selector.of_glob ~dir:src_in_build glob)

I took a look at the eval_pred function, but I don't get how this cycle is introduced. Do you have any ideas?

Also, I think #6541 will heavily affect this PR, so if @anmonteiro is ok, I will probably switch focus to that PR to get it merged before continuing the work here.

@jchavarri
Copy link
Collaborator Author

jchavarri commented Dec 13, 2022

Another realization is that melange.runtime_deps rules behavior will be much more similar to the way Dune copies over source files like .ml files to the build folder. So it might be that my original approach to emulate what is done on Dir_contents for copy_files stanza is not the right way to go, and I should look instead at create_copy_rules as reference. 🤔

* main: (148 commits)
  refactor(rpc): remove mutable callback (ocaml#6786)
  refactor(stdune): make [Id.t] immediate (ocaml#6795)
  refactor(melange): share mode handling (ocaml#6799)
  refactor(scheduler): remove duplicate types (ocaml#6785)
  refactor: move cram stanza definition (ocaml#6800)
  fix: correctly validate argument to top-module (ocaml#6796)
  refactor: move generate_sites_module to own module (ocaml#6798)
  fix(melange): check rules (ocaml#6789)
  refactor(rpc): make [Call.to_dyn] public (ocaml#6797)
  refactor(rpc): invalid session errors (ocaml#6787)
  refactor(melange): remove js globs (ocaml#6782)
  doc: fix version indication for "dune ocaml top-module" (ocaml#6792)
  refactor: print shutdown exception (ocaml#6784)
  refactor(rpc): add [Call.to_dyn] (ocaml#6790)
  fix: do not impose no_sandboxing on ocamldep (ocaml#6749)
  refactor(melange): move stanza definition (ocaml#6775)
  fix: handle missing CLICOLOR_FORCE correctly (ocaml#6781)
  Revert --display tui (ocaml#6780)
  fix: render pending messages
  refactor(coq): inline coqc_rule
  ...
Signed-off-by: Javier Chávarri <[email protected]>
Signed-off-by: Javier Chávarri <[email protected]>
Comment on lines +39 to +43
Error: Dependency cycle between:
Computing directory contents of _build/default
-> Evaluating predicate in directory _build/default/output/assets
-> Computing directory contents of _build/default
[1]
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@rgrinberg do you have any ideas how to fix this dep cycle? It seems it is problematic to use globs with melange runtime_deps, should I just skip glob functionality for now?

Copy link
Collaborator Author

@jchavarri jchavarri Feb 7, 2023

Choose a reason for hiding this comment

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

I managed to get over this error by removing glob functionality in d330036. It is less convenient to not have globs, but if it is going to lead to confusing rule cycles errors, better to leave them out.

However, runtime_deps are still not copied, I believe because the copy rules are there, but nothing depends on the asset files. I wonder though, what exactly should depend on these files? Should these asset paths be passed down and added as dep of the cmj creation rules for each module? Otherwise I am not sure where else they could be added, as there is no such thing as "library-level target" in melange, like cma.

Copy link
Member

Choose a reason for hiding this comment

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

The targets should be added to the alias in the melange.emit stanza I'm thinking

You can use globs as long as you factor things into directories properly. You can also support globs and explicit files with constructors. E.g. (foo.txt (glob_files %{project_root}/*.txt))

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The targets should be added to the alias in the melange.emit stanza I'm thinking

Is there a possibility to group all these copy rules under some "internal" alias that melange.emit can use? Duplicating the targets in melange.emit stanzas kind of defeats the point of having runtime_deps field, as it would roughly be the same as using copy_files.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

One more thought about this coupling between library assets and emit stanza. In a future, there will be authors that publish Melange libraries. These libraries might need some assets to work properly. The problem as we are discussing is that the copying rules + alias deps are only known at melange.emit stanza time. But this is outside the control of the library author.

I am not sure how to represent this in Dune, but it seems we need some kind of "lazy rule", that contains all the information about the assets copying rules, except the prefix path which is the emit target. Then, at emission time, the rules would be "applied" with this prefix.

cc @anmonteiro

Copy link
Collaborator Author

@jchavarri jchavarri Feb 8, 2023

Choose a reason for hiding this comment

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

Another option is to "standardize" the output folders as we have discussed at some point in the past, always choosing either es6 or commonjs target folders, depending on module_system. Or just remove target, as was implemented by Antonio in #6541. Edit: removing target wouldn't solve the problem either, as the paths can differ based on where the melange.emit stanza is found.

@jchavarri
Copy link
Collaborator Author

Superseded by #7234.

@jchavarri jchavarri closed this Mar 13, 2023
@jchavarri jchavarri deleted the melange/extra-files branch March 13, 2023 21:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
melange Melange rules and generator
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants