fix(ocaml-index): modules of overlapping exes#13644
fix(ocaml-index): modules of overlapping exes#13644Alizter wants to merge 1 commit intoocaml:mainfrom
Conversation
test/blackbox-tests/test-cases/ocaml-index/executables-stanza.t
Outdated
Show resolved
Hide resolved
Signed-off-by: Ali Caglayan <alizter@gmail.com>
dbe7690 to
6c5ea28
Compare
voodoos
left a comment
There was a problem hiding this comment.
It's been a while since I had all the context for this, but the change looks reasonable.
I think printing the actual indexing rules in more tests would also us to check more easily that it is. It would also help prevent future regressions.
Now, I am wondering whether we should actually act similarly for libraries (and thus make the api safer), my guess is that we also disrespect actual dependencies there ? But maybe that's less of an issue than for executables ?
| which depends on Lib_a, but bar doesn't have lib_a as a dependency: | ||
| ocaml-index succeeds because each executable only indexes modules reachable | ||
| from its entry point (shared.ml is not reachable from bar.ml): | ||
| $ dune build @ocaml-index |
There was a problem hiding this comment.
These tests are not really telling of the actual success of the index building process.
I suggest adding to this test, and the other indexing tests, a print of the rules of the alias @ocaml-index.
This will allow us to more easily asses the impact of this fix.
As an example, I modified the test to have the Foo executable actually use the Shared module, and printed the rules.
$ cat > foo.ml <<EOF
- > let () = print_endline Lib_a.value_a
+ > let () = print_endline Shared.x
> EOFHere is the rules diff from this patch:
$ dune rules @ocaml-index
((deps
((File
(External
$TESTCASE_ROOT/bin/ocaml-index))
(File (In_build_dir _build/default/.bar.eobjs/byte/dune__exe__Bar.cmt))
(File (In_build_dir _build/default/.bar.eobjs/byte/dune__exe__Bar.cmti))
- (File (In_build_dir _build/default/.bar.eobjs/byte/dune__exe__Foo.cmt))
- (File (In_build_dir _build/default/.bar.eobjs/byte/dune__exe__Shared.cmt))
(File (In_build_dir _build/default/lib_b/.lib_b.objs/cctx.ocaml-index))))
(targets
((files (_build/default/.bar.eobjs/cctx.ocaml-index)) (directories ())))
(context default)
(action
(chdir
_build/default
(run
$TESTCASE_ROOT/bin/ocaml-index
aggregate
-o
.bar.eobjs/cctx.ocaml-index
- .bar.eobjs/byte/dune__exe__Shared.cmt
- .bar.eobjs/byte/dune__exe__Foo.cmt
- .bar.eobjs/byte/dune__exe__Bar.cmt
- .bar.eobjs/byte/dune__exe__Bar.cmti))))
+ .bar.eobjs/byte/dune__exe__Bar.cmti
+ .bar.eobjs/byte/dune__exe__Bar.cmt))))
((deps
((File
(External
$TESTCASE_ROOT/bin/ocaml-index))
- (File (In_build_dir _build/default/.foo.eobjs/byte/dune__exe__Bar.cmt))
(File (In_build_dir _build/default/.foo.eobjs/byte/dune__exe__Foo.cmt))
(File (In_build_dir _build/default/.foo.eobjs/byte/dune__exe__Foo.cmti))
(File (In_build_dir _build/default/.foo.eobjs/byte/dune__exe__Shared.cmt))
(File (In_build_dir _build/default/lib_a/.lib_a.objs/cctx.ocaml-index))))
(targets
((files (_build/default/.foo.eobjs/cctx.ocaml-index)) (directories ())))
(context default)
(action
(chdir
_build/default
(run
$TESTCASE_ROOT/bin/ocaml-index
aggregate
-o
.foo.eobjs/cctx.ocaml-index
.foo.eobjs/byte/dune__exe__Shared.cmt
- .foo.eobjs/byte/dune__exe__Foo.cmt
.foo.eobjs/byte/dune__exe__Foo.cmti
- .foo.eobjs/byte/dune__exe__Bar.cmt))))
+ .foo.eobjs/byte/dune__exe__Foo.cmt))))It does fit better the actual module dependencies.
|
|
||
| (** [index_modules_rule ~modules_to_index cctx] sets up the rules needed to | ||
| generate the indexes for the given modules and aggregates them in a | ||
| cctx.ocaml-index file covering the whole compilation context. |
There was a problem hiding this comment.
and aggregates them in a cctx.ocaml-index file covering the whole compilation context
That's not true anymore, depending on the value of modules_to_index we might be missing things.
rgrinberg
left a comment
There was a problem hiding this comment.
Tbh, I don't really get what this is fixing. In particular:
In the executable case we are more careful with the modules we choose and instead opt for reachable modules.
Why would we limit the index to reachable modules? In the original bug report, the issue was separate executable stanzas. While you're changing the behavior for multiple executable in the same stanza.
| in | ||
| List.rev_append cmts acc) | ||
| List.concat_map modules_to_index ~f:(fun module_ -> | ||
| if Modules.is_user_written module_ |
There was a problem hiding this comment.
Why do you need this check if you're only passing user written modules?
There was a problem hiding this comment.
I think it's because of the now separate treatment for executable which do not use fold_user_written.
It bothers me that there are such different treatments for executables and libraries though, the propose change make the API of the ocaml_index module much less safe to use.
I think it does fix the mentioned issue ? But I really need to see the impact on the I think the core issue is that ocaml_index rules assumed that all modules attached to a stanza are actually built as part of that stanza, and thus share the same set of library dependencies. But it's wrong in cases like #13566 because unreachable (and un-buildable) modules for one of the two executables are still part of the ones iterated over by The index is still global, and not only restricted to reachable modules: we build one index for each stanza. |
This assumption should be correct.
I think the issue is that dune is allowing a module to be a part of two stanzas. If these two stanzas share a module and yet they're trying to build it with different configurations, it's not surprising that ocaml-index is confused. I think merlin would be confused as well. Which In that example, the user should specify the |
|
Here is an example that demonstrates why this configuration is invalid: |
|
@rgrinberg I've tried forbidding such overlapping stanzas in the past here #12451. Is that something we should look into again? We have overlapping module checks for lib-lib, but not for lib-exec nor exec-exec. I can't tell if the latter cases are a feature or a bug. We could introduce such checks in a newer dune lang and forbid merlin / ocaml-index in these cases for older dune lang versions. In the newer dune lang we would requires that people use the modules field. Furthermore, we could introduce something smarter where we check the configuration is the same, but that is not clear how to do, especially in the lib-exec case. The semantics of |
|
I think we should we enforce that every single module belongs to a single enabled stanza. I don't think there's a need to be any smarter than that. |
|
@rgrinberg Is that including library / executable overlap? |
|
Yes |
Rather than make a rule that handles both libraries and executables, we make a rule that handles a collection of modules so that libraries, executables and melange can setup the ocaml index rules accordingly.
In the executable case we are more careful with the modules we choose and instead opt for reachable modules.