123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156(*
* Copyright (c) 2013
* Gabriel Kerneis <gabriel@kerneis.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. The names of the contributors may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*)openCilmoduleE=ErrormsgmoduleD=DynlinkmoduleF=Findlibtypet={mutablefd_enabled:bool;fd_name:string;fd_description:string;fd_extraopt:(string*Arg.spec*string)list;fd_doit:(file->unit);fd_post_check:bool;}letfeatures=ref[]letsame_namesf=s=f.fd_nameletregisterf=ifList.exists(same_namef.fd_name)!featuresthenE.s(E.error"Feature %s is already registered"f.fd_name)elsefeatures:=!features@[f]letlist_registered()=!featuresletfinds=List.find(same_names)!featuresletregistereds=tryignore(finds);truewithNot_found->falseletenableds=try(finds).fd_enabledwithNot_found->falseletenables=tryletf=findsinf.fd_enabled<-truewithNot_found->E.s(E.error"cannot enable feature %s: not found"s)(** Dynamic linking *)letloads=tryD.allow_unsafe_modulestrue;D.loadfileswithD.Errore->E.s(E.error"%s"(D.error_messagee))(** Findlib magic *)letinitialized=reffalseletinit()=ifnot!initializedthenbeginF.init();initialized:=trueendletadapt_filenamef=tryD.adapt_filenamefwith_->fletfindlib_lookuppkg=tryletpreds=[ifD.is_nativethen"native"else"byte";"plugin"]inletcil_deps=F.package_deep_ancestorspreds["goblint-cil"]inletdeps=F.package_deep_ancestorspreds[pkg]inletdeps=List.filter(funx->not(List.memxcil_deps))depsinletfind_modulespkg=letbase=F.package_directorypkginletarchives=tryF.package_propertypredspkg"archive"(* some packages have dependencies but no archive *)withNot_found->""inletmodules=List.filter((<>)"")(Str.split(Str.regexp"[ ,]+")archives)inList.map(funm->F.resolve_path~base(adapt_filenamem))modulesinletfiles=List.mapfind_modulesdepsinList.flattenfileswith|F.No_such_package(pkg,msg)->E.s(E.error"findlib: no such package %s.\n%s"pkgmsg)|F.Package_looppkg->E.s(E.error"findlib: package loop for %s."pkg)letfind_plugins=ifs=""thenE.s(E.error"missing module name")elselets_resolve=adapt_filename(tryF.resolve_pathswith_->s)inifSys.file_existss_resolve&¬(Sys.is_directorys_resolve)then[s_resolve]elsefindlib_lookups(** List of loaded modules *)letplugins=ref[](** Add a single plugin, except if we have added it already *)letadd_pluginpath=ifnot(List.mempath!plugins)thenloadpath;plugins:=path::!plugins(** Look for plugin and dependencies and add them *)letloadWithDepss=letpaths=find_pluginsinList.iteradd_pluginpaths(** Parse only {switch} command-line option, ignoring every error raised by other, unparsed
* options. Return the list of plugins to load. *)letloadFromArgvswitch=letspec=[switch,Arg.StringloadWithDeps,"";(* ignore --help at this stage *)"--help",Arg.Unitignore,"";"-help",Arg.Unitignore,""]inletidx=ref0inletrecaux()=tryArg.parse_argv~current:idxSys.argvspecignore""withArg.Bad_|Arg.Help_->aux()ininit();aux()letloadFromEnvnamedefault=letplugins=tryStr.split(Str.regexp"[ ,]+")(Sys.getenvname)withNot_found->defaultinList.iterloadWithDepsplugins