123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164(******************************************************************************)(* OASIS: architecture for building OCaml libraries and applications *)(* *)(* Copyright (C) 2011-2016, Sylvain Le Gall *)(* Copyright (C) 2008-2011, OCamlCore SARL *)(* *)(* This library is free software; you can redistribute it and/or modify it *)(* under the terms of the GNU Lesser General Public License as published by *)(* the Free Software Foundation; either version 2.1 of the License, or (at *)(* your option) any later version, with the OCaml static compilation *)(* exception. *)(* *)(* This library is distributed in the hope that it will be useful, but *)(* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *)(* or FITNESS FOR A PARTICULAR PURPOSE. See the file COPYING for more *)(* details. *)(* *)(* You should have received a copy of the GNU Lesser General Public License *)(* along with this library; if not, write to the Free Software Foundation, *)(* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *)(******************************************************************************)(** Build using ocamlbuild
@author Sylvain Le Gall
*)openOASISTypesopenOASISGettextopenOASISUtilsopenOASISStringopenBaseEnvopenOCamlbuildCommonopenBaseStandardVarletcond_targets_hook=ref(funlst->lst)letbuild~ctxtargspkgargv=(* Return the filename in build directory *)letin_build_dirfn=Filename.concat(build_dirargv)fnin(* Return the unix filename in host build directory *)letin_build_dir_of_unixfn=in_build_dir(OASISHostPath.of_unixfn)inletcond_targets=List.fold_left(funacc->function|Library(cs,bs,lib)whenvar_choosebs.bs_build->beginletevs,unix_files=BaseBuilt.of_libraryin_build_dir_of_unix(cs,bs,lib)inlettgts=List.flatten(List.filter(funl->l<>[])(List.map(List.filter(funfn->ends_with~what:".cma"fn||ends_with~what:".cmxs"fn||ends_with~what:".cmxa"fn||ends_with~what:(ext_lib())fn||ends_with~what:(ext_dll())fn))unix_files))inmatchtgtswith|_::_->(evs,tgts)::acc|[]->failwithf(f_"No possible ocamlbuild targets for library %s")cs.cs_nameend|Object(cs,bs,obj)whenvar_choosebs.bs_build->beginletevs,unix_files=BaseBuilt.of_objectin_build_dir_of_unix(cs,bs,obj)inlettgts=List.flatten(List.filter(funl->l<>[])(List.map(List.filter(funfn->ends_with~what:".cmo"fn||ends_with~what:".cmx"fn))unix_files))inmatchtgtswith|_::_->(evs,tgts)::acc|[]->failwithf(f_"No possible ocamlbuild targets for object %s")cs.cs_nameend|Executable(cs,bs,exec)whenvar_choosebs.bs_build->beginletevs,_,_=BaseBuilt.of_executablein_build_dir_of_unix(cs,bs,exec)inlettargetext=letunix_tgt=(OASISUnixPath.concatbs.bs_path(OASISUnixPath.chop_extensionexec.exec_main_is))^extinletevs=(* Fix evs, we want to use the unix_tgt, without copying *)List.map(function|BaseBuilt.BExec,nm,_whennm=cs.cs_name->BaseBuilt.BExec,nm,[[in_build_dir_of_unixunix_tgt]]|ev->ev)evsinevs,[unix_tgt]in(* Add executable *)letacc=matchbs.bs_compiled_objectwith|Native->(target".native")::acc|Bestwhenbool_of_string(is_native())->(target".native")::acc|Byte|Best->(target".byte")::accinaccend|Library_|Object_|Executable_|Test_|SrcRepo_|Flag_|Doc_->acc)[](* Keep the pkg.sections ordered *)(List.revpkg.sections);in(* Check and register built files *)letcheck_and_register(bt,bnm,lst)=List.iter(funfns->ifnot(List.existsOASISFileUtil.file_exists_casefns)thenfailwithf(fn_"Expected built file %s doesn't exist.""None of expected built files %s exists."(List.lengthfns))(String.concat(s_" or ")(List.map(Printf.sprintf"'%s'")fns)))lst;(BaseBuilt.register~ctxtbtbnmlst)in(* Run the hook *)letcond_targets=!cond_targets_hookcond_targetsin(* Run a list of target... *)run_ocamlbuild~ctxt{argswithextra=List.flatten(List.mapsndcond_targets)@args.extra}argv;(* ... and register events *)List.itercheck_and_register(List.flatten(List.mapfstcond_targets))letclean~ctxtpkgargs=run_clean~ctxtargs;List.iter(function|Library(cs,_,_)->BaseBuilt.unregister~ctxtBaseBuilt.BLibcs.cs_name|Executable(cs,_,_)->BaseBuilt.unregister~ctxtBaseBuilt.BExeccs.cs_name;BaseBuilt.unregister~ctxtBaseBuilt.BExecLibcs.cs_name|_->())pkg.sections(* END EXPORT *)openOASISFileTemplateopenOASISUtilsopenOASISMessageopenOASISGettextopenOASISPluginopenOASISTypesopenMyOCamlbuildBaseopenOcamlbuild_pluginopenOCamlbuildIdletplugin=`Build,name,Someversionletself_id,all_id=Build.createpluginletpure_interface_test=OASISFeatures.package_test(OASISFeatures.create"pure_interface"~pluginOASISFeatures.alpha(fun()->s_"Allow to have module with only .mli file."))letpivot_data=data_new_propertypluginletonly_h_fileslst=List.filter(funfn->OASISUnixPath.check_extensionfn"h")lstletonly_c_fileslst=List.filter(funfn->OASISUnixPath.check_extensionfn"c")lstletadd_tagstag_ttgtstags=letquote_targetfn=lettest_char=String.containsfniniftest_char'*'||test_char'?'||test_char'{'||test_char'['then"<"^fn^">"else"\""^fn^"\""inList.fold_left(funtag_ttgt->List.fold_left(funtag_ttag->((quote_targettgt)^": "^tag)::tag_t)tag_ttags)tag_ttgtsletprepend_bs_pathbsfn=Tag.filename_concatbs.bs_pathfnletbs_pathsbsfiles=letsubdirs=List.rev_mapOASISUnixPath.dirname(List.rev_map(prepend_bs_pathbs)files)in(* Unique elements *)SetString.elements(SetString.of_list(List.rev_mapOASISUnixPath.reduce(bs.bs_path::subdirs)))letbs_tagspkgsctcsbssrc_dirssrc_internal_dirslink_tgtctxttag_tmyocamlbuild_t=letlink_pkg=(* Only link findlib package with executable *)matchsctwith|Executable_->true|Library_|Object_|Flag_|Test_|SrcRepo_|Doc_->falseinletsrc_tgts=List.rev_append(* .ml files *)(List.rev_map(fundn->Tag.filename_concatdn"*.ml{,i,y}")(src_dirs@src_internal_dirs))(* .c files *)(List.map(prepend_bs_pathbs)(only_c_filesbs.bs_c_sources))inletclib_tgts=ifbs.bs_c_sources<>[]then(List.rev_map(funfmt->(prepend_bs_pathbs)(Printf.sprintffmtcs.cs_name))[(* Unix *)"dll%s_stubs.so";"lib%s_stubs.a";(* Win32 *)"dll%s_stubs.dll";"lib%s_stubs.lib";])else[]in(* Manipulate ocamlbuild's spec *)letatoms=Asinletpaths=Psinletmkspecpre_argtr_arglst=S(List.fold_left(funaccarg->matchpre_argwith|Somes->s::arg::acc|None->arg::acc)[](List.rev_maptr_arglst))in(* Create flag for extra command line option *)letctxt,tag_t,myocamlbuild_t=List.fold_left(fun((ctxt,tag_t,myocamlbuild_t)asacc)(basename,tgts,tags,pre_arg,tr_arg,args_cond)->ifargs_cond<>[OASISExpr.EBooltrue,[]]thenbeginlettag_name=(* e.g. oasis_library_foo_ccopt *)varname_concat"oasis_"(varname_concat(varname_of_string(OASISSection.string_of_sectionsct))basename)inletall_tags=tag_name::tagsinletcond_specs=List.map(fun(cond,lst)->cond,mkspecpre_argtr_arglst)args_condinletflags=(all_tags,cond_specs)::myocamlbuild_t.flagsinlettag_t=add_tagstag_ttgts[tag_name]inctxt,tag_t,{myocamlbuild_twithflags=flags}endelsebeginaccend)(ctxt,tag_t,myocamlbuild_t)(["ccopt",src_tgts,["compile"],Some(A"-ccopt"),atom,bs.bs_ccopt;"cclib",[link_tgt],["link"],Some(A"-cclib"),atom,bs.bs_cclib;"cclib",clib_tgts,["ocamlmklib";"c"],None,atom,bs.bs_cclib;"dlllib",[link_tgt],["link";"byte"],Some(A"-dllib"),path,bs.bs_dlllib;"dllpath",[link_tgt],["link";"byte"],Some(A"-dllpath"),path,bs.bs_dllpath;"dllpath",clib_tgts,["ocamlmklib";"c"],Some(A"-dllpath"),path,bs.bs_dllpath;]@(List.fold_left(funaccflg->("byte",link_tgt::src_tgts,["ocaml";flg;"byte"],None,atom,bs.bs_byteopt)::("native",link_tgt::src_tgts,["ocaml";flg;"native"],None,atom,bs.bs_nativeopt)::acc)[]["compile";"ocamldep";"link"]))in(* Add tag for dependency on C part of the library *)letctxt,tag_t,myocamlbuild_t=ifbs.bs_c_sources<>[]thenbegin(* Generate .clib files *)letfn_clib=OASISHostPath.add_extension(prepend_bs_pathbs("lib"^(nm_libstubscs.cs_name)))"clib"inadd_file(template_makefn_clibcomment_ocamlbuild[](List.map(funfn->(Filename.chop_extensionfn)^".o")(only_c_filesbs.bs_c_sources))[])ctxt,add_tagstag_t[link_tgt][tag_libstubscs.cs_name],{myocamlbuild_twithlib_c=((cs.cs_name,bs.bs_path,List.map(funfn->prepend_bs_pathbsfn)(only_h_filesbs.bs_c_sources))::myocamlbuild_t.lib_c)}endelsectxt,tag_t,myocamlbuild_tin(* Add build depends tags *)lettag_t=letmp=OASISBuildSection.transitive_build_dependspkginletsupports_ocamlfind=ocamlbuild_supports_ocamlfindpkginadd_tagstag_t(iflink_pkgthenlink_tgt::src_tgtselsesrc_tgts)(List.sortString.compare(List.fold_left(funacc->function|FindlibPackage(findlib_pkg,_)->(ifsupports_ocamlfindthen("package("^findlib_pkg^")")else("pkg_"^findlib_pkg))::acc|InternalLibrarynm->("use_"^nm)::acc)[](OASISSection.MapSection.findsctmp)))inletctxt=(* TODO: merge with qstr_cmplt *)set_error(not(List.mem(ExternalTool"ocamlbuild")bs.bs_build_tools))(Printf.sprintf(f_"ocamlbuild in field BuildTools of %s is mandatory")(OASISSection.string_of_sectionsct))ctxtinctxt,tag_t,myocamlbuild_tmoduleMapDirs=Map.Make(structtypet=[`Libraryofstring|`Objectofstring|`Executableofstring]letcomparet1t2=matcht1,t2with|`Library_,`Executable_|`Library_,`Object_|`Object_,`Executable_->-1|`Object_,`Library_|`Executable_,`Library_|`Executable_,`Object_->1|`Librarys1,`Librarys2|`Objects1,`Objects2|`Executables1,`Executables2->String.compares1s2end)letcompute_map_dirspkg=letaddkdirsinternal_dirsmp=letsrc_dirs,src_internal_dirs=tryMapDirs.findkmpwithNot_found->SetString.empty,SetString.emptyinletadd_dirsstdirs=SetString.add_liststdirsinMapDirs.addk(add_dirssrc_dirsdirs,add_dirssrc_internal_dirsinternal_dirs)mpinletmap_dirs=List.fold_left(funmp->function|Library(cs,bs,lib)->add(`Librarycs.cs_name)(* All paths accessed from within the library *)(bs_pathsbslib.lib_modules)(* All paths accessed only by the library *)(bs_pathsbslib.lib_internal_modules)mp|Object(cs,bs,obj)->add(`Objectcs.cs_name)(* All paths accessed from within the (potentially packed)
object *)(bs_pathsbsobj.obj_modules)[](* No internal paths *)mp|Executable(cs,bs,exec)->add(`Executablecs.cs_name)(bs_pathsbs[exec.exec_main_is])[](* No internal paths *)mp|Flag_|SrcRepo_|Test_|Doc_->mp)MapDirs.emptypkg.sectionsin(* Now get rid of internal paths that are also non internal. *)MapDirs.map(fun(src_dirs,src_internal_dirs)->SetString.elementssrc_dirs,SetString.elements(SetString.diffsrc_internal_dirssrc_dirs))map_dirsletcompute_includesmap_dirspkg=letadd_includesdirset_dirsincludes=(* Not self-dependent *)letset_dirs=SetString.diffset_dirs(SetString.singletondir)inletpre_dirs=tryMapString.finddirincludeswithNot_found->SetString.emptyinMapString.adddir(SetString.unionset_dirspre_dirs)includesinletadd_map_dirskbsincludes=letdep_dirs=(* Source dirs of dependent libraries *)List.fold_left(funset->function|InternalLibrarynm->letsrc_dirs,_=tryMapDirs.find(`Librarynm)map_dirswithNot_found->MapDirs.find(`Objectnm)map_dirsinSetString.add_listsetsrc_dirs|FindlibPackage_->set)SetString.emptybs.bs_build_dependsinletself_dirs=(* Source dirs *)letsrc_dirs,src_internal_dirs=MapDirs.findkmap_dirsinSetString.add_list(SetString.of_listsrc_dirs)src_internal_dirsinletall_dirs=SetString.uniondep_dirsself_dirsinletall_dirs=(* No need to include the current dir. *)SetString.filter(fundn->not(OASISUnixPath.is_current_dirdn))all_dirsin(* All self_dirs depends on all_dirs *)SetString.fold(fundirincludes->add_includesdirall_dirsincludes)self_dirsincludesinletincludes=List.fold_left(funincludes->function|Library(cs,bs,_)->add_map_dirs(`Librarycs.cs_name)bsincludes|Object(cs,bs,_)->add_map_dirs(`Objectcs.cs_name)bsincludes|Executable(cs,bs,_)->add_map_dirs(`Executablecs.cs_name)bsincludes|Flag_|SrcRepo_|Test_|Doc_->includes)MapString.emptypkg.sectionsinMapString.fold(fundirinclude_dirsacc->ifSetString.empty<>include_dirsthen(dir,SetString.elementsinclude_dirs)::accelseacc)includes[](* Check if the given files list only contains .mli. *)letis_pure_interface(base_fn,fn_lst)=letrecis_pure_interface_aux=(* TODO: this needs to be refine because sometime we don't have the .ml file
* because it is generated (BaseData.ml) but we have the .mli.
*)function|[fn]->OASISString.ends_with~what:".mli"fn|fn::tl->OASISString.ends_with~what:".mli"fn&&is_pure_interface_auxtl|[]->falseinis_pure_interface_auxfn_lstletadd_ocamlbuild_filesctxtpkg=letmap_dirs=compute_map_dirspkginletctxt,tag_t,myocamlbuild_t=List.fold_left(fun(ctxt,tag_t,myocamlbuild_t)->function|Library(cs,bs,lib)assct->begin(* Extract content for libraries *)(* All paths of the library *)letsrc_dirs,src_internal_dirs=MapDirs.find(`Librarycs.cs_name)map_dirsin(* Generated library *)lettarget_lib=letext=matchbs.bs_compiled_objectwith|Best->"{cma,cmxa}"|Byte->"cma"|Native->"cmxa"inprepend_bs_pathbs(OASISUnixPath.add_extensioncs.cs_nameext)in(* Start comment *)lettag_t=(Printf.sprintf"# Library %s"cs.cs_name)::tag_tin(* Sources of the library. *)letsources=OASISLibrary.source_unix_files~ctxt:ctxt.ctxt(cs,bs,lib)(funufn->OASISFileUtil.file_exists_case(OASISHostPath.of_unixufn))inletintf_module_list,impl_module_list=letto_module(base_fn,_)=OASISString.capitalize_ascii(Filename.basenamebase_fn)inletintf_module_list=ifpure_interface_testpkgthenList.mapto_module(List.filteris_pure_interfacesources)else[]inList.partition(funmodul->List.memmodulintf_module_list)(lib.lib_modules@lib.lib_internal_modules)in(* Add dependency of cmxs to their own library: used
at link time when there is C code *)lettag_t=add_tagstag_t[prepend_bs_pathbs(OASISUnixPath.add_extensioncs.cs_name"cmxs")]["use_"^cs.cs_name]inlettag_t=iflib.lib_packthenadd_tagstag_t(List.rev_map(fun(base_fn,_)->OASISUnixPath.add_extensionbase_fn"cmx")sources)["for-pack("^OASISString.capitalize_asciics.cs_name^")"]elsetag_tinletctxt,tag_t,myocamlbuild_t=bs_tagspkgsctcsbssrc_dirssrc_internal_dirstarget_libctxttag_tmyocamlbuild_tinletmyocamlbuild_t={myocamlbuild_twithlib_ocaml=(cs.cs_name,List.filter(funfn->not(OASISUnixPath.is_currentfn))src_dirs,intf_module_list)::myocamlbuild_t.lib_ocaml}inlet()=iflib.lib_modules=[]thenwarning~ctxt:ctxt.ctxt(f_"No exported module defined for library %s")cs.cs_name;inletctxt=(* Generate .mllib *)letfn_base=prepend_bs_pathbscs.cs_nameinletmllib=OASISHostPath.add_extensionfn_base"mllib"inletmldylib=OASISHostPath.add_extensionfn_base"mldylib"inletmlpack=OASISHostPath.add_extensionfn_base"mlpack"inletmllib_template_lines=(* mllib contains either the name of the pack or the list
* of modules. *)iflib.lib_packthen[OASISString.capitalize_asciics.cs_name]elseimpl_module_listinletctxt=add_file(template_makemllibcomment_ocamlbuild[]mllib_template_lines[])ctxtinletctxt=add_file(template_makemldylibcomment_ocamlbuild[]mllib_template_lines[])ctxtiniflib.lib_packthenbegin(* generate .mlpack for packed libraries *)add_file(template_makemlpackcomment_ocamlbuild[]impl_module_list[])ctxtendelsebegin(* make sure there is no conflicting mlpack file *){ctxtwithother_actions=(fun()->ifOASISFileUtil.file_exists_casemlpackthenOASISMessage.error~ctxt:ctxt.ctxt(f_"Conflicting file '%s' and '%s' \
exists, remove '%s'.")mllibmlpackmlpack)::ctxt.other_actions}endinctxt,tag_t,myocamlbuild_tend|Object(cs,bs,obj)assct->begin(* Extract content for objects *)(* All paths of the library *)letsrc_dirs,src_internal_dirs=MapDirs.find(`Objectcs.cs_name)map_dirsin(* Generated library *)lettarget_lib=letext=matchbs.bs_compiled_objectwith|Best->"{cmo,cmx}"|Byte->"cmo"|Native->"cmx"inprepend_bs_pathbs(OASISUnixPath.add_extensioncs.cs_nameext)in(* Start comment *)lettag_t=(Printf.sprintf"# Object %s"cs.cs_name)::tag_tinlettag_t=ifList.lengthobj.obj_modules<>1thenletbase_sources=OASISObject.source_unix_files~ctxt:ctxt.ctxt(cs,bs,obj)(funufn->OASISFileUtil.file_exists_case(OASISHostPath.of_unixufn))inadd_tagstag_t(List.rev_map(fun(base_fn,_)->OASISUnixPath.add_extensionbase_fn"cmx")base_sources)["for-pack("^OASISString.capitalize_asciics.cs_name^")"]elsetag_tinletctxt,tag_t,myocamlbuild_t=bs_tagspkgsctcsbssrc_dirssrc_internal_dirstarget_libctxttag_tmyocamlbuild_tinletmyocamlbuild_t={myocamlbuild_twithlib_ocaml=(cs.cs_name,List.filter(funfn->not(OASISUnixPath.is_currentfn))src_dirs,[])::myocamlbuild_t.lib_ocaml}inlet()=ifobj.obj_modules=[]thenwarning~ctxt:ctxt.ctxt(f_"No exported module defined for object %s")cs.cs_name;inletctxt=matchobj.obj_moduleswith|[_]->ctxt|_->(* generate mlpack file *)letfn_base=prepend_bs_pathbscs.cs_nameinletfn=OASISHostPath.add_extensionfn_base"mlpack"andnot_fn=OASISHostPath.add_extensionfn_base"ml"inletctxt=add_file(template_makefncomment_ocamlbuild[]obj.obj_modules[])ctxtin{ctxtwithother_actions=(fun()->ifOASISFileUtil.file_exists_casenot_fnthenOASISMessage.error~ctxt:ctxt.ctxt(f_"Conflicting file '%s' and '%s' \
exists, remove '%s'.")fnnot_fnnot_fn)::ctxt.other_actions}inctxt,tag_t,myocamlbuild_tend|Executable(cs,bs,exec)assct->begin(* Extract content for executables *)letsrc_dirs,src_internal_dirs=MapDirs.find(`Executablecs.cs_name)map_dirsinlettarget_exec=letext=matchbs.bs_compiled_objectwith|Best->"{native,byte}"|Byte->"byte"|Native->"native"inprepend_bs_pathbs(OASISUnixPath.replace_extension(exec.exec_main_is)ext)inlettag_t=(Printf.sprintf"# Executable %s"cs.cs_name)::tag_tinletctxt,tag_t,myocamlbuild_t=bs_tagspkgsctcsbssrc_dirssrc_internal_dirstarget_execctxttag_tmyocamlbuild_tinlettag_t=ifexec.exec_customthenadd_tagstag_t[target_exec]["custom"]elsetag_tinctxt,tag_t,myocamlbuild_tend|Flag_|SrcRepo_|Test_|Doc_->ctxt,tag_t,myocamlbuild_t)(ctxt,[],{lib_ocaml=[];lib_c=[];flags=[];includes=[]})pkg.sectionsin(* Filter duplicate and reverse content in tag_t. *)lettag_t=snd(List.fold_left(fun(prev_tag,acc)tag->(* Don't remove comment but remove already seen tag. *)if(String.lengthtag>0&&tag.[0]='#')||not(SetString.memtagprev_tag)then(SetString.addtagprev_tag,tag::acc)else(prev_tag,acc))(SetString.empty,[])tag_t)inletmyocamlbuild_t=(* Fix section order *){lib_ocaml=List.revmyocamlbuild_t.lib_ocaml;lib_c=List.revmyocamlbuild_t.lib_c;flags=List.revmyocamlbuild_t.flags;includes=compute_includesmap_dirspkg;}inlettag_t="# Ignore VCS directories, you can use the same kind of rule outside"::"# OASIS_START/STOP if you want to exclude directories that contains"::"# useless stuff for the build process"::"true: annot, bin_annot"::add_tagstag_t["_darcs";".git";".hg";".bzr";"**/.svn"]["not_hygienic";"-traverse"]inletctxt=List.fold_left(functxttmpl->add_filetmplctxt)ctxt[(* Generate _tags *)template_make"_tags"comment_ocamlbuild[]tag_t[];(* Generate myocamlbuild.ml *)template_of_mlfile"myocamlbuild.ml"[][OASISData.oasissyslight_ml;BaseData.basesysenvironment_ml;OCamlbuildData.myocamlbuild_ml;"open Ocamlbuild_plugin;;";(Format.fprintfFormat.str_formatter"@[<hv2>let package_default =@ %a@,@];;"(OASISDataNotation.pp_odn~opened_modules:["Ocamlbuild_plugin"])(MyOCamlbuildBase.odn_of_tmyocamlbuild_t);Format.flush_str_formatter());"";Printf.sprintf"let conf = {MyOCamlbuildFindlib.no_automatic_syntax = %b}"(OASISFeatures.package_testOASISFeatures.no_automatic_syntaxpkg);"";"let dispatch_default = \
MyOCamlbuildBase.dispatch_default conf package_default;;";"";]["Ocamlbuild_plugin.dispatch dispatch_default;;"];]inctxtletgenerator=ocamlbuild_common_generatorpivot_dataOASISPackage.schemaall_idletdoitctxtpkg=letargs,ctxt=args_ocamlbuild_commonctxtpkg(generatorpkg.schema_data)inletctxt=add_ocamlbuild_filesctxtpkginctxt,{chng_moduls=[OCamlbuildData.ocamlbuildsys_ml];chng_main=OASISDataNotation.func_with_arg_ctxtbuild"OCamlbuildPlugin.build"args(OCamlbuildCommon.odn_of_args);chng_clean=Some(OASISDataNotation.funcclean"OCamlbuildPlugin.clean");chng_distclean=None;}letqstrt_completionpkg=fix_build_tools(ExternalTool"ocamlbuild")pkgletinit()=OCamlbuildId.init();Build.register_actself_iddoit;register_quickstart_completionall_idqstrt_completion;register_generator_packageall_idpivot_datagenerator