CMS 3D CMS Logo

RootAutoLibraryLoader.cc

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 //
00003 // Package:     LibraryLoader
00004 // Class  :     RootAutoLibraryLoader
00005 //
00006 // Implementation:
00007 //     <Notes on implementation>
00008 //
00009 // Original Author:
00010 //         Created:  Wed Nov 30 14:55:01 EST 2005
00011 // $Id: RootAutoLibraryLoader.cc,v 1.14 2008/10/03 18:12:48 wmtan Exp $
00012 //
00013 
00014 // system include files
00015 #include <string>
00016 #include <iostream>
00017 #include <map>
00018 #include "TROOT.h"
00019 #include "G__ci.h"
00020 #include "boost/regex.hpp"
00021 
00022 // user include files
00023 #include "FWCore/RootAutoLibraryLoader/interface/RootAutoLibraryLoader.h"
00024 #include "FWCore/RootAutoLibraryLoader/src/stdNamespaceAdder.h"
00025 
00026 #include "FWCore/PluginManager/interface/PluginManager.h"
00027 #include "FWCore/PluginManager/interface/ProblemTracker.h"
00028 #include "FWCore/PluginManager/interface/PluginCapabilities.h"
00029 
00030 #include "Reflex/Type.h"
00031 #include "Cintex/Cintex.h"
00032 #include "TClass.h" 
00033 //
00034 // constants, enums and typedefs
00035 //
00036 namespace {
00037   //Based on https://root.cern.ch/lxr/source/cintex/src/CINTSourceFile.h
00038   // If a Cint dictionary is accidently loaded as a side effect of loading a CMS
00039   // library Cint must have a file name assigned to that dictionary else Cint may crash
00040   class RootLoadFileSentry {
00041   public:
00042     RootLoadFileSentry()
00043     {
00044        G__setfilecontext("{CMS auto library loader}", &oldIFile_);
00045     }
00046 
00047     ~RootLoadFileSentry()
00048     {
00049       G__input_file* ifile = G__get_ifile();
00050       if (ifile) {
00051         *ifile = oldIFile_;
00052       }
00053       
00054     }
00055     
00056   private:
00057       G__input_file oldIFile_;
00058   };
00059 }
00060 
00061 //
00062 // static data member definitions
00063 //
00064 //hold onto the previous autolibrary loader
00065 typedef int (*CallbackPtr) G__P((char*,char*));
00066 static CallbackPtr gPrevious = 0;
00067 static const char* kDummyLibName = "*dummy";
00068 
00069 //This is actually defined within ROOT's v6_struct.cxx file but is not declared static
00070 // I want to use it so that if the autoloading is already turned on, I can call the previously declared routine
00071 extern CallbackPtr G__p_class_autoloading;
00072 
00073 namespace {
00074    //just want access to the copy constructor
00075    class MyClass : public TClass {
00076    public:
00077       MyClass(const TClass& iOther): TClass(iOther) {}
00078    };
00079 }
00080 
00081 namespace edm {
00082 
00083 static
00084 std::map<std::string,std::string>&
00085 cintToReflexSpecialCasesMap()
00086 {
00087    static std::map<std::string,std::string> s_map;
00088    return s_map;
00089 }
00090 
00091 static
00092 void
00093 addWrapperOfVectorOfBuiltin(std::map<std::string,std::string>& iMap, const char* iBuiltin)
00094 {
00095    static std::string sReflexPrefix("edm::Wrapper<std::vector<");
00096    static std::string sReflexPostfix("> >");
00097 
00098    //Wrapper<vector<float,allocator<float> > >
00099    static std::string sCintPrefix("Wrapper<vector<");
00100    static std::string sCintMiddle(",allocator<");
00101    static std::string sCintPostfix("> > >");
00102 
00103    std::string type(iBuiltin);
00104    iMap.insert(make_pair(sCintPrefix+type+sCintMiddle+type+sCintPostfix,
00105                          sReflexPrefix+type+sReflexPostfix));
00106 }
00107    
00108 static
00109 bool loadLibraryForClass(const char* classname)
00110 {
00111   //std::cout <<"loadLibaryForClass"<<std::endl;
00112   if(0 == classname) {
00113     return false;
00114   }
00115   //std::cout <<"asking to find "<<classname<<std::endl;
00116   static const std::string cPrefix("LCGReflex/");
00117   //std::cout <<"asking to find "<<cPrefix+classname<<std::endl;
00118   try {
00119     //give ROOT a name for the file we are loading
00120     RootLoadFileSentry sentry;
00121     if(edmplugin::PluginCapabilities::get()->tryToLoad(cPrefix+classname)) {
00122       ROOT::Reflex::Type t = ROOT::Reflex::Type::ByName(classname);
00123       if (ROOT::Reflex::Type() == t) {
00124         //would be nice to issue a warning here
00125         return false;
00126       }
00127       if(!t.IsComplete()) {
00128         //would be nice to issue a warning here.  Not sure the remainder of this comment is correct.
00129         // this message happens too often (too many false positives) to be useful plus ROOT will complain about a missing dictionary
00130         //std::cerr <<"Warning: Reflex knows about type '"<<classname<<"' but has no dictionary for it."<<std::endl;
00131         return false;
00132       }
00133     } else {
00134       //see if adding a std namespace helps
00135       std::string name = root::stdNamespaceAdder(classname);
00136       //std::cout <<"see if std helps"<<std::endl;
00137       if (not edmplugin::PluginCapabilities::get()->tryToLoad(cPrefix+name)) {
00138         // Too many false positives on built-in types here.
00139         return false;
00140       }
00141       ROOT::Reflex::Type t = ROOT::Reflex::Type::ByName(name);
00142       if (ROOT::Reflex::Type() == t) {
00143         t = ROOT::Reflex::Type::ByName(classname);
00144         if (ROOT::Reflex::Type() == t) {
00145           //would be nice to issue a warning here
00146           return false;
00147         }
00148       }
00149     }
00150   } catch(cms::Exception& e) {
00151     //would be nice to issue a warning here
00152     return false;
00153   }
00154   //std::cout <<"loaded "<<classname<<std::endl;
00155   return true;
00156 }
00157 
00158 //Based on code in ROOT's TCint.cxx file
00159 
00160 static int ALL_AutoLoadCallback(char *c, char *l) {
00161   //NOTE: if the library (i.e. 'l') is an empty string this means we are dealing with a namespace
00162   // These checks appear to avoid a crash of ROOT during shutdown of the application
00163   if(0==c || 0==l || l[0]==0) {
00164     return 0;
00165   }
00166   ULong_t varp = G__getgvp();
00167   G__setgvp(G__PVOID);
00168   int result = loadLibraryForClass(c) ? 1:0;
00169   G__setgvp(varp);
00170   //NOTE: the check for the library is done since we can have a failure
00171   // if a CMS library has an incomplete set of Reflex dictionaries where
00172   // the remaining dictionaries can be found by Cint.  If the library with
00173   // the Reflex dictionaries is loaded first, then the Cint library then any
00174   // requests for a Reflex::Type from the Reflex library will fail because for
00175   // some reason the loading of the Cint library causes Reflex to forget about
00176   // what types it already loaded from the Reflex library.  This problem was
00177   // seen for libDataFormatsMath and libMathCore.  I do not print an error message
00178   // since the dictionaries are actually loaded so things work fine.
00179   if(!result && 0 != strcmp(l,kDummyLibName) && gPrevious) {
00180     result = gPrevious(c,l);
00181   }
00182   return result;
00183 }
00184 
00185 static std::string
00186 classNameForRoot(const std::string& iCapName)
00187 {
00188   //need to remove any 'std::' since ROOT ignores it
00189   static const boost::regex ex("std::");
00190   const std::string to("");
00191 
00192   return regex_replace(iCapName, ex, to, boost::match_default | boost::format_sed);
00193 
00194   return iCapName;
00195 }
00196 
00197 //Cint requires that we register the type and library containing the type
00198 // before the autoloading will work
00199 namespace {
00200   struct CompareFirst {
00201     bool operator()(const std::pair<std::string,std::string>&iLHS,
00202                     const std::pair<std::string,std::string>&iRHS) const{
00203       return iLHS.first > iRHS.first;
00204     }
00205   };
00206 }
00207 static
00208 void registerTypes() {
00209   edmplugin::PluginManager*db =  edmplugin::PluginManager::get();
00210 
00211   typedef edmplugin::PluginManager::CategoryToInfos CatToInfos;
00212 
00213   CatToInfos::const_iterator itFound = db->categoryToInfos().find("Capability");
00214 
00215   if(itFound == db->categoryToInfos().end()) {
00216     return;
00217   }
00218 
00219   //in order to determine if a name is from a class or a namespace, we will order
00220   // all the classes in descending order so that embedded classes will be seen before
00221   // their containing classes, that way we can say the containing class is a namespace
00222   // before finding out it is actually a class
00223   typedef std::vector<std::pair<std::string,std::string> > ClassAndLibraries;
00224   ClassAndLibraries classes;
00225   classes.reserve(1000);
00226   std::string lastClass;
00227 
00228   //find where special cases come from
00229   std::map<std::string,std::string> specialsToLib;
00230   const std::map<std::string,std::string>& specials = cintToReflexSpecialCasesMap();
00231   for(std::map<std::string,std::string>::const_iterator itSpecial = specials.begin();
00232       itSpecial != specials.end();
00233       ++itSpecial) {
00234     specialsToLib[classNameForRoot(itSpecial->second)];
00235   }
00236   static const std::string cPrefix("LCGReflex/");
00237   for (edmplugin::PluginManager::Infos::const_iterator itInfo = itFound->second.begin(),
00238        itInfoEnd = itFound->second.end();
00239        itInfo != itInfoEnd; ++itInfo)
00240   {
00241     if (lastClass == itInfo->name_) {
00242       continue;
00243     }
00244     lastClass = itInfo->name_;
00245     if(cPrefix == lastClass.substr(0,cPrefix.size())) {
00246       std::string className = classNameForRoot(lastClass.c_str()+cPrefix.size());
00247       classes.push_back(std::pair<std::string,std::string>(className, itInfo->loadable_.native_file_string()));
00248       std::map<std::string,std::string>::iterator itFound = specialsToLib.find(className);
00249       if(itFound !=specialsToLib.end()){
00250         itFound->second = itInfo->loadable_.native_file_string();
00251       }
00252     }
00253   }
00254   //sort_all(classes, std::greater<std::string>());
00255   //sort_all(classes, CompareFirst());
00256   //the values are already sorted by less, so just need to reverse to get greater
00257   for(ClassAndLibraries::reverse_iterator itClass = classes.rbegin(), itClassEnd = classes.rend();
00258       itClass != itClassEnd;
00259       ++itClass) {
00260 
00261     const std::string& className = itClass->first;
00262     const std::string& libraryName = itClass->second;
00263     //need to register namespaces and figure out if we have an embedded class
00264     static const std::string toFind(":<");
00265     std::string::size_type pos=0;
00266     while(std::string::npos != (pos = className.find_first_of(toFind,pos))) {
00267       if (className[pos] == '<') {break;}
00268       if (className.size() <= pos+1 || className[pos+1] != ':') {break;}
00269       //should check to see if this is a class or not
00270       G__set_class_autoloading_table(const_cast<char*>(className.substr(0,pos).c_str()),"");
00271       //std::cout <<"namespace "<<className.substr(0,pos).c_str()<<std::endl;
00272       pos += 2;
00273     }
00274     G__set_class_autoloading_table(const_cast<char*>(className.c_str()), const_cast<char*>(libraryName.c_str()));
00275     //std::cout <<"class "<<className.c_str()<<std::endl;
00276   }
00277    
00278   //now handle the special cases
00279   for(std::map<std::string,std::string>::const_iterator itSpecial = specials.begin();
00280       itSpecial != specials.end();
00281       ++itSpecial) {
00282     //std::cout <<"registering special "<<itSpecial->first<<" "<<itSpecial->second<<" "<<specialsToLib[classNameForRoot(itSpecial->second)]<<std::endl;
00283     //force loading of specials
00284     if(specialsToLib[classNameForRoot(itSpecial->second)].size()) {
00285       //std::cout <<"&&&&& found special case "<<itSpecial->first<<std::endl;
00286       std::string name=itSpecial->second;
00287       if(not edmplugin::PluginCapabilities::get()->tryToLoad(cPrefix+name)) {
00288         std::cout <<"failed to load plugin"<<std::endl;
00289         continue;
00290       } else {
00291         //need to construct the Class ourselves
00292         ROOT::Reflex::Type t = ROOT::Reflex::Type::ByName(name);
00293         if(ROOT::Reflex::Type() == t) {
00294           std::cout <<"reflex did not build "<<name<<std::endl;
00295           continue;
00296         }
00297         TClass* reflexNamedClass = TClass::GetClass(t.TypeInfo());
00298         if(0==reflexNamedClass){
00299           std::cout <<" failed to get TClass by typeid"<<std::endl;
00300           continue;
00301         }
00302         MyClass* myNewlyNamedClass = new MyClass(*reflexNamedClass);
00303         myNewlyNamedClass->SetName(itSpecial->first.c_str());
00304         gROOT->AddClass(myNewlyNamedClass);
00305       }
00306     }
00307   }
00308 }
00309 
00310 //
00311 // constructors and destructor
00312 //
00313 RootAutoLibraryLoader::RootAutoLibraryLoader() :
00314   classNameAttemptingToLoad_(0)
00315 {
00316    edm::AssertHandler h();
00317    gROOT->AddClassGenerator(this);
00318    ROOT::Cintex::Cintex::Enable();
00319 
00320    //set the special cases
00321    std::map<std::string,std::string>& specials = cintToReflexSpecialCasesMap();
00322    if(specials.empty()) {
00323       addWrapperOfVectorOfBuiltin(specials,"char");
00324       addWrapperOfVectorOfBuiltin(specials,"unsigned char");
00325       addWrapperOfVectorOfBuiltin(specials,"signed char");
00326       addWrapperOfVectorOfBuiltin(specials,"short");
00327       addWrapperOfVectorOfBuiltin(specials,"unsigned short");
00328       addWrapperOfVectorOfBuiltin(specials,"int");
00329       addWrapperOfVectorOfBuiltin(specials,"unsigned int");
00330       addWrapperOfVectorOfBuiltin(specials,"long");
00331       addWrapperOfVectorOfBuiltin(specials,"unsigned long");
00332 
00333       addWrapperOfVectorOfBuiltin(specials,"float");
00334       addWrapperOfVectorOfBuiltin(specials,"double");
00335    }
00336    //std::cout <<"my loader"<<std::endl;
00337    //remember if the callback was already set so we can chain together our results
00338    gPrevious = G__p_class_autoloading;
00339    G__set_class_autoloading_callback(&ALL_AutoLoadCallback);
00340    registerTypes();
00341 }
00342 
00343 
00344 //
00345 // member functions
00346 //
00347 
00348 TClass *
00349 RootAutoLibraryLoader::GetClass(const char* classname, Bool_t load)
00350 {
00351   if(classname == classNameAttemptingToLoad_) {
00352     std::cerr <<"WARNING: Reflex failed to create CINT dictionary for "<<classname<<std::endl;
00353     return 0;
00354   }
00355    TClass* returnValue = 0;
00356    //std::cout <<"looking for "<<classname <<" load "<<(load? "T":"F")<< std::endl;
00357    if (load) {
00358      //std::cout <<" going to call loadLibraryForClass"<<std::endl;
00359      if (loadLibraryForClass(classname)) {
00360        //use this to check for infinite recursion attempt
00361        classNameAttemptingToLoad_ = classname;
00362        // This next call will create the TClass object for the class.
00363        // It will also attempt to load the dictionary for the class
00364        // if the second argument is kTRUE. This is the default, so it
00365        // need not be explicitly specified.
00366        returnValue = gROOT->GetClass(classname, kTRUE);
00367        classNameAttemptingToLoad_ = 0;
00368      }
00369    }
00370    return returnValue;
00371 }
00372 
00373 
00374 TClass *
00375 RootAutoLibraryLoader::GetClass(const type_info& typeinfo, Bool_t load)
00376 {
00377   //std::cout <<"looking for type "<<typeinfo.name()<<std::endl;
00378    TClass* returnValue = 0;
00379    if(load){
00380       return GetClass(typeinfo.name(), load);
00381    }
00382    return returnValue;
00383 }
00384 
00385 void
00386 RootAutoLibraryLoader::enable()
00387 {
00388    //static BareRootProductGetter s_getter;
00389    //static edm::EDProductGetter::Operate s_op(&s_getter);
00390    static RootAutoLibraryLoader s_loader;
00391 }
00392 
00393 
00394 
00395 
00396 void
00397 RootAutoLibraryLoader::loadAll()
00398 {
00399   // std::cout <<"LoadAllDictionaries"<<std::endl;
00400   enable();
00401 
00402   edmplugin::PluginManager*db =  edmplugin::PluginManager::get();
00403 
00404   typedef edmplugin::PluginManager::CategoryToInfos CatToInfos;
00405 
00406   CatToInfos::const_iterator itFound = db->categoryToInfos().find("Capability");
00407 
00408   if(itFound == db->categoryToInfos().end()) {
00409     return;
00410   }
00411   std::string lastClass;
00412   const std::string cPrefix("LCGReflex/");
00413 
00414   //give ROOT a name for the file we are loading
00415   RootLoadFileSentry sentry;
00416 
00417   for (edmplugin::PluginManager::Infos::const_iterator itInfo = itFound->second.begin(),
00418        itInfoEnd = itFound->second.end();
00419        itInfo != itInfoEnd; ++itInfo)
00420   {
00421     if (lastClass == itInfo->name_) {
00422       continue;
00423     }
00424 
00425     lastClass = itInfo->name_;
00426     edmplugin::PluginCapabilities::get()->load(lastClass);
00427     //NOTE: since we have the library already, we could be more efficient if we just load it ourselves
00428   }
00429 }
00430 }
00431 
00432 //ClassImp(RootAutoLibraryLoader)

Generated on Tue Jun 9 17:36:32 2009 for CMSSW by  doxygen 1.5.4