aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--library/library.ml384
-rw-r--r--library/library.mli9
2 files changed, 246 insertions, 147 deletions
diff --git a/library/library.ml b/library/library.ml
index c9116b059..cf420d1b7 100644
--- a/library/library.ml
+++ b/library/library.ml
@@ -104,7 +104,8 @@ type module_disk = {
md_name : compilation_unit_name;
md_compiled_env : compiled_env;
md_declarations : library_segment;
- md_deps : (compilation_unit_name * Digest.t * bool) list }
+ md_deps : (compilation_unit_name * Digest.t) list;
+ md_imports : compilation_unit_name list }
(*s Modules loaded in memory contain the following informations. They are
kept in the global table [modules_table]. *)
@@ -114,9 +115,8 @@ type module_t = {
module_filename : System.physical_path;
module_compiled_env : compiled_env;
module_declarations : library_segment;
- mutable module_opened : bool;
- mutable module_exported : bool;
- module_deps : (compilation_unit_name * Digest.t * bool) list;
+ module_deps : (compilation_unit_name * Digest.t) list;
+ module_imports : compilation_unit_name list;
module_digest : Digest.t }
module CompUnitOrdered =
@@ -129,13 +129,37 @@ module CompUnitOrdered =
module CompUnitmap = Map.Make(CompUnitOrdered)
+(* This is a map from names to modules *)
let modules_table = ref CompUnitmap.empty
+(* These are the _ordered_ lists of loaded, imported and exported modules *)
+let modules_loaded_list = ref []
+let modules_imports_list = ref []
+let modules_exports_list = ref []
+
+let freeze () =
+ !modules_table,
+ !modules_loaded_list,
+ !modules_imports_list,
+ !modules_exports_list
+
+let unfreeze (mt,mo,mi,me) =
+ modules_table := mt;
+ modules_loaded_list := mo;
+ modules_imports_list := mi;
+ modules_exports_list := me
+
+let init () =
+ modules_table := CompUnitmap.empty;
+ modules_loaded_list := [];
+ modules_imports_list := [];
+ modules_exports_list := []
+
let _ =
Summary.declare_summary "MODULES"
- { Summary.freeze_function = (fun () -> !modules_table);
- Summary.unfreeze_function = (fun ft -> modules_table := ft);
- Summary.init_function = (fun () -> modules_table := CompUnitmap.empty);
+ { Summary.freeze_function = freeze;
+ Summary.unfreeze_function = unfreeze;
+ Summary.init_function = init;
Summary.survive_section = false }
let find_module s =
@@ -148,18 +172,47 @@ let module_is_loaded dir =
try let _ = CompUnitmap.find dir !modules_table in true
with Not_found -> false
-let module_is_opened s =
- (find_module (make_dirpath [id_of_string s])).module_opened
+let module_is_opened dir =
+ List.exists (fun m -> m.module_name = dir) !modules_imports_list
-let loaded_modules () =
- CompUnitmap.fold (fun s _ l -> s :: l) !modules_table []
+let module_is_exported dir =
+ List.exists (fun m -> m.module_name = dir) !modules_exports_list
-let opened_modules () =
- CompUnitmap.fold
- (fun s m l -> if m.module_opened then s :: l else l)
- !modules_table []
+let loaded_modules () =
+ List.map (fun m -> m.module_name) !modules_loaded_list
-let compunit_cache = ref Stringmap.empty
+let opened_modules () =
+ List.map (fun m -> m.module_name) !modules_imports_list
+
+ (* If a module is loaded several time, then the first occurrence must
+ be performed first, thus the modules_loaded_list ... *)
+
+let register_loaded_module m =
+ let rec aux = function
+ | [] -> [m]
+ | m'::_ as l when m'.module_name = m.module_name -> l
+ | m'::l' -> m' :: aux l' in
+ modules_loaded_list := aux !modules_loaded_list;
+ modules_table := CompUnitmap.add m.module_name m !modules_table
+
+ (* ... while if a module is imported/exported several time, then
+ only the last occurrence is really needed - though the imported
+ list may differ from the exported list (consider the sequence
+ Export A; Export B; Import A which results in A;B for exports but
+ in B;A for imports) *)
+
+let rec remember_last_of_each l m =
+ match l with
+ | [] -> [m]
+ | m'::l' when m'.module_name = m.module_name -> remember_last_of_each l' m
+ | m'::l' -> m' :: remember_last_of_each l' m
+
+let register_open_module export m =
+ modules_imports_list := remember_last_of_each !modules_imports_list m;
+ if export then
+ modules_exports_list := remember_last_of_each !modules_exports_list m
+
+let compunit_cache = ref CompUnitmap.empty
let module_segment = function
| None -> contents_after None
@@ -203,15 +256,24 @@ let segment_iter f =
let open_objects decls =
segment_iter open_object decls
-let rec open_module force s =
- let m = find_module s in
- if force or not m.module_opened then begin
- List.iter (fun (m,_,exp) -> if exp then open_module force m) m.module_deps;
- open_objects m.module_declarations;
- m.module_opened <- true
- end
-
-let import_module = open_module true
+let open_module export m =
+ if not (module_is_opened m.module_name) then
+ (register_open_module export m;
+ open_objects m.module_declarations)
+ else
+ if export then
+ modules_exports_list := remember_last_of_each !modules_exports_list m
+
+let open_modules export modl =
+ let to_open_list =
+ List.fold_left
+ (fun l m ->
+ List.fold_left (fun l m ->
+ let m = find_module m in
+ remember_last_of_each l m)
+ (remember_last_of_each l m)
+ m.module_imports) [] modl in
+ List.iter (open_module export) to_open_list
(*s [load_module s] loads the module [s] from the disk, and [find_module s]
returns the module of name [s], loading it if necessary.
@@ -227,10 +289,10 @@ exception LibNotFound
type library_location = LibLoaded | LibInPath
let locate_absolute_library dir =
- (* Look if loaded *)
+ (* Look if loaded in current environment *)
try
let m = CompUnitmap.find dir !modules_table in
- (LibLoaded, dir, m.module_filename)
+ (dir, m.module_filename)
with Not_found ->
(* Look if in loadpath *)
try
@@ -239,77 +301,120 @@ let locate_absolute_library dir =
if loadpath = [] then raise LibUnmappedDir;
let name = (string_of_id base)^".vo" in
let _, file = System.where_in_path loadpath name in
- (LibInPath, dir, file)
+ (dir, file)
with Not_found -> raise LibNotFound
let with_magic_number_check f a =
try f a
with System.Bad_magic_number fname ->
- errorlabstrm "load_module_from"
+ errorlabstrm "with_magic_number_check"
(str"file " ++ str fname ++ spc () ++ str"has bad magic number." ++
spc () ++ str"It is corrupted" ++ spc () ++
str"or was compiled with another version of Coq.")
-let rec load_module = function
- | (LibLoaded, dir, _) ->
- CompUnitmap.find dir !modules_table
- | (LibInPath, dir, f) ->
- (* [dir] is an absolute name which matches [f] *)
- let md, digest =
- try Stringmap.find f !compunit_cache
+let rec load_module dir =
+ try
+ (* Look if loaded in current env (and consequently its dependencies) *)
+ CompUnitmap.find dir !modules_table
+ with Not_found ->
+ (* [dir] is an absolute name which matches [f] which must be in loadpath *)
+ let m =
+ try CompUnitmap.find dir !compunit_cache
with Not_found ->
- let ch = with_magic_number_check raw_intern_module f in
- let md = System.marshal_in ch in
- let digest = System.marshal_in ch in
- close_in ch;
- if dir <> md.md_name then
- errorlabstrm "load_module"
- (str ("The file " ^ f ^ " contains module") ++ spc () ++
- pr_dirpath md.md_name ++ spc () ++ str "and not module" ++ spc () ++
- pr_dirpath dir);
- compunit_cache := Stringmap.add f (md, digest) !compunit_cache;
- (md, digest) in
- intern_module digest f md
-
-and intern_module digest fname md =
- let m = { module_name = md.md_name;
- module_filename = fname;
- module_compiled_env = md.md_compiled_env;
- module_declarations = md.md_declarations;
- module_opened = false;
- module_exported = false;
- module_deps = md.md_deps;
- module_digest = digest } in
- List.iter (load_mandatory_module md.md_name) m.module_deps;
- Global.import m.module_compiled_env;
- load_objects m.module_declarations;
- modules_table := CompUnitmap.add md.md_name m !modules_table;
- Nametab.push_loaded_library md.md_name;
- m
-
-and load_mandatory_module caller (dir,d,_) =
- let m = load_absolute_module_from dir in
+ anomaly ((string_of_dirpath dir)^" should be in cache")
+ in
+ List.iter (fun (dir,_) -> ignore (load_module dir)) m.module_deps;
+ Global.import m.module_compiled_env;
+ load_objects m.module_declarations;
+ register_loaded_module m;
+ Nametab.push_loaded_library m.module_name;
+ m
+
+let mk_module md f digest = {
+ module_name = md.md_name;
+ module_filename = f;
+ module_compiled_env = md.md_compiled_env;
+ module_declarations = md.md_declarations;
+ module_deps = md.md_deps;
+ module_imports = md.md_imports;
+ module_digest = digest }
+
+let intern_from_file f =
+ let ch = with_magic_number_check raw_intern_module f in
+ let md = System.marshal_in ch in
+ let digest = System.marshal_in ch in
+ close_in ch;
+ mk_module md f digest
+
+let rec intern_module (dir, f) =
+ try
+ (* Look if in the current logical environment *)
+ CompUnitmap.find dir !modules_table
+ with Not_found ->
+ try
+ (* Look if already loaded in cache and consequently its dependencies *)
+ CompUnitmap.find dir !compunit_cache
+ with Not_found ->
+ (* [dir] is an absolute name which matches [f] which must be in loadpath *)
+ let m = intern_from_file f in
+ if dir <> m.module_name then
+ errorlabstrm "load_physical_module"
+ (str ("The file " ^ f ^ " contains module") ++ spc () ++
+ pr_dirpath m.module_name ++ spc () ++ str "and not module" ++
+ spc() ++ pr_dirpath dir);
+ compunit_cache := CompUnitmap.add dir m !compunit_cache;
+ List.iter (intern_mandatory_module dir) m.module_deps;
+ m
+
+and intern_mandatory_module caller (dir,d) =
+ let m = intern_absolute_module_from dir in
if d <> m.module_digest then
error ("compiled module "^(string_of_dirpath caller)^
" makes inconsistent assumptions over module "
^(string_of_dirpath dir))
-and load_absolute_module_from dir =
+and intern_absolute_module_from dir =
try
- load_module (locate_absolute_library dir)
+ intern_module (locate_absolute_library dir)
with
| LibUnmappedDir ->
let prefix, dir = fst (split_dirpath dir), string_of_dirpath dir in
- errorlabstrm "load_module"
+ errorlabstrm "load_absolute_module_from"
(str ("Cannot load "^dir^":") ++ spc () ++
str "no physical path bound to" ++ spc () ++ pr_dirpath prefix ++ fnl ())
| LibNotFound ->
- errorlabstrm "load_module"
+ errorlabstrm "load_absolute_module_from"
(str"Cannot find module " ++ pr_dirpath dir ++ str" in loadpath")
| e -> raise e
+let rec_intern_module mref = let _ = intern_module mref in ()
+
+let check_module_short_name f dir = function
+ | Some id when id <> snd (split_dirpath dir) ->
+ errorlabstrm "check_module_short_name"
+ (str ("The file " ^ f ^ " contains module") ++ spc () ++
+ pr_dirpath dir ++ spc () ++ str "and not module" ++ spc () ++
+ pr_id id)
+ | _ -> ()
+
+let rec_intern_by_filename_only id f =
+ let m = intern_from_file f in
+ (* Only the base name is expected to match *)
+ check_module_short_name f m.module_name id;
+ (* We check no other file containing same module is loaded *)
+ try
+ let m' = CompUnitmap.find m.module_name !modules_table in
+ Options.if_verbose warning
+ ((string_of_dirpath m.module_name)^" is already loaded from file "^
+ m'.module_filename);
+ m.module_name
+ with Not_found ->
+ compunit_cache := CompUnitmap.add m.module_name m !compunit_cache;
+ List.iter (intern_mandatory_module m.module_name) m.module_deps;
+ m.module_name
+
let locate_qualified_library qid =
- (* Look if loaded *)
+ (* Look if loaded in current environment *)
try
let dir = Nametab.locate_loaded_library qid in
(LibLoaded, dir, module_full_filename dir)
@@ -329,82 +434,45 @@ let locate_qualified_library qid =
(LibInPath, extend_dirpath (find_logical_path path) base, file)
with Not_found -> raise LibNotFound
-let try_locate_qualified_library qid =
+let rec_intern_qualified_library qid =
try
- locate_qualified_library qid
+ let (_,dir,f) = locate_qualified_library qid in
+ rec_intern_module (dir,f);
+ dir
with
| LibUnmappedDir ->
let prefix, id = repr_qualid qid in
- errorlabstrm "load_module"
+ errorlabstrm "rec_intern_qualified_library"
(str ("Cannot load "^(string_of_id id)^":") ++ spc () ++
str "no physical path bound to" ++ spc () ++ pr_dirpath prefix ++ fnl ())
| LibNotFound ->
- errorlabstrm "load_module"
+ errorlabstrm "rec_intern_qualified_library"
(str"Cannot find module " ++ pr_qualid qid ++ str" in loadpath")
| _ -> assert false
-let check_module_short_name f dir = function
- | Some id when id <> snd (split_dirpath dir) ->
- errorlabstrm "load_module"
- (str ("The file " ^ f ^ " contains module") ++ spc () ++
- pr_dirpath dir ++ spc () ++ str "and not module" ++ spc () ++
- pr_id id)
- | _ -> ()
-
-let locate_by_filename_only id f =
- let ch = with_magic_number_check raw_intern_module f in
- let md = System.marshal_in ch in
- let digest = System.marshal_in ch in
- close_in ch;
- (* Only the base name is expected to match *)
- check_module_short_name f md.md_name id;
- (* We check no other file containing same module is loaded *)
- try
- let m = CompUnitmap.find md.md_name !modules_table in
- Options.if_verbose warning
- ((string_of_dirpath md.md_name)^" is already loaded from file "^
- m.module_filename);
- (LibLoaded, md.md_name, m.module_filename)
- with Not_found ->
- compunit_cache := Stringmap.add f (md, digest) !compunit_cache;
- (LibInPath, md.md_name, f)
-
-let locate_module qid = function
- | Some f ->
- (* A name is specified, we have to check it contains module id *)
- let prefix, id = repr_qualid qid in
- assert (repr_dirpath prefix = []);
- let _, f = System.find_file_in_path (get_load_path ()) (f^".vo") in
- locate_by_filename_only (Some id) f
- | None ->
- (* No name, we need to find the file name *)
- try_locate_qualified_library qid
-
-let read_module qid =
- ignore (load_module (try_locate_qualified_library qid))
-
-let read_module_from_file f =
+let rec_intern_module_from_file qid f =
+ (* A name is specified, we have to check it contains module id *)
+ let prefix, id = repr_qualid qid in
+ assert (repr_dirpath prefix = []);
let _, f = System.find_file_in_path (get_load_path ()) (f^".vo") in
- ignore (load_module (locate_by_filename_only None f))
-(*
-let reload_module (modref, export) =
- let m = load_module modref in
- if export then m.module_exported <- true;
- open_module false m.module_name
-*)
+ rec_intern_by_filename_only (Some id) f
+
(*s [require_module] loads and opens a module. This is a synchronized
operation. *)
-type module_reference = (library_location * CompUnitmap.key * Util.Stringmap.key) * bool
+type module_reference = dir_path list * bool option
+
+let string_of_module (_,dir,_) = string_of_id (List.hd (repr_dirpath dir))
-let cache_require (_,(modref,export)) =
- let m = load_module modref in
- if export then m.module_exported <- true;
- open_module false m.module_name
+let cache_require (_,(modl,export)) =
+ let ml = list_map_left load_module modl in
+ match export with
+ | None -> ()
+ | Some export -> open_modules export ml
(* keeps the require marker for closed section replay but removes
OS dependent fields from .vo files for cross-platform compatibility *)
-let export_require ((a,b,_),e) = Some ((a,b,""),e)
+let export_require (l,e) = Some (List.map (fun d -> d) l,e)
let (in_require, out_require) =
declare_object
@@ -413,26 +481,53 @@ let (in_require, out_require) =
load_function = (fun _ -> ());
open_function = (fun _ -> ());
export_function = export_require })
-
-let require_module spec qid fileopt export =
-(* Trop contraignant
- if sections_are_opened () then
- warning ("Objets of "^name^" not surviving sections (e.g. Grammar \nand Hints) will be removed at the end of the section");
+
+let require_module spec qidl export =
+(*
+ if sections_are_opened () && Options.verbose () then
+ warning ("Objets of "^(string_of_module modref)^
+ " not surviving sections (e.g. Grammar \nand Hints)\n"^
+ "will be removed at the end of the section");
*)
- let modref = locate_module qid fileopt in
- add_anonymous_leaf (in_require (modref,export));
+ let modrefl = List.map rec_intern_qualified_library qidl in
+ add_anonymous_leaf (in_require (modrefl,Some export));
add_frozen_state ()
-let reload_module (modref, export) =
- add_anonymous_leaf (in_require (modref,export));
+let require_module_from_file spec qid file export =
+ let modref = rec_intern_module_from_file qid file in
+ add_anonymous_leaf (in_require ([modref],Some export));
+ add_frozen_state ()
+
+let import_module export qid =
+ let modref =
+ try
+ Nametab.locate_loaded_library qid
+ with Not_found ->
+ error ((Nametab.string_of_qualid qid)^" not loaded") in
+ add_anonymous_leaf (in_require ([modref],Some export))
+
+let read_module qid =
+ let modref = rec_intern_qualified_library qid in
+ add_anonymous_leaf (in_require ([modref],None));
+ add_frozen_state ()
+
+let read_module_from_file f =
+ let _, f = System.find_file_in_path (get_load_path ()) (f^".vo") in
+ let modref = rec_intern_by_filename_only None f in
+ add_anonymous_leaf (in_require ([modref],None));
+ add_frozen_state ()
+
+let reload_module (modrefl, export) =
+ add_anonymous_leaf (in_require (modrefl,export));
add_frozen_state ()
(*s [save_module s] saves the module [m] to the disk. *)
-let current_imports () =
- CompUnitmap.fold
- (fun _ m l -> (m.module_name, m.module_digest, m.module_exported) :: l)
- !modules_table []
+let current_deps () =
+ List.map (fun m -> (m.module_name, m.module_digest)) !modules_loaded_list
+
+let current_reexports () =
+ List.map (fun m -> m.module_name) !modules_exports_list
let save_module_to s f =
let seg = export_module s in
@@ -440,7 +535,8 @@ let save_module_to s f =
md_name = s;
md_compiled_env = Global.export s;
md_declarations = seg;
- md_deps = current_imports () } in
+ md_deps = current_deps ();
+ md_imports = current_reexports () } in
let (f',ch) = raw_extern_module f in
try
System.marshal_out ch md;
diff --git a/library/library.mli b/library/library.mli
index 3274f7361..5b51780e1 100644
--- a/library/library.mli
+++ b/library/library.mli
@@ -22,10 +22,10 @@ open Libobject
val read_module : Nametab.qualid -> unit
val read_module_from_file : System.physical_path -> unit
-val import_module : dir_path -> unit
+val import_module : bool -> Nametab.qualid -> unit
val module_is_loaded : dir_path -> bool
-val module_is_opened : string -> bool
+val module_is_opened : dir_path -> bool
val loaded_modules : unit -> dir_path list
val opened_modules : unit -> dir_path list
@@ -39,7 +39,10 @@ val fmt_modules_state : unit -> Pp.std_ppcmds
exported. *)
val require_module :
- bool option -> Nametab.qualid -> string option -> bool -> unit
+ bool option -> Nametab.qualid list -> bool -> unit
+
+val require_module_from_file :
+ bool option -> Nametab.qualid -> string -> bool -> unit
(*s [save_module_to s f] saves the current environment as a module [s]
in the file [f]. *)