CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
RootAutoLibraryLoader.cc
Go to the documentation of this file.
1 // -*- C++ -*-
2 //
3 // Package: LibraryLoader
4 // Class : RootAutoLibraryLoader
5 //
6 // Implementation:
7 // <Notes on implementation>
8 //
9 // Original Author:
10 // Created: Wed Nov 30 14:55:01 EST 2005
11 //
12 
13 // system include files
14 #include <string>
15 #include <iostream>
16 #include <map>
17 #include "TROOT.h"
18 #include "G__ci.h"
19 #include "boost/regex.hpp"
20 
21 // user include files
24 
29 
30 #include "Reflex/Type.h"
31 #include "Cintex/Cintex.h"
32 #include "TClass.h"
33 #include "RVersion.h"
34 
35 // We cannot use the MessageLogger here because this is also used by standalones that do not have the logger.
36 
37 //
38 // constants, enums and typedefs
39 //
40 namespace {
41  //Based on http://root.cern.ch/lxr/source/cintex/src/CINTSourceFile.h
42  // If a Cint dictionary is accidently loaded as a side effect of loading a CMS
43  // library Cint must have a file name assigned to that dictionary else Cint may crash
44  class RootLoadFileSentry {
45  public:
46  RootLoadFileSentry() {
47  G__setfilecontext("{CMS auto library loader}", &oldIFile_);
48  }
49 
50  ~RootLoadFileSentry() {
51  G__input_file* ifile = G__get_ifile();
52  if (ifile) {
53  *ifile = oldIFile_;
54  }
55  }
56 
57  private:
58  G__input_file oldIFile_;
59  };
60 }
61 
62 //
63 // static data member definitions
64 //
65 //hold onto the previous autolibrary loader
66 typedef int (*CallbackPtr)(char*, char*);
68 static char const* kDummyLibName = "*dummy";
69 
70 //This is actually defined within ROOT's v6_struct.cxx file but is not declared static
71 // I want to use it so that if the autoloading is already turned on, I can call the previously declared routine
73 
74 namespace edm {
75  namespace {
76 
77  std::map<std::string, std::string>&
78  cintToReflexSpecialCasesMap() {
79  static std::map<std::string, std::string> s_map;
80  return s_map;
81  }
82 
83  void
84  addWrapperOfVectorOfBuiltin(std::map<std::string, std::string>& iMap, char const* iBuiltin) {
85  static std::string sReflexPrefix("edm::Wrapper<std::vector<");
86  static std::string sReflexPostfix("> >");
87 
88  //Wrapper<vector<float, allocator<float> > >
89  static std::string sCintPrefix("Wrapper<vector<");
90  static std::string sCintMiddle(",allocator<");
91  static std::string sCintPostfix("> > >");
92 
93  std::string type(iBuiltin);
94  iMap.insert(make_pair(sCintPrefix + type + sCintMiddle + type + sCintPostfix,
95  sReflexPrefix + type + sReflexPostfix));
96  }
97 
98  bool loadLibraryForClass(char const* classname) {
99  //std::cout << "loadLibaryForClass" << std::endl;
100  if(0 == classname) {
101  return false;
102  }
103  //std::cout << "asking to find " << classname << std::endl;
104  static std::string const cPrefix("LCGReflex/");
105  //std::cout << "asking to find " << cPrefix + classname << std::endl;
106  try {
107  //give ROOT a name for the file we are loading
108  RootLoadFileSentry sentry;
109  if(edmplugin::PluginCapabilities::get()->tryToLoad(cPrefix + classname)) {
110  Reflex::Type t = Reflex::Type::ByName(classname);
111  if (Reflex::Type() == t) {
112  //would be nice to issue a warning here
113  return false;
114  }
115  if(!t.IsComplete()) {
116  //would be nice to issue a warning here. Not sure the remainder of this comment is correct.
117  // this message happens too often (too many false positives) to be useful plus ROOT will complain about a missing dictionary
118  //std::cerr << "Warning: Reflex knows about type '" << classname << "' but has no dictionary for it." << std::endl;
119  return false;
120  }
121  } else {
122  //see if adding a std namespace helps
123  std::string name = root::stdNamespaceAdder(classname);
124  //std::cout << "see if std helps" << std::endl;
125  if (not edmplugin::PluginCapabilities::get()->tryToLoad(cPrefix + name)) {
126  // Too many false positives on built-in types here.
127  return false;
128  }
129  Reflex::Type t = Reflex::Type::ByName(name);
130  if (Reflex::Type() == t) {
131  t = Reflex::Type::ByName(classname);
132  if (Reflex::Type() == t) {
133  //would be nice to issue a warning here
134  return false;
135  }
136  }
137  }
138  } catch(cms::Exception& e) {
139  //would be nice to issue a warning here
140  return false;
141  }
142  //std::cout << "loaded " << classname << std::endl;
143  return true;
144  }
145 
146  //Based on code in ROOT's TCint.cxx file
147 
148  int ALL_AutoLoadCallback(char* c, char* l) {
149  //NOTE: if the library (i.e. 'l') is an empty string this means we are dealing with a namespace
150  // These checks appear to avoid a crash of ROOT during shutdown of the application
151  if(0 == c || 0 == l || l[0] == 0) {
152  return 0;
153  }
154  ULong_t varp = G__getgvp();
155  G__setgvp((long)G__PVOID);
156  int result = loadLibraryForClass(c) ? 1:0;
157  G__setgvp(varp);
158  //NOTE: the check for the library is done since we can have a failure
159  // if a CMS library has an incomplete set of Reflex dictionaries where
160  // the remaining dictionaries can be found by Cint. If the library with
161  // the Reflex dictionaries is loaded first, then the Cint library then any
162  // requests for a Reflex::Type from the Reflex library will fail because for
163  // some reason the loading of the Cint library causes Reflex to forget about
164  // what types it already loaded from the Reflex library. This problem was
165  // seen for libDataFormatsMath and libMathCore. I do not print an error message
166  // since the dictionaries are actually loaded so things work fine.
167  if(!result && 0 != strcmp(l, kDummyLibName) && gPrevious) {
168  result = gPrevious(c, l);
169  }
170  return result;
171  }
172 
173  std::string
174  classNameForRoot(std::string const& iCapName) {
175  //need to remove any 'std::' since ROOT ignores it
176  static boost::regex const ex("std::");
177  std::string const to("");
178 
179  return regex_replace(iCapName, ex, to, boost::match_default | boost::format_sed);
180  }
181 
182  //Cint requires that we register the type and library containing the type
183  // before the autoloading will work
184  struct CompareFirst {
185  bool operator()(std::pair<std::string, std::string> const& iLHS,
186  std::pair<std::string, std::string> const& iRHS) const{
187  return iLHS.first > iRHS.first;
188  }
189  };
190 
191  void registerTypes() {
193 
195 
196  CatToInfos::const_iterator itFound = db->categoryToInfos().find("Capability");
197 
198  if(itFound == db->categoryToInfos().end()) {
199  return;
200  }
201 
202  //in order to determine if a name is from a class or a namespace, we will order
203  // all the classes in descending order so that embedded classes will be seen before
204  // their containing classes, that way we can say the containing class is a namespace
205  // before finding out it is actually a class
206  typedef std::vector<std::pair<std::string, std::string> > ClassAndLibraries;
207  ClassAndLibraries classes;
208  classes.reserve(1000);
209  std::string lastClass;
210 
211  //find where special cases come from
212  std::map<std::string, std::string> specialsToLib;
213  std::map<std::string, std::string> const& specials = cintToReflexSpecialCasesMap();
214  for(std::map<std::string, std::string>::const_iterator itSpecial = specials.begin();
215  itSpecial != specials.end();
216  ++itSpecial) {
217  specialsToLib[classNameForRoot(itSpecial->second)];
218  }
219  static std::string const cPrefix("LCGReflex/");
220  for (edmplugin::PluginManager::Infos::const_iterator itInfo = itFound->second.begin(),
221  itInfoEnd = itFound->second.end();
222  itInfo != itInfoEnd; ++itInfo) {
223  if (lastClass == itInfo->name_) {
224  continue;
225  }
226  lastClass = itInfo->name_;
227  if(cPrefix == lastClass.substr(0, cPrefix.size())) {
228  std::string className = classNameForRoot(lastClass.c_str() + cPrefix.size());
229  classes.push_back(std::pair<std::string, std::string>(className, itInfo->loadable_.native_file_string()));
230  std::map<std::string, std::string>::iterator itFound = specialsToLib.find(className);
231  if(itFound != specialsToLib.end()) {
232  // std::cout << "Found " << lastClass << " : " << className << std::endl;
233  itFound->second = itInfo->loadable_.native_file_string();
234  }
235  }
236  }
237  //sort_all(classes, std::greater<std::string>());
238  //sort_all(classes, CompareFirst());
239  //the values are already sorted by less, so just need to reverse to get greater
240  for(ClassAndLibraries::reverse_iterator itClass = classes.rbegin(), itClassEnd = classes.rend();
241  itClass != itClassEnd;
242  ++itClass) {
243 
244  std::string const& className = itClass->first;
245  std::string const& libraryName = itClass->second;
246  //need to register namespaces and figure out if we have an embedded class
247  static std::string const toFind(":<");
249  while(std::string::npos != (pos = className.find_first_of(toFind, pos))) {
250  if (className[pos] == '<') {break;}
251  if (className.size() <= pos + 1 || className[pos + 1] != ':') {break;}
252  //should check to see if this is a class or not
253  G__set_class_autoloading_table(const_cast<char*>(className.substr(0, pos).c_str()), const_cast<char*>(""));
254  //std::cout << "namespace " << className.substr(0, pos).c_str() << std::endl;
255  pos += 2;
256  }
257  G__set_class_autoloading_table(const_cast<char*>(className.c_str()), const_cast<char*>(libraryName.c_str()));
258  //std::cout << "class " << className.c_str() << std::endl;
259  }
260 
261  //now handle the special cases
262  for(std::map<std::string, std::string>::const_iterator itSpecial = specials.begin();
263  itSpecial != specials.end();
264  ++itSpecial) {
265  //std::cout << "registering special " << itSpecial->first << " " << itSpecial->second << " " << std::endl << " " << specialsToLib[classNameForRoot(itSpecial->second)] << std::endl;
266  //force loading of specials
267  if(specialsToLib[classNameForRoot(itSpecial->second)].size()) {
268  //std::cout << "&&&&& found special case " << itSpecial->first << std::endl;
269  std::string name = itSpecial->second;
270  Reflex::Type t = Reflex::Type::ByName(name);
271 
272  if((Reflex::Type() == t) and
273  (not edmplugin::PluginCapabilities::get()->tryToLoad(cPrefix + name))) {
274  std::cout << "failed to load plugin for " << cPrefix + name << std::endl;
275  continue;
276  } else {
277  //need to construct the Class ourselves
278  Reflex::Type t = Reflex::Type::ByName(name);
279  if(Reflex::Type() == t) {
280  std::cout << "reflex did not build " << name << std::endl;
281  continue;
282  }
283  TClass* reflexNamedClass = TClass::GetClass(t.TypeInfo());
284  if(0 == reflexNamedClass) {
285  std::cout << "failed to get TClass by typeid for " << name << std::endl;
286  continue;
287  }
288  reflexNamedClass->Clone(itSpecial->first.c_str());
289  std::string magictypedef("namespace edm { typedef ");
290  magictypedef += classNameForRoot(name) + " " + itSpecial->first + "; }";
291  // std::cout << "Magic typedef " << magictypedef << std::endl;
292  gROOT->ProcessLine(magictypedef.c_str());
293  }
294  }
295  }
296  }
297  }
298 
299  //
300  // constructors and destructor
301  //
303 #if ROOT_VERSION_CODE >= ROOT_VERSION(5,27,6)
304  classNameAttemptingToLoad_(0),
305  isInitializingCintex_(true) {
306 #else
308 #endif
310  gROOT->AddClassGenerator(this);
311  ROOT::Cintex::Cintex::Enable();
312 #if ROOT_VERSION_CODE >= ROOT_VERSION(5,27,6)
313  isInitializingCintex_ =false;
314 #endif
315  //set the special cases
316  std::map<std::string, std::string>& specials = cintToReflexSpecialCasesMap();
317  if(specials.empty()) {
318  addWrapperOfVectorOfBuiltin(specials,"bool");
319 
320  addWrapperOfVectorOfBuiltin(specials,"char");
321  addWrapperOfVectorOfBuiltin(specials,"unsigned char");
322  addWrapperOfVectorOfBuiltin(specials,"signed char");
323  addWrapperOfVectorOfBuiltin(specials,"short");
324  addWrapperOfVectorOfBuiltin(specials,"unsigned short");
325  addWrapperOfVectorOfBuiltin(specials,"int");
326  addWrapperOfVectorOfBuiltin(specials,"unsigned int");
327  addWrapperOfVectorOfBuiltin(specials,"long");
328  addWrapperOfVectorOfBuiltin(specials,"unsigned long");
329  addWrapperOfVectorOfBuiltin(specials,"long long");
330  addWrapperOfVectorOfBuiltin(specials,"unsigned long long");
331 
332  addWrapperOfVectorOfBuiltin(specials,"float");
333  addWrapperOfVectorOfBuiltin(specials,"double");
334  }
335  //std::cout << "my loader" << std::endl;
336  //remember if the callback was already set so we can chain together our results
337  gPrevious = G__p_class_autoloading;
338  G__set_class_autoloading_callback(&ALL_AutoLoadCallback);
339  registerTypes();
340  }
341 
342  //
343  // member functions
344  //
345 
346  TClass*
347  RootAutoLibraryLoader::GetClass(char const* classname, Bool_t load) {
348  TClass* returnValue = 0;
349  if(classNameAttemptingToLoad_ != 0 && !strcmp(classname, classNameAttemptingToLoad_)) {
350  // We can try to see if the class name contains "basic_string<char>".
351  // If so, we replace "basic_string<char>" with "string" and try again.
352  std::string className(classname);
353  std::string::size_type idx = className.find("basic_string<char>");
354  if (idx != std::string::npos) {
355  className.replace(idx, 18, std::string("string"));
356  //if basic_string<char> was the last argument to a templated class
357  // then there would be an extra space to separate the two '>'
358  if(className.size() > idx + 6 && className[idx + 6] == ' ') {
359  className.replace(idx + 6, 1, "");
360  }
361  classNameAttemptingToLoad_ = className.c_str();
362  returnValue = gROOT->GetClass(className.c_str(), kTRUE);
363  classNameAttemptingToLoad_ = classname;
364  return returnValue;
365  }
366  //NOTE: As of ROOT 5.27.06 this warning generates false positives for HepMC classes because
367  // ROOT has special handling for them built into class.rules
368  //std::cerr << "WARNING[RootAutoLibraryLoader]: Reflex failed to create CINT dictionary for " << classname << std::endl;
369  return 0;
370  }
371  //std::cout << "looking for " << classname << " load " << (load? "T":"F") << std::endl;
372  if (load) {
373  //std::cout << " going to call loadLibraryForClass" << std::endl;
374  //[ROOT 5.28] When Cintex is in its 'Enable' method it will register callbacks to build
375  // TClasses. During this phase we do not want to actually force TClasses to have to
376  // come into existence.
377 #if ROOT_VERSION_CODE >= ROOT_VERSION(5,27,6)
378  if (loadLibraryForClass(classname) and not isInitializingCintex_) {
379 #else
380  if (loadLibraryForClass(classname)) {
381 #endif
382  //use this to check for infinite recursion attempt
383  classNameAttemptingToLoad_ = classname;
384  // This next call will create the TClass object for the class.
385  // It will also attempt to load the dictionary for the class
386  // if the second argument is kTRUE. This is the default, so it
387  // need not be explicitly specified.
388  returnValue = gROOT->GetClass(classname, kTRUE);
390  }
391  }
392  return returnValue;
393  }
394 
395  TClass*
396  RootAutoLibraryLoader::GetClass(type_info const& typeinfo, Bool_t load) {
397  //std::cout << "looking for type " << typeinfo.name() << std::endl;
398  TClass* returnValue = 0;
399  if(load) {
400  return GetClass(typeinfo.name(), load);
401  }
402  return returnValue;
403  }
404 
405  void
407  //static BareRootProductGetter s_getter;
408  //static EDProductGetter::Operate s_op(&s_getter);
409  static RootAutoLibraryLoader s_loader;
410  }
411 
412  void
414  // std::cout << "LoadAllDictionaries" << std::endl;
415  enable();
416 
418 
420 
421  CatToInfos::const_iterator itFound = db->categoryToInfos().find("Capability");
422 
423  if(itFound == db->categoryToInfos().end()) {
424  return;
425  }
426  std::string lastClass;
427  std::string const cPrefix("LCGReflex/");
428 
429  //give ROOT a name for the file we are loading
430  RootLoadFileSentry sentry;
431 
432  for (edmplugin::PluginManager::Infos::const_iterator itInfo = itFound->second.begin(),
433  itInfoEnd = itFound->second.end();
434  itInfo != itInfoEnd; ++itInfo) {
435  if (lastClass == itInfo->name_) {
436  continue;
437  }
438 
439  lastClass = itInfo->name_;
441  //NOTE: since we have the library already, we could be more efficient if we just load it ourselves
442  }
443  }
444 }
445 
446 //ClassImp(RootAutoLibraryLoader)
const CategoryToInfos & categoryToInfos() const
Definition: PluginManager.h:71
type
Definition: HCALResponse.h:22
virtual TClass * GetClass(char const *classname, Bool_t load)
return class type
tuple db
Definition: EcalCondDB.py:151
uint16_t size_type
int(* CallbackPtr)(char *, char *)
std::string stdNamespaceAdder(const std::string &iClassName)
tuple result
Definition: query.py:137
def load
Definition: svgfig.py:546
std::map< std::string, Infos > CategoryToInfos
Definition: PluginManager.h:43
static PluginCapabilities * get()
CallbackPtr G__p_class_autoloading
static void loadAll()
load all known libraries holding dictionaries
static CallbackPtr gPrevious
perl if(1 lt scalar(@::datatypes))
Definition: edlooper.cc:31
tuple cout
Definition: gather_cfg.py:41
void load(const std::string &iName)
static void enable()
interface for TClass generators
tuple ifile
Definition: indexGen.py:77
The Signals That Services Can Subscribe To This is based on ActivityRegistry h
Helper function to determine trigger accepts.
Definition: Activities.doc:4
static PluginManager * get()
static char const * kDummyLibName
std::string className(const T &t)
Definition: ClassName.h:30