Skip to content

Commit

Permalink
feature: enable (include_subdirs qualified)
Browse files Browse the repository at this point in the history
Signed-off-by: Rudi Grinberg <me@rgrinberg.com>

ps-id: f0bdd789-87c5-4047-b418-47cdaf7749ae
  • Loading branch information
rgrinberg committed Dec 6, 2022
1 parent f54e69c commit cbfa4f0
Show file tree
Hide file tree
Showing 69 changed files with 1,704 additions and 667 deletions.
7 changes: 7 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ Unreleased
- Fix missing dependencies when detecting the kind of C compiler we're using
(#6610, fixes #6415, @emillon)

- Allow `(include_subdirs qualified)` for OCaml projects. (#6594, fixes #1084,
@rgrinberg)

- Accurately determine merlin configuration for all sources selected with
`copy#` and `copy_files#`. The old heuristic of looking for a module in
parent directories is removed (#6594, @rgrinberg)

3.6.0 (2022-11-14)
------------------

Expand Down
2 changes: 1 addition & 1 deletion bin/describe.ml
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ module Crawl = struct
Memo.return
@@
match Module.kind unit with
| Alias ->
| Alias _ ->
(* TODO: handle Alias modules, that are generated by dune. They are
currently associated to no ocamldep-related rules. *)
Action_builder.return no_deps
Expand Down
3 changes: 1 addition & 2 deletions bin/ocaml_merlin.ml
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,13 @@ end = struct
let load_merlin_file file =
(* We search for an appropriate merlin configuration in the current
directory and its parents *)
let filename = String.lowercase_ascii (Path.Build.basename file) in
let rec find_closest path =
match
get_merlin_files_paths path
|> List.find_map ~f:(fun file_path ->
match Merlin.Processed.load_file file_path with
| Error msg -> Some (Merlin_conf.make_error msg)
| Ok config -> Merlin.Processed.get config ~filename)
| Ok config -> Merlin.Processed.get config ~file)
with
| Some p -> Some p
| None -> (
Expand Down
4 changes: 1 addition & 3 deletions bin/top.ml
Original file line number Diff line number Diff line change
Expand Up @@ -190,9 +190,7 @@ module Module = struct
let+ (pp, ppx), files_to_load = Memo.fork_and_join pps files_to_load in
let code =
let modules = Dune_rules.Compilation_context.modules cctx in
let opens_ =
Dune_rules.Module_compilation.open_modules modules module_
in
let opens_ = Dune_rules.Modules.local_open modules module_ in
List.map opens_ ~f:(fun name ->
sprintf "open %s" (Dune_rules.Module_name.to_string name))
in
Expand Down
12 changes: 8 additions & 4 deletions src/dune_rules/action_unexpanded.ml
Original file line number Diff line number Diff line change
Expand Up @@ -370,11 +370,12 @@ end = struct
end
end

let rec expand (t : Dune_lang.Action.t) : Action.t Action_expander.t =
let rec expand (t : Dune_lang.Action.t) ~context : Action.t Action_expander.t =
let module A = Action_expander in
let module E = Action_expander.E in
let open Action_expander.O in
let module O (* [O] for "outcome" *) = Action in
let expand = expand ~context in
let expand_run prog args =
let+ args = A.all (List.map args ~f:E.strings)
and+ prog, more_args = E.prog_and_args prog in
Expand Down Expand Up @@ -434,7 +435,7 @@ let rec expand (t : Dune_lang.Action.t) : Action.t Action_expander.t =
| Copy_and_add_line_directive (x, y) ->
let+ x = E.dep x
and+ y = E.target y in
Copy_line_directive.action x y
Copy_line_directive.action context ~src:x ~dst:y
| System x ->
let+ x = E.string x in
O.System x
Expand Down Expand Up @@ -485,8 +486,9 @@ let expand_no_targets t ~loc ~deps:deps_written_by_user ~expander ~what =
Expander.set_expanding_what expander (User_action_without_targets { what })
in
let* { Action_builder.With_targets.build; targets } =
let context = Expander.context expander in
Action_builder.of_memo
(Action_expander.run (expand t) ~targets_dir:None ~expander)
(Action_expander.run (expand ~context t) ~targets_dir:None ~expander)
in
if not (Targets.is_empty targets) then
User_error.raise ~loc
Expand Down Expand Up @@ -529,7 +531,9 @@ let expand t ~loc ~deps:deps_written_by_user ~targets_dir
Expander.set_expanding_what expander (User_action targets_written_by_user)
in
let+! { Action_builder.With_targets.build; targets } =
Action_expander.run (expand t) ~targets_dir:(Some targets_dir) ~expander
let context = Expander.context expander in
Action_expander.run (expand ~context t) ~targets_dir:(Some targets_dir)
~expander
in
let targets =
match (targets_written_by_user : _ Targets_spec.t) with
Expand Down
7 changes: 4 additions & 3 deletions src/dune_rules/buildable_rules.ml
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
open Import
open Memo.O

let gen_select_rules t ~dir compile_info =
let gen_select_rules sctx ~dir compile_info =
let open Memo.O in
Lib.Compile.resolved_selects compile_info
|> Resolve.Memo.read_memo
>>= Memo.parallel_iter
~f:(fun { Lib.Compile.Resolved_select.dst_fn; src_fn } ->
let dst = Path.Build.relative dir dst_fn in
Super_context.add_rule t ~dir
Super_context.add_rule sctx ~dir
(Action_builder.with_file_targets ~file_targets:[ dst ]
(let open Action_builder.O in
let* src_fn = Resolve.read src_fn in
let src = Path.build (Path.Build.relative dir src_fn) in
let+ () = Action_builder.path src in
Action.Full.make (Copy_line_directive.action src dst))))
let context = Super_context.context sctx in
Action.Full.make (Copy_line_directive.action context ~src ~dst))))

