Skip to content

Vlib Cycle Detection#3285

Closed
rgrinberg wants to merge 1 commit intoocaml:mainfrom
rgrinberg:vlib-cycle
Closed

Vlib Cycle Detection#3285
rgrinberg wants to merge 1 commit intoocaml:mainfrom
rgrinberg:vlib-cycle

Conversation

@rgrinberg
Copy link
Copy Markdown
Member

This PR is easier to understand if you read the commits separately. The goal
here is to simplify the implementation. Any suggestions on how to simplify
things further are welcome :)

@rgrinberg rgrinberg requested a review from a user March 20, 2020 16:27
@rgrinberg
Copy link
Copy Markdown
Member Author

@Lupus this PR should properly detect the error that you've encountered with virtual libraries. Testing if it works for you would be quite useful for me to know.

@rgrinberg
Copy link
Copy Markdown
Member Author

@diml I've added a couple of commits to check for invalid implementations. Those occur when an implementation depends on a library that depends on the virtual library being implemented. This is essentially a cycle as there's only one archive when linking in the end.

@Lupus
Copy link
Copy Markdown

Lupus commented Mar 25, 2020

I've just pinned dune to this PR as follows:

$ opam pin dune https://github.com/ocaml/dune.git#55cf5c641746a9c7cf9414a3830ed4f93207c5e2

Cloned this repo: https://github.com/Lupus/virtual-lib-issue

Created fresh switch with 4.08 OCaml, vanilla dune 2.4 gives the following error when I try to build it:

$ dune build
File "_none_", line 1: 
Error: No implementations provided for the following modules:
         A__Real_module referenced from lib/b/b.cmxa(B__Foo)

And with the pinning in place I see no change in the error message. Is my understanding correct that I should see some error about dependency cycle?

@rgrinberg
Copy link
Copy Markdown
Member Author

@Lupus I'd like to reproduce the bug using your example, but I don't have reason installed. Could you port your example to OCaml perhaps?

@Lupus
Copy link
Copy Markdown

Lupus commented Mar 27, 2020

Installing reason with opam seems to be pretty cheap on effort and storage space, but here you are: https://github.com/Lupus/virtual-lib-issue/tree/ocaml

@rgrinberg
Copy link
Copy Markdown
Member Author

It's not about the disk space, it's just that I find the reason syntax hard to read :)

I tried your example, and I can observe the following error message:

Error: Implementation the-lib-unix.a has a dependency that uses the virtual
library the-lib.a
   - the-lib-unix.a at _build/default/lib-unix/a
-> - the-lib at _build/default/lib
-> required by executable Example in examples/dune:2

This is what is expected.

@Lupus
Copy link
Copy Markdown

Lupus commented Mar 29, 2020

Come one, it had only 13 lines of code! :)

Okay, the error message that you show looks much better. Shouldn't pin of dune be sufficient to reproduce this? And anyways, I trust your check of new branch on the repro example, it's a minified version of real codebase that exhibited this error, so I'm pretty confident the fix should improve the error message for that case as well.

@rgrinberg
Copy link
Copy Markdown
Member Author

Okay, the error message that you show looks much better. Shouldn't pin of dune be sufficient to reproduce this?

That's how I produced the error message above. Which command did you use to pin?

| None -> Ok lib
| Some _ ->
let impl = Map.find_exn impls lib in
let+ () = validate_closure ~vlib:lib ~impl impls in
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This calls feels expansive. IIUC, for each virtual library, we scan all the transitive dependencies of the chosen implementation. Is that right?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yeah, that's indeed the case.

@ghost
Copy link
Copy Markdown

ghost commented Apr 1, 2020

I haven't read the whole PR, but I'm a bit worried by the complexity of this check. It seems to me that we are scanning a lot of libraries in a loop, which could have non-negligible performance implications.

@ghost
Copy link
Copy Markdown

ghost commented Apr 1, 2020

Could you remind me what case we are trying to detect again?

@rgrinberg
Copy link
Copy Markdown
Member Author

I haven't read the whole PR, but I'm a bit worried by the complexity of this check. It seems to me that we are scanning a lot of libraries in a loop, which could have non-negligible performance implications.

I agree that the check is expensive. One of the reasons it took me so long to add this check is that I was looking for ways to optimize it or to avoid it in some cases. All of those previous approaches had problems and this is the first implementation of the check where I'm fairly confident that it works correctly and detects all the edge cases. I'd like to hear suggestions on how to optimize it, but even if the check ends up being expensive, I'd say that:

  • It's still better than having no check and having these invalid archives
  • Users only pay for this check if they are using virtual libraries

Could you remind me what case we are trying to detect again?

The test this PR fixes is a good example. Here's a quick example:

;; we have a virtual library
(library (name vlib) (virtual_modules vlib))
;; and a library that depends on it:
(library (name lib) (libraries vlib))
;; now we create an implementation
(library (name impl) (implements vlib) (libraries lib))
;; but the implementation above is invalid. impl cannot depend on any libraries
;; that have lib in vlib in their closure

@ghost
Copy link
Copy Markdown

ghost commented Apr 2, 2020

Does this PR reports the error when we define "impl" or when we try to link an exe against "impl"?

@rgrinberg rgrinberg changed the title Library Closure Improvements Vlib Cycle Detection Apr 2, 2020
@rgrinberg
Copy link
Copy Markdown
Member Author

rgrinberg commented Apr 10, 2020

This PR no longer includes any refactoring. The only change included is the bug fix.

However, it was decided that this check should be linear in the size of the closure rather than quadratic (in the worst case) as it is now. I will attempt to this optimization for 2.6

@rgrinberg rgrinberg marked this pull request as draft April 28, 2020 21:05
We no longer allow dependencies of the form:

impl -> lib -> vlib

Signed-off-by: Rudi Grinberg <me@rgrinberg.com>
Base automatically changed from master to main January 14, 2021 17:08
@rgrinberg
Copy link
Copy Markdown
Member Author

Fixed in main.

@rgrinberg rgrinberg closed this Nov 4, 2021
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.

2 participants