1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
|
(* *********************************************************************)
(* *)
(* The Compcert verified compiler *)
(* *)
(* Bernhard Schommer, AbstInt Angewandte Informatik GmbH *)
(* *)
(* Copyright AbstInt Angewandte Informatik GmbH. All rights reserved. *)
(* This file is distributed under the terms of the GNU General Public *)
(* License as published by the Free Software Foundation, either *)
(* version 2 of the License, or (at your option) any later version. *)
(* *)
(* *********************************************************************)
(* Generate dependencies for directories by calling dependencie tool *)
open Set
module StringSet = Make(String)
(* The tools *)
let ocamlfind = ref "ocamlfind"
let ocamldep = ref "ocamldep"
let menhir = ref "menhir"
(* Some controling options *)
let use_ocamlfind = ref false
let use_menhir = ref false
let dirs_to_search = ref ([] : string list)
let target_file = ref (None: string option)
let error_occured = ref false
(* Options for ocamldep *)
let include_dirs = ref (StringSet.empty)
let ml_synonyms = ref [".ml"]
let mli_synonyms = ref [".mli"]
let slash = ref false
let native_only = ref false
let raw_dependencies = ref false
let pp_command = ref (None: string option)
let ppx_command = ref ([] : string list)
let all_dependencies = ref false
let open_modules = ref ([] : string list)
let one_line = ref false
let ocamlfind_package = ref ""
let ocamlfind_syntax = ref ""
let ocamlfind_ppopt = ref ([] : string list)
(* Helper functions for options *)
let add_to_list li s =
li := s :: !li
let add_to_set set s =
set := StringSet.add s !set
let add_to_synonym_list synonyms suffix =
if (String.length suffix) > 1 && (String.get suffix 0) = '.' then
add_to_list synonyms suffix
else
Printf.eprintf "Bad file suffix '%s'.\n" suffix
let usage = "Usage: recdepend [options] <directories>\nOptions are:"
type file_type =
| ML
| MLL
(* Concats dir and name except for the case when dir is . or equivalent *)
let (^) dir name =
if dir = Filename.current_dir_name then
name
else
Filename.concat dir name
let get_files () =
let rec files_of_dir acc dir =
let files = Sys.readdir dir in
let contains_files = ref false in
let acc = Array.fold_left (fun acc f_name ->
if Sys.is_directory (dir ^ f_name) then
files_of_dir acc (dir ^ f_name)
else
if List.exists (Filename.check_suffix f_name) (!ml_synonyms@ !mli_synonyms) then
begin
contains_files := true;
(ML,(dir ^ f_name))::acc
end
else if !use_menhir && (Filename.check_suffix f_name ".mll") then
begin
contains_files := true;
(MLL,(dir ^ f_name))::acc
end
else
acc) acc files in
if !contains_files && dir <> Filename.current_dir_name then
add_to_set include_dirs dir;
acc in
try
List.fold_left files_of_dir [] !dirs_to_search
with _ ->
error_occured := true;
[]
let translate_arg_list acc name args =
List.fold_left (fun args s -> name::(s::args)) acc args
let compute_dependencies files =
try let out_file = match !target_file with
| None -> Unix.stdout
| Some s -> Unix.openfile s [Unix.O_WRONLY; Unix.O_CREAT; Unix.O_TRUNC] 0o666 in
let call_process args =
let argv = Array.of_list args in
let pid = Unix.create_process argv.(0) argv Unix.stdin out_file Unix.stderr in
let (_,status) =
Unix.waitpid [] pid in
let rc = (match status with
| Unix.WEXITED rc -> rc
| Unix.WSIGNALED _
| Unix.WSTOPPED _ -> -1) in
error_occured := !error_occured || rc <> 0 in
let call_ocamldep file =
let args = StringSet.fold (fun s args -> "-I"::(s::args)) !include_dirs [file] in
let args = translate_arg_list args "-ml-synonym" (List.filter ((<>) ".ml") !ml_synonyms) in
let args = translate_arg_list args "-mli-synonym" (List.filter ((<>) ".mli") !mli_synonyms) in
let args = if !slash then "-slash"::args else args in
let args = if !native_only then "-native"::args else args in
let args = if !raw_dependencies then "-modules"::args else args in
let args = match !pp_command with
| None -> args
| Some s -> "-pp"::(s::args) in
let args = translate_arg_list args "-ppx" !ppx_command in
let args = if !all_dependencies then "-all"::args else args in
let args = translate_arg_list args "-open" !open_modules in
let args = if !one_line then "-one-line"::args else args in
let args = if !use_ocamlfind then
let args = if !ocamlfind_package <> "" then
"-package"::(!ocamlfind_package::args)
else
args in
let args = if !ocamlfind_syntax <> "" then
"-syntax"::(!ocamlfind_syntax::args)
else
args in
let args = translate_arg_list args "-ppopt" !ocamlfind_ppopt in
!ocamlfind::("ocamldep"::args)
else
!ocamldep :: args in
call_process args in
let call_menhir file =
let args = [!menhir;"--depend";"--ocamldep";!ocamldep] in
let args = if !raw_dependencies then args@["--raw-depend"] else args in
call_process args in
List.iter (fun (f_type,f_name) ->
match f_type with
| ML -> call_ocamldep f_name
| MLL -> if !use_menhir then call_menhir f_name) files;
if !target_file <> None then Unix.close out_file
with _ ->
error_occured := true
let _ =
Arg.parse [
"-all", Arg.Set all_dependencies,
" Generate dependencies on all files";
"-dep", Arg.Set_string ocamldep,
"<cmd> Use <cmd> instead of ocamldep";
"-I", Arg.String (add_to_set include_dirs),
"<dir> Add <dir> to the list of include directories";
"-menhir", Arg.String (fun s -> use_menhir:= true; menhir := s),
"<cmd> Use <cmd> instead of menhir";
"-ml-synonym", Arg.String (add_to_synonym_list ml_synonyms),
"<e> Consider <e> as synonym of the .ml extension";
"-mli-synonym", Arg.String (add_to_synonym_list mli_synonyms),
"<e> Consider <e> as synonym of the .mli extension";
"-modules", Arg.Set raw_dependencies,
" Print module dependencies in raw form";
"-native", Arg.Set native_only,
" Generate dependencies for native-code only";
"-o", Arg.String (fun s -> target_file := Some s),
"<f> Write the dependencies in file <f>";
"-ocamlfind", Arg.String (fun s -> use_ocamlfind := true; ocamlfind := s),
"<cmd> Use <cmd> instead of ocamlfind";
"-one-line", Arg.Set one_line,
" Output only ine line per file, regardless of length";
"-open", Arg.String (add_to_list open_modules),
"<module> Opens the module <module> before typing";
"-package", Arg.Set_string ocamlfind_package,
" <p> Pass the package option <p> to ocamlfind";
"-ppopt", Arg.String (add_to_list ocamlfind_ppopt),
" <p> Pass the camlp4 option <p> to ocamlfind";
"-pp", Arg.String (fun s -> pp_command := Some s),
"<cmd> Pipe sources through preprocessor <cmd>";
"-ppx", Arg.String (add_to_list ppx_command),
"<cmd> Pipe abstract syntax trees through preprocessor <cmd>";
"-slash", Arg.Set slash,
" (Windows) Use foward slash / instead of backslash \\ in file paths";
"-syntax", Arg.Set_string ocamlfind_syntax,
" <p> Pass the syntax option <p> to ocamlfind";
"-use-menhir", Arg.Set use_menhir,
" Use menhir to callculate the dependencies of .mll files";
"-use-ocamlfind", Arg.Set use_ocamlfind,
" Use ocamlfind as driver for ocamldepend";]
(add_to_list dirs_to_search) usage;
let files = get_files () in
compute_dependencies files;
exit (if !error_occured then 2 else 0)
|