@@ -486,7 +486,6 @@ let setup_generate sctx ~search_db odoc_file out =
486486 , [ Command.Args. A " -o"
487487 ; Command.Args. Path (Path. build (Paths. markdown_root ctx))
488488 ; Command.Args. Dep (Path. build odoc_file.odocl_file)
489- ; Command.Args. Hidden_targets [ Output_format. target out odoc_file ]
490489 ] )
491490 | Html | Json ->
492491 let search_args =
@@ -520,9 +519,6 @@ let setup_generate_html_and_json sctx ~search_db odoc_file =
520519 setup_generate sctx ~search_db: (Some search_db) odoc_file Json
521520;;
522521
523- let setup_generate_markdown sctx odoc_file =
524- setup_generate sctx ~search_db: None odoc_file Markdown
525- ;;
526522
527523let setup_css_rule sctx =
528524 let ctx = Super_context. context sctx in
@@ -891,10 +887,15 @@ let out_files ctx (output : Output_format.t) odocs =
891887;;
892888
893889let add_format_alias_deps ctx format target odocs =
894- let paths = out_files ctx format odocs in
895- Rules.Produce.Alias. add_deps
896- (Dep. format_alias format ctx target)
897- (Action_builder. paths paths)
890+ match (format : Output_format.t ) with
891+ | Markdown ->
892+ (* skip intermediate aliases since package directories are directory targets *)
893+ Memo. return ()
894+ | Html | Json ->
895+ let paths = out_files ctx format odocs in
896+ Rules.Produce.Alias. add_deps
897+ (Dep. format_alias format ctx target)
898+ (Action_builder. paths paths)
898899;;
899900
900901let setup_lib_html_rules_def =
@@ -994,9 +995,7 @@ let setup_pkg_html_rules sctx ~pkg : unit Memo.t =
994995;;
995996
996997let setup_lib_markdown_rules sctx lib =
997- let target = Lib lib in
998- let * odocs = odoc_artefacts sctx target in
999- let * () = Memo. parallel_iter odocs ~f: (fun odoc -> setup_generate_markdown sctx odoc) in
998+ (* we don't call setup_generate_markdown per module because all modules in a package write to the same directory. Instead, the package-level rule will handle all generation. *)
1000999 Memo.With_implicit_output. exec setup_lib_markdown_rules_def (sctx, lib)
10011000;;
10021001
@@ -1009,8 +1008,45 @@ let setup_pkg_markdown_rules_def =
10091008 Memo.List. concat_map libs ~f: (fun lib -> odoc_artefacts sctx (Lib lib))
10101009 in
10111010 let all_odocs = pkg_odocs @ lib_odocs in
1011+ (* Generate all markdown for this package in ONE rule with directory target.
1012+ Since odoc generates multiple .md files per .odocl and we can't predict the filenames, we declare the entire package directory
1013+ as a directory target. *)
1014+ let * () =
1015+ if List. is_empty all_odocs
1016+ then Memo. return ()
1017+ else
1018+ let pkg_markdown_dir = Paths. markdown ctx (Pkg pkg) in
1019+ let markdown_root = Paths. markdown_root ctx in
1020+ let rule =
1021+ let bash_cmd_args =
1022+ let open Action_builder.O in
1023+ let * odoc_prog = odoc_program sctx (Context. build_dir ctx) in
1024+ let odoc_path = Action.Prog. ok_exn odoc_prog |> Path. to_string in
1025+ let bash_cmd =
1026+ List. map all_odocs ~f: (fun odoc ->
1027+ let odocl_rel = Path. reach (Path. build odoc.odocl_file) ~from: (Path. build markdown_root) in
1028+ Printf. sprintf " %s markdown-generate -o . %s" odoc_path odocl_rel)
1029+ |> String. concat ~sep: " && "
1030+ in
1031+ let * () =
1032+ List. map all_odocs ~f: (fun odoc -> Action_builder. path (Path. build odoc.odocl_file))
1033+ |> Action_builder. all
1034+ >> | ignore
1035+ in
1036+ Action_builder. return (Command.Args. S [ A " -c" ; A bash_cmd ])
1037+ in
1038+ let deps = Action_builder. env_var " ODOC_SYNTAX" in
1039+ let open Action_builder.With_targets.O in
1040+ Action_builder. with_no_targets deps
1041+ >>> Command. run
1042+ ~dir: (Path. build markdown_root)
1043+ (Ok (Path. of_string " /bin/bash" ))
1044+ [ Dyn bash_cmd_args ]
1045+ |> Action_builder.With_targets. add_directories ~directory_targets: [ pkg_markdown_dir ]
1046+ in
1047+ add_rule sctx rule
1048+ in
10121049 let * () = Memo. parallel_iter libs ~f: (setup_lib_markdown_rules sctx) in
1013- let * () = Memo. parallel_iter pkg_odocs ~f: (setup_generate_markdown sctx) in
10141050 add_format_alias_deps ctx Markdown (Pkg pkg) all_odocs
10151051 in
10161052 setup_pkg_rules_def " setup-package-markdown-rules" f
@@ -1031,11 +1067,21 @@ let setup_package_aliases_format sctx (pkg : Package.t) (output : Output_format.
10311067 let * libs =
10321068 Context. name ctx |> libs_of_pkg ~pkg: name >> | List. map ~f: (fun lib -> Lib lib)
10331069 in
1034- Pkg name :: libs
1035- |> List. map ~f: (Dep. format_alias output ctx)
1036- |> Dune_engine.Dep.Set. of_list_map ~f: (fun f -> Dune_engine.Dep. alias f)
1037- |> Action_builder. deps
1038- |> Rules.Produce.Alias. add_deps alias
1070+ let deps =
1071+ match (output : Output_format.t ) with
1072+ | Markdown ->
1073+ let pkg_markdown_dir = Paths. markdown ctx (Pkg name) in
1074+ let index_path = Paths. markdown_index ctx in
1075+ let open Action_builder.O in
1076+ let * () = Action_builder. path (Path. build pkg_markdown_dir) in
1077+ Action_builder. path (Path. build index_path)
1078+ | Html | Json ->
1079+ Pkg name :: libs
1080+ |> List. map ~f: (Dep. format_alias output ctx)
1081+ |> Dune_engine.Dep.Set. of_list_map ~f: (fun f -> Dune_engine.Dep. alias f)
1082+ |> Action_builder. deps
1083+ in
1084+ Rules.Produce.Alias. add_deps alias deps
10391085;;
10401086
10411087let setup_package_aliases sctx (pkg : Package.t ) =
@@ -1171,36 +1217,31 @@ let gen_rules sctx ~dir rest =
11711217 >>> setup_css_rule sctx
11721218 >>> setup_toplevel_index_rule sctx Html
11731219 >>> setup_toplevel_index_rule sctx Json )
1174- | [ " _markdown" ] -> has_rules (setup_toplevel_index_rule sctx Markdown )
1175- | [ " _markdown" ; lib_unique_name_or_pkg ] ->
1220+ | [ " _markdown" ] ->
1221+ (* Generate all markdown and declare package directories as directory targets *)
1222+ let * packages = Dune_load. packages () in
1223+ let ctx = Super_context. context sctx in
1224+ (* Collect all package directories that will be generated as directory targets *)
1225+ let pkg_dirs =
1226+ Package.Name.Map. to_list packages
1227+ |> List. map ~f: (fun (_ , (pkg : Package.t )) ->
1228+ let pkg_name = Package. name pkg in
1229+ Paths. markdown ctx (Pkg pkg_name))
1230+ in
1231+ let directory_targets =
1232+ List. fold_left pkg_dirs ~init: Path.Build.Map. empty ~f: (fun acc dir ->
1233+ Path.Build.Map. set acc dir Loc. none)
1234+ in
11761235 has_rules
1177- (
1178- let ctx = Super_context. context sctx in
1179- let * lib, lib_db = Scope_key. of_string (Context. name ctx) lib_unique_name_or_pkg in
1180- let * lib =
1181- let + lib = Lib.DB. find lib_db lib in
1182- Option. bind ~f: Lib.Local. of_lib lib
1183- in
1184- let + () =
1185- match lib with
1186- | None -> Memo. return ()
1187- | Some lib ->
1188- (match Lib_info. package (Lib.Local. info lib) with
1189- | None ->
1190- (* lib with no package above it *)
1191- setup_lib_markdown_rules sctx lib
1192- | Some pkg -> setup_pkg_markdown_rules sctx ~pkg )
1193- and + () =
1194- let * packages = Dune_load. packages () in
1195- match
1196- Package.Name.Map. find packages (Package.Name. of_string lib_unique_name_or_pkg)
1197- with
1198- | None -> Memo. return ()
1199- | Some pkg ->
1200- let name = Package. name pkg in
1201- setup_pkg_markdown_rules sctx ~pkg: name
1202- in
1203- () )
1236+ ~directory_targets
1237+ (let * () = setup_toplevel_index_rule sctx Markdown in
1238+ Package.Name.Map. to_seq packages
1239+ |> Memo. parallel_iter_seq ~f: (fun (_ , (pkg : Package.t )) ->
1240+ let pkg_name = Package. name pkg in
1241+ setup_pkg_markdown_rules sctx ~pkg: pkg_name))
1242+ | [ " _markdown" ; _lib_unique_name_or_pkg ] ->
1243+ (* Package directories are directory targets, no rules here *)
1244+ Memo. return Gen_rules. no_rules
12041245 | [ " _mlds" ; pkg ] ->
12051246 with_package pkg ~f: (fun pkg ->
12061247 let pkg = Package. name pkg in
0 commit comments