6 (* used both for storing the entities 'defined' and 'used' in a file, but
7 * depending on the use, some fields may not be used
10 macros
: string hashset
; (* object-like or function-like *)
11 variables
: string hashset
;
12 static_variables
: string hashset
; (* for defined only *)
13 functions
: string hashset
;
14 static_functions
: string hashset
; (* for defined only *)
15 structs
: string hashset
; (* union defs, enum defs, enum values *)
16 typedefs
: string hashset
;
17 include_c
: filename hashset
; (* for used only *)
22 idx_macros
: (string, (filename hashset
)) Hashtbl.t
;
23 idx_variables
: (string, (filename hashset
)) Hashtbl.t
;
24 idx_functions
: (string, (filename hashset
)) Hashtbl.t
;
25 idx_structs
: (string, (filename hashset
)) Hashtbl.t
;
26 idx_typedefs
: (string, (filename hashset
)) Hashtbl.t
;
29 let empty_entities () = {
30 macros
= Hashtbl.create
101;
31 variables
= Hashtbl.create
101;
32 static_variables
= Hashtbl.create
101;
33 functions
= Hashtbl.create
101;
34 static_functions
= Hashtbl.create
101;
35 structs
= Hashtbl.create
101;
36 typedefs
= Hashtbl.create
101;
37 include_c
= Hashtbl.create
101;
40 let empty_idx_entities () = {
41 idx_macros
= Hashtbl.create
101;
42 idx_variables
= Hashtbl.create
101;
43 idx_functions
= Hashtbl.create
101;
44 idx_structs
= Hashtbl.create
101;
45 idx_typedefs
= Hashtbl.create
101;
49 let h_to_l h
= Common.hashset_to_list h
51 let print_entities e
=
53 (* e.macros +> h_to_l +> List.iter (fun s -> pr("MACRO: " ^ s)); *)
54 e
.variables
+> h_to_l +> List.iter
(fun s
-> pr
("VAR: " ^ s
));
55 e
.static_variables
+> h_to_l +> List.iter
(fun s
-> pr
("STATICVAR: " ^ s
));
56 e
.functions
+> h_to_l +> List.iter
(fun s
-> pr
("FUNC: " ^ s
));
57 e
.static_functions
+> h_to_l +> List.iter
(fun s
-> pr
("STATICFUNC: " ^ s
));
58 e
.structs
+> h_to_l +> List.iter
(fun s
-> pr
("STRUCT: "^s
));
59 e
.typedefs
+> h_to_l +> List.iter
(fun s
-> pr
("TYPEDEF: "^s
));
60 e
.include_c
+> h_to_l +> List.iter
(fun s
-> pr
("INCLUDEC: "^s
));
64 (* the defined_stuff and used_stuff may not be 100% correct. They don't handle
65 * I think every dark corner of the C. It's possible to shadow in so many
69 (* look only for toplevel definition *)
70 let defined_stuff xs
=
71 let e = empty_entities() in
72 let add h s
= Hashtbl.add h s
true in
74 (* look only for toplevel definition: don't recurse, don't call k *)
75 let bigf = { Visitor_c.default_visitor_c
with
76 Visitor_c.ktoplevel
= (fun (k
,bigf) t
->
80 | DeclList
(xs
, ii
) ->
81 xs
+> List.iter
(fun ((var
, t
, sto
, _local
), iicomma
) ->
82 Visitor_c.vk_type
bigf t
;
85 | Some
((s
, ini
), ii_s_ini
), (StoTypedef
,inline
) ->
87 | Some
((s
, ini
), ii_s_ini
), (Sto Static
,inline
) ->
88 (* need add them to do the adjust_need *)
89 add e.static_variables s
;
91 | Some
((s
, ini
), ii_s_ini
), (Sto Extern
,inline
) ->
93 | Some
((s
, ini
), ii_s_ini
), (_
,inline
) ->
96 | MacroDecl
((s
, args
),ii
) -> ()
100 let ((s
, typ
, sto
, cp
), ii
) = def
in
102 | Sto Static
, inline
->
103 (* need add them to do the adjust_need *)
104 add e.static_functions s
109 | Include includ
-> ()
110 | Define
((s
,ii
), body
) -> add e.macros s
111 | MacroTop
(s
, args
, ii
) -> ()
113 | EmptyDef _
| NotParsedCorrectly _
| FinalDef _
-> ()
116 Visitor_c.ktype
= (fun (k
, bigf) t
->
117 match Ast_c.unwrap_typeC t
with
118 | StructUnion
(su
, sopt
, fields
) ->
119 sopt
+> do_option
(fun s
->
127 xs
+> List.iter
(fun (p
, info_item
) -> Visitor_c.vk_toplevel
bigf p
);
137 (* look only for use of external stuff. Don't consider local vars,
138 * typedefs, structures *)
141 let e = empty_entities() in
142 let add h s
= Hashtbl.replace h s
true in
150 (* !!! sometimes considered as VAR :( *)
153 ] +> List.map
(fun s
-> s
, true);
156 let regexp_macro = Str.regexp
160 let (_env
: (string, bool) Common.scoped_env
ref) = ref initial_env in
163 let bigf = { Visitor_c.default_visitor_c
with
165 (* --------- handling scope of variables (and also some use) --------- *)
166 Visitor_c.kstatement
= (fun (k
, bigf) st
->
168 | Compound statxs
, ii
-> Common.do_in_new_scope _env
(fun () -> k st
);
171 Visitor_c.kdecl
= (fun (k
, bigf) d
->
172 k d
; (* to add possible definition in type found in Decl *)
174 | (DeclList
(xs
, ii
)) ->
175 xs
+> List.iter
(fun ((var
, t
, sto
, _local
), iicomma
) ->
176 var
+> do_option
(fun ((s
, ini
), ii_s_ini
) ->
178 | StoTypedef
, _inline
->
179 (* add_binding (TypeDef (s)) true; *)
182 Common.add_in_scope _env
(s
, true);
188 Visitor_c.ktoplevel
= (fun (k
, bigf) elem
->
191 let (funcs
, ((returnt
, (paramst
, b
))), sto
, statxs
),ii
= def
in
192 Common.do_in_new_scope _env
(fun () ->
193 paramst
+> List.iter
(fun (((b
, s
, t
), _
),_
) ->
195 | Some s
-> Common.add_in_scope _env
(s
, true)
196 | None
-> pr2
"no type, certainly because Void type ?"
200 | Define
(s
, (defkind
, defval
)) ->
201 Common.do_in_new_scope _env
(fun () ->
203 | DefineFunc
(params
, ii
) ->
204 params
+> List.iter
(fun ((s
,iis
), iicomma
) ->
205 Common.add_in_scope _env
(s
, true)
211 | Include
((inc_file
,ii
), posref
) ->
213 | Local
[x
] when x
=~
".*\\.c$" ->
221 (* --------- and now looking for use --------- *)
222 Visitor_c.kexpr
= (fun (k
,bigf) x
->
223 match Ast_c.unwrap_expr x
with
225 | FunCall
(((Ident f
, typ
), ii
), args
) ->
226 if not
(Common.member_env_key f
!_env
)
228 if f
==~
regexp_macro
230 else add e.functions f
232 args
+> List.iter
(fun (x
,ii
) ->
233 Visitor_c.vk_argument
bigf x
236 if not
(Common.member_env_key s
!_env
)
238 if s
==~
regexp_macro
240 else add e.variables s
245 Visitor_c.ktype
= (fun (k
,bigf) t
->
246 match Ast_c.unwrap_typeC t
with
247 | StructUnionName
(su
, s
) ->
248 if not
(Common.member_env_key s
!_env
)
251 | TypeName
(s
,_typ
) ->
252 if not
(Common.member_env_key s
!_env
)
259 xs
+> List.iter
(fun (p
, info_item
) -> Visitor_c.vk_toplevel
bigf p
);
265 (* for the moment, just look if it looks like a linux module file *)
267 let is_module = ref false in
269 (* look only for toplevel definition: don't recurse, don't call k *)
270 let bigf = { Visitor_c.default_visitor_c
with
271 Visitor_c.ktoplevel
= (fun (k
,bigf) t
->
273 | MacroTop
(s
, args
, ii
) ->
275 then is_module := true;
277 let ((s
, typ
, sto
, cp
), ii
) = def
in
279 then is_module := true;
284 xs
+> List.iter
(fun (p
, info_item
) -> Visitor_c.vk_toplevel
bigf p
);
289 let adjust_used_only_external used defined
=
291 used
.variables
+> h_to_l +> List.iter
(fun s
->
292 if Hashtbl.mem defined
.variables s
||
293 Hashtbl.mem defined
.static_variables s
||
294 (* sometimes functions are used as variable, when for example
295 * stored in a pointer variable, so look also for function here.
297 Hashtbl.mem defined
.functions s
||
298 Hashtbl.mem defined
.static_functions s
299 then Hashtbl.remove used
.variables s
301 used
.functions
+> h_to_l +> List.iter
(fun s
->
302 if Hashtbl.mem defined
.functions s
||
303 Hashtbl.mem defined
.static_functions s
304 then Hashtbl.remove used
.functions s
306 used
.structs
+> h_to_l +> List.iter
(fun s
->
307 if Hashtbl.mem defined
.structs s
308 then Hashtbl.remove used
.structs s
310 used
.typedefs
+> h_to_l +> List.iter
(fun s
->
311 if Hashtbl.mem defined
.typedefs s
312 then Hashtbl.remove used
.typedefs s
324 type global_definitions
= idx_entities
326 let mk_global_definitions_index xs
=
327 let idx = empty_idx_entities () in
328 xs
+> List.iter
(fun (file
, {defined
= defined
}) ->
329 defined
.variables
+> h_to_l +> List.iter
(fun s
->
330 Common.hash_hashset_add s file
idx.idx_variables
;
332 defined
.functions
+> h_to_l +> List.iter
(fun s
->
333 Common.hash_hashset_add s file
idx.idx_functions
;
335 defined
.structs
+> h_to_l +> List.iter
(fun s
->
336 Common.hash_hashset_add s file
idx.idx_structs
;
338 defined
.typedefs
+> h_to_l +> List.iter
(fun s
->
339 Common.hash_hashset_add s file
idx.idx_typedefs
;
344 let known_duplicate =
345 ["init_module"; "cleanup_module";
349 let check_no_duplicate_global_definitions idx =
351 pr2
"DUPLICATE processing:";
352 idx.idx_functions
+> hash_to_list
+> List.iter
(fun (f
, set
) ->
353 let xs = hash_to_list set
in
354 if List.length
xs <> 1 && not
(List.mem f
known_duplicate)
356 pr2
("multiple def for : " ^ f ^
" in " ^
357 (join
" " (List.map
(fun x
-> basename
(fst x
)) xs)));
361 type dependencies_graph
=
362 ((filename
* file_info
) * string, bool) Ograph_extended.ograph_mutable
365 let build_graph xs dep graphfile
=
366 let g = ref (new Ograph_extended.ograph_mutable
) in
367 let h = Hashtbl.create
101 in
368 let s_to_nodei s
= Hashtbl.find
h s
in
370 pr2
"BUILDING graph:";
373 (sprintf
"%-20s -- %s:%25s --> %s" a b c d
)
375 with_open_outfile
(graphfile ^
".graph") (fun (pr_no_nl
,chan
) ->
376 let pr_arrow a b c d
=
378 pr_no_nl
(arrow a b c d ^
"\n");
382 xs +> List.iter
(fun (file
, cinfo
) ->
383 let s = (if cinfo
.is_module then "[M]" else "") ^
Filename.basename file
in
384 let xi = !g#add_node
((file
, cinfo
), s) in
385 Hashtbl.add h file
xi;
388 xs +> List.iter
(fun (file
, {used
= used
}) ->
390 used
.functions
+> h_to_l +> List.iter
(fun s ->
391 match Common.optionise
(fun () -> Hashtbl.find dep
.idx_functions
s) with
394 hset
+> h_to_l +> List.iter
(fun file_defined
->
395 !g#add_arc
((s_to_nodei file
, s_to_nodei file_defined
), true);
396 let (file
, file_defined
) = basename file
, basename file_defined
in
397 pr_arrow file
"f" s file_defined
;
400 (* sometime use functions as variable *)
401 used
.variables
+> h_to_l +> List.iter
(fun s ->
402 match Common.optionise
(fun () -> Hashtbl.find dep
.idx_functions
s) with
405 hset
+> h_to_l +> List.iter
(fun file_defined
->
406 !g#add_arc
((s_to_nodei file
, s_to_nodei file_defined
), true);
407 let (file
, file_defined
) = basename file
, basename file_defined
in
408 pr_arrow file
"f" s file_defined
;
412 used
.variables
+> h_to_l +> List.iter
(fun s ->
413 match Common.optionise
(fun () -> Hashtbl.find dep
.idx_variables
s) with
416 hset
+> h_to_l +> List.iter
(fun file_defined
->
417 !g#add_arc
((s_to_nodei file
, s_to_nodei file_defined
), true);
418 let (file
, file_defined
) = basename file
, basename file_defined
in
419 pr_arrow file
"v" s file_defined
;
423 used
.include_c
+> h_to_l +> List.iter
(fun local_file
->
424 let file_defined = Filename.concat
(dirname file
) local_file
in
426 !g#add_arc
((s_to_nodei file
, s_to_nodei file_defined), true);
427 let (file
, file_defined) = basename file
, basename
file_defined in
428 pr_arrow file
"I" "include" file_defined;
431 pr2
("can't find included C file: " ^
file_defined)
435 used.structs +> h_to_l +> List.iter (fun s ->
436 match Common.optionise (fun () -> Hashtbl.find dep.idx_structs s) with
439 hset +> h_to_l +> List.iter (fun file_defined ->
440 !g#add_arc ((s_to_nodei file, s_to_nodei file_defined), true);
444 used.typedefs +> h_to_l +> List.iter (fun s ->
445 match Common.optionise (fun () -> Hashtbl.find dep.idx_typedefs s) with
448 hset +> h_to_l +> List.iter (fun file_defined ->
449 !g#add_arc ((s_to_nodei file, s_to_nodei file_defined), true);
455 Ograph_extended.print_ograph_mutable
!g graphfile
(!Flag.show_misc
);
462 let generate_makefile (g: dependencies_graph
) file
=
463 pr2
"GENERATING makefile";
464 with_open_outfile file
(fun (pr_no_nl
, chan
) ->
466 let nodei_to_file xi =
467 let ((file
, cinfo
), s) = (g#nodes#assoc
xi) in
470 let all_nodes = g#nodes#tolist
+> List.map fst
in
471 let visited_nodes_h = Hashtbl.create
101 in
473 let modules = all_nodes +> List.filter
(fun xi ->
474 let ((file
, cinfo
), s) = g#nodes#assoc
xi in
478 pr_no_nl
" # ---- modules files ---- \n";
479 modules +> List.iter
(fun xi ->
480 pr2
(nodei_to_file xi);
482 g +> Ograph_extended.dfs_iter
xi (fun yi
->
483 pr2
(" " ^
(Filename.basename
(nodei_to_file yi
)));
484 pr_no_nl
(" " ^
(Filename.basename
(nodei_to_file yi
)));
485 Hashtbl.add visited_nodes_h yi
true;
489 let visited_nodes = Common.hashset_to_list
visited_nodes_h in
490 let rest = all_nodes $
-$
visited_nodes in
492 let startfiles = rest +> List.filter
(fun xi ->
493 (g#predecessors
xi)#null
495 pr_no_nl
" # ---- not module starting files ---- \n";
497 startfiles +> List.iter
(fun xi ->
498 pr2
(nodei_to_file xi);
500 g +> Ograph_extended.dfs_iter
xi (fun yi
->
501 pr2
(" " ^
(Filename.basename
(nodei_to_file yi
)));
502 pr_no_nl
(" " ^
(Filename.basename
(nodei_to_file yi
)));
503 Hashtbl.add visited_nodes_h yi
true;
507 let visited_nodes = Common.hashset_to_list
visited_nodes_h in
508 let rest = rest $
-$
visited_nodes in
510 if not
(null
rest) then pr_no_nl
" # ---- files in cycle ---- \n";
511 rest +> List.iter
(fun xi ->
512 if Hashtbl.mem
visited_nodes_h xi then () (* already handled *)
514 pr2
(nodei_to_file xi);
516 g +> Ograph_extended.dfs_iter
xi (fun yi
->
517 pr2
(" " ^
(Filename.basename
(nodei_to_file yi
)));
518 pr_no_nl
(" " ^
(Filename.basename
(nodei_to_file yi
)));
519 Hashtbl.add visited_nodes_h yi
true;