Skip to content

Commit 45e980a

Browse files
committed
Record "weak dependencies" with -trans-mod
Currently, -trans-mod simply ignores dependencies on unused module aliases. This commit changes this behaviour so that unused module aliases are included in the list of imported interfaces but without a CRC. This change means that the imported interfaces list (as displayed by `ocamlobjinfo`) is now an accurate representation of what was used during the compilation of a module. Whilst the contents of unused module aliases is not used, their existance is still required in order for the module to compile successfully. Previously, a simple file `foo.ml` containing an unused module alias to `Bar` would have the following output from `ocamlobjinfo` for `foo.cmo`: File foo.cmo Unit name: Foo Interfaces imported: 4ad29aa1be509426919169d97aad0a82 Pervasives df1763e3e7e64b9b8ebea6f93b0a95b3 Foo Uses unsafe features: no Force link: no with this patch it instead has output: File foo.cmo Unit name: Foo Interfaces imported: -------------------------------- Bar 6cda9672639792333f53de8e8ff9e71d Pervasives df1763e3e7e64b9b8ebea6f93b0a95b3 Foo Uses unsafe features: no Force link: no This is useful because now we can see that if `bar.cmi` is deleted then this module will no longer compile successfully. This commit acheives this change by making the digests optional in every list of imported interfaces and implementations. In the case of implementations this replaces the previous use of the `cmx_not_found_crc` dummy value for implementations where a `.cmx` was not available. `ocamlobjinfo` and `read_cmt` print imports with an empty digest as a line of dashes. All other uses of the imported interface lists ignore imports with an empty digest, leaving their behaviour unchanged. This commit also adds a (new) description of -trans-mod to the man pages.
1 parent 75fd56b commit 45e980a

35 files changed

+206
-122
lines changed

asmcomp/asmlink.ml

+29-22
Original file line numberDiff line numberDiff line change
@@ -33,31 +33,37 @@ exception Error of error
3333
(* Consistency check between interfaces and implementations *)
3434

3535
let crc_interfaces = Consistbl.create ()
36+
let interfaces = ref ([] : string list)
3637
let crc_implementations = Consistbl.create ()
37-
let extra_implementations = ref ([] : string list)
38+
let implementations = ref ([] : string list)
3839
let implementations_defined = ref ([] : (string * string) list)
3940
let cmx_required = ref ([] : string list)
4041

4142
let check_consistency file_name unit crc =
4243
begin try
4344
List.iter
44-
(fun (name, crc) ->
45-
if name = unit.ui_name
46-
then Consistbl.set crc_interfaces name crc file_name
47-
else Consistbl.check crc_interfaces name crc file_name)
45+
(fun (name, crco) ->
46+
interfaces := name :: !interfaces;
47+
match crco with
48+
None -> ()
49+
| Some crc ->
50+
if name = unit.ui_name
51+
then Consistbl.set crc_interfaces name crc file_name
52+
else Consistbl.check crc_interfaces name crc file_name)
4853
unit.ui_imports_cmi
4954
with Consistbl.Inconsistency(name, user, auth) ->
5055
raise(Error(Inconsistent_interface(name, user, auth)))
5156
end;
5257
begin try
5358
List.iter
54-
(fun (name, crc) ->
55-
if crc <> cmx_not_found_crc then
56-
Consistbl.check crc_implementations name crc file_name
57-
else if List.mem name !cmx_required then
58-
raise(Error(Missing_cmx(file_name, name)))
59-
else
60-
extra_implementations := name :: !extra_implementations)
59+
(fun (name, crco) ->
60+
implementations := name :: !implementations;
61+
match crco with
62+
None ->
63+
if List.mem name !cmx_required then
64+
raise(Error(Missing_cmx(file_name, name)))
65+
| Some crc ->
66+
Consistbl.check crc_implementations name crc file_name)
6167
unit.ui_imports_cmx
6268
with Consistbl.Inconsistency(name, user, auth) ->
6369
raise(Error(Inconsistent_implementation(name, user, auth)))
@@ -67,20 +73,17 @@ let check_consistency file_name unit crc =
6773
raise (Error(Multiple_definition(unit.ui_name, file_name, source)))
6874
with Not_found -> ()
6975
end;
76+
implementations := unit.ui_name :: !implementations;
7077
Consistbl.set crc_implementations unit.ui_name crc file_name;
7178
implementations_defined :=
7279
(unit.ui_name, file_name) :: !implementations_defined;
7380
if unit.ui_symbol <> unit.ui_name then
7481
cmx_required := unit.ui_name :: !cmx_required
7582

