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