]> matita.cs.unibo.it Git - helm.git/blob - helm/software/matita/matitadep.ml
514147bd17cb502a1421b966e76eb7731456b382
[helm.git] / helm / software / matita / matitadep.ml
1 (* Copyright (C) 2005, HELM Team.
2  * 
3  * This file is part of HELM, an Hypertextual, Electronic
4  * Library of Mathematics, developed at the Computer Science
5  * Department, University of Bologna, Italy.
6  * 
7  * HELM is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  * 
12  * HELM is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with HELM; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20  * MA  02111-1307, USA.
21  * 
22  * For details, see the HELM World-Wide-Web page,
23  * http://helm.cs.unibo.it/
24  *)
25
26 (* $Id$ *)
27
28 module S = Set.Make (String)
29
30 module GA = GrafiteAst 
31 module U = UriManager
32 module HR = Helm_registry
33
34 let print_times msg = 
35    let times = Unix.times () in
36    let stamp = times.Unix.tms_utime +. times.Unix.tms_utime in
37    Printf.printf "TIME STAMP: %s: %f\n" msg stamp; flush stdout; stamp
38
39 let fix_name f =
40    let f = 
41       if Pcre.pmatch ~pat:"^\\./" f then String.sub f 2 (String.length f - 2)
42       else f
43    in 
44    HExtlib.normalize_path f
45
46 (* FG: old function left for reference *)
47 let exclude excluded_files files =
48    let map file = not (List.mem (fix_name file) excluded_files) in
49    List.filter map files
50
51 let generate_theory theory_file deps =
52    let map (files, deps) (t, d) =
53       if t = theory_file then files, deps else
54       S.add t files, List.fold_left (fun deps dep -> S.add dep deps) deps d
55    in
56    let out_include och dep = 
57       Printf.fprintf och "include \"%s\".\n\n" dep  
58    in
59    let fileset, depset = List.fold_left map (S.empty, S.empty) deps in
60    let top_depset = S.diff fileset depset in
61    let och = open_out theory_file in
62    MatitaMisc.out_preamble och;
63    S.iter (out_include och) top_depset; 
64    close_out och;
65    (theory_file, S.elements top_depset) :: deps
66
67 let main () =
68 (*  let _ = print_times "inizio" in *)
69   let include_paths = ref [] in
70   let use_stdout = ref false in
71   let theory_file = ref "theory.ma" in
72   (* all are maps from "file" to "something" *)
73   let include_deps = Hashtbl.create 13 in
74   let baseuri_of = Hashtbl.create 13 in
75   let baseuri_of_inv = Hashtbl.create 13 in
76   let dot_name = "depends" in 
77   let dot_file = ref "" in
78   let set_dot_file () = dot_file := dot_name^".dot" in
79   let set_theory_file s = theory_file := s ^ ".ma" in
80   (* helpers *)
81   let rec baseuri_of_script s = 
82      try Hashtbl.find baseuri_of s 
83      with Not_found -> 
84        let _,b,_,_ =  
85          Librarian.baseuri_of_script ~include_paths:!include_paths s 
86        in
87        Hashtbl.add baseuri_of s b; 
88        Hashtbl.add baseuri_of_inv b s; 
89        let _ =
90           if Filename.check_suffix s ".mma" then
91              let generated = Filename.chop_suffix s ".mma" ^ ".ma" in
92              ignore (baseuri_of_script generated)
93        in
94        b
95   in
96   let script_of_baseuri ma b =
97     try Some (Hashtbl.find baseuri_of_inv b)
98     with Not_found -> 
99       HLog.error ("Skipping dependency of '"^ma^"' over '"^b^"'");
100       HLog.error ("Please include the file defining such baseuri, or fix");
101       HLog.error ("possibly incorrect verbatim URIs in the .ma file.");
102       None
103   in
104   let buri alias = U.buri_of_uri (U.uri_of_string alias) in
105   let resolve alias current_buri =
106     let buri = buri alias in
107     if buri <> current_buri then Some buri else None 
108   in
109   (* initialization *)
110   MatitaInit.add_cmdline_spec 
111     ["-dot", Arg.Unit set_dot_file,
112         "Save dependency graph in dot format and generate a png";
113      "-stdout", Arg.Set use_stdout,
114         "Print dependences on stdout";
115      "-theory", Arg.String set_theory_file,
116         "Set the name of the theory file (it includes all other files)"
117     ];
118   MatitaInit.parse_cmdline_and_configuration_file ();
119   MatitaInit.initialize_environment ();
120   if not (Helm_registry.get_bool "matita.verbose") then MatitaMisc.shutup ();
121   let cmdline_args = HR.get_list HR.string "matita.args" in
122   let test x =
123      Filename.check_suffix x ".ma" || Filename.check_suffix x ".mma"
124   in
125   let files = fun () -> match cmdline_args with
126      | [] -> HExtlib.find ~test "."
127      | _  -> cmdline_args
128   in
129   let args = 
130       let roots = Librarian.find_roots_in_dir (Sys.getcwd ()) in
131       match roots with
132       | [] -> 
133          prerr_endline ("No roots found in " ^ Sys.getcwd ());
134          exit 1
135       | [x] -> 
136          Sys.chdir (Filename.dirname x);
137          let opts = Librarian.load_root_file "root" in
138          include_paths := 
139            (try Str.split (Str.regexp " ") (List.assoc "include_paths" opts)
140            with Not_found -> []) @ 
141            (HR.get_list HR.string "matita.includes");
142          files ()
143       | _ ->
144          let roots = List.map (HExtlib.chop_prefix (Sys.getcwd()^"/")) roots in
145          prerr_endline ("Too many roots found:\n\t"^String.concat "\n\t" roots);
146          prerr_endline ("\nEnter one of these directories and retry");
147          exit 1
148   in
149   let ma_files = args in
150   (* here we go *)
151   (* fills:
152               Hashtbl.add include_deps     ma_file ma_file
153               Hashtbl.add include_deps_dot ma_file baseuri
154   *)
155 (*  let _ = print_times "prima di iter1" in *)
156   List.iter (fun ma_file -> ignore (baseuri_of_script ma_file)) ma_files;
157 (*  let _ = print_times "in mezzo alle due iter" in *)
158   let map s _ l = s :: l in
159   let ma_files = Hashtbl.fold map baseuri_of [] in
160   List.iter
161    (fun ma_file -> 
162       let _ = if Filename.check_suffix ma_file ".mma" then
163          let generated = Filename.chop_suffix ma_file ".mma" ^ ".ma" in
164          Hashtbl.add include_deps generated ma_file;
165       in
166       let ma_baseuri = baseuri_of_script ma_file in
167       let dependencies = 
168          try DependenciesParser.deps_of_file ma_file
169          with Sys_error _ -> []
170       in
171       let handle_uri uri =
172          if not (Http_getter_storage.is_legacy uri) then
173          let dep = resolve uri ma_baseuri in
174          match dep with 
175             | None   -> ()
176             | Some u -> 
177                  match script_of_baseuri ma_file u with
178                       | Some d -> Hashtbl.add include_deps ma_file d
179                       | None   -> ()
180       in
181       let handle_script path =
182          ignore (baseuri_of_script path);
183          Hashtbl.add include_deps ma_file path
184       in
185       List.iter 
186        (function
187          | DependenciesParser.UriDep uri      ->
188             let uri = UriManager.string_of_uri uri in
189             handle_uri uri 
190          | DependenciesParser.InlineDep path  ->
191             if Librarian.is_uri path
192             then handle_uri path else handle_script path
193          | DependenciesParser.IncludeDep path ->
194             handle_script path) 
195        dependencies)
196    ma_files;
197   (* generate regular depend output *)
198 (*  let _ = print_times "dopo di iter2" in *)
199   let deps =
200     List.fold_left
201      (fun acc ma_file -> 
202       let deps = Hashtbl.find_all include_deps ma_file in
203       let deps = List.fast_sort Pervasives.compare deps in
204       let deps = HExtlib.list_uniq deps in
205       let deps = List.map fix_name deps in
206       (fix_name ma_file, deps) :: acc)
207      [] ma_files
208   in
209   let extern = 
210     List.fold_left
211       (fun acc (_,d) -> 
212         List.fold_left 
213           (fun a x -> 
214              if List.exists (fun (t,_) -> x=t) deps then a 
215              else x::a) 
216           acc d)
217       [] deps
218   in
219   let where = if !use_stdout then None else Some (Sys.getcwd()) in
220   let all_deps = 
221      deps @ 
222      HExtlib.list_uniq (List.sort Pervasives.compare (List.map (fun x -> x,[]) extern))
223   in  
224   (* theory generation *)
225   let all_deps_and_theory = generate_theory !theory_file all_deps in 
226   (* matita depend file generation *)
227   Librarian.write_deps_file where all_deps_and_theory;
228   (* dot generation *)
229   if !dot_file <> "" then
230     begin
231       let oc = open_out !dot_file in
232       let fmt = Format.formatter_of_out_channel oc in 
233       GraphvizPp.Dot.header fmt;
234       List.iter
235        (fun (ma_file,deps) -> 
236         GraphvizPp.Dot.node ma_file fmt;
237         List.iter (fun dep -> GraphvizPp.Dot.edge ma_file dep fmt) deps)
238        deps;
239       List.iter 
240         (fun x -> GraphvizPp.Dot.node ~attrs:["style","dashed"] x fmt) 
241         extern; 
242       GraphvizPp.Dot.trailer fmt;
243       close_out oc;
244       ignore(Sys.command ("tred "^ !dot_file^"| dot -Tpng -o"^dot_name^".png"));
245       HLog.message ("Type 'eog "^dot_name^".png' to view the graph"); 
246     end;
247 (*    let _ = print_times "fine" in () *)