-
Notifications
You must be signed in to change notification settings - Fork 409
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
Support for BUILD_PATH_PREFIX_MAP #7540
base: main
Are you sure you want to change the base?
Conversation
This is still a draft, as it still has some debugging code in it, and output that is not sanitized. Also, I'm still adding tests. |
I have a separate gitlab PR, https://gitlab.com/gasche/build_path_prefix_map/-/merge_requests/2#7facec255884dc55d3818e4dfbea89b1bdd7f49e, for the vendored |
d9a7f59
to
102e240
Compare
@rgrinberg, I've converted this from draft to ready for review, not because it is perfect, but because I need your help with some memo/fiber issues. Also, for the changes to the vendored build_path_prefix_map code, I have a separate PR out to @gasche, so I realize that those changes would not be checked directly into Dune. Hopefully, that PR will be accepted and merged before this PR is ready. I took your suggestion of looking at the The strategy for computing the forward mappings was to start with a map of every single file that will be installed, mapping from its relative location in the build directory to its abstract installation path. That map is then abbreviated by doing directory-level mapping when possible. For the inverse map, we first split out the mappings of installed files that exist in the source directory (i.e. are not generated). We do that because, for the inverse mappings, we want to give precedence to the location in the source directory. One complication that arose was related to sandboxing. Because of it, we could not use the pwd in computing the build directory paths. Instead, we had to take the root that is available in All is working well as far as the mapping goes, but there were some technical challenges, and I'm not sure my solution was the correct or best way. In particular, I'm running into an assertion failure which I'll mention below. But first, let me mention the first challenge. The existing code that does mapping is in the The memo/fiber problem I'm having is showing up when trying to build the This could logically be divided into two PRs, one for the forward mapping, and another for the inverse (i.e. the I'll keep doing more testing and debugging, but if you could take a look and help me with the memo/fiber problem, I'd much appreciate it. Thanks |
that is a prefix of the input [path]. If it succeeds, | ||
it replaces this prefix with the corresponding target. | ||
If it fails, it just returns [None]. *) | ||
|
||
val rewrite_all : map -> path -> path list | ||
(** [rewrite_all map path] finds all sources in [map] |
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.
Are you pulling these changes from upstream? If so, this should be done separately.
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.
As I mentioned, I have a PR to @gasche, to get this change into his upstream repo. I've not gotten any response from him yet on that PR, however, he was the one that merged that change into the OCaml trunk. I suppose if you wanted to merge this into Dune separately you could, and then when it gets upstream you could go back to getting it there.
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've not heard from @gasche on the build_path_prefix_map changes, so we may need to merge this as part of the PR and later vendor it when it is ready. Relative to my build_path_prefix_map I have one change, a local copy of List.find_map, in order to be able to build Dune with versions of OCaml that did not yet have List.find_map.
Probably because of the mutation you've introduced. All memo computation must not have effects. We need to think of a different way to thread this map. |
I'm open to your suggestions on that. I see that the Dune_rules.Main.get() function returns a memo, but I'm storing some results in ref variables from within that function, so that is an effect in a memo computation. Is there a way to use a memo but return a non-memo? Do we have to convert the memo to a fiber and then start up the scheduler? Another question I had: Currently I'm computing the maps up front. Would there be any advantage to computing them lazily? |
88cafcc
to
f9cae2b
Compare
A few comments:
I'm still aware that this PR is in draft mode, so I won't do many comments on the code itself for now since it might change. |
@Alizter, Thanks for pointing that out. I will split out my "dune describe" changes to show packages. My "dune describe maps" is different and I will keep it, as it is also helpful in validating the maps.
OK. Or how would you feel about "dune ocamldebug"? That would be a little more concise (though only by one space, so perhaps your suggestion is better). I'll also be splitting this part into a separate PR. |
Since command groups have a tree structure, |
@@ -7,7 +7,7 @@ in the same dune file, but require different ppx specifications | |||
$ dune build @all --profile release | |||
$ dune ocaml merlin dump-config $PWD | |||
Usesppx1 | |||
((STDLIB /OCAMLC_WHERE) | |||
((STDLIB /install_root/lib/ocaml) |
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 the behaviour of BUILD_PATH_PREFIX_MAP inside a cram test is broken. The setting of the env var above should make this get substituted for OCAMLC_WHERE.
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.
Actually not. The setting of the map in the Dune supersedes the existing setting. For paths not covered by the Dune mappings, the previous settings would take effect.
One difference between the current Dune mappings and the previous settings is that before, only paths under the PWD were mapped. Now paths under the opam root are also mapped (to /install_root/...). That is why the prior mappings are not effective. Perhaps these tests should have these mappings removed since they are no longer needed?
I've converted this back to "ready to review" again. I've removed all of the code that will be split out into a separate PR, and in particular, the code for the "dune ocaml debug" command (and also some debugging code I had added). I have some questions for the reviewers that will guide any final changes (in addition to the comments reviewers will have):
Possible solutions to the above include:
Note that the computations of the maps is now being invoked in Install_rules.Build_map.build_and_save_maps scontexts This is earlier than install information would typically have been computed, but we need to have the mappings available during the build steps. This seems to be having the effect that some messages that previously were being emitted are skipped (though I do not understand exactly why--yet). That's all for now. I look forward to some feedback from reviewers on the issues above. |
src/dune_rules/install_rules.mli
Outdated
-> Install.Entry.Sourced.t list Package.Name.Map.t | ||
-> Build_path_prefix_map.map | ||
|
||
val build_all_maps : |
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.
Where is this function being used outside of this module? If it isn't, it shouldn't be in the mli.
src/dune_rules/install_rules.ml
Outdated
let* packages = Stanzas_to_entries.stanzas_to_entries sctx in | ||
Memo.return (ctxn, packages)) | ||
in | ||
let maps = Context_name.Map.of_list_reduce pairs ~f:(fun old _new -> old) 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.
The reduce doesn't seem right. How could you have a collision on a context name here? Shouldn't it be Map.of_list_exn
?
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 believe that of_list_reduce works correctly, but of_list_exn is more naturally the right function to use, so I will change to use it.
If this possible, I think it would be preferable. Although it does seem a bit more difficult. So what you have currently is fine too. Note that the references introduced in Also, could you move as much of the logic as possible outside of install_rules and into its own module? Those changes in Dune_util.Build_path_prefix_map probably don't belong there either. I understand you wanted a change a single code path that will work for both dune_engine and dune_rules, but this is all quite specialized to our rules. So it should live in dune_rules with sensible hooks in dune_engine. |
bin/describe.ml
Outdated
@@ -817,6 +1001,7 @@ module What = struct | |||
| External_lib_deps | |||
| Opam_files | |||
| Pp of string | |||
| Map |
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.
"map" is a rather general name for a command that does something quite specific. How about "build-path-prefix-map"?
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.
Done (in next push)
package installation. For the testcase for issue ocaml#7413, the issue is resolved with the current Dune changes. The result of the grep now gives a count of 1. For the deployment phase, we need the inverse of the BUILD_PATH_PREFIX_MAP. I've decided that this should use a different environment variable, so I've chosen DEPLY_PATH_PREFIX_MAP. The reason two variables are needed is that a new dune command, `dune ocaml debug` will been added. It is similar to `dune exec`, except instead of invoking the executable directory, it give the executable to the OCaml debugger. But before doing that, it builds the executable, if necessary, to make sure it is up-to-date. During the building, BUILD_PATH_PREFIX_MAP maps build-time absolute paths to abstract paths, but the debugger needs the inverse mapping, so will use DEPLY_PATH_PREFIX_MAP. So forward and inverse mappings are computed, and the `dune describe map` command was added to display and test the forward and reverse maps. Promote tests with expected results for new mapping Add find_map locally to enable build with early OCamls Guard against invalid existing map in order to guarantee we always emit a valid map. Only map .ml files exactly, to decrease map size. This is a temporary solution to avoid exceeding the argument/environment size for execve (exhibited in the benchmarks). Maybe make user-configurable, or have an indirection feature in the mapping environment variable so the full mapping can be in a file. Use String.is_suffix, as it is available in stdune for all versions of OCaml. Signed-off-by: Richard L Ford <[email protected]>
@rgrinberg, I'm having a difficult time finding an alternative that does not require mutation. I spent all last week trying to come up with a solution. Currently, the default execution parameters are set in bin/common.ml, function Computation of the mappings requires reading all the
This builds, but when I run the tests I get a lot of crashes, though I don't see my message in the log. So it seems that computation of the maps must be done later, but since I'm considering abandoning these changes and instead adding Dune documentation that if a package wants its code to be debuggable after installation, then it needs to arrange its source hierarchy to mirror the installation-time hierarchy. Do you have any other suggestions? |
I'm pushed changes to reflect some of the review comments, but have not yet solved the issue of mutation (as mentioned above). |
I'm changing jobs and will not have time to complete this PR. It has proved more complex than expected. If someone else thinks this is worthwhile, they are welcome to continue this effort. As a simpler alternative, I have #7741. It fixes the gap in reproducibility, but the abstract paths will only work for installed libraries if the library authors choose a source layout that mirrors the installation layout. |
Modify Dune to produce
BUILD_PATH_PREFIX_MAP
mappings that map paths to package built artifacts to abstract paths that mirror the installed hierarchy. In particular, for example, if fileis a part of package
pkg
and will be installed in a sectionsec
(e.g.lib
ordoc
) at locationthen the Dune
BUILD_PATH_PREFIX_MAP
will map that file to abstract pathwhere in this case, I have chosen
/install_root
as the literal prefix for mappings of things that are part of a package.If a built artifact is not part of a package, then the mapping remains the same, namely the above file, if not part of a package, will map to
This is implemented by first using Dune's install logic to get a mapping of all installed files from their location in the build directory to the install location. Then that mapping is abbreviated, taking advantage of the fact that for many artifacts we can do a directory-level mapping rather than mapping each individual file. When the basename of a file changes when installed, the file needs its own mapping.
In addition, the
dune describe
command was expanded.The
dune describe workspace
command now includes package information.There is a new
dune describe map
command that outputs information about theBUILD_PATH_PREFIX_MAP
mappings, both full and abbreviated.The net effect of this change is that for any installed file, its runtime location can be obtained from its abstract path by merely replacing
/install_root
with the actual install location, e.g.$OPAMROOT/$SWITCH
.Fixes #7413.