-
Notifications
You must be signed in to change notification settings - Fork 414
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
Add an option to replace external-lib-deps command #6045
Conversation
Thanks for explaining the implementation strategy. I still don't under the point of this |
I should note that using mutation and global variables is also highly suspicious. We've worked very hard to remove all mutable state in our codebase to make it memoization safe. It's very unlikely we're going to undo all that work to reimplement |
The |
Where is the association from directory to package is done? I don't see in the code. For that matter, I don't see why we need to be concerned with packages at all. The check works on libraries only. |
True. This is a first shot, I did think about that. Is Memoizing them going to be better in this case ? |
Memoization is an optimization, so it is something we can think about if our implementation is slow. For now, I'd suggest just trying to extract the information you need by climbing the workspace and building what is needed to extract lib deps (kind of like dune describe for example). There might not be enough information, or the api is insufficient. In that case, we can tweak |
Sorry I didn't precise, those information are important to |
Before discussing the implementation I think it's important to discuss the design of the features and the expectations we have for it.
What do you think about these? thanks! |
The new version of dune (from 3.0.0) removed "dune external-lib-deps" and this is a patch that work with a patch of dune from "https://github.com/moyodiallo/dune/tree/opam-dune-lint". There's already a PR(ocaml/dune#6045) in dune about this patch, but not garanty to be merged. The command may change also.
The new version of dune (from 3.0.0) removed "dune external-lib-deps" and this is a patch that work with a patch of dune from "https://github.com/moyodiallo/dune/tree/opam-dune-lint". There's already a PR(ocaml/dune#6045) in dune about this patch, but not guarantee to be merged. The command may change also.
Yep this is an issue, because the command is not expected to fail. |
Yes, It's better to have a separate command, like @rgrinberg propose a good starting point is |
This argument was put to group by package for opam-dune-lint. Starting with |
To summarize little bit
With this modification in What do you think ? (don't consider those 2 commits because, they will be reverted) |
Sure, it's fine to add something to the interface. |
2851533
to
6f8771a
Compare
@emillon you were right about |
Thanks. Can you rebase and reformat this PR? I'll have some comments on it but they'll move around too much. |
6f8771a
to
91ce790
Compare
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. I think that it's going in the right direction. In addition to the comments I have 2 general remarks:
- I wonder if this should be a
describe
target rather than a top-level command. - please add tests for this feature, including for corner cases like "optional" and CLI errors (if relevant)
bin/external_lib_deps.ml
Outdated
|
||
let to_dyn kind = | ||
match kind with | ||
| Required -> Dyn.String "require" |
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.
| Required -> Dyn.String "require" | |
| Required -> Dyn.String "required" |
bin/external_lib_deps.ml
Outdated
select.choices | ||
|> Memo.parallel_map ~f:(fun choice -> | ||
Lib_name.Set.to_string_list | ||
choice.Lib_dep.Select.Choice.required |
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.
style: in dune we variables parameters with their type rather than use a.M.b
, so that would be (choice : Lib_dep. ...) ->
bin/external_lib_deps.ml
Outdated
|> Memo.parallel_map ~f:(fun name -> | ||
let name = Lib_name.of_string name in | ||
let+ resolved = resolve db name in | ||
(resolved, Kind.Optional, name))) |
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.
does "optional" in this command mean to "behind a select"? that's a bit different from what is meant by (optional)
in dune. for example how does this command report dependencies of a binary that's marked (optional)
?
bin/external_lib_deps.ml
Outdated
| Dune_file.Executables exes -> | ||
Memo.return [ (exes.buildable.libraries, dir) ] | ||
| Dune_file.Library lib -> | ||
Memo.return [ (lib.buildable.libraries, 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.
I don't think that anything uses Memo
in this part, so you can use plain list iteration and replace let*
by let+
above.
bin/external_lib_deps.ml
Outdated
let run ~context_name ~external_resolved_libs ~by_dir ~sexp ~only_missing = | ||
if only_missing then ( | ||
if by_dir || sexp then | ||
User_error.raise |
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.
can you move this logic to the main term? there's effectively command line parse errors. the strategy I recommend is to define a type that defines the command can do (for example a record with a format field (sexp/plain), a boolean by_dir, etc), and let the run
function be total about this.
bin/external_lib_deps.ml
Outdated
(Sexp.pp (Sexp.List [ Sexp.Atom context_name; sexp ]))) | ||
else ( | ||
if by_dir then | ||
User_error.raise [ Pp.textf "--by-dir cannot be used without --sexp" ]; |
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.
BTW some of these limitations seem artificial - could we have a by-dir plain output?
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 was trying keep the old interface, there's no by-dir plain output. I asked myself if the by-dir
is necessary because only sexp
could be ok, I think.
src/dune_rules/lib.mli
Outdated
type t = | ||
| Installed_libs | ||
| Public_libs | ||
| Project_libs |
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.
is the distinction between project and public libs used? I wonder if we could do without this kind
field. we can check if a db is the installed_lib ones by checking if its parent is None maybe?
bin/external_lib_deps.ml
Outdated
if not by_dir then User_error.raise [ Pp.textf "--sexp requires --by-dir" ]; | ||
let sexp = | ||
external_resolved_libs | ||
|> List.map ~f:(fun (dir, libs) -> |
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 is duplicated with the branch below. I would recommend defining an appropriate data structure, build it in both cases, and print it differently (using to_dyn in one case)
I don't get what you mean. |
29dccd5
to
aaf6032
Compare
The sub-command |
aaf6032
to
e097816
Compare
src/dune_lang/action.ml
Outdated
@@ -398,6 +398,31 @@ let rec map_string_with_vars t ~f = | |||
| Pipe (o, ts) -> Pipe (o, List.map ts ~f:(map_string_with_vars ~f)) | |||
| Cram sw -> Cram (f sw) | |||
|
|||
let rec list_of_string_with_vars t = |
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.
looks like there's a bunch of unrelated code that has been pulled 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.
Recycling the old tests, I find out there was lib-available:<library-name>
and it's considered like an optional dependency.
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.
When you cherry-picked old tests in a8b6272, the commit also added some changes in src/
. Can you remove those?
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 didn't do a cherry-pick, the tests was not consequent. So I just did a copy paste mentioning it was the all tests.
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.
OK I understand now. I don't think that this approach is going to work, since it only collects pforms in (rule)
. Can we stick to the simpler version (that does not try to collect lib names in pforms) for 3.5? Otherwise we can try something that somehow folds over pforms in all stanzas, but this is going to be more involved so we can't do that before 3.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.
Ok agree
bin/describe.ml
Outdated
, "Print out external libraries needed to build the project. It's an \ | ||
approximated set of libraries." | ||
, return External_lib_deps ) | ||
; ( "missing-external-lib-deps" |
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.
does dune-opam-lint
require this second one? we said we'd start with the bare minimum to support that command for now.
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.
No. I'm going to retract that.
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.
Yeah, even with only external libs we can find missing one without dune
.
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.
Okay, looks much better now. Left some remarks and comments.
src/dune_rules/lib.ml
Outdated
@@ -775,7 +775,7 @@ module rec Resolve_names : sig | |||
val resolve_dep : | |||
db -> Loc.t * Lib_name.t -> private_deps:private_deps -> lib Resolve.Memo.t | |||
|
|||
val resolve_name : db -> Lib_name.t -> Status.t Memo.t | |||
val resolve_name : db -> Lib_name.t -> (Status.t * db) Memo.t |
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.
Can you explain why we need this 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.
This is the last db
where the lib_name
where searched(or resolved) and with that, we can determine if the lib_name
is external or not(external ifdb.parent
is None).
Yeah I see your concern. I think it would it be better to expand Status.t by having External
in it and remove db
.
src/dune_lang/string_with_vars.mli
Outdated
@@ -10,6 +10,8 @@ open Dune_util | |||
(** A sequence of text and variables. *) | |||
type t | |||
|
|||
val pforms : t -> Pform.t list |
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?
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.
Yeah Previous commit, I did forgot. I'll remove it.
Thanks.
src/dune_rules/expander.mli
Outdated
@@ -141,3 +141,5 @@ val expand_locks : | |||
base:[ `Of_expander | `This of Path.t ] -> t -> Locks.t -> Path.t list Memo.t | |||
|
|||
val sites : t -> Sites.t | |||
|
|||
val bindings : t -> value Pform.Map.t |
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?
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.
Same thing. Thanks.
It looks like there's still a bit of work for this feature to be stable so I'm marking this for 3.6 to avoid delaying the 3.5 release. |
Just one more little thing. It's gonna be possible. 😁 |
b9589bb
to
f3a71e8
Compare
I did another review to delete all the parasite code that I introduced(git diff main). And I think it's good for me, unless you have another remarks or concern. |
src/dune_rules/lib.mli
Outdated
@@ -131,6 +131,8 @@ module DB : sig | |||
|
|||
val find_even_when_hidden : t -> Lib_name.t -> lib option Memo.t | |||
|
|||
val is_external : t -> Lib_name.t -> bool Memo.t |
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.
Instead of introducing this function. How about just doing a resolve first (with find_even_when_hidden). Once the library is resolved, you can check if it's external by looking at the status.
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.
Status.t
don't give the information if the lib is external or not. And expanding status it's not a good idea, I tried it.
Resolve then a check, could end up with the case when the library is not installed(not found). We want to print the information whether or not the library is installed.
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 constructors Installed
and Installed_private
correspond to external libraries.
Why is expanding the status not a good idea?
Resolve then a check, could end up with the case when the library is not installed(not found). We want to print the information whether or not the library is installed.
I don't understand. Is there a test case that corresponds to this situation?
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 said not a good Idea because I tried to have a constructor External
in the status. It was conflicting whether the lib is Found
or Not_found
.
Yeah I see you suggestion, we doesn't need to expand the status if it's true:
Is it that, if find_even_hidden give None
the lib is external and if we get a lib, we test whether it's Installed
?
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 a lib is not found, we can assume it is an external 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.
Is it that, if find_even_hidden give None the lib is external and if we get a lib, we test whether it's Installed?
Yes, we can do that.
If a lib is not found, we can assume it is an external lib.
That's the best we can do.
In general, we don't want to modify any existing code in lib.ml
. It's pretty complicated already and we'd prefer changes that simplify things or at least add things independently. That's why I'm pushing against these changes.
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 understand, that sounds good for me and it's equivalent to what I was already doing.
The irony(git diff main), using |
08f2860
to
f6562c2
Compare
f6562c2
to
795526b
Compare
Determining the missing library dependencies is revived under $ dune describe external-lib-deps. Signed-off-by: Alpha DIALLO <[email protected]>
795526b
to
1a9eb8b
Compare
Thanks. I merged after a few cleanups. |
Thanks All of you. I learnt a lot during this PR. |
…ne-site, dune-rpc, dune-rpc-lwt, dune-private-libs, dune-glob, dune-configurator, dune-build-info, dune-action-plugin and chrome-trace (3.6.0) CHANGES: - Forbid multiple instances of dune running concurrently in the same workspace. (ocaml/dune#6360, fixes ocaml/dune#236, @rgrinberg) - Allow promoting into source directories specified by `subdir` (ocaml/dune#6404, fixes ocaml/dune#3502, @rgrinberg) - Make dune describe workspace return the correct root path (ocaml/dune#6380, fixes ocaml/dune#6379, @esope) - Introduce a `$ dune ocaml top-module` subcommand to load modules directly without sealing them behind the signature. (ocaml/dune#5940, @rgrinberg) - [ctypes] do not mangle user written names in the ctypes stanza (ocaml/dune#6374, fixes ocaml/dune#5561, @rgrinberg) - Support `CLICOLOR` and `CLICOLOR_FORCE` to enable/disable/force ANSI colors. (ocaml/dune#6340, fixes ocaml/dune#6323, @MisterDA). - Forbid private libraries with `(package ..)` set from depending on private libraries that don't belong to a package (ocaml/dune#6385, fixes ocaml/dune#6153, @rgrinberg) - Allow `Byte_complete` binaries to be installable (ocaml/dune#4873, @AltGr, @rgrinberg) - Revive `$ dune external-lib-deps` under `$ dune describe external-lib-deps`. (ocaml/dune#6045, @moyodiallo) - Fix running inline tests in bytecode mode (ocaml/dune#5622, fixes ocaml/dune#5515, @dariusf) - [ctypes] always re-run `pkg-config` because we aren't tracking its external dependencies (ocaml/dune#6052, @rgrinberg) - [ctypes] remove dependency on configurator in the generated rules (ocaml/dune#6052, @rgrinberg) - Build progress status now shows number of failed jobs (ocaml/dune#6242, @Alizter) - Allow absolute build directories to find public executables. For example, those specified with `(deps %{bin:...})` (ocaml/dune#6326, @anmonteiro) - Create a fake socket file `_build/.rpc/dune` on windows to allow rpc clients to connect using the build directory. (ocaml/dune#6329, @rgrinberg) - Prevent crash if absolute paths are used in the install stanza and in recursive globs. These cases now result in a user error. (ocaml/dune#6331, @gridbugs) - Add `(glob_files <glob>)` and `(glob_files_rec <glob>)` terms to the `files` field of the `install` stanza (ocaml/dune#6250, closes ocaml/dune#6018, @gridbugs) - Allow `:standard` in the `(modules)` field of the `coq.pp` stanza (ocaml/dune#6229, fixes ocaml/dune#2414, @Alizter) - Fix passing of flags to dune coq top (ocaml/dune#6369, fixes ocaml/dune#6366, @Alizter) - Extend the promotion CLI to a `dune promotion` group: `dune promote` is moved to `dune promotion apply` (the former still works) and the new `dune promotion diff` command can be used to just display the promotion without applying it. (ocaml/dune#6160, fixes ocaml/dune#5368, @emillon)
The new version of dune (from 3.0.0) removed "dune external-lib-deps" and this is a patch that work with a patch of dune from "https://github.com/moyodiallo/dune/tree/opam-dune-lint". There's already a PR(ocaml/dune#6045) in dune about this patch, but not guarantee to be merged. The command may change also.
This PR is motivate by dune-opam-lint. The command
dune external-lib-deps
is used by it and this command is removed in dune #4298. Getting the command back is not realistic, I think. Instead of getting all information by doing a static analysis of the build graph. We extract all the information we need during the build, sodynamically
.Project_libs
db,Public_libs
db,Installed_libs
db. Then, during the resolution catch all libs that searched inInstalled_libs
, potentially there are external libs. Easy to add but you have to propagate thebuild_dir
in order to get the dependencies bybuild_dir
.Lib_info
. So you don't have to propagate thebuild_dir
across many functions, but the issue is you could miss external dependency (likeselect
rule). In the case of a dune project not all external deps will be resolved in some particular build.In this PR the first approach was chosen, why not propagate the
build_dir
and get all external dependencies during the build.