1 exception NoRootFor of string
5 if String.length path > 0 && path.[0] <> '/' then
6 Sys.getcwd () ^ "/" ^ path
10 HExtlib.normalize_path path
15 let path = absolutize path in
16 let paths = List.rev (Str.split (Str.regexp "/") path) in
17 let rec build = function
18 | he::tl as l -> ("/" ^ String.concat "/" (List.rev l) ^ "/") :: build tl
21 let paths = List.map HExtlib.normalize_path (build paths) in
22 try HExtlib.find_in paths "root"
23 with Failure "find_in" ->
24 raise (NoRootFor (path ^ " (" ^ String.concat ", " paths ^ ")"))
27 let ensure_trailing_slash s =
28 if s = "" then "/" else
29 if s.[String.length s-1] <> '/' then s^"/" else s
32 let remove_trailing_slash s =
33 if s = "" then "" else
34 let len = String.length s in
35 if s.[len-1] = '/' then String.sub s 0 (len-1) else s
38 let load_root_file rootpath =
39 let data = HExtlib.input_file rootpath in
40 let lines = Str.split (Str.regexp "\n") data in
41 let clean s = Pcre.replace ~pat:"^ *" (Pcre.replace ~pat:" *$" s) in
44 match Str.split (Str.regexp "=") l with
45 | [k;v] -> clean k, Http_getter_misc.strip_trailing_slash (clean v)
46 | _ -> raise (Failure ("Malformed root file: " ^ rootpath)))
50 let find_root_for ~include_paths file =
51 let include_paths = "" :: Sys.getcwd () :: include_paths in
53 let path = HExtlib.find_in include_paths file in
54 let path = absolutize path in
55 (* HLog.debug ("file "^file^" resolved as "^path); *)
56 let rootpath, root, buri =
58 let mburi = Helm_registry.get "matita.baseuri" in
59 match Str.split (Str.regexp " ") mburi with
60 | [root; buri] when HExtlib.is_prefix_of root path ->
61 ":registry:", root, buri
62 | _ -> raise (Helm_registry.Key_not_found "matita.baseuri")
63 with Helm_registry.Key_not_found "matita.baseuri" ->
64 let rootpath = find_root path in
65 let buri = List.assoc "baseuri" (load_root_file rootpath) in
66 rootpath, Filename.dirname rootpath, buri
68 (* HLog.debug ("file "^file^" rooted by "^rootpath^""); *)
69 let uri = Http_getter_misc.strip_trailing_slash buri in
70 if String.length uri < 5 || String.sub uri 0 5 <> "cic:/" then
71 HLog.error (rootpath ^ " sets an incorrect baseuri: " ^ buri);
72 ensure_trailing_slash root, remove_trailing_slash uri, path
73 with Failure "find_in" ->
74 HLog.error ("We are in: " ^ Sys.getcwd ());
75 HLog.error ("Unable to find: "^file^"\nPaths explored:");
76 List.iter (fun x -> HLog.error (" - "^x)) include_paths;
77 raise (NoRootFor file)
80 let baseuri_of_script ~include_paths file =
81 let root, buri, path = find_root_for ~include_paths file in
82 let path = HExtlib.normalize_path path in
83 let root = HExtlib.normalize_path root in
84 let lpath = Str.split (Str.regexp "/") path in
85 let lroot = Str.split (Str.regexp "/") root in
86 let rec substract l1 l2 =
88 | h1::tl1,h2::tl2 when h1 = h2 -> substract tl1 tl2
90 | _ -> raise (NoRootFor (file ^" "^path^" "^root))
92 let extra_buri = substract lpath lroot in
94 assert(Filename.check_suffix name ".ma");
95 try Filename.chop_extension name
96 with Invalid_argument "Filename.chop_extension" -> name
98 let extra = String.concat "/" extra_buri in
100 remove_trailing_slash (HExtlib.normalize_path
101 (buri ^ "/" ^ chop extra)),
106 let find_roots_in_dir dir =
107 HExtlib.find ~test:(fun f ->
108 Filename.basename f = "root" &&
109 try (Unix.stat f).Unix.st_kind = Unix.S_REG
110 with Unix.Unix_error _ -> false)
115 let load_deps_file f =
117 let ic = open_in f in
121 let l = input_line ic in
122 match Str.split (Str.regexp " ") l with
124 HLog.error ("Malformed deps file: " ^ f);
125 raise (Failure ("Malformed deps file: " ^ f))
126 | he::tl -> deps := (he,tl) :: !deps
129 with End_of_file -> !deps
132 type options = (string * string) list
138 val load_deps_file: string -> (source_object * source_object list) list
139 val target_of: options -> source_object -> target_object
140 val string_of_source_object: source_object -> string
141 val string_of_target_object: target_object -> string
142 val build: options -> source_object -> bool
143 val root_of: options -> source_object -> string option
144 val mtime_of_source_object: source_object -> float option
145 val mtime_of_target_object: target_object -> float option
148 module Make = functor (F:Format) -> struct
150 let prerr_endline _ = ();;
152 let younger_s_t a b =
153 match F.mtime_of_source_object a, F.mtime_of_target_object b with
154 | Some a, Some b -> a < b
155 | _ -> false (* XXX check if correct *)
157 let younger_t_t a b =
158 match F.mtime_of_target_object a, F.mtime_of_target_object b with
159 | Some a, Some b -> a < b
160 | _ -> false (* XXX check if correct *)
163 let is_built opts t = younger_s_t t (F.target_of opts t);;
165 let rec needs_build opts deps compiled (t,dependencies) =
166 prerr_endline ("Checking if "^F.string_of_source_object t^" needs to be built");
167 if List.mem t compiled then
168 (prerr_endline "already compiled";
171 if not (is_built opts t) then
172 (prerr_endline (F.string_of_source_object t^
173 " is not built, thus needs to be built");
179 (needs_build opts deps compiled)
180 (List.map (fun x -> x, List.assoc x deps) dependencies)
183 (F.string_of_source_object t^" depends on "^F.string_of_source_object (fst unsat)^
184 " that needs to be built, thus needs to be built");
189 List.find (younger_t_t (F.target_of opts t))
190 (List.map (F.target_of opts) dependencies)
193 (F.string_of_source_object t^" depends on "^F.string_of_target_object
194 unsat^" and "^F.string_of_source_object t^".o is younger than "^
195 F.string_of_target_object unsat^", thus needs to be built");
197 with Not_found -> false
200 let is_buildable opts compiled deps (t,dependencies) =
201 prerr_endline ("Checking if "^F.string_of_source_object t^" is buildable");
202 let b = needs_build opts deps compiled (t,dependencies) in
204 (prerr_endline (F.string_of_source_object t^
205 " does not need to be built, thus it not buildable");
210 List.find (needs_build opts deps compiled)
211 (List.map (fun x -> x, List.assoc x deps) dependencies)
214 (F.string_of_source_object t^" depends on "^
215 F.string_of_source_object (fst unsat)^
216 " that needs build, thus is not buildable");
220 ("None of "^F.string_of_source_object t^
221 " dependencies needs to be built, thus it is buildable");
225 let rec purge_unwanted_roots wanted deps =
229 not (List.exists (fun (_,d1) -> List.mem t d1) deps))
232 let newroots = List.filter (fun (t,_) -> List.mem t wanted) roots in
233 if newroots = roots then
236 purge_unwanted_roots wanted (newroots @ rest)
240 let rec make_aux root local_options compiled failed deps =
241 let todo = List.filter (is_buildable local_options compiled deps) deps in
242 let todo = List.filter (fun (f,_) -> not (List.mem f failed)) todo in
244 let compiled, failed =
249 d<>[] || F.root_of local_options file = Some root)
255 (fun (c,f) (file,_) ->
256 let froot = F.root_of local_options file in
259 | Some froot when froot = root ->
260 F.build local_options file
264 HLog.error ("No root for: "^F.string_of_source_object file);
267 if rc then (file::c,f)
269 (compiled,failed) todo
271 make_aux root local_options compiled failed deps
275 and make root targets =
276 let deps = F.load_deps_file (root^"/depends") in
277 let local_options = load_root_file (root^"/root") in
278 HLog.debug ("Entering directory '"^root^"'");
279 let old_root = Sys.getcwd () in
281 let _compiled, failed =
283 make_aux root local_options [] [] deps
285 make_aux root local_options [] [] (purge_unwanted_roots targets deps)
287 HLog.debug ("Leaving directory '"^root^"'");
294 let write_deps_file root deps =
295 let oc = open_out (root ^ "/depends") in
297 (fun (t,d) -> output_string oc (t^" "^String.concat " " d^"\n"))
300 HLog.message ("Generated: " ^ root ^ "/depends")