let with_lib_deps (t : Context.t) compile_info ~dir ~f =
let prefix =
Expand Down
78 changes: 70 additions & 8 deletions src/dune_rules/copy_line_directive.ml
Original file line number Diff line number Diff line change
@@ -1,54 +1,116 @@
open Import

module DB = struct
(* Needed to tell resolve the configuration of sources merlin gives us.
This is all ugly and doesn't work well for watch mode, but it's better
than the old hack. It's temporary until we have something RPC based.
*)
module Persistent = Dune_util.Persistent.Make (struct
type nonrec t = Path.Build.t Path.Build.Table.t

let name = "COPY-LINE-DIRECTIVE-MAP"

let version = 1

let to_dyn = Path.Build.Table.to_dyn Path.Build.to_dyn
end)

let needs_dumping = ref false

let file = Path.relative Path.build_dir ".copy-db"

let t =
(* This mutable table is safe: it's only observed by [$ dune ocaml merlin] *)
lazy
(match Persistent.load file with
| None -> Path.Build.Table.create 128
| Some t -> t)

let dump () =
if !needs_dumping && Path.build_dir_exists () then (
needs_dumping := false;
Persistent.dump file (Lazy.force t))

let () = at_exit dump

let rec follow_while path ~f =
let t = Lazy.force t in
match Path.Build.Table.find t path with
| None -> None
| Some p -> (
match f p with
| None -> follow_while p ~f
| Some p -> Some p)

let set ~src ~dst =
let t = Lazy.force t in
needs_dumping := true;
Path.Build.Table.set t src dst
end

let line_directive ~filename:fn ~line_number =
let directive =
if Foreign_language.has_foreign_extension ~fn then "line" else ""
in
sprintf "#%s %d %S\n" directive line_number fn

module Spec = struct
type ('path, 'target) t = 'path * 'target
type merlin =
| Yes
| No

let bool_of_merlin = function
| Yes -> true
| No -> false

type ('path, 'target) t = 'path * 'target * merlin

let name = "copy-line-directive"

let version = 1

let bimap (src, dst) f g = (f src, g dst)
let bimap (src, dst, merlin) f g = (f src, g dst, merlin)

let is_useful_to ~distribute:_ ~memoize = memoize

let encode (src, dst) path target : Dune_lang.t =
let encode (src, dst, merlin) path target : Dune_lang.t =
List
[ Dune_lang.atom_or_quoted_string "copy-line-directive"
; path src
; target dst
; Dune_lang.atom_or_quoted_string (Bool.to_string (bool_of_merlin merlin))
]

let action (src, dst) ~ectx:_ ~eenv:_ =
let action (src, dst, merlin) ~ectx:_ ~eenv:_ =
Io.with_file_in src ~f:(fun ic ->
Path.build dst
|> Io.with_file_out ~f:(fun oc ->
let fn = Path.drop_optional_build_context_maybe_sandboxed src in
output_string oc
(line_directive ~filename:(Path.to_string fn) ~line_number:1);
Io.copy_channels ic oc));
(match merlin with
| No -> ()
| Yes ->
Path.as_in_build_dir src |> Option.iter ~f:(fun src -> DB.set ~src ~dst));
Fiber.return ()
end

let action src dst =
let action (context : Context.t) ~src ~dst =
let module M = struct
type path = Path.t

type target = Path.Build.t

module Spec = Spec

let v = (src, dst)
let v = (src, dst, if context.merlin then Spec.Yes else No)
end in
Action.Extension (module M)

let builder ~src ~dst =
let builder context ~src ~dst =
let open Action_builder.O in
Action_builder.with_file_targets ~file_targets:[ dst ]
(Action_builder.path src
>>> Action_builder.return (Action.Full.make (action src dst)))
>>> Action_builder.return (Action.Full.make (action context ~src ~dst)))
11 changes: 9 additions & 2 deletions src/dune_rules/copy_line_directive.mli
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
open Import

