diff --git a/src/gen_rules.ml b/src/gen_rules.ml index 7407dfad..2b8f8c94 100644 --- a/src/gen_rules.ml +++ b/src/gen_rules.ml @@ -301,22 +301,25 @@ module Gen(P : Params) = struct end let all_rules = ref [] - let known_targets_by_dir_so_far = ref Path.Map.empty + let known_targets_by_src_dir_so_far = ref Path.Map.empty let add_rule build = let rule = Build_interpret.Rule.make build in all_rules := rule :: !all_rules; - known_targets_by_dir_so_far := - List.fold_left rule.targets ~init:!known_targets_by_dir_so_far ~f:(fun acc target -> - let path = Build_interpret.Target.path target in - let dir = Path.parent path in - let fn = Path.basename path in - let files = - match Path.Map.find dir acc with - | None -> String_set.singleton fn - | Some set -> String_set.add fn set - in - Path.Map.add acc ~key:dir ~data:files) + known_targets_by_src_dir_so_far := + List.fold_left rule.targets ~init:!known_targets_by_src_dir_so_far + ~f:(fun acc target -> + match Path.extract_build_context (Build_interpret.Target.path target) with + | None -> acc + | Some (_, path) -> + let dir = Path.parent path in + let fn = Path.basename path in + let files = + match Path.Map.find dir acc with + | None -> String_set.singleton fn + | Some set -> String_set.add fn set + in + Path.Map.add acc ~key:dir ~data:files) let sources_and_targets_known_so_far ~src_path = let sources = @@ -324,7 +327,7 @@ module Gen(P : Params) = struct | None -> String_set.empty | Some dir -> File_tree.Dir.files dir in - match Path.Map.find src_path !known_targets_by_dir_so_far with + match Path.Map.find src_path !known_targets_by_src_dir_so_far with | None -> sources | Some set -> String_set.union sources set @@ -1454,62 +1457,74 @@ module Gen(P : Params) = struct let impls = parse_one_set ml_files in let intfs = parse_one_set mli_files in String_map.merge impls intfs ~f:(fun name ml_fname mli_fname -> - match ml_fname with - | None -> - die "module %s in %s doesn't have a corresponding .ml file" - name (Path.to_string dir) - | Some ml_fname -> - Some - { Module. - name - ; ml_fname = ml_fname - ; mli_fname = mli_fname - ; obj_name = "" - }) + let ml_fname = + match ml_fname with + | None -> + let mli_fname = Option.value_exn mli_fname in + let ml_fname = String.sub mli_fname ~pos:0 ~len:(String.length mli_fname - 1) in + Format.eprintf + "@{Warning@}: module %s in %s doesn't have a corresponding\ + .ml file.\n\ + I'm setting up a rule for copying %s to %s.\n" + name (Path.to_string dir) + mli_fname ml_fname; + let dir = Path.append ctx.build_dir dir in + add_rule + (Build.copy + ~src:(Path.relative dir mli_fname) + ~dst:(Path.relative dir ml_fname)); + ml_fname + | Some ml_fname -> ml_fname + in + Some + { Module. + name + ; ml_fname = ml_fname + ; mli_fname = mli_fname + ; obj_name = "" + }) (* +-----------------------------------------------------------------+ | Stanza | +-----------------------------------------------------------------+ *) let rules { src_dir; ctx_dir; stanzas } = + (* Interpret user rules and other simple stanzas first in order to populate the known + target table, which is needed for guessing the list of modules. *) + List.iter stanzas ~f:(fun stanza -> + let dir = ctx_dir in + match (stanza : Stanza.t) with + | Rule rule -> user_rule rule ~dir + | Ocamllex conf -> ocamllex_rules conf ~dir + | Ocamlyacc conf -> ocamlyacc_rules conf ~dir + | Alias alias -> alias_rules alias ~dir + | Library _ | Executables _ | Provides _ | Install _ -> ()); let files = lazy ( - let src_files = - match File_tree.find_dir P.file_tree src_dir with - | None -> String_set.empty - | Some dir -> File_tree.Dir.files dir - in - let files_produced_by_rules = - List.concat_map stanzas ~f:(fun stanza -> - match (stanza : Stanza.t) with - | Rule rule -> rule.targets - | Ocamllex conf -> List.map conf.names ~f:(fun name -> name ^ ".ml") - | Ocamlyacc conf -> List.concat_map conf.names ~f:(fun name -> - [ name ^ ".ml"; name ^ ".mli" ]) - | Library { buildable; _ } | Executables { buildable; _ } -> - List.filter_map buildable.libraries ~f:(function - | Direct _ -> None - | Select s -> Some s.result_fn) - | _ -> []) - |> String_set.of_list - in - String_set.union src_files files_produced_by_rules) - in + let files = sources_and_targets_known_so_far ~src_path:src_dir in + (* Manually add files generated by the (select ...) dependencies since we haven't + interpreted libraries and executables yet. *) + List.fold_left stanzas ~init:files ~f:(fun acc stanza -> + match (stanza : Stanza.t) with + | Library { buildable; _ } | Executables { buildable; _ } -> + List.fold_left buildable.libraries ~init:acc ~f:(fun acc dep -> + match (dep : Jbuild_types.Lib_dep.t) with + | Direct _ -> acc + | Select s -> String_set.add s.result_fn acc) + | _ -> acc) + ) in let all_modules = lazy ( guess_modules ~dir:src_dir ~files:(Lazy.force files)) in - let some x = Some x in - let none () = None in List.filter_map stanzas ~f:(fun stanza -> let dir = ctx_dir in match (stanza : Stanza.t) with - | Library lib -> library_rules lib ~dir ~all_modules:(Lazy.force all_modules) ~files:(Lazy.force files) |> some - | Executables exes -> executables_rules exes ~dir ~all_modules:(Lazy.force all_modules) |> some - | Rule rule -> user_rule rule ~dir |> none - | Ocamllex conf -> ocamllex_rules conf ~dir |> none - | Ocamlyacc conf -> ocamlyacc_rules conf ~dir |> none - | Alias alias -> alias_rules alias ~dir |> none - | Provides _ | Install _ -> () |> none) + | Library lib -> + Some (library_rules lib ~dir + ~all_modules:(Lazy.force all_modules) ~files:(Lazy.force files)) + | Executables exes -> + Some (executables_rules exes ~dir ~all_modules:(Lazy.force all_modules)) + | _ -> None) |> merge_dot_merlin ~dir:ctx_dir let () = List.iter P.stanzas ~f:rules