123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379(************************************************************************)(* * The Coq Proof Assistant / The Coq Development Team *)(* v * Copyright INRIA, CNRS and contributors *)(* <O___,, * (see version control and CREDITS file for authors & dates) *)(* \VV/ **************************************************************)(* // * This file is distributed under the terms of the *)(* * GNU Lesser General Public License Version 2.1 *)(* * (see LICENSE file for the text of the license) *)(************************************************************************)openCErrorsopenUtilopenPpopenSystem(* Code to hook Coq into the ML toplevel -- depends on having the
objective-caml compiler mostly visible. The functions implemented here are:
\begin{itemize}
\item [dir_ml_load name]: Loads the ML module fname from the current ML
path.
\item [dir_ml_use]: Directive #use of Ocaml toplevel
\item [add_ml_dir]: Directive #directory of Ocaml toplevel
\end{itemize}
How to build an ML module interface with these functions.
The idea is that the ML directory path is like the Coq directory
path. So we can maintain the two in parallel.
In the same way, we can use the "ml_env" as a kind of ML
environment, which we freeze, unfreeze, and add things to just like
to the other environments.
Finally, we can create an object which is an ML module, and require
that the "caching" of the ML module cause the loading of the
associated ML file, if that file has not been yet loaded. Of
course, the problem is how to record dependencies between ML
modules.
(I do not know of a solution to this problem, other than to
put all the needed names into the ML Module object.) *)(* NB: this module relies on OCaml's Dynlink library. The bytecode version
of Dynlink is always available, but there are some architectures
with native compilation and no dynlink.cmxa. Instead of nasty IFDEF's
here for hiding the calls to Dynlink, we now simply reject this rather
rare situation during ./configure, and give instructions there about how
to build a dummy dynlink.cmxa, cf. dev/dynlink.ml. *)(* This path is where we look for .cmo *)letcoq_mlpath_copy=ref[Sys.getcwd()]letkeep_copy_mlpathpath=letcpath=CUnix.canonical_path_namepathinletfilterpath'=not(String.equalcpathpath')incoq_mlpath_copy:=cpath::List.filterfilter!coq_mlpath_copy(* If there is a toplevel under Coq *)typetoplevel={load_obj:string->unit;add_dir:string->unit;ml_loop:unit->unit}(* Determines the behaviour of Coq with respect to ML files (compiled
or not) *)typekind_load=|WithTopoftoplevel|WithoutTop(* Must be always initialized *)letload=refWithoutTop(* Sets and initializes a toplevel (if any) *)letset_toptoplevel=load:=WithToptoplevel;Nativelib.load_obj:=toplevel.load_obj(* Removes the toplevel (if any) *)letremove()=load:=WithoutTop;Nativelib.load_obj:=(funx->():string->unit)(* Tests if an Ocaml toplevel runs under Coq *)letis_ocaml_top()=match!loadwith|WithTop_->true|_->false(* Tests if we can load ML files *)lethas_dynlink=Coq_config.has_natdynlink||notSys.(backend_type=Native)(* Runs the toplevel loop of Ocaml *)letocaml_toploop()=match!loadwith|WithTopt->Printexc.catcht.ml_loop()|_->()(* Dynamic loading of .cmo/.cma *)(* We register errors at least for Dynlink, it is possible to do so Symtable
too, as we do in the bytecode init code.
*)let_=CErrors.register_handler(function|Dynlink.Errore->Some(hov0(str"Dynlink error: "++strDynlink.(error_messagee)))|_->None)letml_loads=(match!loadwith|WithTopt->t.load_objs|WithoutTop->Dynlink.loadfiles);sletdir_ml_loads=match!loadwith|WithTop_->ml_loads|WithoutTop->letwarn=not!Flags.quietinlet_,gname=find_file_in_path~warn!coq_mlpath_copysinml_loadgname(* Adds a path to the ML paths *)letadd_ml_dirs=match!loadwith|WithTopt->t.add_dirs;keep_copy_mlpaths|WithoutTopwhenhas_dynlink->keep_copy_mlpaths|_->()(* convertit un nom quelconque en nom de fichier ou de module *)letmod_of_namename=ifFilename.check_suffixname".cmo"thenFilename.chop_suffixname".cmo"elsenameletget_ml_object_suffixname=ifFilename.check_suffixname".cmo"thenSome".cmo"elseifFilename.check_suffixname".cma"thenSome".cma"elseifFilename.check_suffixname".cmxs"thenSome".cmxs"elseNoneletfile_of_namename=letsuffix=get_ml_object_suffixnameinletfails=user_err~hdr:"Mltop.load_object"(str"File not found on loadpath : "++strs++str"\n"++str"Loadpath: "++str(String.concat":"!coq_mlpath_copy))inifnot(Filename.is_relativename)thenifSys.file_existsnamethennameelsefailnameelseifSys.(backend_type=Native)then(* XXX: Dynlink.adapt_filename does the same? *)letname=matchsuffixwith|Some((".cmo"|".cma")assuffix)->(Filename.chop_suffixnamesuffix)^".cmxs"|Some".cmxs"->name|_->name^".cmxs"inifis_in_path!coq_mlpath_copynamethennameelsefailnameelselet(full,base)=matchsuffixwith|Some".cmo"|Some".cma"->true,name|Some".cmxs"->false,Filename.chop_suffixname".cmxs"|_->false,nameiniffullthenifis_in_path!coq_mlpath_copybasethenbaseelsefailbaseelseletname=base^".cma"inifis_in_path!coq_mlpath_copynamethennameelseletname=base^".cmo"inifis_in_path!coq_mlpath_copynamethennameelsefail(base^".cm[ao]")(** Is the ML code of the standard library placed into loadable plugins
or statically compiled into coqtop ? For the moment this choice is
made according to the presence of native dynlink : even if bytecode
coqtop could always load plugins, we prefer to have uniformity between
bytecode and native versions. *)(* [known_loaded_module] contains the names of the loaded ML modules
* (linked or loaded with load_object). It is used not to load a
* module twice. It is NOT the list of ML modules Coq knows. *)letknown_loaded_modules=refString.Map.emptyletadd_known_modulemnamepath=ifnot(String.Map.memmname!known_loaded_modules)||String.Map.findmname!known_loaded_modules=Nonethenknown_loaded_modules:=String.Map.addmnamepath!known_loaded_modulesletmodule_is_knownmname=String.Map.memmname!known_loaded_modulesletknown_module_pathmname=String.Map.findmname!known_loaded_modules(** A plugin is just an ML module with an initialization function. *)letknown_loaded_plugins=refString.Map.emptyletadd_known_plugininitname=add_known_modulenameNone;known_loaded_plugins:=String.Map.addnameinit!known_loaded_pluginsletinit_known_plugins()=String.Map.iter(fun_f->f())!known_loaded_plugins(** Registering functions to be used at caching time, that is when the Declare
ML module command is issued. *)letcache_objs=refString.Map.emptyletdeclare_cache_objfname=letobjs=tryString.Map.findname!cache_objswithNot_found->[]inletobjs=f::objsincache_objs:=String.Map.addnameobjs!cache_objsletperform_cache_objname=letobjs=tryString.Map.findname!cache_objswithNot_found->[]inletobjs=List.revobjsinList.iter(funf->f())objs(** ml object = ml module or plugin *)letinit_ml_objectmname=tryString.Map.findmname!known_loaded_plugins()withNot_found->()letload_ml_objectmname?pathfname=letpath=matchpathwith|None->dir_ml_loadfname|Somep->ml_loadpinadd_known_modulemname(Somepath);init_ml_objectmname;pathletadd_known_modulem=add_known_modulemNone(* Summary of declared ML Modules *)(* List and not String.Set because order is important: most recent first. *)letloaded_modules=ref[]letget_loaded_modules()=List.rev!loaded_modulesletadd_loaded_modulemdpath=ifnot(List.mem_assocmd!loaded_modules)thenloaded_modules:=(md,path)::!loaded_modulesletreset_loaded_modules()=loaded_modules:=[]letif_verbose_loadverbfname?pathfname=ifnotverbthenfname?pathfnameelseletinfo=str"[Loading ML file "++strfname++str" ..."intryletpath=fname?pathfnameinFeedback.msg_info(info++str" done]");pathwithreraise->Feedback.msg_info(info++str" failed]");raisereraise(** Load a module for the first time (i.e. dynlink it)
or simulate its reload (i.e. doing nothing except maybe
an initialization function). *)lettrigger_ml_objectverbcachereinit?pathname=ifmodule_is_knownnamethenbeginifreinittheninit_ml_objectname;add_loaded_modulename(known_module_pathname);ifcachethenperform_cache_objnameendelseifnothas_dynlinkthenuser_err~hdr:"Mltop.trigger_ml_object"(str"Dynamic link not supported (module "++strname++str")")elsebeginletfile=file_of_name(Option.defaultnamepath)inletpath=if_verbose_load(verb&¬!Flags.quiet)load_ml_objectname?pathfileinadd_loaded_modulename(Somepath);ifcachethenperform_cache_objnameendletunfreeze_ml_modulesx=reset_loaded_modules();List.iter(fun(name,path)->trigger_ml_objectfalsefalsefalse?pathname)xlet_=Summary.declare_ml_modules_summary{Summary.freeze_function=(fun~marshallable->get_loaded_modules());Summary.unfreeze_function=unfreeze_ml_modules;Summary.init_function=reset_loaded_modules}(* Liboject entries of declared ML Modules *)(* Digest of module used to compile the file *)typeml_module_digest=|NoDigest|AnyDigestofDigest.t(* digest of any used cma / cmxa *)typeml_module_object={mlocal:Vernacexpr.locality_flag;mnames:(string*ml_module_digest)list}letadd_module_digestm=ifnothas_dynlinkthenm,NoDigestelsetryletfile=file_of_nameminletpath,file=System.where_in_path~warn:false!coq_mlpath_copyfileinm,AnyDigest(Digest.filefile)with|Not_found->m,NoDigestletcache_ml_objects(_,{mnames=mnames})=letiter(obj,_)=trigger_ml_objecttruetruetrueobjinList.iteritermnamesletload_ml_objects_(_,{mnames=mnames})=letiter(obj,_)=trigger_ml_objecttruefalsetrueobjinList.iteritermnamesletclassify_ml_objects({mlocal=mlocal}aso)=ifmlocalthenLibobject.DisposeelseLibobject.SubstituteoletinMLModule:ml_module_object->Libobject.obj=letopenLibobjectindeclare_object{(default_object"ML-MODULE")withcache_function=cache_ml_objects;load_function=load_ml_objects;subst_function=(fun(_,o)->o);classify_function=classify_ml_objects}letdeclare_ml_moduleslocall=letl=List.mapmod_of_namelinletl=List.mapadd_module_digestlinLib.add_anonymous_leaf~cache_first:false(inMLModule{mlocal=local;mnames=l})letprint_ml_path()=letl=!coq_mlpath_copyinstr"ML Load Path:"++fnl()++str" "++hv0(prlist_with_sepfnlstrl)(* Printing of loaded ML modules *)letprint_ml_modules()=letl=get_loaded_modules()instr"Loaded ML Modules: "++pr_vertical_liststr(List.mapfstl)letprint_gc()=letstat=Gc.stat()inletmsg=str"minor words: "++realstat.Gc.minor_words++fnl()++str"promoted words: "++realstat.Gc.promoted_words++fnl()++str"major words: "++realstat.Gc.major_words++fnl()++str"minor_collections: "++intstat.Gc.minor_collections++fnl()++str"major_collections: "++intstat.Gc.major_collections++fnl()++str"heap_words: "++intstat.Gc.heap_words++fnl()++str"heap_chunks: "++intstat.Gc.heap_chunks++fnl()++str"live_words: "++intstat.Gc.live_words++fnl()++str"live_blocks: "++intstat.Gc.live_blocks++fnl()++str"free_words: "++intstat.Gc.free_words++fnl()++str"free_blocks: "++intstat.Gc.free_blocks++fnl()++str"largest_free: "++intstat.Gc.largest_free++fnl()++str"fragments: "++intstat.Gc.fragments++fnl()++str"compactions: "++intstat.Gc.compactions++fnl()++str"top_heap_words: "++intstat.Gc.top_heap_words++fnl()++str"stack_size: "++intstat.Gc.stack_sizeinhv0msg