aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools/coqdep.ml
diff options
context:
space:
mode:
authorGravatar Pierre-Marie Pédrot <pierre-marie.pedrot@inria.fr>2014-01-06 19:16:31 +0100
committerGravatar Pierre-Marie Pédrot <pierre-marie.pedrot@inria.fr>2014-01-06 20:37:13 +0100
commit093529c6d4f8eba7370c30b97d8d648340039374 (patch)
treec592d82a5867ee524eebdc1266b0eefa3a11a8ed /tools/coqdep.ml
parent27d9da372a1c407221e687d9fb0d08fc6fca805f (diff)
Adding a -dumpgraph option to Coqdep that output the graph dependency of the
considered files. Original patch by Guillaume Allais.
Diffstat (limited to 'tools/coqdep.ml')
-rw-r--r--tools/coqdep.ml153
1 files changed, 151 insertions, 2 deletions
diff --git a/tools/coqdep.ml b/tools/coqdep.ml
index 8a514f7f4..578f47336 100644
--- a/tools/coqdep.ml
+++ b/tools/coqdep.ml
@@ -19,6 +19,7 @@ open Coqdep_common
let option_D = ref false
let option_w = ref false
let option_sort = ref false
+let option_dump = ref None
let warning_mult suf iter =
let tab = Hashtbl.create 151 in
@@ -156,11 +157,150 @@ let declare_dependencies () =
flush stdout)
(List.rev !vAccu)
+module Graph =
+struct
+(** Dumping a dependency graph **)
+
+(** TODO: we should share this code with Coqdep_common *)
+let treat_coq_file chan =
+ let buf = Lexing.from_channel chan in
+ let deja_vu_v = ref ([]: string list list)
+ and deja_vu_ml = ref ([] : string list) in
+ let mark_v_done acc str =
+ let seen = List.mem str !deja_vu_v in
+ if not seen then
+ let () = addQueue deja_vu_v str in
+ try
+ let file_str = Hashtbl.find vKnown str in
+ (canonize file_str, !suffixe) :: acc
+ with Not_found -> acc
+ else acc
+ in
+ let rec loop acc =
+ let token = try Some (coq_action buf) with Fin_fichier -> None in
+ match token with
+ | None -> acc
+ | Some action ->
+ let acc = match action with
+ | Require strl ->
+ List.fold_left mark_v_done acc strl
+ | RequireString s ->
+ let str = Filename.basename s in
+ mark_v_done acc [str]
+ | Declare sl ->
+ let declare suff dir s =
+ let base = file_name s dir in
+ let opt = if !option_natdynlk then " " ^ base ^ ".cmxs" else "" in
+ (escape base, suff ^ opt)
+ in
+ let decl acc str =
+ let s = basename_noext str in
+ if not (List.mem s !deja_vu_ml) then
+ let () = addQueue deja_vu_ml s in
+ match search_mllib_known s with
+ | Some mldir -> (declare ".cma" mldir s) :: acc
+ | None ->
+ match search_ml_known s with
+ | Some mldir -> (declare ".cmo" mldir s) :: acc
+ | None -> acc
+ else acc
+ in
+ List.fold_left decl acc sl
+ | Load str ->
+ let str = Filename.basename str in
+ let seen = List.mem [str] !deja_vu_v in
+ if not seen then
+ let () = addQueue deja_vu_v [str] in
+ try
+ let file_str = Hashtbl.find vKnown [str] in
+ (canonize file_str, ".v") :: acc
+ with Not_found -> acc
+ else acc
+ | AddLoadPath _ | AddRecLoadPath _ -> acc (** TODO *)
+ in
+ loop acc
+ in
+ loop []
+
+let treat_coq_file f =
+ let chan = try Some (open_in f) with Sys_error _ -> None in
+ match chan with
+ | None -> []
+ | Some chan ->
+ try
+ let ans = treat_coq_file chan in
+ let () = close_in chan in
+ ans
+ with Syntax_error (i, j) -> close_in chan; error_cannot_parse f (i, j)
+
+type graph =
+ | Element of string
+ | Subgraph of string * graph list
+
+let rec insert_graph name path graphs = match path, graphs with
+ | [] , graphs -> (Element name) :: graphs
+ | (box :: boxes), (Subgraph (hd, names)) :: tl when hd = box ->
+ Subgraph (hd, insert_graph name boxes names) :: tl
+ | _, hd :: tl -> hd :: (insert_graph name path tl)
+ | (box :: boxes), [] -> [ Subgraph (box, insert_graph name boxes []) ]
+
+let print_graphs chan graph =
+ let rec print_aux name = function
+ | [] -> name
+ | (Element str) :: tl -> fprintf chan "%s\n" str; print_aux name tl
+ | Subgraph (box, names) :: tl ->
+ fprintf chan "subgraph cluster%n {\n label=\"%s\"" name box;
+ let name = print_aux (name + 1) names in
+ fprintf chan "}\n"; print_aux name tl
+ in
+ ignore (print_aux 0 graph)
+
+let rec pop_common_prefix = function
+ | [Subgraph (_, graphs)] -> pop_common_prefix graphs
+ | graphs -> graphs
+
+let split_path = Str.split (Str.regexp "/")
+
+let rec pop_last = function
+ | [] -> []
+ | [ x ] -> []
+ | x :: xs -> x :: pop_last xs
+
+let get_boxes path = pop_last (split_path path)
+
+let insert_raw_graph file =
+ insert_graph (basename_noext file) (get_boxes file)
+
+let rec get_dependencies name args =
+ let ename = basename_noext name in
+ let vdep = treat_coq_file (name ^ ".v") in
+ List.fold_left
+ (fun (deps, graphs, alseen) (dep, _) ->
+ if not (List.mem dep alseen)
+ then get_dependencies dep ((ename, dep) :: deps, insert_raw_graph dep graphs, dep :: alseen)
+ else ((ename, dep) :: deps, graphs, alseen))
+ args vdep
+
+let coq_dependencies_dump chan dumpboxes =
+ let (deps, graphs, _) =
+ List.fold_left (fun ih (name, _) -> get_dependencies name ih)
+ ([], List.fold_left (fun ih (file, _) -> insert_raw_graph file ih) [] !vAccu,
+ List.map fst !vAccu) !vAccu
+ in
+ fprintf chan "digraph dependencies {\n"; flush chan;
+ if dumpboxes then print_graphs chan (pop_common_prefix graphs)
+ else List.iter (fun (name, _) -> fprintf chan "%s\n" (basename_noext name)) !vAccu;
+ List.iter (fun (name, dep) -> fprintf chan "%s -> %s\n" (basename_noext dep) name) deps;
+ fprintf chan "}\n"
+
+end
+
let usage () =
eprintf " usage: coqdep [-w] [-c] [-D] [-I dir] [-R dir coqdir] <filename>+\n";
eprintf " extra options:\n";
eprintf " -coqlib dir : set the coq standard library directory\n";
- eprintf " -exclude-dir f : skip subdirectories named f during -R search\n";
+ eprintf " -exclude-dir f : skip subdirectories named 'f' during -R search\n";
+ eprintf " -dumpgraph f : print a dot dependency graph in file 'f'\n";
exit 1
let rec parse = function
@@ -178,6 +318,8 @@ let rec parse = function
| "-R" :: r :: "-as" :: [] -> usage ()
| "-R" :: r :: ln :: ll -> add_rec_dir add_known r [ln]; parse ll
| "-R" :: ([] | [_]) -> usage ()
+ | "-dumpgraph" :: f :: ll -> option_dump := Some (false, f); parse ll
+ | "-dumpgraphbox" :: f :: ll -> option_dump := Some (true, f); parse ll
| "-exclude-dir" :: r :: ll -> norec_dirnames := r::!norec_dirnames; parse ll
| "-exclude-dir" :: [] -> usage ()
| "-coqlib" :: r :: ll -> Flags.coqlib_spec := true; Flags.coqlib := r; parse ll
@@ -218,6 +360,13 @@ let coqdep () =
if !option_sort then begin sort (); exit 0 end;
if !option_c && not !option_D then mL_dependencies ();
if not !option_D then coq_dependencies ();
- if !option_w || !option_D then declare_dependencies ()
+ if !option_w || !option_D then declare_dependencies ();
+ begin match !option_dump with
+ | None -> ()
+ | Some (box, file) ->
+ let chan = open_out file in
+ try Graph.coq_dependencies_dump chan box; close_out chan
+ with e -> close_out chan; raise e
+ end
let _ = Printexc.catch coqdep ()