7683
let extract_crc_interfaces () =
77-
Consistbl.extract crc_interfaces
84+
Consistbl.extract !interfaces crc_interfaces
7885
let extract_crc_implementations () =
79-
List.fold_left
80-
(fun ncl n ->
81-
if List.mem_assoc n ncl then ncl else (n, cmx_not_found_crc) :: ncl)
82-
(Consistbl.extract crc_implementations)
83-
!extra_implementations
86+
Consistbl.extract !implementations crc_implementations
8487

8588
(* Add C objects and options and "custom" info from a library descriptor.
8689
See bytecomp/bytelink.ml for comments on the order of C objects. *)
@@ -214,10 +217,14 @@ let make_startup_file ppf filename units_list =
214217
(Cmmgen.globals_map
215218
(List.map
216219
(fun (unit,_,crc) ->
217-
try (unit.ui_name, List.assoc unit.ui_name unit.ui_imports_cmi,
218-
crc,
219-
unit.ui_defines)
220-
with Not_found -> assert false)
220+
let intf_crc =
221+
try
222+
match List.assoc unit.ui_name unit.ui_imports_cmi with
223+
None -> assert false
224+
| Some crc -> crc
225+
with Not_found -> assert false
226+
in
227+
(unit.ui_name, intf_crc, crc, unit.ui_defines))
221228
units_list));
222229
compile_phrase(Cmmgen.data_segment_table ("_startup" :: name_list));
223230
compile_phrase(Cmmgen.code_segment_table ("_startup" :: name_list));

asmcomp/asmlink.mli

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ val link_shared: formatter -> string list -> string -> unit
2121
val call_linker_shared: string list -> string -> unit
2222

2323
val check_consistency: string -> Cmx_format.unit_infos -> Digest.t -> unit
24-
val extract_crc_interfaces: unit -> (string * Digest.t) list
25-
val extract_crc_implementations: unit -> (string * Digest.t) list
24+
val extract_crc_interfaces: unit -> (string * Digest.t option) list
25+
val extract_crc_implementations: unit -> (string * Digest.t option) list
2626

2727
type error =
2828
File_not_found of string

asmcomp/asmpackager.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ let build_package_cmx members cmxfile =
130130
List.flatten (List.map (fun info -> info.ui_defines) units) @
131131
[ui.ui_symbol];
132132
ui_imports_cmi =
133-
(ui.ui_name, Env.crc_of_unit ui.ui_name) ::
133+
(ui.ui_name, Some (Env.crc_of_unit ui.ui_name)) ::
134134
filter(Asmlink.extract_crc_interfaces());
135135
ui_imports_cmx =
136136
filter(Asmlink.extract_crc_implementations());

asmcomp/cmx_format.mli

