From 718e39f83296139fde79575e65a8d353ef133083 Mon Sep 17 00:00:00 2001 From: Ali Caglayan Date: Thu, 12 Mar 2026 13:14:42 +0100 Subject: [PATCH 1/4] fix(show): dune show targets now accepts build-only directories Use Load_rules instead of Source_tree to check directory existence. Fixes #13782 Signed-off-by: Ali Caglayan --- bin/describe/aliases_targets.ml | 92 +++++++++++-------- doc/changes/fixed/14664.md | 2 + doc/reference/cli.rst | 4 +- .../test-cases/describe/targets.t/run.t | 10 +- 4 files changed, 66 insertions(+), 42 deletions(-) create mode 100644 doc/changes/fixed/14664.md diff --git a/bin/describe/aliases_targets.ml b/bin/describe/aliases_targets.ml index 976c0f4a77e..eafd9ecea73 100644 --- a/bin/describe/aliases_targets.ml +++ b/bin/describe/aliases_targets.ml @@ -54,26 +54,44 @@ let ls_term (fetch_results : Path.Build.t -> string list Action_builder.t) = Action_builder.of_memo @@ let open Memo.O in - Source_tree.find_dir src_dir + (* First check if it's a directory target *) + Load_rules.load_dir ~dir:(Path.build build_dir) >>= function - | Some _ -> Memo.return () - | None -> - (* The directory didn't exist. We therefore check if it was a - directory target and error for the user accordingly. *) - let+ is_dir_target = - Load_rules.is_under_directory_target (Path.build build_dir) - in - if is_dir_target - then - User_error.raise - [ Pp.textf - "Directory %s is a directory target. This command does not support \ - the inspection of directory targets." - (Path.to_string dir) - ] - else - User_error.raise - [ Pp.textf "Directory %s does not exist." (Path.to_string dir) ] + | Load_rules.Loaded.Build_under_directory_target _ -> + User_error.raise + [ Pp.textf + "Directory %s is a directory target. This command does not support the \ + inspection of directory targets." + (Path.to_string dir) + ] + | External _ | Build _ | Source _ -> + (* Check if directory exists in source tree or is a valid build-only directory *) + Source_tree.find_dir src_dir + >>= (function + | Some _ -> Memo.return () (* Exists in source tree *) + | None -> + (* Not in source tree, check if it's a valid build-only subdirectory *) + (match Path.Build.parent build_dir with + | None -> + (* Build context root always exists *) + Memo.return () + | Some parent_dir -> + Load_rules.load_dir ~dir:(Path.build parent_dir) + >>| (function + | Load_rules.Loaded.Build { allowed_subdirs; _ } -> + let subdir_set = + Dune_engine.Dir_set.descend + allowed_subdirs + (Path.Build.basename build_dir) + in + if Dune_engine.Dir_set.here subdir_set + then () + else + User_error.raise + [ Pp.textf "Directory %s does not exist." (Path.to_string dir) ] + | _ -> + User_error.raise + [ Pp.textf "Directory %s does not exist." (Path.to_string dir) ]))) in let+ targets = fetch_results build_dir in (* If we are printing multiple directories, we print the directory @@ -116,23 +134,25 @@ end module Targets_cmd = struct let fetch_results (dir : Path.Build.t) = let open Action_builder.O in - let+ targets = - let open Memo.O in - Target.all_direct_targets (Some (Path.Build.drop_build_context_exn dir)) - >>| Path.Build.Map.to_list - |> Action_builder.of_memo - in - List.filter_map targets ~f:(fun (path, kind) -> - match Path.Build.equal (Path.Build.parent_exn path) dir with - | false -> None - | true -> - (* directory targets can be distinguied by the trailing path separator - *) - Some - (match kind with - | Target.File -> Path.Build.basename path |> Filename.to_string - | Directory -> - (Path.Build.basename path |> Filename.to_string) ^ Filename.dir_sep)) + let+ load_dir = Action_builder.of_memo (Load_rules.load_dir ~dir:(Path.build dir)) in + match load_dir with + | Load_rules.Loaded.Build { rules_here; _ } -> + let file_targets = + Path.Build.Map.keys rules_here.by_file_targets + |> List.filter_map ~f:(fun path -> + if Path.Build.equal (Path.Build.parent_exn path) dir + then Some (Path.Build.basename path |> Filename.to_string) + else None) + in + let dir_targets = + Path.Build.Map.keys rules_here.by_directory_targets + |> List.filter_map ~f:(fun path -> + if Path.Build.equal (Path.Build.parent_exn path) dir + then Some ((Path.Build.basename path |> Filename.to_string) ^ Filename.dir_sep) + else None) + in + List.sort ~compare:String.compare (file_targets @ dir_targets) + | _ -> [] ;; let term = ls_term fetch_results diff --git a/doc/changes/fixed/14664.md b/doc/changes/fixed/14664.md new file mode 100644 index 00000000000..c4f66283751 --- /dev/null +++ b/doc/changes/fixed/14664.md @@ -0,0 +1,2 @@ +- `dune show targets` now accepts build-only directories such as + `_build/default/.simple.objs`. (#14664, fixes #13782, @Alizter) diff --git a/doc/reference/cli.rst b/doc/reference/cli.rst index 3e9aca7f7f7..e4c2c67503a 100644 --- a/doc/reference/cli.rst +++ b/doc/reference/cli.rst @@ -71,7 +71,9 @@ documentation for each command is available through ``dune COMMAND --help``. .. describe:: dune describe targets - Print targets in a given directory. Works similarly to ls. + Print targets in a given directory. Works similarly to ls. The directory + may be a path in the source tree, or a build-only directory under + ``_build/`` (such as ``_build/default/.lib.objs``). .. describe:: dune describe workspace diff --git a/test/blackbox-tests/test-cases/describe/targets.t/run.t b/test/blackbox-tests/test-cases/describe/targets.t/run.t index e7f701a39fd..225c4435c57 100644 --- a/test/blackbox-tests/test-cases/describe/targets.t/run.t +++ b/test/blackbox-tests/test-cases/describe/targets.t/run.t @@ -70,15 +70,15 @@ We cannot see inside directory targets Error: Directory d is a directory target. This command does not support the inspection of directory targets. -We cannot show targets in build-only directories that don't exist in the source -tree, like .simple.objs: +Build-only directories that don't exist in the source tree, like .simple.objs +(Dune's internal object directory for the `simple` library), can now be +queried: $ dune show targets .simple.objs - Error: Directory .simple.objs does not exist. + cctx.ocaml-index -CR-soon Alizter: This should work $ dune show targets _build/default/.simple.objs - Error: Directory _build/default/.simple.objs does not exist. + cctx.ocaml-index And we error on non-existent directories From 10ffc791e92dbcfe4aafb89751fb22ac8dfac3d6 Mon Sep 17 00:00:00 2001 From: Ali Caglayan Date: Thu, 12 Mar 2026 13:49:04 +0100 Subject: [PATCH 2/4] refactor(show): add ls_term_gen to support extra arguments Extract the shared term-building logic of `dune show targets` and `dune show aliases` into a generic `ls_term_gen` that accepts an extra argument term. This lets descendant commits expose additional flags without duplicating the path/context handling. Signed-off-by: Ali Caglayan --- bin/describe/aliases_targets.ml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/bin/describe/aliases_targets.ml b/bin/describe/aliases_targets.ml index eafd9ecea73..f22263429fc 100644 --- a/bin/describe/aliases_targets.ml +++ b/bin/describe/aliases_targets.ml @@ -1,13 +1,13 @@ open Import -let ls_term (fetch_results : Path.Build.t -> string list Action_builder.t) = +let ls_term_gen extra_args fetch_results = let+ builder = Common.Builder.term (* CR-someday Alizter: document this option *) and+ paths = Arg.(value & pos_all string [ "." ] & info [] ~docv:"DIR" ~doc:None) and+ context = Common.context_arg ~doc:(Some "The context to look in. Defaults to the default context.") - in + and+ extra = extra_args in let common, config = Common.init builder in let request (_ : Dune_rules.Main.build_system) = let header = List.length paths > 1 in @@ -93,7 +93,7 @@ let ls_term (fetch_results : Path.Build.t -> string list Action_builder.t) = User_error.raise [ Pp.textf "Directory %s does not exist." (Path.to_string dir) ]))) in - let+ targets = fetch_results build_dir in + let+ targets = fetch_results extra build_dir in (* If we are printing multiple directories, we print the directory name as a header. *) (if header then [ Pp.textf "%s:" (Path.to_string dir) ] else []) @@ -110,7 +110,7 @@ let ls_term (fetch_results : Path.Build.t -> string list Action_builder.t) = ;; module Aliases_cmd = struct - let fetch_results (dir : Path.Build.t) = + let fetch_results () (dir : Path.Build.t) = let open Action_builder.O in let+ alias_targets = let+ load_dir = @@ -123,7 +123,7 @@ module Aliases_cmd = struct List.map ~f:Dune_engine.Alias.Name.to_string alias_targets ;; - let term = ls_term fetch_results + let term = ls_term_gen (Term.const ()) fetch_results let command = let doc = "Print aliases in a given directory. Works similarly to ls." in @@ -132,7 +132,7 @@ module Aliases_cmd = struct end module Targets_cmd = struct - let fetch_results (dir : Path.Build.t) = + let fetch_results () (dir : Path.Build.t) = let open Action_builder.O in let+ load_dir = Action_builder.of_memo (Load_rules.load_dir ~dir:(Path.build dir)) in match load_dir with @@ -155,7 +155,7 @@ module Targets_cmd = struct | _ -> [] ;; - let term = ls_term fetch_results + let term = ls_term_gen (Term.const ()) fetch_results let command = let doc = "Print targets in a given directory. Works similarly to ls." in From 7405cd39d3de1d5c3eae56a3c43dd2661803d31c Mon Sep 17 00:00:00 2001 From: Ali Caglayan Date: Thu, 12 Mar 2026 13:41:08 +0100 Subject: [PATCH 3/4] feat(show): include directories with targets in dune show targets Walk the `allowed_subdirs` of the loaded directory and surface those containing build targets in the listing. Add an `-a`/`--all` flag to also include hidden directories (those starting with `.`). Fixes #13783 Signed-off-by: Ali Caglayan --- bin/describe/aliases_targets.ml | 26 ++++++++++++++++--- doc/changes/changed/14665.md | 3 +++ doc/reference/cli.rst | 4 ++- .../test-cases/describe/targets.t/run.t | 25 ++++++++++++++++++ 4 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 doc/changes/changed/14665.md diff --git a/bin/describe/aliases_targets.ml b/bin/describe/aliases_targets.ml index f22263429fc..71c2db340cc 100644 --- a/bin/describe/aliases_targets.ml +++ b/bin/describe/aliases_targets.ml @@ -132,11 +132,11 @@ module Aliases_cmd = struct end module Targets_cmd = struct - let fetch_results () (dir : Path.Build.t) = + let fetch_results all (dir : Path.Build.t) = let open Action_builder.O in let+ load_dir = Action_builder.of_memo (Load_rules.load_dir ~dir:(Path.build dir)) in match load_dir with - | Load_rules.Loaded.Build { rules_here; _ } -> + | Load_rules.Loaded.Build { rules_here; allowed_subdirs; _ } -> let file_targets = Path.Build.Map.keys rules_here.by_file_targets |> List.filter_map ~f:(fun path -> @@ -151,11 +151,29 @@ module Targets_cmd = struct then Some ((Path.Build.basename path |> Filename.to_string) ^ Filename.dir_sep) else None) in - List.sort ~compare:String.compare (file_targets @ dir_targets) + let subdirs = + match Dune_engine.Dir_set.toplevel_subdirs allowed_subdirs with + | Infinite -> [] + | Finite set -> + Filename.Set.to_list set + |> Filename.L.to_string + |> List.filter ~f:(fun name -> all || String.length name = 0 || name.[0] <> '.') + |> List.map ~f:(fun name -> name ^ Filename.dir_sep) + in + List.sort ~compare:String.compare (file_targets @ dir_targets @ subdirs) | _ -> [] ;; - let term = ls_term_gen (Term.const ()) fetch_results + let extra_args = + Arg.( + value + & flag + & info + [ "a"; "all" ] + ~doc:(Some "Show hidden directories (those starting with '.').")) + ;; + + let term = ls_term_gen extra_args fetch_results let command = let doc = "Print targets in a given directory. Works similarly to ls." in diff --git a/doc/changes/changed/14665.md b/doc/changes/changed/14665.md new file mode 100644 index 00000000000..52ba9cb042e --- /dev/null +++ b/doc/changes/changed/14665.md @@ -0,0 +1,3 @@ +- `dune show targets` now includes subdirectories that contain build targets, + and accepts an `-a`/`--all` flag to also include hidden directories (those + starting with `.`). (#14665, fixes #13783, @Alizter) diff --git a/doc/reference/cli.rst b/doc/reference/cli.rst index e4c2c67503a..e3fd1942059 100644 --- a/doc/reference/cli.rst +++ b/doc/reference/cli.rst @@ -73,7 +73,9 @@ documentation for each command is available through ``dune COMMAND --help``. Print targets in a given directory. Works similarly to ls. The directory may be a path in the source tree, or a build-only directory under - ``_build/`` (such as ``_build/default/.lib.objs``). + ``_build/`` (such as ``_build/default/.lib.objs``). Subdirectories + containing build targets are listed alongside the targets themselves; + pass ``-a``/``--all`` to also include hidden directories. .. describe:: dune describe workspace diff --git a/test/blackbox-tests/test-cases/describe/targets.t/run.t b/test/blackbox-tests/test-cases/describe/targets.t/run.t index 225c4435c57..0a86df0d807 100644 --- a/test/blackbox-tests/test-cases/describe/targets.t/run.t +++ b/test/blackbox-tests/test-cases/describe/targets.t/run.t @@ -8,7 +8,10 @@ With no directory provided to the command, it should default to the current working directory. $ dune show targets + _doc/ + _doc_new/ a.ml + b/ d/ dune dune-project @@ -23,7 +26,10 @@ used, and only the targets available in that directory will be displayed. $ dune show targets . b/ .: + _doc/ + _doc_new/ a.ml + b/ d/ dune dune-project @@ -45,7 +51,10 @@ used, and only the targets available in that directory will be displayed. The command also works with files in the _build directory. $ dune show targets _build/default/ + _doc/ + _doc_new/ a.ml + b/ d/ dune dune-project @@ -75,10 +84,26 @@ Build-only directories that don't exist in the source tree, like .simple.objs queried: $ dune show targets .simple.objs + byte/ cctx.ocaml-index + jsoo/ + native/ $ dune show targets _build/default/.simple.objs + byte/ cctx.ocaml-index + jsoo/ + native/ + +With --all, hidden directories are also shown: + + $ dune show targets --all .simple.objs + .bin/ + .utop/ + byte/ + cctx.ocaml-index + jsoo/ + native/ And we error on non-existent directories From 0884ab92af6c70eb5e7b45b458b7e23530905e98 Mon Sep 17 00:00:00 2001 From: Ali Caglayan Date: Thu, 12 Mar 2026 09:41:25 +0100 Subject: [PATCH 4/4] feat(show): let dune show targets look inside directory targets Introduce `Build_system.targets_of` to resolve the targets at a given build directory, including paths underneath directory targets. The listing uses validated targets so users can inspect the contents of directory targets directly. Fixes #13780 Signed-off-by: Ali Caglayan --- bin/describe/aliases_targets.ml | 72 +++++++++---------- doc/changes/changed/14666.md | 2 + doc/reference/cli.rst | 9 +-- src/dune_engine/build_system.ml | 51 +++++++++++++ src/dune_engine/build_system.mli | 4 ++ .../test-cases/describe/targets.t/dune | 4 +- .../test-cases/describe/targets.t/run.t | 23 +++++- 7 files changed, 120 insertions(+), 45 deletions(-) create mode 100644 doc/changes/changed/14666.md diff --git a/bin/describe/aliases_targets.ml b/bin/describe/aliases_targets.ml index 71c2db340cc..3bf075c5469 100644 --- a/bin/describe/aliases_targets.ml +++ b/bin/describe/aliases_targets.ml @@ -49,21 +49,17 @@ let ls_term_gen extra_args fetch_results = (Path.to_string_maybe_quoted dir) ] in - (* Check if the directory exists. *) + (* Check if the directory exists (in source tree, as a directory target, + or as a build-only directory). *) let* () = Action_builder.of_memo @@ let open Memo.O in - (* First check if it's a directory target *) Load_rules.load_dir ~dir:(Path.build build_dir) >>= function | Load_rules.Loaded.Build_under_directory_target _ -> - User_error.raise - [ Pp.textf - "Directory %s is a directory target. This command does not support the \ - inspection of directory targets." - (Path.to_string dir) - ] + (* Directory target - allow it through for inspection *) + Memo.return () | External _ | Build _ | Source _ -> (* Check if directory exists in source tree or is a valid build-only directory *) Source_tree.find_dir src_dir @@ -134,34 +130,38 @@ end module Targets_cmd = struct let fetch_results all (dir : Path.Build.t) = let open Action_builder.O in - let+ load_dir = Action_builder.of_memo (Load_rules.load_dir ~dir:(Path.build dir)) in - match load_dir with - | Load_rules.Loaded.Build { rules_here; allowed_subdirs; _ } -> - let file_targets = - Path.Build.Map.keys rules_here.by_file_targets - |> List.filter_map ~f:(fun path -> - if Path.Build.equal (Path.Build.parent_exn path) dir - then Some (Path.Build.basename path |> Filename.to_string) - else None) - in - let dir_targets = - Path.Build.Map.keys rules_here.by_directory_targets - |> List.filter_map ~f:(fun path -> - if Path.Build.equal (Path.Build.parent_exn path) dir - then Some ((Path.Build.basename path |> Filename.to_string) ^ Filename.dir_sep) - else None) - in - let subdirs = - match Dune_engine.Dir_set.toplevel_subdirs allowed_subdirs with - | Infinite -> [] - | Finite set -> - Filename.Set.to_list set - |> Filename.L.to_string - |> List.filter ~f:(fun name -> all || String.length name = 0 || name.[0] <> '.') - |> List.map ~f:(fun name -> name ^ Filename.dir_sep) - in - List.sort ~compare:String.compare (file_targets @ dir_targets @ subdirs) - | _ -> [] + let* targets = + Action_builder.of_memo (Build_system.targets_of ~dir:(Path.build dir)) + in + let+ subdirs = + Action_builder.of_memo + (let open Memo.O in + Load_rules.load_dir ~dir:(Path.build dir) + >>| function + | Load_rules.Loaded.Build { allowed_subdirs; _ } -> + (match Dune_engine.Dir_set.toplevel_subdirs allowed_subdirs with + | Infinite -> [] + | Finite set -> + Filename.Set.to_list set + |> Filename.L.to_string + |> List.filter ~f:(fun name -> + all || String.length name = 0 || name.[0] <> '.') + |> List.map ~f:(fun name -> name ^ Filename.dir_sep)) + | _ -> []) + in + let target_names = + match Dune_targets.validate targets with + | Valid validated -> + Dune_targets.Validated.fold + validated + ~init:[] + ~file:(fun p acc -> (Path.Build.basename p |> Filename.to_string) :: acc) + ~dir:(fun p acc -> + ((Path.Build.basename p |> Filename.to_string) ^ Filename.dir_sep) :: acc) + | No_targets -> [] + | Inconsistent_parent_dir | File_and_directory_target_with_the_same_name _ -> [] + in + List.sort ~compare:String.compare (target_names @ subdirs) ;; let extra_args = diff --git a/doc/changes/changed/14666.md b/doc/changes/changed/14666.md new file mode 100644 index 00000000000..24ffd0142fe --- /dev/null +++ b/doc/changes/changed/14666.md @@ -0,0 +1,2 @@ +- `dune show targets` now looks inside directory targets, so users can inspect + the files produced under a directory target. (#14666, fixes #13780, @Alizter) diff --git a/doc/reference/cli.rst b/doc/reference/cli.rst index e3fd1942059..b298a58edd8 100644 --- a/doc/reference/cli.rst +++ b/doc/reference/cli.rst @@ -72,10 +72,11 @@ documentation for each command is available through ``dune COMMAND --help``. .. describe:: dune describe targets Print targets in a given directory. Works similarly to ls. The directory - may be a path in the source tree, or a build-only directory under - ``_build/`` (such as ``_build/default/.lib.objs``). Subdirectories - containing build targets are listed alongside the targets themselves; - pass ``-a``/``--all`` to also include hidden directories. + may be a path in the source tree, a build-only directory under + ``_build/`` (such as ``_build/default/.lib.objs``), or a directory + target (including subdirectories of one). Subdirectories containing + build targets are listed alongside the targets themselves; pass + ``-a``/``--all`` to also include hidden directories. .. describe:: dune describe workspace diff --git a/src/dune_engine/build_system.ml b/src/dune_engine/build_system.ml index 3edbadd92fa..50b35f07abe 100644 --- a/src/dune_engine/build_system.ml +++ b/src/dune_engine/build_system.ml @@ -1062,6 +1062,57 @@ let files_of ~dir = Filename_set.create ~dir filenames ;; +let targets_of ~dir = + Load_rules.load_dir ~dir + >>= function + | Source _ | External _ -> + (* Source/external dirs have no build targets *) + Memo.return Targets.empty + | Build { rules_here; _ } -> + let files = + Path.Build.Map.keys rules_here.by_file_targets |> Path.Build.Set.of_list + in + let dirs = + Path.Build.Map.keys rules_here.by_directory_targets |> Path.Build.Set.of_list + in + Memo.return (Targets.create ~files ~dirs) + | Build_under_directory_target { directory_target_ancestor } -> + let+ produced = build_dir (Path.build directory_target_ancestor) in + let build_dir_path = Path.as_in_build_dir_exn dir in + (* Navigate to the requested directory within the produced targets *) + let rec find_dir_contents (contents : _ Targets.Produced.dir_contents) path = + match path with + | [] -> Some contents + | component :: rest -> + (match Filename.Map.find contents.subdirs component with + | Some sub -> find_dir_contents sub rest + | None -> None) + in + let path_within = + match + Path.Local.descendant + (Path.Build.local build_dir_path) + ~of_:(Path.Build.local produced.root) + with + | Some p -> Path.Local.explode p + | None -> [] + in + (match find_dir_contents produced.contents path_within with + | Some contents -> + let files = + Filename.Map.keys contents.files + |> List.map ~f:(Path.Build.relative_fname build_dir_path) + |> Path.Build.Set.of_list + in + let dirs = + Filename.Map.keys contents.subdirs + |> List.map ~f:(Path.Build.relative_fname build_dir_path) + |> Path.Build.Set.of_list + in + Targets.create ~files ~dirs + | None -> Targets.empty) +;; + let caused_by_cancellation (exn : Exn_with_backtrace.t) = match exn.exn with | Scheduler.Run.Build_cancelled -> true diff --git a/src/dune_engine/build_system.mli b/src/dune_engine/build_system.mli index aadf2ee8437..d120b1c16f8 100644 --- a/src/dune_engine/build_system.mli +++ b/src/dune_engine/build_system.mli @@ -35,6 +35,10 @@ val eval_pred : File_selector.t -> Filename_set.t Memo.t (** Same as [eval_pred] with [Predicate.true_] as predicate. *) val files_of : dir:Path.t -> Filename_set.t Memo.t +(** Return all targets (files and directories) in a directory. + Handles directory targets by building them first. *) +val targets_of : dir:Path.t -> Targets.t Memo.t + (** Execute an action. The execution is cached. *) val execute_action : observing_facts:Dep.Facts.t -> Rule.Anonymous_action.t -> unit Memo.t diff --git a/test/blackbox-tests/test-cases/describe/targets.t/dune b/test/blackbox-tests/test-cases/describe/targets.t/dune index b848d9cd25e..3d2aa22c2e8 100644 --- a/test/blackbox-tests/test-cases/describe/targets.t/dune +++ b/test/blackbox-tests/test-cases/describe/targets.t/dune @@ -5,5 +5,5 @@ (targets (dir d)) (action (progn - (run mkdir d) - (run cat > d/foo)))) + (run mkdir -p d/subdir) + (run touch d/foo d/bar d/subdir/nested)))) diff --git a/test/blackbox-tests/test-cases/describe/targets.t/run.t b/test/blackbox-tests/test-cases/describe/targets.t/run.t index 0a86df0d807..392cc9a01ab 100644 --- a/test/blackbox-tests/test-cases/describe/targets.t/run.t +++ b/test/blackbox-tests/test-cases/describe/targets.t/run.t @@ -73,11 +73,28 @@ The command also works with files in the _build directory. simple2.cmxs simple2.ml-gen -We cannot see inside directory targets +We can see inside directory targets. The directory target `d` contains files +and a subdirectory. $ dune show targets d - Error: Directory d is a directory target. This command does not support the - inspection of directory targets. + bar + foo + subdir/ + +We can also inspect directory targets using the _build path: + + $ dune show targets _build/default/d + bar + foo + subdir/ + +We can also look inside subdirectories of directory targets: + + $ dune show targets d/subdir + nested + + $ dune show targets _build/default/d/subdir + nested Build-only directories that don't exist in the source tree, like .simple.objs (Dune's internal object directory for the `simple` library), can now be