val action : Path.t -> Path.Build.t -> Action.t
module DB : sig
val follow_while : Path.Build.t -> f:(Path.Build.t -> 'a option) -> 'a option
end

val action : Context.t -> src:Path.t -> dst:Path.Build.t -> Action.t

val builder :
src:Path.t -> dst:Path.Build.t -> Action.Full.t Action_builder.With_targets.t
Context.t
-> src:Path.t
-> dst:Path.Build.t
-> Action.Full.t Action_builder.With_targets.t
19 changes: 14 additions & 5 deletions src/dune_rules/dep_rules.ml
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,23 @@ let ooi_deps { vimpl; sctx; dir; obj_dir; modules = _; stdlib = _; sandbox = _ }
in
read

let deps_of_module md ~ml_kind m =
let deps_of_module ({ modules; _ } as md) ~ml_kind m =
match Module.kind m with
| Wrapped_compat ->
let modules = md.modules in
let interface_module =
match Modules.lib_interface modules with
| Some m -> m
| None -> Modules.compat_for_exn modules m
in
Action_builder.return (List.singleton interface_module) |> Memo.return
| _ -> Ocamldep.deps_of md ~ml_kind m
List.singleton interface_module |> Action_builder.return |> Memo.return
| _ -> (
let+ deps = Ocamldep.deps_of md ~ml_kind m in
match Modules.alias_for modules m with
| [] -> deps
| aliases ->
let open Action_builder.O in
let+ deps = deps in
aliases @ deps)

let deps_of_vlib_module ({ obj_dir; vimpl; dir; sctx; _ } as md) ~ml_kind m =
let vimpl = Option.value_exn vimpl in
Expand Down Expand Up @@ -82,8 +88,11 @@ let deps_of_vlib_module ({ obj_dir; vimpl; dir; sctx; _ } as md) ~ml_kind m =
let rec deps_of md ~ml_kind (m : Modules.Sourced_module.t) =
let is_alias =
match m with
| Imported_from_vlib m | Normal m -> Module.kind m = Alias
| Impl_of_virtual_module _ -> false
| Imported_from_vlib m | Normal m -> (
match Module.kind m with
| Alias _ -> true
| _ -> false)
in
if is_alias then Memo.return (Action_builder.return [])
else
Expand Down
15 changes: 10 additions & 5 deletions src/dune_rules/dune_file.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2143,11 +2143,16 @@ module Include_subdirs = struct
| Include of qualification

let decode ~enable_qualified =
let opts_list =
[ ("no", No); ("unqualified", Include Unqualified) ]
@ if enable_qualified then [ ("qualified", Include Qualified) ] else []
in
enum opts_list
sum
[ ("no", return No)
; ("unqualified", return (Include Unqualified))
; ( "qualified"
, let+ () =
if enable_qualified then return ()
else Syntax.since Stanza.syntax (3, 7)
in
Include Qualified )
]
end

module Library_redirect = struct
Expand Down

0 comments on commit cbfa4f0

Please sign in to comment.