-
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
[WIP] Expand variables in install
stanzas -- take 2
#1354
Conversation
Yes, that's correct. However, there is a simpler way to achieve this: instead of going through all the dune files in |
I am fairly sure the code is incorrect in multiuple places right now, but I am trying to figure out why it is not yet even parsing correctly the
I thought that 7813792#diff-8caffdb0f0d1de5eb40eee1dc4ece1f9R1182 was doing the right thing |
I found out the issue: Using |
Ok, I'm having a look at the code. The segfault is probably be due to a stack overflow |
src/artifacts.ml
Outdated
String.Map.add acc key in_bin_dir) | ||
| _ -> | ||
local_bins)) | ||
(*Build_system.targets_of build_system ~dir:bin_dir |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The is that the local_bins
field should be a Lazy.t
, and this while computation should be under a lazy (...)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even if this is lazy, as soon as it is used, it blows up
src/dune_file.ml
Outdated
| Atom (_, A src) -> junk >>| fun () -> { src; dst = None } | ||
| List (_, [Atom (_, A src); Atom (_, A "as"); Atom (_, A dst)]) -> | ||
junk >>> return { src; dst = Some dst } | ||
| Atom (_, A _) -> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be: Atom _ | Quoted_string _ | Template _
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated, thanks!
It is, I can post you what it looks like if you want. I think the most meaningful part of the overflow is
|
The overflow above is generated using the lazy version of the code. I have pushed that code as well, I hope it can help to understand what is wrong |
I believe it's the expansion of |
Thanks for the analysis. I'll have a look and let you know! |
The generated values before the failure are:
Changing |
Doing the same in Also I can declutter a lot the stack by using a |
I added the following code inside the
and got the following backtrace:
Looking at We can solve the issue by making sure that let module Install_rules =
Install_rules.Gen(P)
in
Install_rules.init (); to just before the following line: let module M = Gen(struct let sctx = sctx end) in |
Unfortunately, moving the install rules init in One big source of failures was the sometimes unnecessary call to |
Independently of how one puts it, there seems to be an issue when we need to expand strings with vars too early and this is called:
This happens for example when looking for |
I have added a commit with the wrong behaviour of postponing looking in the local bins to after querying the context. I just want to see how far would the tests go with that (locally with the change it could compile every package I tried) |
Hmm, I see it must be because |
I have been away without the laptop, this PR is still alive. I'll try to split the setup as you suggest. Thanks |
Ping @mseri |
Thanks for the ping, I had some very busy days. I have rebased on the current master, fixed the merge issues and I am looking at the code changes. I think to make it work the setup of the install rules has to happen at init, but the rest has to be delayed. When I try to do that I incur in the issue that I am generating multiple install rules for |
If you look at the function What you should do with these is create the So essentially the process should be as follow (in pseudo-code): let step1 () =
let bin_entries, other_stanzas = List.partition_map stanzas_to_consider ... in
let bin_entries = local_install_rules bin_entries ... in
(bin_entries, other_stanzas)
let step2 (bin_entries, other_stanzas) =
let other_entries = ... in
let entries = List.rev_append bin_entries other_entries in
generate_install_file entries |
|
Thanks! Indeed, this seems to work for all the packges I've tested, including the one that used to fail |
I cannot reproduce appveyor's failure locally, I have also tried with an empty switch. But I don't have a Windows machine to try it. |
src/artifacts.ml
Outdated
lazy ( | ||
Build_system.targets_of build_system ~dir:bin_dir | ||
|> Path.Set.fold ~init:String.Map.empty ~f:(fun path acc -> | ||
let name = Filename.basename (Path.to_string path) in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you keep the let key = if Sys.win32 ... in
and use key
instead of name
in the following line, then the Windows error should go away. The idea is that the keys in the map are the executable names without the .exe
, even on Windows.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. This regression seems fixed now!
(String_with_vars.decode >>= fun src -> | ||
keyword "as" >>> | ||
String_with_vars.decode >>= fun dst -> | ||
return { src; dst = Some dst }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general we try to produce helpful error messages when users use a new feature without upgrading the (lang dune ...)
line in their dune-project
file. In this case I suggest to replace the String_with_vars.decode
by:
let%map is_atom = peek_exn >>| function Atom _ -> true | _ -> false
and s = String_with_vars.decode
and version = Syntax.get_exn Stanza.syntax in
if not is_atom && version < (1, 6) then
Syntax.Error.since (String_with_vars.loc s) Syntax.version (1, 6)
~what:(sprintf "Using %s here" (if String_with_vars.has_vars s then "variables" else "quoted strings"));
s
and then bump the language version in stanza.ml
to (1, 6)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right, I had seen a similar pattern in the file when I started and completely forgotten about it. Thanks
src/install_rules.ml
Outdated
let init_install () = | ||
let entries_per_package = | ||
List.concat_map (SC.stanzas_to_consider_for_install sctx) | ||
let preinit = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find the following more descriptive:
let preinit = | |
let bin_entries, other_stanzas = |
And I suppose init_install
can just take ()
as argument and access these directly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed! That remained as an artifact of one of the intermediate changes.
src/gen_rules.ml
Outdated
let module P = struct let sctx = sctx end in | ||
(* We need to instantiate Install_rules earlier to avoid issues whenever | ||
* Super_context is used too soon. | ||
* See: https://github.com/ocaml/dune/pull/1354#issuecomment-427922592 *) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment looks good, but I would put it closer to the module Install_rules = Install_rules.Gen(P)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure
src/install_rules.ml
Outdated
let install_file (package : Package.t) entries = | ||
let entries = | ||
let install_paths = | ||
Install.Section.Paths.make ~package:package.name ~destdir:Path.root () |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that we are effectively calling this 3 times: once here and twice through process_entries
. It'd be nice if we could call it only once, though it's probably not a big deal in practice sowe can keep the code as it if it's annoying to change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had thought about that and was not sure what would have been better. I refactored it out, it will be called once at the price of a lookup in the map and a call to Option.value_exn
(that should be safe in this case as we are computing the install paths for all the packages). It can be extracted further instead of staying in the pre-init step but I think it is more consistent to keep it all contained
Thanks, this all looks good! Could you run |
I was adding a test to check that the variables were working correctly. I can remove it if you think it's not robust enough or if it is not needed. While doing that I also checked that the version error comes up nicely:
|
Thanks, testing new features is always welcome 👍 Could you just remove the library and executable from the test? Just to keep the output short and focused on the feature to test. |
Installing install/man/man1/a-man-page.default.1 | ||
Installing install/man/man3/another-man-page.3 | ||
|
||
If prefix is passed, the default for libdir is `$prefix/lib`: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The rest of this file shouldn't be necessary, the first test is enough to check that variable expansion works correctly.
Done, thanks! Should I cleanup the history or you want to keep it to make it easier to reconstruct what issues we had? |
I prefer a shorter history, so if you could clean it that would be nice, thanks. But TBH, I'm not too fuzzy regarding the history, I'm happy with everything squashed into a single commit. |
This requires adding lazyness to the sctx resolution of the documentation, and splitting the preparation of install stanzas in two parts: in the first step we only process binary install paths, to make sure that they are available when the rest of the dune file is processed and some of the variables are expanded, in the second step we finish processing all the other install stanzas and complete the of init the install targets. Signed-off-by: Marcello Seri <marcello.seri@gmail.com>
Signed-off-by: Marcello Seri <marcello.seri@gmail.com>
Signed-off-by: Marcello Seri <marcello.seri@gmail.com>
I have rebased into three commits. I think it is better this way as two of them where somewhat unrelated to the rest of the changes |
Thanks again for this PR! It is a nice user feature and a nice simplification of the code handling executables. |
Thank you very much for guiding me through it! |
CHANGES: - Expand variables in `install` stanzas (ocaml/dune#1354, @mseri) - Add predicate language support for specifying sub directories. This allows the use globs, set operations, and special values in specifying the sub directories used for the build. For example: `(dirs :standard \ lib*)` will use all directories except those that start with `lib`. (ocaml/dune#1517, ocaml/dune#1568, @rgrinberg) - Add `binaries` field to the `(env ..)` stanza. This field sets and overrides binaries for rules defined in a directory. (ocaml/dune#1521, @rgrinberg) - Fix a crash caused by using an extension in a project without dune-project file (ocaml/dune#1535, fix ocaml/dune#1529, @diml) - Allow `%{bin:..}`, `%{exe:..}`, and other static expansions in the `deps` field. (ocaml/dune#1155, fix ocaml/dune#1531, @rgrinberg) - Fix bad interaction between on-demand ppx rewriters and using multiple build contexts (ocaml/dune#1545, @diml) - Fix handling of installed .dune files when the backend is declared via a `dune` file (ocaml/dune#1551, fixes ocaml/dune#1549, @diml) - Add a `--stats` command line option to record resource usage (ocaml/dune#1543, @diml) - Fix `dune build @doc` deleting `highlight.pack.js` on rebuilds, after the first build (ocaml/dune#1557, @aantron). - Allow targets to be directories, which Dune will treat opaquely (ocaml/dune#1547, @jordwalke) - Support for OCaml 4.08: `List.t` is now provided by OCaml (ocaml/dune#1561, @ejgallego) - Exclude the local esy directory (`_esy`) from the list of watched directories (ocaml/dune#1578, @andreypopp) - Fix the output of `dune external-lib-deps` (ocaml/dune#1594, @diml) - Introduce `data_only_dirs` to replace `ignored_subdirs`. `ignored_subdirs` is deprecated since 1.6. (ocaml/dune#1590, @rgrinberg)
This PR is very preliminary and reflects my work towards fixing issue #690. I used #962 as the starting point and I have opened this to track the work and see if I am heading to the right directory.
To generate
String_with_vars
for now I usedmake_text
, but in the discussion in #962 you recommendedvirt_text
. Here maybe I misunderstood something.The build now fails in https://github.com/mseri/dune/blob/814f0d52dbc4feda11aa9ad5605f41a8e592e71f/src/artifacts.ml#L19
There I see that we do lots of operations on
src
anddst
seen as normalstring
types. If I understand correctly I need the super context to be able to expand them, so I was thinking to change the get the values out beforehand in https://github.com/mseri/dune/blob/814f0d52dbc4feda11aa9ad5605f41a8e592e71f/src/super_context.ml#L547Is that correct or I am missing something?