diff --git a/doc/manual.org b/doc/manual.org index 4000b29c..f4053cf5 100644 --- a/doc/manual.org +++ b/doc/manual.org @@ -166,8 +166,12 @@ anyway. *** Odig conventions Jbuilder follows the [[http://erratique.ch/software/odig][odig]] conventions and automatically installs any -README*, CHANGE* and LICENSE* files in the same directory as the -=.opam= file to a location where odig will find them. +README*, CHANGE*, HISTORY* and LICENSE* files in the same directory as +the =.opam= file to a location where odig will find them. + +Note that this include files present in the source tree as well as +generated files. So for instance a changelog generated by a rule will +be automatically installed as well. ** jbuild diff --git a/src/build_interpret.ml b/src/build_interpret.ml new file mode 100644 index 00000000..cf7e10c8 --- /dev/null +++ b/src/build_interpret.ml @@ -0,0 +1,94 @@ +open Import +open Build.Repr + +module Pset = Path.Set +module Pmap = Path.Map +module Vspec = Build.Vspec + +module Target = struct + type t = + | Normal of Path.t + | Vfile : _ Vspec.t -> t + + let path = function + | Normal p -> p + | Vfile (Vspec.T (p, _)) -> p + + let paths ts = + List.fold_left ts ~init:Pset.empty ~f:(fun acc t -> + Pset.add (path t) acc) +end + +let deps t ~all_targets_by_dir = + let rec loop : type a b. (a, b) t -> Pset.t -> Pset.t = fun t acc -> + match t with + | Arr _ -> acc + | Prim _ -> acc + | Store_vfile _ -> acc + | Compose (a, b) -> loop a (loop b acc) + | First t -> loop t acc + | Second t -> loop t acc + | Split (a, b) -> loop a (loop b acc) + | Fanout (a, b) -> loop a (loop b acc) + | Paths fns -> Pset.union fns acc + | Vpath (Vspec.T (fn, _)) -> Pset.add fn acc + | Paths_glob (dir, re) -> begin + match Pmap.find dir (Lazy.force all_targets_by_dir) with + | None -> Pset.empty + | Some targets -> + Pset.filter targets ~f:(fun path -> + Re.execp re (Path.basename path)) + end + | Dyn_paths t -> loop t acc + | Record_lib_deps _ -> acc + | Fail _ -> acc + in + loop (Build.repr t) Pset.empty + +let lib_deps = + let rec loop : type a b. (a, b) t -> Build.lib_deps Pmap.t -> Build.lib_deps Pmap.t + = fun t acc -> + match t with + | Arr _ -> acc + | Prim _ -> acc + | Store_vfile _ -> acc + | Compose (a, b) -> loop a (loop b acc) + | First t -> loop t acc + | Second t -> loop t acc + | Split (a, b) -> loop a (loop b acc) + | Fanout (a, b) -> loop a (loop b acc) + | Paths _ -> acc + | Vpath _ -> acc + | Paths_glob _ -> acc + | Dyn_paths t -> loop t acc + | Record_lib_deps (dir, deps) -> + let data = + match Pmap.find dir acc with + | None -> deps + | Some others -> Build.merge_lib_deps deps others + in + Pmap.add acc ~key:dir ~data + | Fail _ -> acc + in + fun t -> loop (Build.repr t) Pmap.empty + +let targets = + let rec loop : type a b. (a, b) t -> Target.t list -> Target.t list = fun t acc -> + match t with + | Arr _ -> acc + | Prim { targets; _ } -> + List.fold_left targets ~init:acc ~f:(fun acc fn -> Target.Normal fn :: acc) + | Store_vfile spec -> Vfile spec :: acc + | Compose (a, b) -> loop a (loop b acc) + | First t -> loop t acc + | Second t -> loop t acc + | Split (a, b) -> loop a (loop b acc) + | Fanout (a, b) -> loop a (loop b acc) + | Paths _ -> acc + | Vpath _ -> acc + | Paths_glob _ -> acc + | Dyn_paths t -> loop t acc + | Record_lib_deps _ -> acc + | Fail _ -> acc + in + fun t -> loop (Build.repr t) [] diff --git a/src/build_interpret.mli b/src/build_interpret.mli new file mode 100644 index 00000000..c4805eee --- /dev/null +++ b/src/build_interpret.mli @@ -0,0 +1,23 @@ +open Import + +module Target : sig + type t = + | Normal of Path.t + | Vfile : _ Build.Vspec.t -> t + + val path : t -> Path.t + val paths : t list -> Path.Set.t +end + +val deps + : (_, _) Build.t + -> all_targets_by_dir:Path.Set.t Path.Map.t Lazy.t + -> Path.Set.t + +val lib_deps + : (_, _) Build.t + -> Build.lib_deps Path.Map.t + +val targets + : (_, _) Build.t + -> Target.t list diff --git a/src/build_system.ml b/src/build_system.ml index b005098e..b44871ed 100644 --- a/src/build_system.ml +++ b/src/build_system.ml @@ -130,19 +130,7 @@ let wait_for_file t fn ~targeting = (String.concat ~sep:"\n--> " (List.map loop ~f:Path.to_string)) -module Target = struct - type t = - | Normal of Path.t - | Vfile : _ Vspec.t -> t - - let path = function - | Normal p -> p - | Vfile (Vspec.T (p, _)) -> p - - let paths ts = - List.fold_left ts ~init:Pset.empty ~f:(fun acc t -> - Pset.add (path t) acc) -end +module Target = Build_interpret.Target let get_file : type a. t -> Path.t -> a File_kind.t -> a File_spec.t = fun t fn kind -> match Hashtbl.find t.files fn with @@ -154,82 +142,8 @@ let get_file : type a. t -> Path.t -> a File_kind.t -> a File_spec.t = fun t fn let save_vfile (type a) (module K : Vfile_kind.S with type t = a) fn x = K.save x ~filename:(Path.to_string fn) -module Build_interpret = struct - include Build.Repr - - let deps t ~all_targets_by_dir = - let rec loop : type a b. (a, b) t -> Pset.t -> Pset.t = fun t acc -> - match t with - | Arr _ -> acc - | Prim _ -> acc - | Store_vfile _ -> acc - | Compose (a, b) -> loop a (loop b acc) - | First t -> loop t acc - | Second t -> loop t acc - | Split (a, b) -> loop a (loop b acc) - | Fanout (a, b) -> loop a (loop b acc) - | Paths fns -> Pset.union fns acc - | Vpath (Vspec.T (fn, _)) -> Pset.add fn acc - | Paths_glob (dir, re) -> begin - match Pmap.find dir (Lazy.force all_targets_by_dir) with - | None -> Pset.empty - | Some targets -> - Pset.filter targets ~f:(fun path -> - Re.execp re (Path.basename path)) - end - | Dyn_paths t -> loop t acc - | Record_lib_deps _ -> acc - | Fail _ -> acc - in - loop t Pset.empty - - let lib_deps = - let rec loop : type a b. (a, b) t -> Build.lib_deps Pmap.t -> Build.lib_deps Pmap.t - = fun t acc -> - match t with - | Arr _ -> acc - | Prim _ -> acc - | Store_vfile _ -> acc - | Compose (a, b) -> loop a (loop b acc) - | First t -> loop t acc - | Second t -> loop t acc - | Split (a, b) -> loop a (loop b acc) - | Fanout (a, b) -> loop a (loop b acc) - | Paths _ -> acc - | Vpath _ -> acc - | Paths_glob _ -> acc - | Dyn_paths t -> loop t acc - | Record_lib_deps (dir, deps) -> - let data = - match Pmap.find dir acc with - | None -> deps - | Some others -> Build.merge_lib_deps deps others - in - Pmap.add acc ~key:dir ~data - | Fail _ -> acc - in - fun t -> loop t Pmap.empty - - let targets = - let rec loop : type a b. (a, b) t -> Target.t list -> Target.t list = fun t acc -> - match t with - | Arr _ -> acc - | Prim { targets; _ } -> - List.fold_left targets ~init:acc ~f:(fun acc fn -> Target.Normal fn :: acc) - | Store_vfile spec -> Vfile spec :: acc - | Compose (a, b) -> loop a (loop b acc) - | First t -> loop t acc - | Second t -> loop t acc - | Split (a, b) -> loop a (loop b acc) - | Fanout (a, b) -> loop a (loop b acc) - | Paths _ -> acc - | Vpath _ -> acc - | Paths_glob _ -> acc - | Dyn_paths t -> loop t acc - | Record_lib_deps _ -> acc - | Fail _ -> acc - in - fun t -> loop t [] +module Build_exec = struct + open Build.Repr let exec bs t x ~targeting = let rec exec @@ -271,7 +185,7 @@ module Build_interpret = struct | Record_lib_deps _ -> return x | Fail { fail } -> fail () in - exec t x + exec (Build.repr t) x end let add_spec t fn spec ~allow_override = @@ -288,12 +202,11 @@ let create_file_specs t targets rule ~allow_override = module Pre_rule = struct type t = - { build : (unit, unit) Build.Repr.t + { build : (unit, unit) Build.t ; targets : Target.t list } let make build = - let build = Build.repr build in { build ; targets = Build_interpret.targets build } @@ -335,7 +248,7 @@ let compile_rule t ~all_targets_by_dir ?(allow_override=false) pre_rule = all_unit (Pset.fold deps ~init:[] ~f:(fun fn acc -> wait_for_file t fn ~targeting :: acc)) >>= fun () -> - Build_interpret.exec t build () ~targeting + Build_exec.exec t build () ~targeting ) in let rule = { Rule. diff --git a/src/gen_rules.ml b/src/gen_rules.ml index 8ec31393..d936c680 100644 --- a/src/gen_rules.ml +++ b/src/gen_rules.ml @@ -1466,6 +1466,19 @@ module Gen(P : Params) = struct | Installation | +-----------------------------------------------------------------+ *) + let known_targets_by_dir_so_far = + List.fold_left !all_rules ~init:Path.Map.empty ~f:(fun acc rule -> + List.fold_left (Build_interpret.targets rule) ~init:acc ~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)) + let lib_install_files ~dir (lib : Library.t) = let byte = List.mem Mode.Byte ~set:lib.modes in let native = List.mem Mode.Native ~set:lib.modes in @@ -1526,8 +1539,9 @@ module Gen(P : Params) = struct ]) |> List.map ~f:(Install.Entry.make Lib) - let odig_doc_file_re = - Re.(compile (alt [str "README"; str "LICENSE"; str "CHANGE"; str "HISTORY"])) + let is_odig_doc_file fn = + List.exists [ "README"; "LICENSE"; "CHANGE"; "HISTORY"] + ~f:(fun prefix -> String.is_prefix fn ~prefix) let install_file package = let entries = @@ -1550,9 +1564,14 @@ module Gen(P : Params) = struct in let entries = let root_listing = File_tree.Dir.files (File_tree.root P.file_tree) in - String_set.fold root_listing ~init:entries ~f:(fun fn acc -> - if Re.execp odig_doc_file_re fn then - Install.Entry.make Doc (Path.relative Path.root fn) :: acc + let root_targets = + match Path.Map.find ctx.build_dir known_targets_by_dir_so_far with + | None -> root_listing + | Some set -> String_set.union root_listing set + in + String_set.fold root_targets ~init:entries ~f:(fun fn acc -> + if is_odig_doc_file fn then + Install.Entry.make Doc (Path.relative ctx.build_dir fn) :: acc else acc) in