+5-4
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@ type unit_infos =
2626
{ mutable ui_name: string; (* Name of unit implemented *)
2727
mutable ui_symbol: string; (* Prefix for symbols *)
2828
mutable ui_defines: string list; (* Unit and sub-units implemented *)
29-
mutable ui_imports_cmi: (string * Digest.t) list; (* Interfaces imported *)
30-
mutable ui_imports_cmx: (string * Digest.t) list; (* Infos imported *)
29+
mutable ui_imports_cmi:
30+
(string * Digest.t option) list; (* Interfaces imported *)
31+
mutable ui_imports_cmx:(string * Digest.t option) list; (* Infos imported *)
3132
mutable ui_approx: Clambda.value_approximation; (* Approx of the structure*)
3233
mutable ui_curry_fun: int list; (* Currying functions needed *)
3334
mutable ui_apply_fun: int list; (* Apply functions needed *)
@@ -49,8 +50,8 @@ type library_infos =
4950
type dynunit = {
5051
dynu_name: string;
5152
dynu_crc: Digest.t;
52-
dynu_imports_cmi: (string * Digest.t) list;
53-
dynu_imports_cmx: (string * Digest.t) list;
53+
dynu_imports_cmi: (string * Digest.t option) list;
54+
dynu_imports_cmx: (string * Digest.t option) list;
5455
dynu_defines: string list;
5556
}
5657

asmcomp/compilenv.ml

+3-6
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,6 @@ let read_library_info filename =
143143

144144
(* Read and cache info on global identifiers *)
145145

146-
let cmx_not_found_crc =
147-
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
148-
149146
let get_global_info global_ident = (
150147
let modname = Ident.name global_ident in
151148
if modname = current_unit.ui_name then
@@ -161,9 +158,9 @@ let get_global_info global_ident = (
161158
let (ui, crc) = read_unit_info filename in
162159
if ui.ui_name <> modname then
163160
raise(Error(Illegal_renaming(modname, ui.ui_name, filename)));
164-
(Some ui, crc)
161+
(Some ui, Some crc)
165162
with Not_found ->
166-
(None, cmx_not_found_crc) in
163+
(None, None) in
167164
current_unit.ui_imports_cmx <-
168165
(modname, crc) :: current_unit.ui_imports_cmx;
169166
Hashtbl.add global_infos_table modname infos;
@@ -231,7 +228,7 @@ let write_unit_info info filename =
231228
close_out oc
232229

233230
let save_unit_info filename =
234-
current_unit.ui_imports_cmi <- Env.imported_units();
231+
current_unit.ui_imports_cmi <- Env.imports();
235232
write_unit_info current_unit filename
236233

237234

asmcomp/compilenv.mli

-4
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,6 @@ val cache_unit_info: unit_infos -> unit
7979
honored by [symbol_for_global] and [global_approx]
8080
without looking at the corresponding .cmx file. *)
8181

82-
val cmx_not_found_crc: Digest.t
83-
(* Special digest used in the [ui_imports_cmx] list to signal
84-
that no [.cmx] file was found and used for the imported unit *)
85-
8682
val read_library_info: string -> library_infos
8783

8884
type error =

boot/ocamlc

753 Bytes
Binary file not shown.

boot/ocamldep

-68 Bytes
Binary file not shown.

boot/ocamllex

27 Bytes
Binary file not shown.

bytecomp/bytelink.ml

+16-7
Original file line numberDiff line numberDiff line change
@@ -158,15 +158,20 @@ let scan_file obj_name tolink =
158158
(* Consistency check between interfaces *)
159159

160160
let crc_interfaces = Consistbl.create ()
161+
let interfaces = ref ([] : string list)
161162
let implementations_defined = ref ([] : (string * string) list)
162163

163164
let check_consistency ppf file_name cu =
164165
begin try
165166
List.iter
166-
(fun (name, crc) ->
167-
if name = cu.cu_name
168-
then Consistbl.set crc_interfaces name crc file_name
169-
else Consistbl.check crc_interfaces name crc file_name)
167+
(fun (name, crco) ->
168+
interfaces := name :: !interfaces;
169+
match crco with
170+
None -> ()
171+
| Some crc ->
172+
if name = cu.cu_name
173+
then Consistbl.set crc_interfaces name crc file_name
174+
else Consistbl.check crc_interfaces name crc file_name)
170175
cu.cu_imports
171176
with Consistbl.Inconsistency(name, user, auth) ->
172177
raise(Error(Inconsistent_import(name, user, auth)))
@@ -183,7 +188,11 @@ let check_consistency ppf file_name cu =
183188
(cu.cu_name, file_name) :: !implementations_defined
184189

185190
let extract_crc_interfaces () =
186-
Consistbl.extract crc_interfaces
191+
Consistbl.extract !interfaces crc_interfaces
192+
193+
let clear_crc_interfaces () =
194+
Consistbl.clear crc_interfaces;
195+
interfaces := []
187196

188197
(* Record compilation events *)
189198

@@ -307,7 +316,7 @@ let link_bytecode ppf tolink exec_name standalone =
307316
(* The bytecode *)
308317
let start_code = pos_out outchan in
309318
Symtable.init();
310-
Consistbl.clear crc_interfaces;
319+
clear_crc_interfaces ();
311320
let sharedobjs = List.map Dll.extract_dll_name !Clflags.dllibs in
312321
let check_dlls = standalone && Config.target = Config.host in
313322
if check_dlls then begin
@@ -440,7 +449,7 @@ let link_bytecode_as_c ppf tolink outfile =
440449
\n char **argv);\n";
441450
output_string outchan "static int caml_code[] = {\n";
442451
Symtable.init();
443-
Consistbl.clear crc_interfaces;
452+
clear_crc_interfaces ();
444453
let currpos = ref 0 in
445454
let output_fun code =
446455
output_code_string outchan code;

bytecomp/bytelink.mli

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ val link : Format.formatter -> string list -> string -> unit
1717
val check_consistency:
1818
Format.formatter -> string -> Cmo_format.compilation_unit -> unit
1919

20-
val extract_crc_interfaces: unit -> (string * Digest.t) list
20+
val extract_crc_interfaces: unit -> (string * Digest.t option) list
2121

2222
type error =
2323
File_not_found of string

bytecomp/bytepackager.ml

+2-1
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,8 @@ let package_object_files ppf files targetfile targetname coercion =
233233
cu_pos = pos_code;
234234
cu_codesize = pos_debug - pos_code;
235235
cu_reloc = List.rev !relocs;
236-
cu_imports = (targetname, Env.crc_of_unit targetname) :: imports;
236+
cu_imports =
237+
(targetname, Some (Env.crc_of_unit targetname)) :: imports;
237238
cu_primitives = !primitives;
238239
cu_force_link = !force_link;
239240
cu_debug = if pos_final > pos_debug then pos_debug else 0;

bytecomp/cmo_format.mli

+2-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ type compilation_unit =
2727
mutable cu_pos: int; (* Absolute position in file *)
2828
cu_codesize: int; (* Size of code block *)
2929
cu_reloc: (reloc_info * int) list; (* Relocation information *)
30-
cu_imports: (string * Digest.t) list; (* Names and CRC of intfs imported *)
30+
cu_imports:
31+
(string * Digest.t option) list; (* Names and CRC of intfs imported *)
3132
cu_primitives: string list; (* Primitives declared inside *)
3233
mutable cu_force_link: bool; (* Must be linked even if unref'ed *)
3334
mutable cu_debug: int; (* Position of debugging info, or 0 *)

bytecomp/emitcode.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ let to_file outchan unit_name code =
381381
cu_pos = pos_code;
382382
cu_codesize = !out_position;
383383
cu_reloc = List.rev !reloc_info;
384-
cu_imports = Env.imported_units();
384+
cu_imports = Env.imports();
385385
cu_primitives = List.map Primitive.byte_name
386386
!Translmod.primitive_declarations;
387387
cu_force_link = false;

bytecomp/symtable.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ let init_toplevel () =
300300
Dll.init_toplevel dllpath;
301301
(* Recover CRC infos for interfaces *)
302302
let crcintfs =
303-
try (Obj.magic (sect.read_struct "CRCS") : (string * Digest.t) list)
303+
try (Obj.magic (sect.read_struct "CRCS") : (string * Digest.t option) list)
304304
with Not_found -> [] in
305305
(* Done *)
306306
sect.close_reader();

bytecomp/symtable.mli

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ val data_primitive_names: unit -> string
2929

3030
(* Functions for the toplevel *)
3131

32-
val init_toplevel: unit -> (string * Digest.t) list
32+
val init_toplevel: unit -> (string * Digest.t option) list
3333
val update_global_table: unit -> unit
3434
val get_global_value: Ident.t -> Obj.t
3535
val is_global_defined: Ident.t -> bool

driver/main_args.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ let mk_thread f =
267267

268268
let mk_trans_mod f =
269269
"-trans-mod", Arg.Unit f,
270-
" Make typing and linking only depend on normalized paths"
270+
" Do not import unused module aliases"
271271

272272
let mk_unsafe f =
273273
"-unsafe", Arg.Unit f,

man/ocamlc.m

+3
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,9 @@ Build a bytecode object file (.cmo file) and its associated compiled
532532
system "threads" library described in
533533
.IR The\ OCaml\ user's\ manual .
534534
.TP
535+
.B \-trans-mod
536+
Do not import unused module aliases.
537+
.TP
535538
.B \-unsafe
536539
Turn bound checking off for array and string accesses (the
537540
.BR v.(i) and s.[i]

man/ocamlopt.m

+3
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,9 @@ apply to the way the extra native objects have been compiled (under
506506
system threads library described in
507507
.IR "The OCaml user's manual" .
508508
.TP
509+
.B \-trans-mod
510+
Do not import unused module aliases.
511+
.TP
509512
.B \-unsafe
510513
Turn bound checking off for array and string accesses (the
511514
.BR v.(i) and s.[i]

otherlibs/dynlink/dynlink.ml

+20-11
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,16 @@ let allow_extension = ref true
7979
let check_consistency file_name cu =
8080
try
8181
List.iter
82-
(fun (name, crc) ->
83-
if name = cu.cu_name then
84-
Consistbl.set !crc_interfaces name crc file_name
85-
else if !allow_extension then
86-
Consistbl.check !crc_interfaces name crc file_name
87-
else
88-
Consistbl.check_noadd !crc_interfaces name crc file_name)
82+
(fun (name, crco) ->
83+
match crco with
84+
None -> ()
85+
| Some crc ->
86+
if name = cu.cu_name then
87+
Consistbl.set !crc_interfaces name crc file_name
88+
else if !allow_extension then
89+
Consistbl.check !crc_interfaces name crc file_name
90+
else
91+
Consistbl.check_noadd !crc_interfaces name crc file_name)
8992
cu.cu_imports
9093
with Consistbl.Inconsistency(name, user, auth) ->
9194
raise(Error(Inconsistent_import name))
@@ -113,15 +116,21 @@ let prohibit names =
113116
(* Initialize the crc_interfaces table with a list of units with fixed CRCs *)
114117

115118
let add_available_units units =
116-
List.iter (fun (unit, crc) -> Consistbl.set !crc_interfaces unit crc "")
117-
units
119+
List.iter
120+
(fun (unit, crc) -> Consistbl.set !crc_interfaces unit crc "")
121+
units
118122

119123
(* Default interface CRCs: those found in the current executable *)
120124
let default_crcs = ref []
121125

122126
let default_available_units () =
123127
clear_available_units();
124-
add_available_units !default_crcs;
128+
List.iter
129+
(fun (unit, crco) ->
130+
match crco with
131+
None -> ()
132+
| Some crc -> Consistbl.set !crc_interfaces unit crc "")
133+
!default_crcs;
125134
allow_extension := true
126135

127136
(* Initialize the linker tables and everything *)
@@ -161,7 +170,7 @@ let digest_interface unit loadpath =
161170
close_in ic;
162171
let crc =
163172
match cmi.Cmi_format.cmi_crcs with
164-
(_, crc) :: _ -> crc
173+
(_, Some crc) :: _ -> crc
165174
| _ -> raise(Error(Corrupted_interface filename))
166175
in
167176
crc

0 commit comments

Comments
 (0)