123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279(************************************************************************)(* * 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) *)(************************************************************************)openUtilmoduleDP=Names.DirPath(** Load paths. Mapping from physical to logical paths. *)typet={path_physical:CUnix.physical_path;path_logical:DP.t;path_implicit:bool;}letload_paths=Summary.ref([]:tlist)~name:"LOADPATHS"letlogicalp=p.path_logicalletphysicalp=p.path_physicalletppp=letdir=DP.printp.path_logicalinletpath=Pp.str(CUnix.escaped_string_of_physical_pathp.path_physical)inPp.(hov2(dir++spc()++path))letget_load_paths()=!load_pathsletanomaly_too_many_pathspath=CErrors.anomalyPp.(str"Several logical paths are associated to"++spc()++strpath++str".")letfind_load_pathphys_dir=letphys_dir=CUnix.canonical_path_namephys_dirinletfilterp=String.equalp.path_physicalphys_dirinletpaths=List.filterfilter!load_pathsinmatchpathswith|[]->raiseNot_found|[p]->p|_->anomaly_too_many_pathsphys_dirletremove_load_pathdir=letfilterp=not(String.equalp.path_physicaldir)inload_paths:=List.filterfilter!load_pathsletwarn_overriding_logical_loadpath=CWarnings.create~name:"overriding-logical-loadpath"~category:"loadpath"(fun(phys_path,old_path,coq_path)->Pp.(seq[strphys_path;strbrk" was previously bound to ";DP.printold_path;strbrk"; it is remapped to ";DP.printcoq_path]))letadd_load_pathphys_pathcoq_path~implicit=letphys_path=CUnix.canonical_path_namephys_pathinletfilterp=String.equalp.path_physicalphys_pathinletbinding={path_logical=coq_path;path_physical=phys_path;path_implicit=implicit;}inmatchList.filterfilter!load_pathswith|[]->load_paths:=binding::!load_paths|[{path_logical=old_path;path_implicit=old_implicit}]->letreplace=ifDP.equalcoq_pathold_paththenimplicit<>old_implicitelselet()=(* Do not warn when overriding the default "-I ." path *)ifnot(DP.equalold_pathLibnames.default_root_prefix)thenwarn_overriding_logical_loadpath(phys_path,old_path,coq_path)intrueinifreplacethenbeginremove_load_pathphys_path;load_paths:=binding::!load_paths;end|_->anomaly_too_many_pathsphys_pathletfilter_pathf=letrecaux=function|[]->[]|p::l->iffp.path_logicalthen(p.path_physical,p.path_logical)::auxlelseauxlinaux!load_pathsletexpand_path?rootdir=letrecaux=function|[]->[]|{path_physical=ph;path_logical=lg;path_implicit=implicit}::l->letsuccess=matchrootwith|None->ifimplicitthenLibnames.is_dirpath_suffix_ofdirlgelseDP.equaldirlg|Someroot->Libnames.(is_dirpath_prefix_ofrootlg&&is_dirpath_suffix_ofdir(drop_dirpath_prefixrootlg))inifsuccessthen(ph,lg)::auxlelseauxlinaux!load_pathsletlocate_filefname=letpaths=List.mapphysical!load_pathsinlet_,longfname=System.find_file_in_path~warn:(not!Flags.quiet)pathsfnameinlongfname(************************************************************************)(*s Locate absolute or partially qualified library names in the path *)typelibrary_location=LibLoaded|LibInPathtypelocate_error=LibUnmappedDir|LibNotFoundtype'alocate_result=('a,locate_error)resultletwarn_several_object_files=CWarnings.create~name:"several-object-files"~category:"require"Pp.(fun(vi,vo)->seq[str"Loading";spc();strvi;strbrk" instead of ";strvo;strbrk" because it is more recent"])letselect_vo_file~warnloadpathbase=letfindext=letloadpath=List.mapfstloadpathintryletname=Names.Id.to_stringbase^extinletlpath,file=System.where_in_path~warnloadpathnameinSome(lpath,file)withNot_found->Nonein(* If [!Flags.load_vos_libraries]
and the .vos file exists
and this file is not empty
Then load this library
Else load the most recent between the .vo file and the .vio file,
or if there is only of the two files, take this one,
or raise an error if both are missing. *)letload_most_recent_of_vo_and_vio()=matchfind".vo",find".vio"with|None,None->ErrorLibNotFound|Someres,None|None,Someres->Okres|Some(_,vo),Some(_,viasresvi)whenUnix.((statvo).st_mtime<(statvi).st_mtime)->warn_several_object_files(vi,vo);Okresvi|Someresvo,Some_->Okresvoinif!Flags.load_vos_librariesthenbeginmatchfind".vos"with|Some(_,vosasresvos)when(Unix.statvos).Unix.st_size>0->Okresvos|_->load_most_recent_of_vo_and_vio()endelseload_most_recent_of_vo_and_vio()letlocate_absolute_librarydir:CUnix.physical_pathlocate_result=(* Search in loadpath *)letpref,base=Libnames.split_dirpathdirinletloadpath=filter_path(fundir->DP.equaldirpref)inmatchloadpathwith|[]->ErrorLibUnmappedDir|_->matchselect_vo_file~warn:falseloadpathbasewith|Ok(_,file)->Okfile|Errorfail->Errorfailletlocate_qualified_library?root?(warn=true)qid:(library_location*DP.t*CUnix.physical_path)locate_result=(* Search library in loadpath *)letdir,base=Libnames.repr_qualidqidinletloadpath=expand_path?rootdirinmatchloadpathwith|[]->ErrorLibUnmappedDir|_->matchselect_vo_file~warnloadpathbasewith|Ok(lpath,file)->letdir=Libnames.add_dirpath_suffix(CString.List.assoclpathloadpath)basein(* Look if loaded *)ifLibrary.library_is_loadeddirthenOk(LibLoaded,dir,Library.library_full_filenamedir)(* Otherwise, look for it in the file system *)elseOk(LibInPath,dir,file)|Errorfail->Errorfailleterror_unmapped_dirqid=letprefix,_=Libnames.repr_qualidqidinCErrors.user_err~hdr:"load_absolute_library_from"Pp.(seq[str"Cannot load ";Libnames.pr_qualidqid;str":";spc();str"no physical path bound to";spc();DP.printprefix;fnl()])leterror_lib_not_foundqid=letvos=!Flags.load_vos_librariesinletvos_msg=ifvosthen[Pp.str" (while searching for a .vos file)"]else[]inCErrors.user_err~hdr:"load_absolute_library_from"Pp.(seq([str"Cannot find library ";Libnames.pr_qualidqid;str" in loadpath"]@vos_msg))lettry_locate_absolute_librarydir=matchlocate_absolute_librarydirwith|Okres->res|ErrorLibUnmappedDir->error_unmapped_dir(Libnames.qualid_of_dirpathdir)|ErrorLibNotFound->error_lib_not_found(Libnames.qualid_of_dirpathdir)(** { 5 Extending the load path } *)typevo_path={unix_path:string(** Filesystem path containing vo/ml files *);coq_path:DP.t(** Coq prefix for the path *);implicit:bool(** [implicit = true] avoids having to qualify with [coq_path] *);has_ml:bool(** If [has_ml] is true, the directory will also be added to the ml include path *);recursive:bool(** [recursive] will determine whether we explore sub-directories *)}letwarn_cannot_open_path=CWarnings.create~name:"cannot-open-path"~category:"filesystem"(fununix_path->Pp.(str"Cannot open "++strunix_path))letwarn_cannot_use_directory=CWarnings.create~name:"cannot-use-directory"~category:"filesystem"(fund->Pp.(str"Directory "++strd++strbrk" cannot be used as a Coq identifier (skipped)"))letconvert_stringd=tryNames.Id.of_stringdwith|CErrors.UserError_->letd=Unicode.escaped_if_non_utf8dinwarn_cannot_use_directoryd;raiseExitletadd_vo_pathlp=letunix_path=lp.unix_pathinletimplicit=lp.implicitinletrecursive=lp.recursiveinifSystem.exists_dirunix_paththenletdirs=ifrecursivethenSystem.all_subdirs~unix_pathelse[]inletprefix=DP.reprlp.coq_pathinletconvert_dirs(lp,cp)=tryletpath=List.rev_mapconvert_stringcp@prefixinSome(lp,DP.makepath)withExit->Noneinletdirs=List.map_filterconvert_dirsdirsinlet()=iflp.has_ml&¬lp.recursivethenMltop.add_ml_dirunix_pathelseiflp.has_ml&&lp.recursivethen(List.iter(fun(lp,_)->Mltop.add_ml_dirlp)dirs;Mltop.add_ml_dirunix_path)else()inletadd(path,dir)=add_load_pathpath~implicitdirinlet()=List.iteradddirsinadd_load_pathunix_path~implicitlp.coq_pathelsewarn_cannot_open_pathunix_path