Logo ROOT  
Reference Guide
rootcling_impl.cxx
Go to the documentation of this file.
1 // Authors: Axel Naumann, Philippe Canal, Danilo Piparo
2 
3 /*************************************************************************
4  * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
5  * All rights reserved. *
6  * *
7  * For the licensing terms see $ROOTSYS/LICENSE. *
8  * For the list of contributors see $ROOTSYS/README/CREDITS. *
9  *************************************************************************/
10 
11 #include "rootcling_impl.h"
12 #include "rootclingCommandLineOptionsHelp.h"
13 
14 #include "RConfigure.h"
15 #include <ROOT/RConfig.hxx>
16 #include <ROOT/FoundationUtils.hxx>
17 #include "snprintf.h"
18 
19 #include <iostream>
20 #include <iomanip>
21 #include <memory>
22 #include <vector>
23 #include <algorithm>
24 #include <cstdio>
25 
26 #include <errno.h>
27 #include <string>
28 #include <list>
29 #include <sstream>
30 #include <map>
31 #include <fstream>
32 #include <sys/stat.h>
33 #include <unordered_map>
34 #include <unordered_set>
35 #include <numeric>
36 
37 
38 #ifdef _WIN32
39 #ifdef system
40 #undef system
41 #endif
42 #undef UNICODE
43 #include <windows.h>
44 #include <Tlhelp32.h> // for MAX_MODULE_NAME32
45 #include <process.h>
46 #define PATH_MAX _MAX_PATH
47 #ifdef interface
48 // prevent error coming from clang/AST/Attrs.inc
49 #undef interface
50 #endif
51 #endif
52 
53 #ifdef __APPLE__
54 #include <mach-o/dyld.h>
55 #endif
56 
57 #if !defined(R__WIN32)
58 #include <limits.h>
59 #include <unistd.h>
60 #endif
61 
62 
63 #include "cling/Interpreter/Interpreter.h"
64 #include "cling/Interpreter/InterpreterCallbacks.h"
65 #include "cling/Interpreter/LookupHelper.h"
66 #include "cling/Interpreter/Value.h"
67 #include "clang/AST/CXXInheritance.h"
68 #include "clang/Basic/Diagnostic.h"
69 #include "clang/Basic/MemoryBufferCache.h"
70 #include "clang/Frontend/CompilerInstance.h"
71 #include "clang/Frontend/FrontendActions.h"
72 #include "clang/Frontend/FrontendDiagnostic.h"
73 #include "clang/Lex/HeaderSearch.h"
74 #include "clang/Lex/Preprocessor.h"
75 #include "clang/Lex/ModuleMap.h"
76 #include "clang/Lex/Pragma.h"
77 #include "clang/Sema/Sema.h"
78 #include "clang/Serialization/ASTWriter.h"
79 #include "cling/Utils/AST.h"
80 
81 #include "llvm/Bitcode/BitstreamWriter.h"
82 #include "llvm/Support/CommandLine.h"
83 #include "llvm/Support/Path.h"
84 #include "llvm/Support/PrettyStackTrace.h"
85 #include "llvm/Support/Signals.h"
86 
87 #include "RtypesCore.h"
88 #include "TModuleGenerator.h"
89 #include "TClassEdit.h"
90 #include "TClingUtils.h"
91 #include "RStl.h"
92 #include "XMLReader.h"
93 #include "LinkdefReader.h"
94 #include "DictSelectionReader.h"
95 #include "SelectionRules.h"
96 #include "Scanner.h"
97 #include "strlcpy.h"
98 
99 #include "OptionParser.h"
100 
101 #ifdef WIN32
102 const std::string gLibraryExtension(".dll");
103 #else
104 const std::string gLibraryExtension(".so"); // no dylib for the moment
105 #endif
107 
108 #ifdef __APPLE__
109 #include <mach-o/dyld.h>
110 #endif
111 
112 #if defined(R__WIN32)
113 #include "cygpath.h"
114 #define strcasecmp _stricmp
115 #define strncasecmp _strnicmp
116 #else
117 #include <unistd.h>
118 #endif
119 
120 bool gBuildingROOT = false;
122 
123 
124 // Maybe too ugly? let's see how it performs.
125 using HeadersDeclsMap_t = std::map<std::string, std::list<std::string>>;
126 
127 using namespace ROOT;
128 using namespace TClassEdit;
129 
130 using namespace std;
131 
132 namespace genreflex {
133  bool verbose = false;
134 }
135 
136 ////////////////////////////////////////////////////////////////////////////////
137 
138 static llvm::cl::OptionCategory gRootclingOptions("rootcling common options");
139 
140  // FIXME: We should remove after removal of r flag.
141 static llvm::cl::opt<bool>
143  llvm::cl::desc("Deprecated. Similar to -f but it ignores the dictionary generation. \
144 When -r is present rootcling becomes a tool to generate rootmaps (and capability files)."),
145  llvm::cl::Hidden,
146  llvm::cl::cat(gRootclingOptions));
147 
148 ////////////////////////////////////////////////////////////////////////////////
149 
150 void SetRootSys();
151 
153  // rootcling's libCore needs "our" ROOTSYS:
154  SetRootSys();
155 };
156 
157 ////////////////////////////////////////////////////////////////////////////////
158 
159 void EmitStreamerInfo(const char *normName)
160 {
163 }
164 static void EmitTypedefs(const std::vector<const clang::TypedefNameDecl *> &tdvec)
165 {
167  return;
168  for (const auto td : tdvec)
169  gDriverConfig->fAddTypedefToROOTFile(td->getQualifiedNameAsString().c_str());
170 }
171 static void EmitEnums(const std::vector<const clang::EnumDecl *> &enumvec)
172 {
174  return;
175  for (const auto en : enumvec) {
176  // Enums within tag decls are processed as part of the tag.
177  if (clang::isa<clang::TranslationUnitDecl>(en->getDeclContext())
178  || clang::isa<clang::LinkageSpecDecl>(en->getDeclContext())
179  || clang::isa<clang::NamespaceDecl>(en->getDeclContext()))
180  gDriverConfig->fAddEnumToROOTFile(en->getQualifiedNameAsString().c_str());
181  }
182 }
183 
184 ////////////////////////////////////////////////////////////////////////////////
185 /// Returns the executable path name, used e.g. by SetRootSys().
186 
187 const char *GetExePath()
188 {
189  static std::string exepath;
190  if (exepath == "") {
191 #ifdef __APPLE__
192  exepath = _dyld_get_image_name(0);
193 #endif
194 #if defined(__linux) || defined(__linux__)
195  char linkname[PATH_MAX]; // /proc/<pid>/exe
196  char buf[PATH_MAX]; // exe path name
197  pid_t pid;
198 
199  // get our pid and build the name of the link in /proc
200  pid = getpid();
201  snprintf(linkname, PATH_MAX, "/proc/%i/exe", pid);
202  int ret = readlink(linkname, buf, 1024);
203  if (ret > 0 && ret < 1024) {
204  buf[ret] = 0;
205  exepath = buf;
206  }
207 #endif
208 #ifdef _WIN32
209  char *buf = new char[MAX_MODULE_NAME32 + 1];
210  ::GetModuleFileName(NULL, buf, MAX_MODULE_NAME32 + 1);
211  char *p = buf;
212  while ((p = strchr(p, '\\')))
213  * (p++) = '/';
214  exepath = buf;
215  delete[] buf;
216 #endif
217  }
218  return exepath.c_str();
219 }
220 
221 ////////////////////////////////////////////////////////////////////////////////
222 
223 bool Namespace__HasMethod(const clang::NamespaceDecl *cl, const char *name,
224  const cling::Interpreter &interp)
225 {
226  return ROOT::TMetaUtils::ClassInfo__HasMethod(cl, name, interp);
227 }
228 
229 ////////////////////////////////////////////////////////////////////////////////
230 
231 static void AnnotateFieldDecl(clang::FieldDecl &decl,
232  const std::list<VariableSelectionRule> &fieldSelRules)
233 {
234  using namespace ROOT::TMetaUtils;
235  // See if in the VariableSelectionRules there are attributes and names with
236  // which we can annotate.
237  // We may look for a smarter algorithm.
238 
239  // Nothing to do then ...
240  if (fieldSelRules.empty()) return;
241 
242  clang::ASTContext &C = decl.getASTContext();
243  clang::SourceRange commentRange; // Empty: this is a fake comment
244 
245  const std::string declName(decl.getNameAsString());
246  std::string varName;
247  for (std::list<VariableSelectionRule>::const_iterator it = fieldSelRules.begin();
248  it != fieldSelRules.end(); ++it) {
249  if (! it->GetAttributeValue(propNames::name, varName)) continue;
250  if (declName == varName) { // we have the rule!
251  // Let's extract the attributes
252  BaseSelectionRule::AttributesMap_t attrMap(it->GetAttributes());
253  BaseSelectionRule::AttributesMap_t::iterator iter;
254  std::string userDefinedProperty;
255  for (iter = attrMap.begin(); iter != attrMap.end(); ++iter) {
256  const std::string &name = iter->first;
257  const std::string &value = iter->second;
258 
259  if (name == propNames::name) continue;
260 
261  /* This test is here since in ROOT5, when using genreflex,
262  * for pods, iotype is ignored */
263 
264  if (name == propNames::iotype &&
265  (decl.getType()->isArrayType() || decl.getType()->isPointerType())) {
266  const char *msg = "Data member \"%s\" is an array or a pointer. "
267  "It is not possible to assign to it the iotype \"%s\". "
268  "This transformation is possible only with data members "
269  "which are not pointers or arrays.\n";
270  ROOT::TMetaUtils::Error("AnnotateFieldDecl",
271  msg, varName.c_str(), value.c_str());
272  continue;
273  }
274 
275 
276  // These lines are here to use the root pcms. Indeed we need to annotate the AST
277  // before persisting the ProtoClasses in the root pcms.
278  // BEGIN ROOT PCMS
279  if (name == propNames::comment) {
280  decl.addAttr(new(C) clang::AnnotateAttr(commentRange, C, value, 0));
281  }
282  // END ROOT PCMS
283 
284  if ((name == propNames::transient && value == "true") ||
285  (name == propNames::persistent && value == "false")) { // special case
286  userDefinedProperty = propNames::comment + propNames::separator + "!";
287  // This next line is here to use the root pcms. Indeed we need to annotate the AST
288  // before persisting the ProtoClasses in the root pcms.
289  // BEGIN ROOT PCMS
290  decl.addAttr(new(C) clang::AnnotateAttr(commentRange, C, "!", 0));
291  // END ROOT PCMS
292  // The rest of the lines are not changed to leave in place the system which
293  // works with bulk header parsing on library load.
294  } else {
295  userDefinedProperty = name + propNames::separator + value;
296  }
297  ROOT::TMetaUtils::Info(0, "%s %s\n", varName.c_str(), userDefinedProperty.c_str());
298  decl.addAttr(new(C) clang::AnnotateAttr(commentRange, C, userDefinedProperty, 0));
299 
300  }
301  }
302  }
303 }
304 
305 ////////////////////////////////////////////////////////////////////////////////
306 
307 void AnnotateDecl(clang::CXXRecordDecl &CXXRD,
308  const RScanner::DeclsSelRulesMap_t &declSelRulesMap,
309  cling::Interpreter &interpreter,
310  bool isGenreflex)
311 {
312  // In order to store the meaningful for the IO comments we have to transform
313  // the comment into annotation of the given decl.
314  // This works only with comments in the headers, so no selection rules in an
315  // xml file.
316 
317  using namespace clang;
318  SourceLocation commentSLoc;
319  llvm::StringRef comment;
320 
321  ASTContext &C = CXXRD.getASTContext();
322  Sema &S = interpreter.getCI()->getSema();
323 
324  SourceRange commentRange;
325 
326  // Fetch the selection rule associated to this class
327  clang::Decl *declBaseClassPtr = static_cast<clang::Decl *>(&CXXRD);
328  auto declSelRulePair = declSelRulesMap.find(declBaseClassPtr->getCanonicalDecl());
329  if (declSelRulePair == declSelRulesMap.end()){
330  const std::string thisClassName(CXXRD.getName());
331  ROOT::TMetaUtils::Error("AnnotateDecl","Cannot find class %s in the list of selected classes.\n",thisClassName.c_str());
332  return;
333  }
334  const BaseSelectionRule *thisClassBaseSelectionRule = declSelRulePair->second;
335  // If the rule is there
336  if (thisClassBaseSelectionRule) {
337  // Fetch and loop over Class attributes
338  // if the name of the attribute is not "name", add attr to the ast.
339  BaseSelectionRule::AttributesMap_t::iterator iter;
340  std::string userDefinedProperty;
341  for (auto const & attr : thisClassBaseSelectionRule->GetAttributes()) {
342  const std::string &name = attr.first;
343  if (name == ROOT::TMetaUtils::propNames::name) continue;
344  const std::string &value = attr.second;
345  userDefinedProperty = name + ROOT::TMetaUtils::propNames::separator + value;
346  if (genreflex::verbose) std::cout << " * " << userDefinedProperty << std::endl;
347  CXXRD.addAttr(new(C) AnnotateAttr(commentRange, C, userDefinedProperty, 0));
348  }
349  }
350 
351  // See if the rule is a class selection rule (FIX dynamic_cast)
352  const ClassSelectionRule *thisClassSelectionRule = reinterpret_cast<const ClassSelectionRule *>(thisClassBaseSelectionRule);
353 
354  for (CXXRecordDecl::decl_iterator I = CXXRD.decls_begin(),
355  E = CXXRD.decls_end(); I != E; ++I) {
356 
357  // CXXMethodDecl,FieldDecl and VarDecl inherit from NamedDecl
358  // See: http://clang.llvm.org/doxygen/classclang_1_1DeclaratorDecl.html
359  if (!(*I)->isImplicit()
360  && (isa<CXXMethodDecl>(*I) || isa<FieldDecl>(*I) || isa<VarDecl>(*I))) {
361 
362 
363  // For now we allow only a special macro (ClassDef) to have meaningful comments
364  SourceLocation maybeMacroLoc = (*I)->getLocation();
365  bool isClassDefMacro = maybeMacroLoc.isMacroID() && S.findMacroSpelling(maybeMacroLoc, "ClassDef");
366  if (isClassDefMacro) {
367  while (isa<NamedDecl>(*I) && cast<NamedDecl>(*I)->getName() != "DeclFileLine") {
368  ++I;
369  }
370  }
371 
372  comment = ROOT::TMetaUtils::GetComment(**I, &commentSLoc);
373  if (comment.size()) {
374  // Keep info for the source range of the comment in case we want to issue
375  // nice warnings, eg. empty comment and so on.
376  commentRange = SourceRange(commentSLoc, commentSLoc.getLocWithOffset(comment.size()));
377  // The ClassDef annotation is for the class itself
378  if (isClassDefMacro) {
379  CXXRD.addAttr(new(C) AnnotateAttr(commentRange, C, comment.str(), 0));
380  } else if (!isGenreflex) {
381  // Here we check if we are in presence of a selection file so that
382  // the comment does not ends up as a decoration in the AST,
383  // Nevertheless, w/o PCMS this has no effect, since the headers
384  // are parsed at runtime and the information in the AST dumped by
385  // rootcling is not relevant.
386  (*I)->addAttr(new(C) AnnotateAttr(commentRange, C, comment.str(), 0));
387  }
388  }
389  // Match decls with sel rules if we are in presence of a selection file
390  // and the cast was successful
391  if (isGenreflex && thisClassSelectionRule != 0) {
392  const std::list<VariableSelectionRule> &fieldSelRules = thisClassSelectionRule->GetFieldSelectionRules();
393 
394  // This check is here to avoid asserts in debug mode (LLVMDEV env variable set)
395  if (FieldDecl *fieldDecl = dyn_cast<FieldDecl>(*I)) {
396  AnnotateFieldDecl(*fieldDecl, fieldSelRules);
397  }
398  } // End presence of XML selection file
399  }
400  }
401 }
402 
403 ////////////////////////////////////////////////////////////////////////////////
404 
405 size_t GetFullArrayLength(const clang::ConstantArrayType *arrayType)
406 {
407  llvm::APInt len = arrayType->getSize();
408  while (const clang::ConstantArrayType *subArrayType = llvm::dyn_cast<clang::ConstantArrayType>(arrayType->getArrayElementTypeNoTypeQual())) {
409  len *= subArrayType->getSize();
410  arrayType = subArrayType;
411  }
412  return len.getLimitedValue();
413 }
414 
415 ////////////////////////////////////////////////////////////////////////////////
416 
417 bool InheritsFromTObject(const clang::RecordDecl *cl,
418  const cling::Interpreter &interp)
419 {
420  static const clang::CXXRecordDecl *TObject_decl
421  = ROOT::TMetaUtils::ScopeSearch("TObject", interp, true /*diag*/, 0);
422 
423  const clang::CXXRecordDecl *clxx = llvm::dyn_cast<clang::CXXRecordDecl>(cl);
424  return ROOT::TMetaUtils::IsBase(clxx, TObject_decl, nullptr, interp);
425 }
426 
427 ////////////////////////////////////////////////////////////////////////////////
428 
429 bool InheritsFromTSelector(const clang::RecordDecl *cl,
430  const cling::Interpreter &interp)
431 {
432  static const clang::CXXRecordDecl *TObject_decl
433  = ROOT::TMetaUtils::ScopeSearch("TSelector", interp, false /*diag*/, 0);
434 
435  return ROOT::TMetaUtils::IsBase(llvm::dyn_cast<clang::CXXRecordDecl>(cl), TObject_decl, nullptr, interp);
436 }
437 
438 ////////////////////////////////////////////////////////////////////////////////
439 
440 bool IsSelectionXml(const char *filename)
441 {
442  size_t len = strlen(filename);
443  size_t xmllen = 4; /* strlen(".xml"); */
444  if (strlen(filename) >= xmllen) {
445  return (0 == strcasecmp(filename + (len - xmllen), ".xml"));
446  } else {
447  return false;
448  }
449 }
450 
451 ////////////////////////////////////////////////////////////////////////////////
452 
453 bool IsLinkdefFile(const clang::PresumedLoc& PLoc)
454 {
455  return ROOT::TMetaUtils::IsLinkdefFile(PLoc.getFilename());
456 }
457 
458 ////////////////////////////////////////////////////////////////////////////////
459 
460 bool IsSelectionFile(const char *filename)
461 {
462  return ROOT::TMetaUtils::IsLinkdefFile(filename) || IsSelectionXml(filename);
463 }
464 
465 ////////////////////////////////////////////////////////////////////////////////
466 /// Set the ROOTSYS env var based on the executable location.
467 
469 {
470  const char *exepath = GetExePath();
471  if (exepath && *exepath) {
472 #if !defined(_WIN32)
473  char *ep = new char[PATH_MAX];
474  if (!realpath(exepath, ep)) {
475  fprintf(stderr, "rootcling: error getting realpath of rootcling!");
476  strlcpy(ep, exepath, PATH_MAX);
477  }
478 #else
479  int nche = strlen(exepath) + 1;
480  char *ep = new char[nche];
481  strlcpy(ep, exepath, nche);
482 #endif
483  char *s;
484 
485  if ((s = strrchr(ep, '/'))) {
486  // $ROOTSYS/bin/rootcling
487  int removesubdirs = 2;
488  if (!strncmp(s + 1, "rootcling_stage1.exe", 20)) {
489  // $ROOTSYS/bin/rootcling_stage1.exe
490  removesubdirs = 2;
491  gBuildingROOT = true;
492  } else if (!strncmp(s + 1, "rootcling_stage1", 16)) {
493  // $ROOTSYS/core/rootcling_stage1/src/rootcling_stage1
494  removesubdirs = 4;
495  gBuildingROOT = true;
496  }
497  for (int i = 1; s && i < removesubdirs; ++i) {
498  *s = 0;
499  s = strrchr(ep, '/');
500  }
501  if (s) *s = 0;
502  } else {
503  // There was no slashes at all let now change ROOTSYS
504  delete [] ep;
505  return;
506  }
507 
508  if (!gBuildingROOT) {
509  delete [] ep;
510  return; // don't mess with user's ROOTSYS.
511  }
512 
513  int ncha = strlen(ep) + 10;
514  char *env = new char[ncha];
515  snprintf(env, ncha, "ROOTSYS=%s", ep);
516 
517  if (gDriverConfig) {
518  // After the putenv below, gRootDir might point to the old ROOTSYS
519  // entry, i.e. to deleted memory. Update it.
520  const char** pRootDir = gDriverConfig->fPRootDir;
521  if (pRootDir) {
522  *pRootDir = env + 8;
523  }
524  }
525 
526  putenv(env);
527  // intentionally not call delete [] env, while GLIBC keep use pointer
528  delete [] ep;
529  }
530 }
531 
532 ////////////////////////////////////////////////////////////////////////////////
533 /// Check whether the #pragma line contains expectedTokens (0-terminated array).
534 
535 bool ParsePragmaLine(const std::string &line,
536  const char *expectedTokens[],
537  size_t *end = 0)
538 {
539  if (end) *end = 0;
540  if (line[0] != '#') return false;
541  size_t pos = 1;
542  for (const char **iToken = expectedTokens; *iToken; ++iToken) {
543  while (isspace(line[pos])) ++pos;
544  size_t lenToken = strlen(*iToken);
545  if (line.compare(pos, lenToken, *iToken)) {
546  if (end) *end = pos;
547  return false;
548  }
549  pos += lenToken;
550  }
551  if (end) *end = pos;
552  return true;
553 }
554 
555 
556 map<string, string> gAutoloads;
557 string gLibsNeeded;
558 
559 ////////////////////////////////////////////////////////////////////////////////
560 
561 void RecordDeclCallback(const clang::RecordDecl* recordDecl)
562 {
563  std::string need;
564  if (recordDecl->hasOwningModule()) {
565  clang::Module *M = recordDecl->getOwningModule()->getTopLevelModule();
566  need = "lib" + M->Name + gLibraryExtension;
567  } else {
568  std::string qual_name;
569  RScanner::GetDeclQualName(recordDecl, qual_name);
570 
571  need = gAutoloads[qual_name];
572  }
573 
574  if (need.length() && gLibsNeeded.find(need) == string::npos) {
575  gLibsNeeded += " " + need;
576  }
577 }
578 
579 ////////////////////////////////////////////////////////////////////////////////
580 
581 void CheckClassNameForRootMap(const std::string &classname, map<string, string> &autoloads)
582 {
583  if (classname.find(':') == std::string::npos) return;
584 
585  // We have a namespace and we have to check it first
586  int slen = classname.size();
587  for (int k = 0; k < slen; ++k) {
588  if (classname[k] == ':') {
589  if (k + 1 >= slen || classname[k + 1] != ':') {
590  // we expected another ':'
591  break;
592  }
593  if (k) {
594  string base = classname.substr(0, k);
595  if (base == "std") {
596  // std is not declared but is also ignored by CINT!
597  break;
598  } else {
599  autoloads[base] = ""; // We never load namespaces on their own.
600  }
601  ++k;
602  }
603  } else if (classname[k] == '<') {
604  // We do not want to look at the namespace inside the template parameters!
605  break;
606  }
607  }
608 }
609 
610 ////////////////////////////////////////////////////////////////////////////////
611 /// Parse the rootmap and add entries to the autoload map
612 
613 void ParseRootMapFile(ifstream &file, map<string, string> &autoloads)
614 {
615  std::string classname;
616  std::string line;
617  while (file >> line) {
618 
619  if (line.find("Library.") != 0) continue;
620 
621  int pos = line.find(":", 8);
622  classname = line.substr(8, pos - 8);
623 
624  ROOT::TMetaUtils::ReplaceAll(classname, "@@", "::");
625  ROOT::TMetaUtils::ReplaceAll(classname, "-", " ");
626 
627  getline(file, line, '\n');
628  while (line[0] == ' ') line.replace(0, 1, "");
629 
630  CheckClassNameForRootMap(classname, autoloads);
631 
632  if (classname == "ROOT::TImpProxy") {
633  // Do not register the ROOT::TImpProxy so that they can be instantiated.
634  continue;
635  }
636  autoloads[classname] = line;
637  }
638 
639 }
640 
641 ////////////////////////////////////////////////////////////////////////////////
642 /// Parse the rootmap and add entries to the autoload map, using the new format
643 
644 void ParseRootMapFileNewFormat(ifstream &file, map<string, string> &autoloads)
645 {
646  std::string keyname;
647  std::string libs;
648  std::string line;
649 
650  // For "class ", "namespace " and "typedef " respectively
651  const std::unordered_map<char, unsigned int> keyLenMap = {{'c', 6}, {'n', 10}, {'t', 8}};
652 
653  while (getline(file, line, '\n')) {
654  if (line == "{ decls }") {
655  while (getline(file, line, '\n')) {
656  if (line[0] == '[') break;
657  }
658  }
659  const char firstChar = line[0];
660  if (firstChar == '[') {
661  // new section
662  libs = line.substr(1, line.find(']') - 1);
663  while (libs[0] == ' ') libs.replace(0, 1, "");
664  } else if (0 != keyLenMap.count(firstChar)) {
665  unsigned int keyLen = keyLenMap.at(firstChar);
666  keyname = line.substr(keyLen, line.length() - keyLen);
667  CheckClassNameForRootMap(keyname, autoloads);
668  autoloads[keyname] = libs;
669  }
670  }
671 
672 }
673 
674 ////////////////////////////////////////////////////////////////////////////////
675 /// Fill the map of libraries to be loaded in presence of a class
676 /// Transparently support the old and new rootmap file format
677 
678 void LoadLibraryMap(const std::string &fileListName, map<string, string> &autoloads)
679 {
680  std::ifstream filelist(fileListName.c_str());
681 
682  std::string filename;
683  std::string line;
684 
685  while (filelist >> filename) {
686 
687  if (llvm::sys::fs::is_directory(filename)) continue;
688 
689  ifstream file(filename.c_str());
690 
691  // Check which format is this
692  file >> line;
693  bool new_format = (line[0] == '[' || line[0] == '{') ;
694  file.clear();
695  file.seekg(0, std::ios::beg);
696 
697  // Now act
698  if (new_format) {
699  ParseRootMapFileNewFormat(file, autoloads);
700  } else {
701  ParseRootMapFile(file, autoloads);
702  }
703 
704  file.close();
705 
706  } // end loop on files
707  filelist.close();
708 }
709 
710 ////////////////////////////////////////////////////////////////////////////////
711 /// Check if the specified operator (what) has been properly declared if the user has
712 /// requested a custom version.
713 
714 bool CheckInputOperator(const char *what,
715  const char *proto,
716  const string &fullname,
717  const clang::RecordDecl *cl,
718  cling::Interpreter &interp)
719 {
720 
721  const clang::FunctionDecl *method
722  = ROOT::TMetaUtils::GetFuncWithProto(llvm::dyn_cast<clang::Decl>(cl->getDeclContext()), what, proto, interp,
723  false /*diags*/);
724  if (!method) {
725  // This intended to find the global scope.
726  clang::TranslationUnitDecl *TU =
727  cl->getASTContext().getTranslationUnitDecl();
728  method = ROOT::TMetaUtils::GetFuncWithProto(TU, what, proto, interp,
729  false /*diags*/);
730  }
731  bool has_input_error = false;
732  if (method != 0 && (method->getAccess() == clang::AS_public || method->getAccess() == clang::AS_none)) {
733  std::string filename = ROOT::TMetaUtils::GetFileName(*method, interp);
734  if (strstr(filename.c_str(), "TBuffer.h") != 0 ||
735  strstr(filename.c_str(), "Rtypes.h") != 0) {
736 
737  has_input_error = true;
738  }
739  } else {
740  has_input_error = true;
741  }
742  if (has_input_error) {
743  // We don't want to generate duplicated error messages in several dictionaries (when generating temporaries)
744  const char *maybeconst = "";
745  const char *mayberef = "&";
746  if (what[strlen(what) - 1] == '<') {
747  maybeconst = "const ";
748  mayberef = "";
749  }
751  "in this version of ROOT, the option '!' used in a linkdef file\n"
752  " implies the actual existence of customized operators.\n"
753  " The following declaration is now required:\n"
754  " TBuffer &%s(TBuffer &,%s%s *%s);\n", what, maybeconst, fullname.c_str(), mayberef);
755  }
756  return has_input_error;
757 
758 }
759 
760 ////////////////////////////////////////////////////////////////////////////////
761 /// Check if the operator>> has been properly declared if the user has
762 /// requested a custom version.
763 
764 bool CheckInputOperator(const clang::RecordDecl *cl, cling::Interpreter &interp)
765 {
766  string fullname;
767  ROOT::TMetaUtils::GetQualifiedName(fullname, *cl);
768  int ncha = fullname.length() + 13;
769  char *proto = new char[ncha];
770  snprintf(proto, ncha, "TBuffer&,%s*&", fullname.c_str());
771 
772  ROOT::TMetaUtils::Info(0, "Class %s: Do not generate operator>>()\n",
773  fullname.c_str());
774 
775  // We do want to call both CheckInputOperator all the times.
776  bool has_input_error = CheckInputOperator("operator>>", proto, fullname, cl, interp);
777  has_input_error = CheckInputOperator("operator<<", proto, fullname, cl, interp) || has_input_error;
778 
779  delete [] proto;
780 
781  return has_input_error;
782 }
783 
784 ////////////////////////////////////////////////////////////////////////////////
785 /// Return false if the class does not have ClassDef even-though it should.
786 
787 bool CheckClassDef(const clang::RecordDecl &cl, const cling::Interpreter &interp)
788 {
789 
790  // Detect if the class has a ClassDef
791  bool hasClassDef = ROOT::TMetaUtils::ClassInfo__HasMethod(&cl, "Class_Version", interp);
792 
793  const clang::CXXRecordDecl *clxx = llvm::dyn_cast<clang::CXXRecordDecl>(&cl);
794  if (!clxx) {
795  return false;
796  }
797  bool isAbstract = clxx->isAbstract();
798 
799  if (!isAbstract && InheritsFromTObject(clxx, interp) && !InheritsFromTSelector(clxx, interp) && !hasClassDef) {
800  std::string qualName;
802  const char *qualName_c = qualName.c_str();
803  ROOT::TMetaUtils::Warning(qualName_c, "The data members of %s will not be stored, "
804  "because it inherits from TObject but does not "
805  "have its own ClassDef.\n",
806  qualName_c);
807  }
808 
809  return true;
810 }
811 
812 ////////////////////////////////////////////////////////////////////////////////
813 /// Return the name of the data member so that it can be used
814 /// by non-const operation (so it includes a const_cast if necessary).
815 
816 string GetNonConstMemberName(const clang::FieldDecl &m, const string &prefix = "")
817 {
818  if (m.getType().isConstQualified()) {
819  string ret = "const_cast< ";
820  string type_name;
821  ROOT::TMetaUtils::GetQualifiedName(type_name, m.getType(), m);
822  if (type_name.substr(0,6)=="const ") {
823  ret += type_name.c_str()+6;
824  } else {
825  ret += type_name;
826  }
827  ret += " &>( ";
828  ret += prefix;
829  ret += m.getName().str();
830  ret += " )";
831  return ret;
832  } else {
833  return prefix + m.getName().str();
834  }
835 }
836 
837 ////////////////////////////////////////////////////////////////////////////////
838 /// Create Streamer code for an STL container. Returns 1 if data member
839 /// was an STL container and if Streamer code has been created, 0 otherwise.
840 
841 int STLContainerStreamer(const clang::FieldDecl &m,
842  int rwmode,
843  const cling::Interpreter &interp,
844  const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt,
845  std::ostream &dictStream)
846 {
848  std::string mTypename;
849  ROOT::TMetaUtils::GetQualifiedName(mTypename, m.getType(), m);
850 
851  const clang::CXXRecordDecl *clxx = llvm::dyn_cast_or_null<clang::CXXRecordDecl>(ROOT::TMetaUtils::GetUnderlyingRecordDecl(m.getType()));
852 
853  if (stltype == ROOT::kNotSTL) {
854  return 0;
855  }
856  // fprintf(stderr,"Add %s (%d) which is also %s\n",
857  // m.Type()->Name(), stltype, m.Type()->TrueName() );
858  clang::QualType utype(ROOT::TMetaUtils::GetUnderlyingType(m.getType()), 0);
859  Internal::RStl::Instance().GenerateTClassFor(utype, interp, normCtxt);
860 
861  if (clxx->getTemplateSpecializationKind() == clang::TSK_Undeclared) return 0;
862 
863  const clang::ClassTemplateSpecializationDecl *tmplt_specialization = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl> (clxx);
864  if (!tmplt_specialization) return 0;
865 
866 
867  string stlType(ROOT::TMetaUtils::ShortTypeName(mTypename.c_str()));
868  string stlName;
869  stlName = ROOT::TMetaUtils::ShortTypeName(m.getName().str().c_str());
870 
871  string fulName1, fulName2;
872  const char *tcl1 = 0, *tcl2 = 0;
873  const clang::TemplateArgument &arg0(tmplt_specialization->getTemplateArgs().get(0));
874  clang::QualType ti = arg0.getAsType();
875 
876  if (ROOT::TMetaUtils::ElementStreamer(dictStream, m, ti, 0, rwmode, interp)) {
877  tcl1 = "R__tcl1";
878  fulName1 = ti.getAsString(); // Should we be passing a context?
879  }
880  if (stltype == kSTLmap || stltype == kSTLmultimap) {
881  const clang::TemplateArgument &arg1(tmplt_specialization->getTemplateArgs().get(1));
882  clang::QualType tmplti = arg1.getAsType();
883  if (ROOT::TMetaUtils::ElementStreamer(dictStream, m, tmplti, 0, rwmode, interp)) {
884  tcl2 = "R__tcl2";
885  fulName2 = tmplti.getAsString(); // Should we be passing a context?
886  }
887  }
888 
889  int isArr = 0;
890  int len = 1;
891  int pa = 0;
892  const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(m.getType().getTypePtr());
893  if (arrayType) {
894  isArr = 1;
895  len = GetFullArrayLength(arrayType);
896  pa = 1;
897  while (arrayType) {
898  if (arrayType->getArrayElementTypeNoTypeQual()->isPointerType()) {
899  pa = 3;
900  break;
901  }
902  arrayType = llvm::dyn_cast<clang::ConstantArrayType>(arrayType->getArrayElementTypeNoTypeQual());
903  }
904  } else if (m.getType()->isPointerType()) {
905  pa = 2;
906  }
907  if (rwmode == 0) {
908  // create read code
909  dictStream << " {" << std::endl;
910  if (isArr) {
911  dictStream << " for (Int_t R__l = 0; R__l < " << len << "; R__l++) {" << std::endl;
912  }
913 
914  switch (pa) {
915  case 0: //No pointer && No array
916  dictStream << " " << stlType.c_str() << " &R__stl = " << stlName.c_str() << ";" << std::endl;
917  break;
918  case 1: //No pointer && array
919  dictStream << " " << stlType.c_str() << " &R__stl = " << stlName.c_str() << "[R__l];" << std::endl;
920  break;
921  case 2: //pointer && No array
922  dictStream << " delete *" << stlName.c_str() << ";" << std::endl
923  << " *" << stlName.c_str() << " = new " << stlType.c_str() << ";" << std::endl
924  << " " << stlType.c_str() << " &R__stl = **" << stlName.c_str() << ";" << std::endl;
925  break;
926  case 3: //pointer && array
927  dictStream << " delete " << stlName.c_str() << "[R__l];" << std::endl
928  << " " << stlName.c_str() << "[R__l] = new " << stlType.c_str() << ";" << std::endl
929  << " " << stlType.c_str() << " &R__stl = *" << stlName.c_str() << "[R__l];" << std::endl;
930  break;
931  }
932 
933  dictStream << " R__stl.clear();" << std::endl;
934 
935  if (tcl1) {
936  dictStream << " TClass *R__tcl1 = TBuffer::GetClass(typeid(" << fulName1.c_str() << "));" << std::endl
937  << " if (R__tcl1==0) {" << std::endl
938  << " Error(\"" << stlName.c_str() << " streamer\",\"Missing the TClass object for "
939  << fulName1.c_str() << "!\");" << std::endl
940  << " return;" << std::endl
941  << " }" << std::endl;
942  }
943  if (tcl2) {
944  dictStream << " TClass *R__tcl2 = TBuffer::GetClass(typeid(" << fulName2.c_str() << "));" << std::endl
945  << " if (R__tcl2==0) {" << std::endl
946  << " Error(\"" << stlName.c_str() << " streamer\",\"Missing the TClass object for "
947  << fulName2.c_str() << "!\");" << std::endl
948  << " return;" << std::endl
949  << " }" << std::endl;
950  }
951 
952  dictStream << " int R__i, R__n;" << std::endl
953  << " R__b >> R__n;" << std::endl;
954 
955  if (stltype == kSTLvector) {
956  dictStream << " R__stl.reserve(R__n);" << std::endl;
957  }
958  dictStream << " for (R__i = 0; R__i < R__n; R__i++) {" << std::endl;
959 
960  ROOT::TMetaUtils::ElementStreamer(dictStream, m, arg0.getAsType(), "R__t", rwmode, interp, tcl1);
961  if (stltype == kSTLmap || stltype == kSTLmultimap) { //Second Arg
962  const clang::TemplateArgument &arg1(tmplt_specialization->getTemplateArgs().get(1));
963  ROOT::TMetaUtils::ElementStreamer(dictStream, m, arg1.getAsType(), "R__t2", rwmode, interp, tcl2);
964  }
965 
966  /* Need to go from
967  type R__t;
968  R__t.Stream;
969  vec.push_back(R__t);
970  to
971  vec.push_back(type());
972  R__t_p = &(vec.last());
973  *R__t_p->Stream;
974 
975  */
976  switch (stltype) {
977 
978  case kSTLmap:
979  case kSTLmultimap:
980  case kSTLunorderedmap:
981  case kSTLunorderedmultimap:{
982  std::string keyName(ti.getAsString());
983  dictStream << " typedef " << keyName << " Value_t;" << std::endl
984  << " std::pair<Value_t const, " << tmplt_specialization->getTemplateArgs().get(1).getAsType().getAsString() << " > R__t3(R__t,R__t2);" << std::endl
985  << " R__stl.insert(R__t3);" << std::endl;
986  //fprintf(fp, " R__stl.insert(%s::value_type(R__t,R__t2));\n",stlType.c_str());
987  break;
988  }
989  case kSTLset:
990  case kSTLunorderedset:
992  case kSTLmultiset:
993  dictStream << " R__stl.insert(R__t);" << std::endl;
994  break;
995  case kSTLvector:
996  case kSTLlist:
997  case kSTLdeque:
998  dictStream << " R__stl.push_back(R__t);" << std::endl;
999  break;
1000  case kSTLforwardlist:
1001  dictStream << " R__stl.push_front(R__t);" << std::endl;
1002  break;
1003  default:
1004  assert(0);
1005  }
1006  dictStream << " }" << std::endl
1007  << " }" << std::endl;
1008  if (isArr) dictStream << " }" << std::endl;
1009 
1010  } else {
1011 
1012  // create write code
1013  if (isArr) {
1014  dictStream << " for (Int_t R__l = 0; R__l < " << len << "; R__l++) {" << std::endl;
1015  }
1016  dictStream << " {" << std::endl;
1017  switch (pa) {
1018  case 0: //No pointer && No array
1019  dictStream << " " << stlType.c_str() << " &R__stl = " << stlName.c_str() << ";" << std::endl;
1020  break;
1021  case 1: //No pointer && array
1022  dictStream << " " << stlType.c_str() << " &R__stl = " << stlName.c_str() << "[R__l];" << std::endl;
1023  break;
1024  case 2: //pointer && No array
1025  dictStream << " " << stlType.c_str() << " &R__stl = **" << stlName.c_str() << ";" << std::endl;
1026  break;
1027  case 3: //pointer && array
1028  dictStream << " " << stlType.c_str() << " &R__stl = *" << stlName.c_str() << "[R__l];" << std::endl;
1029  break;
1030  }
1031 
1032  dictStream << " int R__n=int(R__stl.size());" << std::endl
1033  << " R__b << R__n;" << std::endl
1034  << " if(R__n) {" << std::endl;
1035 
1036  if (tcl1) {
1037  dictStream << " TClass *R__tcl1 = TBuffer::GetClass(typeid(" << fulName1.c_str() << "));" << std::endl
1038  << " if (R__tcl1==0) {" << std::endl
1039  << " Error(\"" << stlName.c_str() << " streamer\",\"Missing the TClass object for "
1040  << fulName1.c_str() << "!\");" << std::endl
1041  << " return;" << std::endl
1042  << " }" << std::endl;
1043  }
1044  if (tcl2) {
1045  dictStream << " TClass *R__tcl2 = TBuffer::GetClass(typeid(" << fulName2.c_str() << "));" << std::endl
1046  << " if (R__tcl2==0) {" << std::endl
1047  << " Error(\"" << stlName.c_str() << "streamer\",\"Missing the TClass object for " << fulName2.c_str() << "!\");" << std::endl
1048  << " return;" << std::endl
1049  << " }" << std::endl;
1050  }
1051 
1052  dictStream << " " << stlType.c_str() << "::iterator R__k;" << std::endl
1053  << " for (R__k = R__stl.begin(); R__k != R__stl.end(); ++R__k) {" << std::endl;
1054  if (stltype == kSTLmap || stltype == kSTLmultimap) {
1055  const clang::TemplateArgument &arg1(tmplt_specialization->getTemplateArgs().get(1));
1056  clang::QualType tmplti = arg1.getAsType();
1057  ROOT::TMetaUtils::ElementStreamer(dictStream, m, ti, "((*R__k).first )", rwmode, interp, tcl1);
1058  ROOT::TMetaUtils::ElementStreamer(dictStream, m, tmplti, "((*R__k).second)", rwmode, interp, tcl2);
1059  } else {
1060  ROOT::TMetaUtils::ElementStreamer(dictStream, m, ti, "(*R__k)" , rwmode, interp, tcl1);
1061  }
1062 
1063  dictStream << " }" << std::endl
1064  << " }" << std::endl
1065  << " }" << std::endl;
1066  if (isArr) dictStream << " }" << std::endl;
1067  }
1068  return 1;
1069 }
1070 
1071 ////////////////////////////////////////////////////////////////////////////////
1072 /// Create Streamer code for a standard string object. Returns 1 if data
1073 /// member was a standard string and if Streamer code has been created,
1074 /// 0 otherwise.
1075 
1076 int STLStringStreamer(const clang::FieldDecl &m, int rwmode, std::ostream &dictStream)
1077 {
1078  std::string mTypenameStr;
1079  ROOT::TMetaUtils::GetQualifiedName(mTypenameStr, m.getType(), m);
1080  // Note: here we could to a direct type comparison!
1081  const char *mTypeName = ROOT::TMetaUtils::ShortTypeName(mTypenameStr.c_str());
1082  if (!strcmp(mTypeName, "string")) {
1083 
1084  std::string fieldname = m.getName().str();
1085  if (rwmode == 0) {
1086  // create read mode
1087  if (m.getType()->isConstantArrayType()) {
1088  if (m.getType().getTypePtr()->getArrayElementTypeNoTypeQual()->isPointerType()) {
1089  dictStream << "// Array of pointer to std::string are not supported (" << fieldname << "\n";
1090  } else {
1091  std::stringstream fullIdx;
1092  const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(m.getType().getTypePtr());
1093  int dim = 0;
1094  while (arrayType) {
1095  dictStream << " for (int R__i" << dim << "=0; R__i" << dim << "<"
1096  << arrayType->getSize().getLimitedValue() << "; ++R__i" << dim << " )" << std::endl;
1097  fullIdx << "[R__i" << dim << "]";
1098  arrayType = llvm::dyn_cast<clang::ConstantArrayType>(arrayType->getArrayElementTypeNoTypeQual());
1099  ++dim;
1100  }
1101  dictStream << " { TString R__str; R__str.Streamer(R__b); "
1102  << fieldname << fullIdx.str() << " = R__str.Data();}" << std::endl;
1103  }
1104  } else {
1105  dictStream << " { TString R__str; R__str.Streamer(R__b); ";
1106  if (m.getType()->isPointerType())
1107  dictStream << "if (*" << fieldname << ") delete *" << fieldname << "; (*"
1108  << fieldname << " = new string(R__str.Data())); }" << std::endl;
1109  else
1110  dictStream << fieldname << " = R__str.Data(); }" << std::endl;
1111  }
1112  } else {
1113  // create write mode
1114  if (m.getType()->isPointerType())
1115  dictStream << " { TString R__str; if (*" << fieldname << ") R__str = (*"
1116  << fieldname << ")->c_str(); R__str.Streamer(R__b);}" << std::endl;
1117  else if (m.getType()->isConstantArrayType()) {
1118  std::stringstream fullIdx;
1119  const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(m.getType().getTypePtr());
1120  int dim = 0;
1121  while (arrayType) {
1122  dictStream << " for (int R__i" << dim << "=0; R__i" << dim << "<"
1123  << arrayType->getSize().getLimitedValue() << "; ++R__i" << dim << " )" << std::endl;
1124  fullIdx << "[R__i" << dim << "]";
1125  arrayType = llvm::dyn_cast<clang::ConstantArrayType>(arrayType->getArrayElementTypeNoTypeQual());
1126  ++dim;
1127  }
1128  dictStream << " { TString R__str(" << fieldname << fullIdx.str() << ".c_str()); R__str.Streamer(R__b);}" << std::endl;
1129  } else
1130  dictStream << " { TString R__str = " << fieldname << ".c_str(); R__str.Streamer(R__b);}" << std::endl;
1131  }
1132  return 1;
1133  }
1134  return 0;
1135 }
1136 
1137 ////////////////////////////////////////////////////////////////////////////////
1138 
1139 bool isPointerToPointer(const clang::FieldDecl &m)
1140 {
1141  if (m.getType()->isPointerType()) {
1142  if (m.getType()->getPointeeType()->isPointerType()) {
1143  return true;
1144  }
1145  }
1146  return false;
1147 }
1148 
1149 ////////////////////////////////////////////////////////////////////////////////
1150 /// Write "[0]" for all but the 1st dimension.
1151 
1152 void WriteArrayDimensions(const clang::QualType &type, std::ostream &dictStream)
1153 {
1154  const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(type.getTypePtr());
1155  if (arrayType) {
1156  arrayType = llvm::dyn_cast<clang::ConstantArrayType>(arrayType->getArrayElementTypeNoTypeQual());
1157  while (arrayType) {
1158  dictStream << "[0]";
1159  arrayType = llvm::dyn_cast<clang::ConstantArrayType>(arrayType->getArrayElementTypeNoTypeQual());
1160  }
1161  }
1162 }
1163 
1164 ////////////////////////////////////////////////////////////////////////////////
1165 /// Write the code to set the class name and the initialization object.
1166 
1167 void WriteClassFunctions(const clang::CXXRecordDecl *cl, std::ostream &dictStream, bool autoLoad = false)
1168 {
1169  bool add_template_keyword = ROOT::TMetaUtils::NeedTemplateKeyword(cl);
1170 
1171  string fullname;
1172  string clsname;
1173  string nsname;
1174  int enclSpaceNesting = 0;
1175 
1176  if (ROOT::TMetaUtils::GetNameWithinNamespace(fullname, clsname, nsname, cl)) {
1177  enclSpaceNesting = ROOT::TMetaUtils::WriteNamespaceHeader(dictStream, cl);
1178  }
1179 
1180  if (autoLoad)
1181  dictStream << "#include \"TInterpreter.h\"\n";
1182 
1183  dictStream << "//_______________________________________"
1184  << "_______________________________________" << std::endl;
1185  if (add_template_keyword) dictStream << "template <> ";
1186  dictStream << "atomic_TClass_ptr " << clsname << "::fgIsA(0); // static to hold class pointer" << std::endl
1187  << std::endl
1188 
1189  << "//_______________________________________"
1190  << "_______________________________________" << std::endl;
1191  if (add_template_keyword) dictStream << "template <> ";
1192  dictStream << "const char *" << clsname << "::Class_Name()" << std::endl << "{" << std::endl
1193  << " return \"" << fullname << "\";" << std::endl << "}" << std::endl << std::endl;
1194 
1195  dictStream << "//_______________________________________"
1196  << "_______________________________________" << std::endl;
1197  if (add_template_keyword) dictStream << "template <> ";
1198  dictStream << "const char *" << clsname << "::ImplFileName()" << std::endl << "{" << std::endl
1199  << " return ::ROOT::GenerateInitInstanceLocal((const ::" << fullname
1200  << "*)0x0)->GetImplFileName();" << std::endl << "}" << std::endl << std::endl
1201 
1202  << "//_______________________________________"
1203  << "_______________________________________" << std::endl;
1204  if (add_template_keyword) dictStream << "template <> ";
1205  dictStream << "int " << clsname << "::ImplFileLine()" << std::endl << "{" << std::endl
1206  << " return ::ROOT::GenerateInitInstanceLocal((const ::" << fullname
1207  << "*)0x0)->GetImplFileLine();" << std::endl << "}" << std::endl << std::endl
1208 
1209  << "//_______________________________________"
1210  << "_______________________________________" << std::endl;
1211  if (add_template_keyword) dictStream << "template <> ";
1212  dictStream << "TClass *" << clsname << "::Dictionary()" << std::endl << "{" << std::endl;
1213 
1214  // Trigger autoloading if dictionary is split
1215  if (autoLoad)
1216  dictStream << " gInterpreter->AutoLoad(\"" << fullname << "\");\n";
1217  dictStream << " fgIsA = ::ROOT::GenerateInitInstanceLocal((const ::" << fullname
1218  << "*)0x0)->GetClass();" << std::endl
1219  << " return fgIsA;\n"
1220  << "}" << std::endl << std::endl
1221 
1222  << "//_______________________________________"
1223  << "_______________________________________" << std::endl;
1224  if (add_template_keyword) dictStream << "template <> ";
1225  dictStream << "TClass *" << clsname << "::Class()" << std::endl << "{" << std::endl;
1226  if (autoLoad) {
1227  dictStream << " Dictionary();\n";
1228  } else {
1229  dictStream << " if (!fgIsA.load()) { R__LOCKGUARD(gInterpreterMutex); fgIsA = ::ROOT::GenerateInitInstanceLocal((const ::";
1230  dictStream << fullname << "*)0x0)->GetClass(); }" << std::endl;
1231  }
1232  dictStream << " return fgIsA;" << std::endl
1233  << "}" << std::endl << std::endl;
1234 
1235  while (enclSpaceNesting) {
1236  dictStream << "} // namespace " << nsname << std::endl;
1237  --enclSpaceNesting;
1238  }
1239 }
1240 
1241 ////////////////////////////////////////////////////////////////////////////////
1242 /// Write the code to initialize the namespace name and the initialization object.
1243 
1244 void WriteNamespaceInit(const clang::NamespaceDecl *cl,
1245  cling::Interpreter &interp,
1246  std::ostream &dictStream)
1247 {
1248  if (cl->isAnonymousNamespace()) {
1249  // Don't write a GenerateInitInstance for the anonymous namespaces.
1250  return;
1251  }
1252 
1253  // coverity[fun_call_w_exception] - that's just fine.
1254  string classname = ROOT::TMetaUtils::GetQualifiedName(*cl).c_str();
1255  string mappedname;
1256  TMetaUtils::GetCppName(mappedname, classname.c_str());
1257 
1258  int nesting = 0;
1259  // We should probably unwind the namespace to properly nest it.
1260  if (classname != "ROOT") {
1261  nesting = ROOT::TMetaUtils::WriteNamespaceHeader(dictStream,cl);
1262  }
1263 
1264  dictStream << " namespace ROOT {" << std::endl;
1265 
1266 #if !defined(R__AIX)
1267  dictStream << " inline ::ROOT::TGenericClassInfo *GenerateInitInstance();" << std::endl;
1268 #endif
1269 
1270  if (!Namespace__HasMethod(cl, "Dictionary", interp))
1271  dictStream << " static TClass *" << mappedname.c_str() << "_Dictionary();" << std::endl;
1272  dictStream << std::endl
1273 
1274  << " // Function generating the singleton type initializer" << std::endl
1275 
1276 #if !defined(R__AIX)
1277  << " inline ::ROOT::TGenericClassInfo *GenerateInitInstance()" << std::endl
1278  << " {" << std::endl
1279 #else
1280  << " ::ROOT::TGenericClassInfo *GenerateInitInstance()" << std::endl
1281  << " {" << std::endl
1282 #endif
1283 
1284  << " static ::ROOT::TGenericClassInfo " << std::endl
1285 
1286  << " instance(\"" << classname.c_str() << "\", ";
1287 
1288  if (Namespace__HasMethod(cl, "Class_Version", interp)) {
1289  dictStream << "::" << classname.c_str() << "::Class_Version(), ";
1290  } else {
1291  dictStream << "0 /*version*/, ";
1292  }
1293 
1294  std::string filename = ROOT::TMetaUtils::GetFileName(*cl, interp);
1295  for (unsigned int i = 0; i < filename.length(); i++) {
1296  if (filename[i] == '\\') filename[i] = '/';
1297  }
1298  dictStream << "\"" << filename << "\", " << ROOT::TMetaUtils::GetLineNumber(cl) << "," << std::endl
1299  << " ::ROOT::Internal::DefineBehavior((void*)0,(void*)0)," << std::endl
1300  << " ";
1301 
1302  if (Namespace__HasMethod(cl, "Dictionary", interp)) {
1303  dictStream << "&::" << classname.c_str() << "::Dictionary, ";
1304  } else {
1305  dictStream << "&" << mappedname.c_str() << "_Dictionary, ";
1306  }
1307 
1308  dictStream << 0 << ");" << std::endl
1309 
1310  << " return &instance;" << std::endl
1311  << " }" << std::endl
1312  << " // Insure that the inline function is _not_ optimized away by the compiler\n"
1313  << " ::ROOT::TGenericClassInfo *(*_R__UNIQUE_DICT_(InitFunctionKeeper))() = &GenerateInitInstance; " << std::endl
1314  << " // Static variable to force the class initialization" << std::endl
1315  // must be one long line otherwise R__UseDummy does not work
1316  << " static ::ROOT::TGenericClassInfo *_R__UNIQUE_DICT_(Init) = GenerateInitInstance();"
1317  << " R__UseDummy(_R__UNIQUE_DICT_(Init));" << std::endl;
1318 
1319  if (!Namespace__HasMethod(cl, "Dictionary", interp)) {
1320  dictStream << std::endl << " // Dictionary for non-ClassDef classes" << std::endl
1321  << " static TClass *" << mappedname.c_str() << "_Dictionary() {" << std::endl
1322  << " return GenerateInitInstance()->GetClass();" << std::endl
1323  << " }" << std::endl << std::endl;
1324  }
1325 
1326  dictStream << " }" << std::endl;
1327  while (nesting--) {
1328  dictStream << "}" << std::endl;
1329  }
1330  dictStream << std::endl;
1331 }
1332 
1333 ////////////////////////////////////////////////////////////////////////////////
1334 /// GrabIndex returns a static string (so use it or copy it immediately, do not
1335 /// call GrabIndex twice in the same expression) containing the size of the
1336 /// array data member.
1337 /// In case of error, or if the size is not specified, GrabIndex returns 0.
1338 
1339 llvm::StringRef GrabIndex(const clang::FieldDecl &member, int printError)
1340 {
1341  int error;
1342  llvm::StringRef where;
1343 
1344  llvm::StringRef index = ROOT::TMetaUtils::DataMemberInfo__ValidArrayIndex(member, &error, &where);
1345  if (index.size() == 0 && printError) {
1346  const char *errorstring;
1347  switch (error) {
1348  case TMetaUtils::NOT_INT:
1349  errorstring = "is not an integer";
1350  break;
1351  case TMetaUtils::NOT_DEF:
1352  errorstring = "has not been defined before the array";
1353  break;
1355  errorstring = "is a private member of a parent class";
1356  break;
1357  case TMetaUtils::UNKNOWN:
1358  errorstring = "is not known";
1359  break;
1360  default:
1361  errorstring = "UNKNOWN ERROR!!!!";
1362  }
1363 
1364  if (where.size() == 0) {
1365  ROOT::TMetaUtils::Error(0, "*** Datamember %s::%s: no size indication!\n",
1366  member.getParent()->getName().str().c_str(), member.getName().str().c_str());
1367  } else {
1368  ROOT::TMetaUtils::Error(0, "*** Datamember %s::%s: size of array (%s) %s!\n",
1369  member.getParent()->getName().str().c_str(), member.getName().str().c_str(), where.str().c_str(), errorstring);
1370  }
1371  }
1372  return index;
1373 }
1374 
1375 ////////////////////////////////////////////////////////////////////////////////
1376 
1378  const cling::Interpreter &interp,
1379  const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt,
1380  std::ostream &dictStream)
1381 {
1382  const clang::CXXRecordDecl *clxx = llvm::dyn_cast<clang::CXXRecordDecl>(cl.GetRecordDecl());
1383  if (clxx == 0) return;
1384 
1385  bool add_template_keyword = ROOT::TMetaUtils::NeedTemplateKeyword(clxx);
1386 
1387  string fullname;
1388  string clsname;
1389  string nsname;
1390  int enclSpaceNesting = 0;
1391 
1392  if (ROOT::TMetaUtils::GetNameWithinNamespace(fullname, clsname, nsname, clxx)) {
1393  enclSpaceNesting = ROOT::TMetaUtils::WriteNamespaceHeader(dictStream, cl);
1394  }
1395 
1396  dictStream << "//_______________________________________"
1397  << "_______________________________________" << std::endl;
1398  if (add_template_keyword) dictStream << "template <> ";
1399  dictStream << "void " << clsname << "::Streamer(TBuffer &R__b)" << std::endl << "{" << std::endl
1400  << " // Stream an object of class " << fullname << "." << std::endl << std::endl;
1401 
1402  // In case of VersionID<=0 write dummy streamer only calling
1403  // its base class Streamer(s). If no base class(es) let Streamer
1404  // print error message, i.e. this Streamer should never have been called.
1405  int version = ROOT::TMetaUtils::GetClassVersion(clxx, interp);
1406  if (version <= 0) {
1407  // We also need to look at the base classes.
1408  int basestreamer = 0;
1409  for (clang::CXXRecordDecl::base_class_const_iterator iter = clxx->bases_begin(), end = clxx->bases_end();
1410  iter != end;
1411  ++iter) {
1412  if (ROOT::TMetaUtils::ClassInfo__HasMethod(iter->getType()->getAsCXXRecordDecl(), "Streamer", interp)) {
1413  string base_fullname;
1414  ROOT::TMetaUtils::GetQualifiedName(base_fullname, * iter->getType()->getAsCXXRecordDecl());
1415 
1416  if (strstr(base_fullname.c_str(), "::")) {
1417  // there is a namespace involved, trigger MS VC bug workaround
1418  dictStream << " //This works around a msvc bug and should be harmless on other platforms" << std::endl
1419  << " typedef " << base_fullname << " baseClass" << basestreamer << ";" << std::endl
1420  << " baseClass" << basestreamer << "::Streamer(R__b);" << std::endl;
1421  } else {
1422  dictStream << " " << base_fullname << "::Streamer(R__b);" << std::endl;
1423  }
1424  basestreamer++;
1425  }
1426  }
1427  if (!basestreamer) {
1428  dictStream << " ::Error(\"" << fullname << "::Streamer\", \"version id <=0 in ClassDef,"
1429  " dummy Streamer() called\"); if (R__b.IsReading()) { }" << std::endl;
1430  }
1431  dictStream << "}" << std::endl << std::endl;
1432  while (enclSpaceNesting) {
1433  dictStream << "} // namespace " << nsname.c_str() << std::endl;
1434  --enclSpaceNesting;
1435  }
1436  return;
1437  }
1438 
1439  // loop twice: first time write reading code, second time writing code
1440  string classname = fullname;
1441  if (strstr(fullname.c_str(), "::")) {
1442  // there is a namespace involved, trigger MS VC bug workaround
1443  dictStream << " //This works around a msvc bug and should be harmless on other platforms" << std::endl
1444  << " typedef ::" << fullname << " thisClass;" << std::endl;
1445  classname = "thisClass";
1446  }
1447  for (int i = 0; i < 2; i++) {
1448 
1449  int decli = 0;
1450 
1451  if (i == 0) {
1452  dictStream << " UInt_t R__s, R__c;" << std::endl;
1453  dictStream << " if (R__b.IsReading()) {" << std::endl;
1454  dictStream << " Version_t R__v = R__b.ReadVersion(&R__s, &R__c); if (R__v) { }" << std::endl;
1455  } else {
1456  dictStream << " R__b.CheckByteCount(R__s, R__c, " << classname.c_str() << "::IsA());" << std::endl;
1457  dictStream << " } else {" << std::endl;
1458  dictStream << " R__c = R__b.WriteVersion(" << classname.c_str() << "::IsA(), kTRUE);" << std::endl;
1459  }
1460 
1461  // Stream base class(es) when they have the Streamer() method
1462  int base = 0;
1463  for (clang::CXXRecordDecl::base_class_const_iterator iter = clxx->bases_begin(), end = clxx->bases_end();
1464  iter != end;
1465  ++iter) {
1466  if (ROOT::TMetaUtils::ClassInfo__HasMethod(iter->getType()->getAsCXXRecordDecl(), "Streamer", interp)) {
1467  string base_fullname;
1468  ROOT::TMetaUtils::GetQualifiedName(base_fullname, * iter->getType()->getAsCXXRecordDecl());
1469 
1470  if (strstr(base_fullname.c_str(), "::")) {
1471  // there is a namespace involved, trigger MS VC bug workaround
1472  dictStream << " //This works around a msvc bug and should be harmless on other platforms" << std::endl
1473  << " typedef " << base_fullname << " baseClass" << base << ";" << std::endl
1474  << " baseClass" << base << "::Streamer(R__b);" << std::endl;
1475  ++base;
1476  } else {
1477  dictStream << " " << base_fullname << "::Streamer(R__b);" << std::endl;
1478  }
1479  }
1480  }
1481  // Stream data members
1482  // Loop over the non static data member.
1483  for (clang::RecordDecl::field_iterator field_iter = clxx->field_begin(), end = clxx->field_end();
1484  field_iter != end;
1485  ++field_iter) {
1486  const char *comment = ROOT::TMetaUtils::GetComment(**field_iter).data();
1487 
1488  clang::QualType type = field_iter->getType();
1489  std::string type_name = type.getAsString(clxx->getASTContext().getPrintingPolicy());
1490 
1491  const clang::Type *underling_type = ROOT::TMetaUtils::GetUnderlyingType(type);
1492 
1493  // we skip:
1494  // - static members
1495  // - members with an ! as first character in the title (comment) field
1496 
1497  //special case for Float16_t
1498  int isFloat16 = 0;
1499  if (strstr(type_name.c_str(), "Float16_t")) isFloat16 = 1;
1500 
1501  //special case for Double32_t
1502  int isDouble32 = 0;
1503  if (strstr(type_name.c_str(), "Double32_t")) isDouble32 = 1;
1504 
1505  // No need to test for static, there are not in this list.
1506  if (strncmp(comment, "!", 1)) {
1507 
1508  // fundamental type: short, int, long, etc....
1509  if (underling_type->isFundamentalType() || underling_type->isEnumeralType()) {
1510  if (type.getTypePtr()->isConstantArrayType() &&
1511  type.getTypePtr()->getArrayElementTypeNoTypeQual()->isPointerType()) {
1512  const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(type.getTypePtr());
1513  int s = GetFullArrayLength(arrayType);
1514 
1515  if (!decli) {
1516  dictStream << " int R__i;" << std::endl;
1517  decli = 1;
1518  }
1519  dictStream << " for (R__i = 0; R__i < " << s << "; R__i++)" << std::endl;
1520  if (i == 0) {
1521  ROOT::TMetaUtils::Error(0, "*** Datamember %s::%s: array of pointers to fundamental type (need manual intervention)\n", fullname.c_str(), field_iter->getName().str().c_str());
1522  dictStream << " ;//R__b.ReadArray(" << field_iter->getName().str() << ");" << std::endl;
1523  } else {
1524  dictStream << " ;//R__b.WriteArray(" << field_iter->getName().str() << ", __COUNTER__);" << std::endl;
1525  }
1526  } else if (type.getTypePtr()->isPointerType()) {
1527  llvm::StringRef indexvar = GrabIndex(**field_iter, i == 0);
1528  if (indexvar.size() == 0) {
1529  if (i == 0) {
1530  ROOT::TMetaUtils::Error(0, "*** Datamember %s::%s: pointer to fundamental type (need manual intervention)\n", fullname.c_str(), field_iter->getName().str().c_str());
1531  dictStream << " //R__b.ReadArray(" << field_iter->getName().str() << ");" << std::endl;
1532  } else {
1533  dictStream << " //R__b.WriteArray(" << field_iter->getName().str() << ", __COUNTER__);" << std::endl;
1534  }
1535  } else {
1536  if (i == 0) {
1537  dictStream << " delete [] " << field_iter->getName().str() << ";" << std::endl
1538  << " " << GetNonConstMemberName(**field_iter) << " = new "
1539  << ROOT::TMetaUtils::ShortTypeName(**field_iter) << "[" << indexvar.str() << "];" << std::endl;
1540  if (isFloat16) {
1541  dictStream << " R__b.ReadFastArrayFloat16(" << GetNonConstMemberName(**field_iter)
1542  << "," << indexvar.str() << ");" << std::endl;
1543  } else if (isDouble32) {
1544  dictStream << " R__b.ReadFastArrayDouble32(" << GetNonConstMemberName(**field_iter)
1545  << "," << indexvar.str() << ");" << std::endl;
1546  } else {
1547  dictStream << " R__b.ReadFastArray(" << GetNonConstMemberName(**field_iter)
1548  << "," << indexvar.str() << ");" << std::endl;
1549  }
1550  } else {
1551  if (isFloat16) {
1552  dictStream << " R__b.WriteFastArrayFloat16("
1553  << field_iter->getName().str() << "," << indexvar.str() << ");" << std::endl;
1554  } else if (isDouble32) {
1555  dictStream << " R__b.WriteFastArrayDouble32("
1556  << field_iter->getName().str() << "," << indexvar.str() << ");" << std::endl;
1557  } else {
1558  dictStream << " R__b.WriteFastArray("
1559  << field_iter->getName().str() << "," << indexvar.str() << ");" << std::endl;
1560  }
1561  }
1562  }
1563  } else if (type.getTypePtr()->isArrayType()) {
1564  if (i == 0) {
1565  if (type.getTypePtr()->getArrayElementTypeNoTypeQual()->isArrayType()) { // if (m.ArrayDim() > 1) {
1566  if (underling_type->isEnumeralType())
1567  dictStream << " R__b.ReadStaticArray((Int_t*)" << field_iter->getName().str() << ");" << std::endl;
1568  else {
1569  if (isFloat16) {
1570  dictStream << " R__b.ReadStaticArrayFloat16((" << ROOT::TMetaUtils::TrueName(**field_iter)
1571  << "*)" << field_iter->getName().str() << ");" << std::endl;
1572  } else if (isDouble32) {
1573  dictStream << " R__b.ReadStaticArrayDouble32((" << ROOT::TMetaUtils::TrueName(**field_iter)
1574  << "*)" << field_iter->getName().str() << ");" << std::endl;
1575  } else {
1576  dictStream << " R__b.ReadStaticArray((" << ROOT::TMetaUtils::TrueName(**field_iter)
1577  << "*)" << field_iter->getName().str() << ");" << std::endl;
1578  }
1579  }
1580  } else {
1581  if (underling_type->isEnumeralType()) {
1582  dictStream << " R__b.ReadStaticArray((Int_t*)" << field_iter->getName().str() << ");" << std::endl;
1583  } else {
1584  if (isFloat16) {
1585  dictStream << " R__b.ReadStaticArrayFloat16(" << field_iter->getName().str() << ");" << std::endl;
1586  } else if (isDouble32) {
1587  dictStream << " R__b.ReadStaticArrayDouble32(" << field_iter->getName().str() << ");" << std::endl;
1588  } else {
1589  dictStream << " R__b.ReadStaticArray((" << ROOT::TMetaUtils::TrueName(**field_iter)
1590  << "*)" << field_iter->getName().str() << ");" << std::endl;
1591  }
1592  }
1593  }
1594  } else {
1595  const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(type.getTypePtr());
1596  int s = GetFullArrayLength(arrayType);
1597 
1598  if (type.getTypePtr()->getArrayElementTypeNoTypeQual()->isArrayType()) {// if (m.ArrayDim() > 1) {
1599  if (underling_type->isEnumeralType())
1600  dictStream << " R__b.WriteArray((Int_t*)" << field_iter->getName().str() << ", "
1601  << s << ");" << std::endl;
1602  else if (isFloat16) {
1603  dictStream << " R__b.WriteArrayFloat16((" << ROOT::TMetaUtils::TrueName(**field_iter)
1604  << "*)" << field_iter->getName().str() << ", " << s << ");" << std::endl;
1605  } else if (isDouble32) {
1606  dictStream << " R__b.WriteArrayDouble32((" << ROOT::TMetaUtils::TrueName(**field_iter)
1607  << "*)" << field_iter->getName().str() << ", " << s << ");" << std::endl;
1608  } else {
1609  dictStream << " R__b.WriteArray((" << ROOT::TMetaUtils::TrueName(**field_iter)
1610  << "*)" << field_iter->getName().str() << ", " << s << ");" << std::endl;
1611  }
1612  } else {
1613  if (underling_type->isEnumeralType())
1614  dictStream << " R__b.WriteArray((Int_t*)" << field_iter->getName().str() << ", " << s << ");" << std::endl;
1615  else if (isFloat16) {
1616  dictStream << " R__b.WriteArrayFloat16(" << field_iter->getName().str() << ", " << s << ");" << std::endl;
1617  } else if (isDouble32) {
1618  dictStream << " R__b.WriteArrayDouble32(" << field_iter->getName().str() << ", " << s << ");" << std::endl;
1619  } else {
1620  dictStream << " R__b.WriteArray(" << field_iter->getName().str() << ", " << s << ");" << std::endl;
1621  }
1622  }
1623  }
1624  } else if (underling_type->isEnumeralType()) {
1625  if (i == 0) {
1626  dictStream << " void *ptr_" << field_iter->getName().str() << " = (void*)&" << field_iter->getName().str() << ";\n";
1627  dictStream << " R__b >> *reinterpret_cast<Int_t*>(ptr_" << field_iter->getName().str() << ");" << std::endl;
1628  } else
1629  dictStream << " R__b << (Int_t)" << field_iter->getName().str() << ";" << std::endl;
1630  } else {
1631  if (isFloat16) {
1632  if (i == 0)
1633  dictStream << " {float R_Dummy; R__b >> R_Dummy; " << GetNonConstMemberName(**field_iter)
1634  << "=Float16_t(R_Dummy);}" << std::endl;
1635  else
1636  dictStream << " R__b << float(" << GetNonConstMemberName(**field_iter) << ");" << std::endl;
1637  } else if (isDouble32) {
1638  if (i == 0)
1639  dictStream << " {float R_Dummy; R__b >> R_Dummy; " << GetNonConstMemberName(**field_iter)
1640  << "=Double32_t(R_Dummy);}" << std::endl;
1641  else
1642  dictStream << " R__b << float(" << GetNonConstMemberName(**field_iter) << ");" << std::endl;
1643  } else {
1644  if (i == 0)
1645  dictStream << " R__b >> " << GetNonConstMemberName(**field_iter) << ";" << std::endl;
1646  else
1647  dictStream << " R__b << " << GetNonConstMemberName(**field_iter) << ";" << std::endl;
1648  }
1649  }
1650  } else {
1651  // we have an object...
1652 
1653  // check if object is a standard string
1654  if (STLStringStreamer(**field_iter, i, dictStream))
1655  continue;
1656 
1657  // check if object is an STL container
1658  if (STLContainerStreamer(**field_iter, i, interp, normCtxt, dictStream))
1659  continue;
1660 
1661  // handle any other type of objects
1662  if (type.getTypePtr()->isConstantArrayType() &&
1663  type.getTypePtr()->getArrayElementTypeNoTypeQual()->isPointerType()) {
1664  const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(type.getTypePtr());
1665  int s = GetFullArrayLength(arrayType);
1666 
1667  if (!decli) {
1668  dictStream << " int R__i;" << std::endl;
1669  decli = 1;
1670  }
1671  dictStream << " for (R__i = 0; R__i < " << s << "; R__i++)" << std::endl;
1672  if (i == 0)
1673  dictStream << " R__b >> " << GetNonConstMemberName(**field_iter);
1674  else {
1675  if (ROOT::TMetaUtils::IsBase(**field_iter, "TObject", interp) && ROOT::TMetaUtils::IsBase(**field_iter, "TArray", interp))
1676  dictStream << " R__b << (TObject*)" << field_iter->getName().str();
1677  else
1678  dictStream << " R__b << " << GetNonConstMemberName(**field_iter);
1679  }
1680  WriteArrayDimensions(field_iter->getType(), dictStream);
1681  dictStream << "[R__i];" << std::endl;
1682  } else if (type.getTypePtr()->isPointerType()) {
1683  // This is always good. However, in case of a pointer
1684  // to an object that is guaranteed to be there and not
1685  // being referenced by other objects we could use
1686  // xx->Streamer(b);
1687  // Optimize this with control statement in title.
1688  if (isPointerToPointer(**field_iter)) {
1689  if (i == 0) {
1690  ROOT::TMetaUtils::Error(0, "*** Datamember %s::%s: pointer to pointer (need manual intervention)\n", fullname.c_str(), field_iter->getName().str().c_str());
1691  dictStream << " //R__b.ReadArray(" << field_iter->getName().str() << ");" << std::endl;
1692  } else {
1693  dictStream << " //R__b.WriteArray(" << field_iter->getName().str() << ", __COUNTER__);";
1694  }
1695  } else {
1696  if (ROOT::TMetaUtils::GetQualifiedName(*ROOT::TMetaUtils::GetUnderlyingType(field_iter->getType()), **field_iter) == "TClonesArray") {
1697  dictStream << " " << field_iter->getName().str() << "->Streamer(R__b);" << std::endl;
1698  } else {
1699  if (i == 0) {
1700  // The following:
1701  // if (strncmp(m.Title(),"->",2) != 0) fprintf(fp, " delete %s;\n", GetNonConstMemberName(**field_iter).c_str());
1702  // could be used to prevent a memory leak since the next statement could possibly create a new object.
1703  // In the TStreamerInfo based I/O we made the previous statement conditional on TStreamerInfo::CanDelete
1704  // to allow the user to prevent some inadvisable deletions. So we should be offering this flexibility
1705  // here to and should not (technically) rely on TStreamerInfo for it, so for now we leave it as is.
1706  // Note that the leak should happen from here only if the object is stored in an unsplit object
1707  // and either the user request an old branch or the streamer has been customized.
1708  dictStream << " R__b >> " << GetNonConstMemberName(**field_iter) << ";" << std::endl;
1709  } else {
1710  if (ROOT::TMetaUtils::IsBase(**field_iter, "TObject", interp) && ROOT::TMetaUtils::IsBase(**field_iter, "TArray", interp))
1711  dictStream << " R__b << (TObject*)" << field_iter->getName().str() << ";" << std::endl;
1712  else
1713  dictStream << " R__b << " << GetNonConstMemberName(**field_iter) << ";" << std::endl;
1714  }
1715  }
1716  }
1717  } else if (const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(type.getTypePtr())) {
1718  int s = GetFullArrayLength(arrayType);
1719 
1720  if (!decli) {
1721  dictStream << " int R__i;" << std::endl;
1722  decli = 1;
1723  }
1724  dictStream << " for (R__i = 0; R__i < " << s << "; R__i++)" << std::endl;
1725  std::string mTypeNameStr;
1726  ROOT::TMetaUtils::GetQualifiedName(mTypeNameStr, field_iter->getType(), **field_iter);
1727  const char *mTypeName = mTypeNameStr.c_str();
1728  const char *constwd = "const ";
1729  if (strncmp(constwd, mTypeName, strlen(constwd)) == 0) {
1730  mTypeName += strlen(constwd);
1731  dictStream << " const_cast< " << mTypeName << " &>(" << field_iter->getName().str();
1732  WriteArrayDimensions(field_iter->getType(), dictStream);
1733  dictStream << "[R__i]).Streamer(R__b);" << std::endl;
1734  } else {
1735  dictStream << " " << GetNonConstMemberName(**field_iter);
1736  WriteArrayDimensions(field_iter->getType(), dictStream);
1737  dictStream << "[R__i].Streamer(R__b);" << std::endl;
1738  }
1739  } else {
1740  if (ROOT::TMetaUtils::ClassInfo__HasMethod(ROOT::TMetaUtils::GetUnderlyingRecordDecl(field_iter->getType()), "Streamer", interp))
1741  dictStream << " " << GetNonConstMemberName(**field_iter) << ".Streamer(R__b);" << std::endl;
1742  else {
1743  dictStream << " R__b.StreamObject(&(" << field_iter->getName().str() << "),typeid("
1744  << field_iter->getName().str() << "));" << std::endl; //R__t.Streamer(R__b);\n");
1745  //VP if (i == 0)
1746  //VP Error(0, "*** Datamember %s::%s: object has no Streamer() method (need manual intervention)\n",
1747  //VP fullname, field_iter->getName().str());
1748  //VP fprintf(fp, " //%s.Streamer(R__b);\n", m.Name());
1749  }
1750  }
1751  }
1752  }
1753  }
1754  }
1755  dictStream << " R__b.SetByteCount(R__c, kTRUE);" << std::endl
1756  << " }" << std::endl
1757  << "}" << std::endl << std::endl;
1758 
1759  while (enclSpaceNesting) {
1760  dictStream << "} // namespace " << nsname.c_str() << std::endl;
1761  --enclSpaceNesting;
1762  }
1763 }
1764 
1765 ////////////////////////////////////////////////////////////////////////////////
1766 
1768  const cling::Interpreter &interp,
1769  const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt,
1770  std::ostream &dictStream)
1771 {
1772  // Write Streamer() method suitable for automatic schema evolution.
1773 
1774  const clang::CXXRecordDecl *clxx = llvm::dyn_cast<clang::CXXRecordDecl>(cl.GetRecordDecl());
1775  if (clxx == 0) return;
1776 
1777  bool add_template_keyword = ROOT::TMetaUtils::NeedTemplateKeyword(clxx);
1778 
1779  // We also need to look at the base classes.
1780  for (clang::CXXRecordDecl::base_class_const_iterator iter = clxx->bases_begin(), end = clxx->bases_end();
1781  iter != end;
1782  ++iter) {
1783  int k = ROOT::TMetaUtils::IsSTLContainer(*iter);
1784  if (k != 0) {
1785  Internal::RStl::Instance().GenerateTClassFor(iter->getType(), interp, normCtxt);
1786  }
1787  }
1788 
1789  string fullname;
1790  string clsname;
1791  string nsname;
1792  int enclSpaceNesting = 0;
1793 
1794  if (ROOT::TMetaUtils::GetNameWithinNamespace(fullname, clsname, nsname, clxx)) {
1795  enclSpaceNesting = ROOT::TMetaUtils::WriteNamespaceHeader(dictStream, cl);
1796  }
1797 
1798  dictStream << "//_______________________________________"
1799  << "_______________________________________" << std::endl;
1800  if (add_template_keyword) dictStream << "template <> ";
1801  dictStream << "void " << clsname << "::Streamer(TBuffer &R__b)" << std::endl
1802  << "{" << std::endl
1803  << " // Stream an object of class " << fullname << "." << std::endl << std::endl
1804  << " if (R__b.IsReading()) {" << std::endl
1805  << " R__b.ReadClassBuffer(" << fullname << "::Class(),this);" << std::endl
1806  << " } else {" << std::endl
1807  << " R__b.WriteClassBuffer(" << fullname << "::Class(),this);" << std::endl
1808  << " }" << std::endl
1809  << "}" << std::endl << std::endl;
1810 
1811  while (enclSpaceNesting) {
1812  dictStream << "} // namespace " << nsname << std::endl;
1813  --enclSpaceNesting;
1814  }
1815 }
1816 
1817 ////////////////////////////////////////////////////////////////////////////////
1818 
1820  const cling::Interpreter &interp,
1821  const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt,
1822  std::ostream &dictStream,
1823  bool isAutoStreamer)
1824 {
1825  if (isAutoStreamer) {
1826  WriteAutoStreamer(cl, interp, normCtxt, dictStream);
1827  } else {
1828  WriteStreamer(cl, interp, normCtxt, dictStream);
1829  }
1830 }
1831 
1832 ////////////////////////////////////////////////////////////////////////////////
1833 
1834 void GenerateLinkdef(llvm::cl::list<std::string> &InputFiles,
1835  std::string &code_for_parser)
1836 {
1837  code_for_parser += "#ifdef __CINT__\n\n";
1838  code_for_parser += "#pragma link off all globals;\n";
1839  code_for_parser += "#pragma link off all classes;\n";
1840  code_for_parser += "#pragma link off all functions;\n\n";
1841 
1842  for (std::string& arg : InputFiles) {
1843  char trail[3];
1844  int nostr = 0, noinp = 0, bcnt = 0, l = arg.length() - 1;
1845  for (int j = 0; j < 3; j++) {
1846  if (arg[l] == '-') {
1847  arg[l] = '\0';
1848  nostr = 1;
1849  l--;
1850  }
1851  if (arg[l] == '!') {
1852  arg[l] = '\0';
1853  noinp = 1;
1854  l--;
1855  }
1856  if (arg[l] == '+') {
1857  arg[l] = '\0';
1858  bcnt = 1;
1859  l--;
1860  }
1861  }
1862  if (nostr || noinp) {
1863  trail[0] = 0;
1864  if (nostr) strlcat(trail, "-", 3);
1865  if (noinp) strlcat(trail, "!", 3);
1866  }
1867  if (bcnt) {
1868  strlcpy(trail, "+", 3);
1869  if (nostr)
1870  ROOT::TMetaUtils::Error(0, "option + mutual exclusive with -\n");
1871  }
1872  llvm::SmallString<256> filestem = llvm::sys::path::filename(arg);
1873  llvm::sys::path::replace_extension(filestem, "");
1874 
1875  code_for_parser += "#pragma link C++ class ";
1876  code_for_parser += filestem.str().str();
1877  if (nostr || noinp || bcnt)
1878  code_for_parser += trail;
1879  code_for_parser += ";\n";
1880  }
1881 
1882  code_for_parser += "\n#endif\n";
1883 }
1884 
1885 ////////////////////////////////////////////////////////////////////////////////
1886 /// Find file name in path specified via -I statements to Cling.
1887 /// Return false if the file can not be found.
1888 /// If the file is found, set pname to the full path name and return true.
1889 
1890 bool Which(cling::Interpreter &interp, const char *fname, string &pname)
1891 {
1892  FILE *fp = 0;
1893 
1894 #ifdef WIN32
1895  static const char *fopenopts = "rb";
1896 #else
1897  static const char *fopenopts = "r";
1898 #endif
1899 
1900  pname = fname;
1901  fp = fopen(pname.c_str(), fopenopts);
1902  if (fp) {
1903  fclose(fp);
1904  return true;
1905  }
1906 
1907  llvm::SmallVector<std::string, 10> includePaths;//Why 10? Hell if I know.
1908  //false - no system header, false - with flags.
1909  interp.GetIncludePaths(includePaths, false, false);
1910 
1911  const size_t nPaths = includePaths.size();
1912  for (size_t i = 0; i < nPaths; i += 1 /* 2 */) {
1913 
1914  pname = includePaths[i].c_str() + gPathSeparator + fname;
1915 
1916  fp = fopen(pname.c_str(), fopenopts);
1917  if (fp) {
1918  fclose(fp);
1919  return true;
1920  }
1921  }
1922  pname = "";
1923  return false;
1924 }
1925 
1926 ////////////////////////////////////////////////////////////////////////////////
1927 /// If the argument starts with MODULE/inc, strip it
1928 /// to make it the name we can use in #includes.
1929 
1930 const char *CopyArg(const char *original)
1931 {
1932  if (!gBuildingROOT)
1933  return original;
1934 
1935  if (IsSelectionFile(original))
1936  return original;
1937 
1938  const char *inc = strstr(original, "\\inc\\");
1939  if (!inc)
1940  inc = strstr(original, "/inc/");
1941  if (inc && strlen(inc) > 5)
1942  return inc + 5;
1943  return original;
1944 }
1945 
1946 ////////////////////////////////////////////////////////////////////////////////
1947 /// Copy the command line argument, stripping MODULE/inc if
1948 /// necessary.
1949 
1950 void StrcpyArg(string &dest, const char *original)
1951 {
1952  dest = CopyArg(original);
1953 }
1954 
1955 ////////////////////////////////////////////////////////////////////////////////
1956 /// Write the extra header injected into the module:
1957 /// umbrella header if (umbrella) else content header.
1958 
1959 static bool InjectModuleUtilHeader(const char *argv0,
1960  TModuleGenerator &modGen,
1961  cling::Interpreter &interp,
1962  bool umbrella)
1963 {
1964  std::ostringstream out;
1965  if (umbrella) {
1966  // This will duplicate the -D,-U from clingArgs - but as they are surrounded
1967  // by #ifndef there is no problem here.
1968  modGen.WriteUmbrellaHeader(out);
1969  if (interp.declare(out.str()) != cling::Interpreter::kSuccess) {
1970  const std::string &hdrName
1971  = umbrella ? modGen.GetUmbrellaName() : modGen.GetContentName();
1972  ROOT::TMetaUtils::Error(0, "%s: compilation failure (%s)\n", argv0,
1973  hdrName.c_str());
1974  return false;
1975  }
1976  } else {
1977  modGen.WriteContentHeader(out);
1978  }
1979  return true;
1980 }
1981 
1982 ////////////////////////////////////////////////////////////////////////////////
1983 /// Write the AST of the given CompilerInstance to the given File while
1984 /// respecting the given isysroot.
1985 /// If module is not a null pointer, we only write the given module to the
1986 /// given file and not the whole AST.
1987 /// Returns true if the AST was successfully written.
1988 static bool WriteAST(StringRef fileName, clang::CompilerInstance *compilerInstance, StringRef iSysRoot,
1989  clang::Module *module = nullptr)
1990 {
1991  // From PCHGenerator and friends:
1992  llvm::SmallVector<char, 128> buffer;
1993  llvm::BitstreamWriter stream(buffer);
1994  clang::ASTWriter writer(stream, buffer, compilerInstance->getPCMCache(), /*Extensions=*/{});
1995  std::unique_ptr<llvm::raw_ostream> out =
1996  compilerInstance->createOutputFile(fileName, /*Binary=*/true,
1997  /*RemoveFileOnSignal=*/false, /*InFile*/ "",
1998  /*Extension=*/"", /*useTemporary=*/false,
1999  /*CreateMissingDirectories*/ false);
2000  if (!out) {
2001  ROOT::TMetaUtils::Error("WriteAST", "Couldn't open output stream to '%s'!\n", fileName.data());
2002  return false;
2003  }
2004 
2005  compilerInstance->getFrontendOpts().RelocatablePCH = true;
2006 
2007  writer.WriteAST(compilerInstance->getSema(), fileName, module, iSysRoot);
2008 
2009  // Write the generated bitstream to "Out".
2010  out->write(&buffer.front(), buffer.size());
2011 
2012  // Make sure it hits disk now.
2013  out->flush();
2014 
2015  return true;
2016 }
2017 
2018 ////////////////////////////////////////////////////////////////////////////////
2019 /// Generates a PCH from the given ModuleGenerator and CompilerInstance.
2020 /// Returns true iff the PCH was successfully generated.
2021 static bool GenerateAllDict(TModuleGenerator &modGen, clang::CompilerInstance *compilerInstance,
2022  const std::string &currentDirectory)
2023 {
2024  assert(modGen.IsPCH() && "modGen must be in PCH mode");
2025 
2026  std::string iSysRoot("/DUMMY_SYSROOT/include/");
2027  if (gBuildingROOT) iSysRoot = (currentDirectory + "/");
2028  return WriteAST(modGen.GetModuleFileName(), compilerInstance, iSysRoot);
2029 }
2030 
2031 ////////////////////////////////////////////////////////////////////////////////
2032 /// Includes all given headers in the interpreter. Returns true when we could
2033 /// include the headers and otherwise false on an error when including.
2034 static bool IncludeHeaders(const std::vector<std::string> &headers, cling::Interpreter &interpreter)
2035 {
2036  // If no headers are given, this is a no-op.
2037  if (headers.empty())
2038  return true;
2039 
2040  // Turn every header name into an include and parse it in the interpreter.
2041  std::stringstream includes;
2042  for (const std::string &header : headers) {
2043  includes << "#include \"" << header << "\"\n";
2044  }
2045  std::string includeListStr = includes.str();
2046  auto result = interpreter.declare(includeListStr);
2047  return result == cling::Interpreter::CompilationResult::kSuccess;
2048 }
2049 
2050 
2051 ////////////////////////////////////////////////////////////////////////////////
2052 
2053 void AddPlatformDefines(std::vector<std::string> &clingArgs)
2054 {
2055  char platformDefines[64] = {0};
2056 #ifdef __INTEL_COMPILER
2057  snprintf(platformDefines, 64, "-DG__INTEL_COMPILER=%ld", (long)__INTEL_COMPILER);
2058  clingArgs.push_back(platformDefines);
2059 #endif
2060 #ifdef __xlC__
2061  snprintf(platformDefines, 64, "-DG__xlC=%ld", (long)__xlC__);
2062  clingArgs.push_back(platformDefines);
2063 #endif
2064 #ifdef __GNUC__
2065  snprintf(platformDefines, 64, "-DG__GNUC=%ld", (long)__GNUC__);
2066  snprintf(platformDefines, 64, "-DG__GNUC_VER=%ld", (long)__GNUC__ * 1000 + __GNUC_MINOR__);
2067  clingArgs.push_back(platformDefines);
2068 #endif
2069 #ifdef __GNUC_MINOR__
2070  snprintf(platformDefines, 64, "-DG__GNUC_MINOR=%ld", (long)__GNUC_MINOR__);
2071  clingArgs.push_back(platformDefines);
2072 #endif
2073 #ifdef __HP_aCC
2074  snprintf(platformDefines, 64, "-DG__HP_aCC=%ld", (long)__HP_aCC);
2075  clingArgs.push_back(platformDefines);
2076 #endif
2077 #ifdef __sun
2078  snprintf(platformDefines, 64, "-DG__sun=%ld", (long)__sun);
2079  clingArgs.push_back(platformDefines);
2080 #endif
2081 #ifdef __SUNPRO_CC
2082  snprintf(platformDefines, 64, "-DG__SUNPRO_CC=%ld", (long)__SUNPRO_CC);
2083  clingArgs.push_back(platformDefines);
2084 #endif
2085 #ifdef _STLPORT_VERSION
2086  // stlport version, used on e.g. SUN
2087  snprintf(platformDefines, 64, "-DG__STLPORT_VERSION=%ld", (long)_STLPORT_VERSION);
2088  clingArgs.push_back(platformDefines);
2089 #endif
2090 #ifdef __ia64__
2091  snprintf(platformDefines, 64, "-DG__ia64=%ld", (long)__ia64__);
2092  clingArgs.push_back(platformDefines);
2093 #endif
2094 #ifdef __x86_64__
2095  snprintf(platformDefines, 64, "-DG__x86_64=%ld", (long)__x86_64__);
2096  clingArgs.push_back(platformDefines);
2097 #endif
2098 #ifdef __i386__
2099  snprintf(platformDefines, 64, "-DG__i386=%ld", (long)__i386__);
2100  clingArgs.push_back(platformDefines);
2101 #endif
2102 #ifdef __arm__
2103  snprintf(platformDefines, 64, "-DG__arm=%ld", (long)__arm__);
2104  clingArgs.push_back(platformDefines);
2105 #endif
2106 #ifdef _WIN32
2107  snprintf(platformDefines, 64, "-DG__WIN32=%ld", (long)_WIN32);
2108  clingArgs.push_back(platformDefines);
2109 #else
2110 # ifdef WIN32
2111  snprintf(platformDefines, 64, "-DG__WIN32=%ld", (long)WIN32);
2112  clingArgs.push_back(platformDefines);
2113 # endif
2114 #endif
2115 #ifdef _MSC_VER
2116  snprintf(platformDefines, 64, "-DG__MSC_VER=%ld", (long)_MSC_VER);
2117  clingArgs.push_back(platformDefines);
2118  snprintf(platformDefines, 64, "-DG__VISUAL=%ld", (long)_MSC_VER);
2119  clingArgs.push_back(platformDefines);
2120 #endif
2121 }
2122 
2123 ////////////////////////////////////////////////////////////////////////////////
2124 /// Extract the filename from a fullpath
2125 
2126 std::string ExtractFileName(const std::string &path)
2127 {
2128  return llvm::sys::path::filename(path);
2129 }
2130 
2131 ////////////////////////////////////////////////////////////////////////////////
2132 /// Extract the path from a fullpath finding the last \ or /
2133 /// according to the content in gPathSeparator
2134 
2135 void ExtractFilePath(const std::string &path, std::string &dirname)
2136 {
2137  const size_t pos = path.find_last_of(gPathSeparator);
2138  if (std::string::npos != pos) {
2139  dirname.assign(path.begin(), path.begin() + pos + 1);
2140  } else {
2141  dirname.assign("");
2142  }
2143 }
2144 
2145 ////////////////////////////////////////////////////////////////////////////////
2146 /// Check if file has a path
2147 
2148 bool HasPath(const std::string &name)
2149 {
2150  std::string dictLocation;
2151  ExtractFilePath(name, dictLocation);
2152  return !dictLocation.empty();
2153 }
2154 
2155 ////////////////////////////////////////////////////////////////////////////////
2156 
2157 void AdjustRootMapNames(std::string &rootmapFileName,
2158  std::string &rootmapLibName)
2159 {
2160  // If the rootmap file name does not exist, create one following the libname
2161  // I.E. put into the directory of the lib the rootmap and within the rootmap the normalised path to the lib
2162  if (rootmapFileName.empty()) {
2163  size_t libExtensionPos = rootmapLibName.find_last_of(gLibraryExtension) - gLibraryExtension.size() + 1;
2164  rootmapFileName = rootmapLibName.substr(0, libExtensionPos) + ".rootmap";
2165  size_t libCleanNamePos = rootmapLibName.find_last_of(gPathSeparator) + 1;
2166  rootmapLibName = rootmapLibName.substr(libCleanNamePos, std::string::npos);
2167  ROOT::TMetaUtils::Info(0, "Rootmap file name %s built from rootmap lib name %s",
2168  rootmapLibName.c_str(),
2169  rootmapFileName.c_str());
2170  }
2171 }
2172 
2173 ////////////////////////////////////////////////////////////////////////////////
2174 /// Extract the proper autoload key for nested classes
2175 /// The routine does not erase the name, just updates it
2176 
2177 void GetMostExternalEnclosingClassName(const clang::DeclContext &theContext,
2178  std::string &ctxtName,
2179  const cling::Interpreter &interpreter,
2180  bool treatParent = true)
2181 {
2182  const clang::DeclContext *outerCtxt = treatParent ? theContext.getParent() : &theContext;
2183  // If the context has no outer context, we are finished
2184  if (!outerCtxt) return;
2185  // If the context is a class, we update the name
2186  if (const clang::RecordDecl *thisRcdDecl = llvm::dyn_cast<clang::RecordDecl>(outerCtxt)) {
2187  ROOT::TMetaUtils::GetNormalizedName(ctxtName, thisRcdDecl, interpreter);
2188  }
2189  // We recurse
2190  GetMostExternalEnclosingClassName(*outerCtxt, ctxtName, interpreter);
2191 }
2192 
2193 ////////////////////////////////////////////////////////////////////////////////
2194 
2195 void GetMostExternalEnclosingClassNameFromDecl(const clang::Decl &theDecl,
2196  std::string &ctxtName,
2197  const cling::Interpreter &interpreter)
2198 {
2199  const clang::DeclContext *theContext = theDecl.getDeclContext();
2200  GetMostExternalEnclosingClassName(*theContext, ctxtName, interpreter, false);
2201 }
2202 
2203 ////////////////////////////////////////////////////////////////////////////////
2204 template<class COLL>
2205 int ExtractAutoloadKeys(std::list<std::string> &names,
2206  const COLL &decls,
2207  const cling::Interpreter &interp)
2208 {
2209  if (!decls.empty()) {
2210  std::string autoLoadKey;
2211  for (auto & d : decls) {
2212  autoLoadKey = "";
2213  GetMostExternalEnclosingClassNameFromDecl(*d, autoLoadKey, interp);
2214  // If there is an outer class, it is already considered
2215  if (autoLoadKey.empty()) {
2216  names.push_back(d->getQualifiedNameAsString());
2217  }
2218  }
2219  }
2220  return 0;
2221 }
2222 
2223 ////////////////////////////////////////////////////////////////////////////////
2224 /// Generate a rootmap file in the new format, like
2225 /// { decls }
2226 /// namespace A { namespace B { template <typename T> class myTemplate; } }
2227 /// [libGpad.so libGraf.so libHist.so libMathCore.so]
2228 /// class TAttCanvas
2229 /// class TButton
2230 /// (header1.h header2.h .. headerN.h)
2231 /// class TMyClass
2232 
2233 int CreateNewRootMapFile(const std::string &rootmapFileName,
2234  const std::string &rootmapLibName,
2235  const std::list<std::string> &classesDefsList,
2236  const std::list<std::string> &classesNames,
2237  const std::list<std::string> &nsNames,
2238  const std::list<std::string> &tdNames,
2239  const std::list<std::string> &enNames,
2240  const std::list<std::string> &varNames,
2241  const HeadersDeclsMap_t &headersClassesMap,
2242  const std::unordered_set<std::string> headersToIgnore)
2243 {
2244  // Create the rootmap file from the selected classes and namespaces
2245  std::ofstream rootmapFile(rootmapFileName.c_str());
2246  if (!rootmapFile) {
2247  ROOT::TMetaUtils::Error(0, "Opening new rootmap file %s\n", rootmapFileName.c_str());
2248  return 1;
2249  }
2250 
2251  // Keep track of the classes keys
2252  // This is done to avoid duplications of keys with typedefs
2253  std::unordered_set<std::string> classesKeys;
2254 
2255 
2256  // Add the "section"
2257  if (!classesNames.empty() || !nsNames.empty() || !tdNames.empty() ||
2258  !enNames.empty() || !varNames.empty()) {
2259 
2260  // Add the template definitions
2261  if (!classesDefsList.empty()) {
2262  rootmapFile << "{ decls }\n";
2263  for (auto & classDef : classesDefsList) {
2264  rootmapFile << classDef << std::endl;
2265  }
2266  rootmapFile << "\n";
2267  }
2268  rootmapFile << "[ " << rootmapLibName << " ]\n";
2269 
2270  // Loop on selected classes and insert them in the rootmap
2271  if (!classesNames.empty()) {
2272  rootmapFile << "# List of selected classes\n";
2273  for (auto & className : classesNames) {
2274  rootmapFile << "class " << className << std::endl;
2275  classesKeys.insert(className);
2276  }
2277  // And headers
2278  std::unordered_set<std::string> treatedHeaders;
2279  for (auto & className : classesNames) {
2280  // Don't treat templates
2281  if (className.find("<") != std::string::npos) continue;
2282  if (headersClassesMap.count(className)) {
2283  auto &headers = headersClassesMap.at(className);
2284  if (!headers.empty()){
2285  auto &header = headers.front();
2286  if (treatedHeaders.insert(header).second &&
2287  headersToIgnore.find(header) == headersToIgnore.end() &&
2289  rootmapFile << "header " << header << std::endl;
2290  }
2291  }
2292  }
2293  }
2294  }
2295 
2296  // Same for namespaces
2297  if (!nsNames.empty()) {
2298  rootmapFile << "# List of selected namespaces\n";
2299  for (auto & nsName : nsNames) {
2300  rootmapFile << "namespace " << nsName << std::endl;
2301  }
2302  }
2303 
2304  // And typedefs. These are used just to trigger the autoload mechanism
2305  if (!tdNames.empty()) {
2306  rootmapFile << "# List of selected typedefs and outer classes\n";
2307  for (const auto & autoloadKey : tdNames)
2308  if (classesKeys.insert(autoloadKey).second)
2309  rootmapFile << "typedef " << autoloadKey << std::endl;
2310  }
2311 
2312  // And Enums. There is no incomplete type for an enum but we can nevertheless
2313  // have the key for the cases where the root typesystem is interrogated.
2314  if (!enNames.empty()){
2315  rootmapFile << "# List of selected enums and outer classes\n";
2316  for (const auto & autoloadKey : enNames)
2317  if (classesKeys.insert(autoloadKey).second)
2318  rootmapFile << "enum " << autoloadKey << std::endl;
2319  }
2320 
2321  // And variables.
2322  if (!varNames.empty()){
2323  rootmapFile << "# List of selected vars\n";
2324  for (const auto & autoloadKey : varNames)
2325  if (classesKeys.insert(autoloadKey).second)
2326  rootmapFile << "var " << autoloadKey << std::endl;
2327  }
2328 
2329  }
2330 
2331  return 0;
2332 
2333 }
2334 
2335 ////////////////////////////////////////////////////////////////////////////////
2336 /// Performance is not critical here.
2337 
2338 std::pair<std::string,std::string> GetExternalNamespaceAndContainedEntities(const std::string line)
2339 {
2340  auto nsPattern = '{'; auto nsPatternLength = 1;
2341  auto foundNsPos = line.find_last_of(nsPattern);
2342  if (foundNsPos == std::string::npos) return {"",""};
2343  foundNsPos+=nsPatternLength;
2344  auto extNs = line.substr(0,foundNsPos);
2345 
2346  auto nsEndPattern = '}';
2347  auto foundEndNsPos = line.find(nsEndPattern);
2348  auto contained = line.substr(foundNsPos, foundEndNsPos-foundNsPos);
2349 
2350  return {extNs, contained};
2351 
2352 
2353 }
2354 
2355 ////////////////////////////////////////////////////////////////////////////////
2356 /// If two identical namespaces are there, just declare one only
2357 /// Example:
2358 /// namespace A { namespace B { fwd1; }}
2359 /// namespace A { namespace B { fwd2; }}
2360 /// get a namespace A { namespace B { fwd1; fwd2; }} line
2361 
2362 std::list<std::string> CollapseIdenticalNamespaces(const std::list<std::string>& fwdDeclarationsList)
2363 {
2364  // Temp data structure holding the namespaces and the entities therewith
2365  // contained
2366  std::map<std::string, std::string> nsEntitiesMap;
2367  std::list<std::string> optFwdDeclList;
2368  for (auto const & fwdDecl : fwdDeclarationsList){
2369  // Check if the decl(s) are contained in a ns and which one
2370  auto extNsAndEntities = GetExternalNamespaceAndContainedEntities(fwdDecl);
2371  if (extNsAndEntities.first.empty()) {
2372  // no namespace found. Just put this on top
2373  optFwdDeclList.push_front(fwdDecl);
2374  };
2375  auto currentVal = nsEntitiesMap[extNsAndEntities.first];
2376  nsEntitiesMap[extNsAndEntities.first] = currentVal +=extNsAndEntities.second;
2377  }
2378 
2379  // Now fill the new, optimised list
2380  std::string optFwdDecl;
2381  for (auto const & extNsAndEntities : nsEntitiesMap) {
2382  optFwdDecl = extNsAndEntities.first;
2383  optFwdDecl += extNsAndEntities.second;
2384  for (int i = 0; i < std::count(optFwdDecl.begin(), optFwdDecl.end(), '{'); ++i ){
2385  optFwdDecl += " }";
2386  }
2387  optFwdDeclList.push_front(optFwdDecl);
2388  }
2389 
2390  return optFwdDeclList;
2391 
2392 }
2393 
2394 ////////////////////////////////////////////////////////////////////////////////
2395 /// Separate multiline strings
2396 
2397 bool ProcessAndAppendIfNotThere(const std::string &el,
2398  std::list<std::string> &el_list,
2399  std::unordered_set<std::string> &el_set)
2400 {
2401  std::stringstream elStream(el);
2402  std::string tmp;
2403  bool added = false;
2404  while (getline(elStream, tmp, '\n')) {
2405  // Add if not there
2406  if (el_set.insert(tmp).second && !tmp.empty()) {
2407  el_list.push_back(tmp);
2408  added = true;
2409  }
2410  }
2411 
2412  return added;
2413 }
2414 
2415 ////////////////////////////////////////////////////////////////////////////////
2416 
2418  std::list<std::string> &classesList,
2419  std::list<std::string> &classesListForRootmap,
2420  std::list<std::string> &fwdDeclarationsList,
2421  const cling::Interpreter &interpreter)
2422 {
2423  // Loop on selected classes. If they don't have the attribute "rootmap"
2424  // set to "false", store them in the list of classes for the rootmap
2425  // Returns 0 in case of success and 1 in case of issues.
2426 
2427  // An unordered_set to keep track of the existing classes.
2428  // We want to avoid duplicates there as they may hint to a serious corruption
2429  std::unordered_set<std::string> classesSet;
2430  std::unordered_set<std::string> outerMostClassesSet;
2431 
2432  std::string attrName, attrValue;
2433  bool isClassSelected;
2434  std::unordered_set<std::string> availableFwdDecls;
2435  std::string fwdDeclaration;
2436  for (auto const & selVar : scan.fSelectedVariables) {
2437  fwdDeclaration = "";
2438  int retCode = ROOT::TMetaUtils::AST2SourceTools::EncloseInNamespaces(*selVar, fwdDeclaration);
2439  if (retCode == 0) ProcessAndAppendIfNotThere(fwdDeclaration, fwdDeclarationsList, availableFwdDecls);
2440  }
2441 
2442  for (auto const & selEnum : scan.fSelectedEnums) {
2443  fwdDeclaration = "";
2444  int retCode = ROOT::TMetaUtils::AST2SourceTools::EncloseInNamespaces(*selEnum, fwdDeclaration);
2445  if (retCode == 0) ProcessAndAppendIfNotThere(fwdDeclaration, fwdDeclarationsList, availableFwdDecls);
2446  }
2447 
2448  // Loop on selected classes and put them in a list
2449  for (auto const & selClass : scan.fSelectedClasses) {
2450  isClassSelected = true;
2451  const clang::RecordDecl *rDecl = selClass.GetRecordDecl();
2452  std::string normalizedName;
2453  normalizedName = selClass.GetNormalizedName();
2454  if (!normalizedName.empty() &&
2455  !classesSet.insert(normalizedName).second &&
2456  outerMostClassesSet.count(normalizedName) == 0) {
2457  std::cerr << "FATAL: A class with normalized name " << normalizedName
2458  << " was already selected. This means that two different instances of"
2459  << " clang::RecordDecl had the same name, which is not possible."
2460  << " This can be a hint of a serious problem in the class selection."
2461  << " In addition, the generated dictionary would not even compile.\n";
2462  return 1;
2463  }
2464  classesList.push_back(normalizedName);
2465  // Allow to autoload with the name of the class as it was specified in the
2466  // selection xml or linkdef
2467  const char *reqName(selClass.GetRequestedName());
2468 
2469  // Get always the containing namespace, put it in the list if not there
2470  fwdDeclaration = "";
2471  int retCode = ROOT::TMetaUtils::AST2SourceTools::EncloseInNamespaces(*rDecl, fwdDeclaration);
2472  if (retCode == 0) ProcessAndAppendIfNotThere(fwdDeclaration, fwdDeclarationsList, availableFwdDecls);
2473 
2474  // Get template definition and put it in if not there
2475  if (llvm::isa<clang::ClassTemplateSpecializationDecl>(rDecl)) {
2476  fwdDeclaration = "";
2477  retCode = ROOT::TMetaUtils::AST2SourceTools::FwdDeclFromRcdDecl(*rDecl, interpreter, fwdDeclaration);
2478  if (retCode == 0) ProcessAndAppendIfNotThere(fwdDeclaration, fwdDeclarationsList, availableFwdDecls);
2479  }
2480 
2481 
2482  // Loop on attributes, if rootmap=false, don't put it in the list!
2483  for (auto ait = rDecl->attr_begin(); ait != rDecl->attr_end(); ++ait) {
2484  if (0 == ROOT::TMetaUtils::extractPropertyNameVal(*ait, attrName, attrValue) &&
2485  attrName == "rootmap" &&
2486  attrValue == "false") {
2487  attrName = attrValue = "";
2488  isClassSelected = false;
2489  break;
2490  }
2491  }
2492  if (isClassSelected) {
2493  // Now, check if this is an internal class. If yes, we check the name of the outermost one
2494  // This is because of ROOT-6517. On the other hand, we exclude from this treatment
2495  // classes which are template instances which are nested in classes. For example:
2496  // class A{
2497  // class B{};
2498  // };
2499  // selection: <class name="A::B" />
2500  // Will result in a rootmap entry like "class A"
2501  // On the other hand, taking
2502  // class A{
2503  // public:
2504  // template <class T> class B{};
2505  // };
2506  // selection: <class name="A::B<int>" />
2507  // Would result in an entry like "class A::B<int>"
2508  std::string outerMostClassName;
2509  GetMostExternalEnclosingClassName(*rDecl, outerMostClassName, interpreter);
2510  if (!outerMostClassName.empty() &&
2511  !llvm::isa<clang::ClassTemplateSpecializationDecl>(rDecl) &&
2512  classesSet.insert(outerMostClassName).second &&
2513  outerMostClassesSet.insert(outerMostClassName).second) {
2514  classesListForRootmap.push_back(outerMostClassName);
2515  } else {
2516  classesListForRootmap.push_back(normalizedName);
2517  if (reqName && reqName[0] && reqName != normalizedName) {
2518  classesListForRootmap.push_back(reqName);
2519  }
2520 
2521  // Also register typeinfo::name(), unless we have pseudo-strong typedefs.
2522  // GetDemangledTypeInfo() checks for Double32_t etc already and returns an empty string.
2523  std::string demangledName = selClass.GetDemangledTypeInfo();
2524  if (!demangledName.empty()) {
2525  // See the operations in TCling::AutoLoad(type_info)
2527  splitname.ShortType(demangledName, TClassEdit::kDropStlDefault | TClassEdit::kDropStd);
2528 
2529  if (demangledName != normalizedName && (!reqName || demangledName != reqName)) {
2530  // if demangledName != other name
2531  classesListForRootmap.push_back(demangledName);
2532  }
2533  }
2534  }
2535  }
2536  }
2537  classesListForRootmap.sort();
2538 
2539  // Disable for the moment
2540  // fwdDeclarationsList = CollapseIdenticalNamespaces(fwdDeclarationsList);
2541 
2542  return 0;
2543 }
2544 
2545 ////////////////////////////////////////////////////////////////////////////////
2546 /// Loop on selected classes and put them in a list
2547 
2548 void ExtractSelectedNamespaces(RScanner &scan, std::list<std::string> &nsList)
2549 {
2550  for (RScanner::NamespaceColl_t::const_iterator selNsIter = scan.fSelectedNamespaces.begin();
2551  selNsIter != scan.fSelectedNamespaces.end(); ++selNsIter) {
2552  nsList.push_back(ROOT::TMetaUtils::GetQualifiedName(* selNsIter->GetNamespaceDecl()));
2553  }
2554 }
2555 
2556 ////////////////////////////////////////////////////////////////////////////////
2557 /// We need annotations even in the PCH: // !, // || etc.
2558 
2559 void AnnotateAllDeclsForPCH(cling::Interpreter &interp,
2560  RScanner &scan)
2561 {
2562  auto const & declSelRulesMap = scan.GetDeclsSelRulesMap();
2563  for (auto const & selClass : scan.fSelectedClasses) {
2564  // Very important: here we decide if we want to attach attributes to the decl.
2565  if (clang::CXXRecordDecl *CXXRD =
2566  llvm::dyn_cast<clang::CXXRecordDecl>(const_cast<clang::RecordDecl *>(selClass.GetRecordDecl()))) {
2567  AnnotateDecl(*CXXRD, declSelRulesMap, interp, false);
2568  }
2569  }
2570 }
2571 
2572 ////////////////////////////////////////////////////////////////////////////////
2573 
2574 int CheckClassesForInterpreterOnlyDicts(cling::Interpreter &interp,
2575  RScanner &scan)
2576 {
2577  for (auto const & selClass : scan.fSelectedClasses) {
2578  if (!selClass.GetRecordDecl()->isCompleteDefinition() || selClass.RequestOnlyTClass()) {
2579  continue;
2580  }
2581  const clang::CXXRecordDecl *cxxdecl = llvm::dyn_cast<clang::CXXRecordDecl>(selClass.GetRecordDecl());
2582  if (cxxdecl && ROOT::TMetaUtils::ClassInfo__HasMethod(selClass, "Class_Name", interp)) {
2583  ROOT::TMetaUtils::Error("CheckClassesForInterpreterOnlyDicts",
2584  "Interactivity only dictionaries are not supported for classes with ClassDef\n");
2585  return 1;
2586  }
2587  }
2588  return 0;
2589 }
2590 
2591 ////////////////////////////////////////////////////////////////////////////////
2592 /// Make up for skipping RegisterModule, now that dictionary parsing
2593 /// is done and these headers cannot be selected anymore.
2594 
2595 int FinalizeStreamerInfoWriting(cling::Interpreter &interp, bool writeEmptyRootPCM=false)
2596 {
2598  return 0;
2599 
2600  if (interp.parseForModule("#include \"TStreamerInfo.h\"\n"
2601  "#include \"TFile.h\"\n"
2602  "#include \"TObjArray.h\"\n"
2603  "#include \"TVirtualArray.h\"\n"
2604  "#include \"TStreamerElement.h\"\n"
2605  "#include \"TProtoClass.h\"\n"
2606  "#include \"TBaseClass.h\"\n"
2607  "#include \"TListOfDataMembers.h\"\n"
2608  "#include \"TListOfEnums.h\"\n"
2609  "#include \"TListOfEnumsWithLock.h\"\n"
2610  "#include \"TDataMember.h\"\n"
2611  "#include \"TEnum.h\"\n"
2612  "#include \"TEnumConstant.h\"\n"
2613  "#include \"TDictAttributeMap.h\"\n"
2614  "#include \"TMessageHandler.h\"\n"
2615  "#include \"TArray.h\"\n"
2616  "#include \"TRefArray.h\"\n"
2617  "#include \"root_std_complex.h\"\n")
2618  != cling::Interpreter::kSuccess)
2619  return 1;
2620  if (!gDriverConfig->fCloseStreamerInfoROOTFile(writeEmptyRootPCM)) {
2621  return 1;
2622  }
2623  return 0;
2624 }
2625 
2626 ////////////////////////////////////////////////////////////////////////////////
2627 
2628 int GenerateFullDict(std::ostream &dictStream,
2629  cling::Interpreter &interp,
2630  RScanner &scan,
2631  const ROOT::TMetaUtils::RConstructorTypes &ctorTypes,
2632  bool isSplit,
2633  bool isGenreflex,
2634  bool writeEmptyRootPCM)
2635 {
2636  ROOT::TMetaUtils::TNormalizedCtxt normCtxt(interp.getLookupHelper());
2637 
2638  bool needsCollectionProxy = false;
2639 
2640  //
2641  // We will loop over all the classes several times.
2642  // In order we will call
2643  //
2644  // WriteClassInit (code to create the TGenericClassInfo)
2645  // check for constructor and operator input
2646  // WriteClassFunctions (declared in ClassDef)
2647  // WriteClassCode (Streamer,ShowMembers,Auxiliary functions)
2648  //
2649 
2650 
2651  //
2652  // Loop over all classes and create Streamer() & Showmembers() methods
2653  //
2654 
2655  // SELECTION LOOP
2656  for (auto const & ns : scan.fSelectedNamespaces) {
2657  if (!gOptIgnoreExistingDict) {
2658  WriteNamespaceInit(ns, interp, dictStream);
2659  }
2660  auto nsName = ns.GetNamespaceDecl()->getQualifiedNameAsString();
2661  if (nsName.find("(anonymous)") == std::string::npos)
2662  EmitStreamerInfo(nsName.c_str());
2663  }
2664 
2665  for (auto const & selClass : scan.fSelectedClasses) {
2666  if (!selClass.GetRecordDecl()->isCompleteDefinition()) {
2667  ROOT::TMetaUtils::Error(0, "A dictionary has been requested for %s but there is no declaration!\n", ROOT::TMetaUtils::GetQualifiedName(selClass).c_str());
2668  continue;
2669  }
2670  if (selClass.RequestOnlyTClass()) {
2671  // fprintf(stderr,"rootcling: Skipping class %s\n",R__GetQualifiedName(* selClass.GetRecordDecl()).c_str());
2672  // For now delay those for later.
2673  continue;
2674  }
2675 
2676  // Very important: here we decide if we want to attach attributes to the decl.
2677 
2678  if (clang::CXXRecordDecl *CXXRD =
2679  llvm::dyn_cast<clang::CXXRecordDecl>(const_cast<clang::RecordDecl *>(selClass.GetRecordDecl()))) {
2680  AnnotateDecl(*CXXRD, scan.GetDeclsSelRulesMap() , interp, isGenreflex);
2681  }
2682 
2683  const clang::CXXRecordDecl *CRD = llvm::dyn_cast<clang::CXXRecordDecl>(selClass.GetRecordDecl());
2684 
2685  if (CRD) {
2686  ROOT::TMetaUtils::Info(0, "Generating code for class %s\n", selClass.GetNormalizedName());
2687  if (TMetaUtils::IsStdClass(*CRD) && 0 != TClassEdit::STLKind(CRD->getName().str() /* unqualified name without template argument */)) {
2688  // Register the collections
2689  // coverity[fun_call_w_exception] - that's just fine.
2690  Internal::RStl::Instance().GenerateTClassFor(selClass.GetNormalizedName(), CRD, interp, normCtxt);
2691  } else {
2692  if (!gOptIgnoreExistingDict) {
2693  ROOT::TMetaUtils::WriteClassInit(dictStream, selClass, CRD, interp, normCtxt, ctorTypes,
2694  needsCollectionProxy);
2695  }
2696  EmitStreamerInfo(selClass.GetNormalizedName());
2697  }
2698  }
2699  }
2700 
2701  //
2702  // Write all TBuffer &operator>>(...), Class_Name(), Dictionary(), etc.
2703  // first to allow template specialisation to occur before template
2704  // instantiation (STK)
2705  //
2706  // SELECTION LOOP
2707  for (auto const & selClass : scan.fSelectedClasses) {
2708 
2709  if (!selClass.GetRecordDecl()->isCompleteDefinition() || selClass.RequestOnlyTClass()) {
2710  // For now delay those for later.
2711  continue;
2712  }
2713  const clang::CXXRecordDecl *cxxdecl = llvm::dyn_cast<clang::CXXRecordDecl>(selClass.GetRecordDecl());
2714  if (cxxdecl && ROOT::TMetaUtils::ClassInfo__HasMethod(selClass, "Class_Name", interp) && !gOptIgnoreExistingDict) {
2715  WriteClassFunctions(cxxdecl, dictStream, isSplit);
2716  }
2717  }
2718 
2719  // LINKDEF SELECTION LOOP
2720  // Loop to get the shadow class for the class marked 'RequestOnlyTClass' (but not the
2721  // STL class which is done via Internal::RStl::Instance().WriteClassInit(0);
2722  // and the ClassInit
2723 
2724  for (auto const & selClass : scan.fSelectedClasses) {
2725  if (!selClass.GetRecordDecl()->isCompleteDefinition() || !selClass.RequestOnlyTClass()) {
2726  continue;
2727  }
2728 
2729  const clang::CXXRecordDecl *CRD = llvm::dyn_cast<clang::CXXRecordDecl>(selClass.GetRecordDecl());
2730 
2731  if (!ROOT::TMetaUtils::IsSTLContainer(selClass)) {
2732  if (!gOptIgnoreExistingDict) {
2733  ROOT::TMetaUtils::WriteClassInit(dictStream, selClass, CRD, interp, normCtxt, ctorTypes,
2734  needsCollectionProxy);
2735  }
2736  EmitStreamerInfo(selClass.GetNormalizedName());
2737  }
2738  }
2739  // Loop to write all the ClassCode
2740  if (!gOptIgnoreExistingDict) {
2741  for (auto const &selClass : scan.fSelectedClasses) {
2743  selClass,
2744  interp,
2745  normCtxt,
2746  dictStream,
2747  ctorTypes,
2748  isGenreflex);
2749  }
2750 
2751  // Loop on the registered collections internally
2752  // coverity[fun_call_w_exception] - that's just fine.
2753  ROOT::Internal::RStl::Instance().WriteClassInit(dictStream, interp, normCtxt, ctorTypes, needsCollectionProxy,
2755  }
2756 
2759  EmitEnums(scan.fSelectedEnums);
2760  // Make up for skipping RegisterModule, now that dictionary parsing
2761  // is done and these headers cannot be selected anymore.
2762  int finRetCode = FinalizeStreamerInfoWriting(interp, writeEmptyRootPCM);
2763  if (finRetCode != 0) return finRetCode;
2764  }
2765 
2766  return 0;
2767 }
2768 
2769 ////////////////////////////////////////////////////////////////////////////////
2770 
2771 void CreateDictHeader(std::ostream &dictStream, const std::string &main_dictname)
2772 {
2773  dictStream << "// Do NOT change. Changes will be lost next time file is generated\n\n"
2774  << "#define R__DICTIONARY_FILENAME " << main_dictname << std::endl
2775 
2776  // We do not want deprecation warnings to fire in dictionaries
2777  << "#define R__NO_DEPRECATION" << std::endl
2778 
2779  // Now that CINT is not longer there to write the header file,
2780  // write one and include in there a few things for backward
2781  // compatibility.
2782  << "\n/*******************************************************************/\n"
2783  << "#include <stddef.h>\n"
2784  << "#include <stdio.h>\n"
2785  << "#include <stdlib.h>\n"
2786  << "#include <string.h>\n"
2787  << "#include <assert.h>\n"
2788  << "#define G__DICTIONARY\n"
2789  << "#include \"RConfig.h\"\n"
2790  << "#include \"TClass.h\"\n"
2791  << "#include \"TDictAttributeMap.h\"\n"
2792  << "#include \"TInterpreter.h\"\n"
2793  << "#include \"TROOT.h\"\n"
2794  << "#include \"TBuffer.h\"\n"
2795  << "#include \"TMemberInspector.h\"\n"
2796  << "#include \"TInterpreter.h\"\n"
2797  << "#include \"TVirtualMutex.h\"\n"
2798  << "#include \"TError.h\"\n\n"
2799  << "#ifndef G__ROOT\n"
2800  << "#define G__ROOT\n"
2801  << "#endif\n\n"
2802  << "#include \"RtypesImp.h\"\n"
2803  << "#include \"TIsAProxy.h\"\n"
2804  << "#include \"TFileMergeInfo.h\"\n"
2805  << "#include <algorithm>\n"
2806  << "#include \"TCollectionProxyInfo.h\"\n"
2807  << "/*******************************************************************/\n\n"
2808  << "#include \"TDataMember.h\"\n\n"; // To set their transiency
2809 }
2810 
2811 ////////////////////////////////////////////////////////////////////////////////
2812 
2813 void AddNamespaceSTDdeclaration(std::ostream &dictStream)
2814 {
2815  dictStream << "// The generated code does not explicitly qualifies STL entities\n"
2816  << "namespace std {} using namespace std;\n\n";
2817 }
2818 
2819 ////////////////////////////////////////////////////////////////////////////////
2820 
2821 void GenerateNecessaryIncludes(std::ostream &dictStream,
2822  const std::string &includeForSource,
2823  const std::string &extraIncludes)
2824 {
2825  dictStream << "// Header files passed as explicit arguments\n"
2826  << includeForSource << std::endl
2827  << "// Header files passed via #pragma extra_include\n"
2828  << extraIncludes << std::endl;
2829 }
2830 
2831 //______________________________________________________________________________
2832 
2833 // cross-compiling for iOS and iOS simulator (assumes host is Intel Mac OS X)
2834 #if defined(R__IOSSIM) || defined(R__IOS)
2835 #ifdef __x86_64__
2836 #undef __x86_64__
2837 #endif
2838 #ifdef __i386__
2839 #undef __i386__
2840 #endif
2841 #ifdef R__IOSSIM
2842 #define __i386__ 1
2843 #endif
2844 #ifdef R__IOS
2845 #define __arm__ 1
2846 #endif
2847 #endif
2848 
2849 ////////////////////////////////////////////////////////////////////////////////
2850 /// Little helper class to bookkeep the files names which we want to make
2851 /// temporary.
2852 
2853 class tempFileNamesCatalog {
2854 public:
2855  //______________________________________________
2856  tempFileNamesCatalog(): m_size(0), m_emptyString("") {};
2857 
2858  std::string getTmpFileName(const std::string &filename) {
2859  return filename + "_tmp_" + std::to_string(getpid());
2860  }
2861  /////////////////////////////////////////////////////////////////////////////
2862  /// Adds the name and the associated temp name to the catalog.
2863  /// Changes the name into the temp name
2864 
2865  void addFileName(std::string &nameStr) {
2866  if (nameStr.empty()) return;
2867 
2868  std::string tmpNameStr(getTmpFileName(nameStr));
2869 
2870  // For brevity
2871  const char *name(nameStr.c_str());
2872  const char *tmpName(tmpNameStr.c_str());
2873 
2874  m_names.push_back(nameStr);
2875  m_tempNames.push_back(tmpNameStr);
2876  ROOT::TMetaUtils::Info(0, "File %s added to the tmp catalog.\n", name);
2877 
2878  // This is to allow update of existing files
2879  if (0 == std::rename(name , tmpName)) {
2880  ROOT::TMetaUtils::Info(0, "File %s existing. Preserved as %s.\n", name, tmpName);
2881  }
2882 
2883  // To change the name to its tmp version
2884  nameStr = tmpNameStr;
2885 
2886  m_size++;
2887 
2888  }
2889 
2890  /////////////////////////////////////////////////////////////////////////////
2891 
2892  int clean() {
2893  int retval = 0;
2894  // rename the temp files into the normal ones
2895  for (unsigned int i = 0; i < m_size; ++i) {
2896  const char *tmpName = m_tempNames[i].c_str();
2897  // Check if the file exists
2898  std::ifstream ifile(tmpName);
2899  if (!ifile)
2900  ROOT::TMetaUtils::Error(0, "Cannot find %s!\n", tmpName);
2901 
2902  if (0 != std::remove(tmpName)) {
2903  ROOT::TMetaUtils::Error(0, "Removing %s!\n", tmpName);
2904  retval++;
2905  }
2906  }
2907  return retval;
2908  }
2909 
2910  /////////////////////////////////////////////////////////////////////////////
2911 
2912  int commit() {
2913  int retval = 0;
2914  // rename the temp files into the normal ones
2915  for (unsigned int i = 0; i < m_size; ++i) {
2916  const char *tmpName = m_tempNames[i].c_str();
2917  const char *name = m_names[i].c_str();
2918  // Check if the file exists
2919  std::ifstream ifile(tmpName);
2920  if (!ifile)
2921  ROOT::TMetaUtils::Error(0, "Cannot find %s!\n", tmpName);
2922 #ifdef WIN32
2923  // Sometimes files cannot be renamed on Windows if they don't have
2924  // been released by the system. So just copy them and try to delete
2925  // the old one afterwards.
2926  if (ifile.is_open())
2927  ifile.close();
2928  if (0 != std::rename(tmpName , name)) {
2929  if (llvm::sys::fs::copy_file(tmpName , name)) {
2930  llvm::sys::fs::remove(tmpName);
2931  }
2932  }
2933 #else
2934  if (0 != std::rename(tmpName , name)) {
2935  ROOT::TMetaUtils::Error(0, "Renaming %s into %s!\n", tmpName, name);
2936  retval++;
2937  }
2938 #endif
2939  }
2940  return retval;
2941  }
2942 
2943  /////////////////////////////////////////////////////////////////////////////
2944 
2945  const std::string &getFileName(const std::string &tmpFileName) {
2946  size_t i = std::distance(m_tempNames.begin(),
2947  find(m_tempNames.begin(), m_tempNames.end(), tmpFileName));
2948  if (i == m_tempNames.size()) return m_emptyString;
2949  return m_names[i];
2950  }
2951 
2952  /////////////////////////////////////////////////////////////////////////////
2953 
2954  void dump() {
2955  std::cout << "Restoring files in temporary file catalog:\n";
2956  for (unsigned int i = 0; i < m_size; ++i) {
2957  std::cout << m_tempNames[i] << " --> " << m_names[i] << std::endl;
2958  }
2959  }
2960 
2961 private:
2962  unsigned int m_size;
2963  const std::string m_emptyString;
2964  std::vector<std::string> m_names;
2965  std::vector<std::string> m_tempNames;
2966 };
2967 
2968 ////////////////////////////////////////////////////////////////////////////////
2969 /// Transform name of dictionary
2970 
2971 std::ostream *CreateStreamPtrForSplitDict(const std::string &dictpathname,
2972  tempFileNamesCatalog &tmpCatalog)
2973 {
2974  std::string splitDictName(tmpCatalog.getFileName(dictpathname));
2975  const size_t dotPos = splitDictName.find_last_of(".");
2976  splitDictName.insert(dotPos, "_classdef");
2977  tmpCatalog.addFileName(splitDictName);
2978  return new std::ofstream(splitDictName.c_str());
2979 }
2980 
2981 ////////////////////////////////////////////////////////////////////////////////
2982 /// Transform -W statements in diagnostic pragmas for cling reacting on "-Wno-"
2983 /// For example
2984 /// -Wno-deprecated-declarations --> #pragma clang diagnostic ignored "-Wdeprecated-declarations"
2985 
2986 static void CheckForMinusW(std::string arg,
2987  std::list<std::string> &diagnosticPragmas)
2988 {
2989  static const std::string pattern("-Wno-");
2990 
2991  if (arg.find(pattern) != 0)
2992  return;
2993  if (arg == "-Wno-noexcept-type") {
2994  // GCC7 warning not supported by clang 3.9
2995  return;
2996  }
2997 
2998  ROOT::TMetaUtils::ReplaceAll(arg, pattern, "#pragma clang diagnostic ignored \"-W");
2999  arg += "\"";
3000  diagnosticPragmas.push_back(arg);
3001 }
3002 
3003 ////////////////////////////////////////////////////////////////////////////////
3004 
3006  cling::Interpreter &interp)
3007 {
3008  using namespace ROOT::TMetaUtils::AST2SourceTools;
3009  std::string fwdDecl;
3010  std::string initStr("{");
3011  auto &fwdDeclnArgsToSkipColl = normCtxt.GetTemplNargsToKeepMap();
3012  for (auto & strigNargsToKeepPair : fwdDeclnArgsToSkipColl) {
3013  auto &clTemplDecl = *strigNargsToKeepPair.first;
3014  FwdDeclFromTmplDecl(clTemplDecl , interp, fwdDecl);
3015  initStr += "{\"" +
3016  fwdDecl + "\", "
3017  + std::to_string(strigNargsToKeepPair.second)
3018  + "},";
3019  }
3020  if (!fwdDeclnArgsToSkipColl.empty())
3021  initStr.pop_back();
3022  initStr += "}";
3023  return initStr;
3024 }
3025 
3026 ////////////////////////////////////////////////////////////////////////////////
3027 /// Get the pointee type if possible
3028 
3029 clang::QualType GetPointeeTypeIfPossible(const clang::QualType &qt)
3030 {
3031  if (qt.isNull()) return qt;
3032  clang::QualType thisQt(qt);
3033  while (thisQt->isPointerType() ||
3034  thisQt->isReferenceType()) {
3035  thisQt = thisQt->getPointeeType();
3036  }
3037  return thisQt;
3038 
3039 }
3040 
3041 ////////////////////////////////////////////////////////////////////////////////
3042 /// Extract the list of headers necessary for the Decl
3043 
3044 std::list<std::string> RecordDecl2Headers(const clang::CXXRecordDecl &rcd,
3045  const cling::Interpreter &interp,
3046  std::set<const clang::CXXRecordDecl *> &visitedDecls)
3047 {
3048  std::list<std::string> headers;
3049 
3050  // We push a new transaction because we could deserialize decls here
3051  cling::Interpreter::PushTransactionRAII RAII(&interp);
3052 
3053  // Avoid infinite recursion
3054  if (!visitedDecls.insert(rcd.getCanonicalDecl()).second)
3055  return headers;
3056 
3057  // If this is a template
3058  if (const clang::ClassTemplateSpecializationDecl *tsd = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(&rcd)) {
3059 
3060  // Loop on the template args
3061  for (auto & tArg : tsd->getTemplateArgs().asArray()) {
3062  if (clang::TemplateArgument::ArgKind::Type != tArg.getKind()) continue;
3063  auto tArgQualType = GetPointeeTypeIfPossible(tArg.getAsType());
3064  if (tArgQualType.isNull()) continue;
3065  if (const clang::CXXRecordDecl *tArgCxxRcd = tArgQualType->getAsCXXRecordDecl()) {
3066  headers.splice(headers.end(), RecordDecl2Headers(*tArgCxxRcd, interp, visitedDecls));
3067  }
3068  }
3069 
3070  if (!ROOT::TMetaUtils::IsStdClass(rcd) && rcd.hasDefinition()) {
3071 
3072  // Loop on base classes - with a newer llvm, range based possible
3073  for (auto baseIt = tsd->bases_begin(); baseIt != tsd->bases_end(); baseIt++) {
3074  auto baseQualType = GetPointeeTypeIfPossible(baseIt->getType());
3075  if (baseQualType.isNull()) continue;
3076  if (const clang::CXXRecordDecl *baseRcdPtr = baseQualType->getAsCXXRecordDecl()) {
3077  headers.splice(headers.end(), RecordDecl2Headers(*baseRcdPtr, interp, visitedDecls));
3078  }
3079  }
3080 
3081  // Loop on the data members - with a newer llvm, range based possible
3082  for (auto declIt = tsd->decls_begin(); declIt != tsd->decls_end(); ++declIt) {
3083  if (const clang::FieldDecl *fieldDecl = llvm::dyn_cast<clang::FieldDecl>(*declIt)) {
3084  auto fieldQualType = GetPointeeTypeIfPossible(fieldDecl->getType());
3085  if (fieldQualType.isNull()) continue ;
3086  if (const clang::CXXRecordDecl *fieldCxxRcd = fieldQualType->getAsCXXRecordDecl()) {
3087  if (fieldCxxRcd->hasDefinition())
3088  headers.splice(headers.end(), RecordDecl2Headers(*fieldCxxRcd, interp, visitedDecls));
3089  }
3090  }
3091  }
3092 
3093  // Loop on methods
3094  for (auto methodIt = tsd->method_begin(); methodIt != tsd->method_end(); ++methodIt) {
3095  // Check arguments
3096  for (auto & fPar : methodIt->parameters()) {
3097  auto fParQualType = GetPointeeTypeIfPossible(fPar->getOriginalType());
3098  if (fParQualType.isNull()) continue;
3099  if (const clang::CXXRecordDecl *fParCxxRcd = fParQualType->getAsCXXRecordDecl()) {
3100  if (fParCxxRcd->hasDefinition())
3101  headers.splice(headers.end(), RecordDecl2Headers(*fParCxxRcd, interp, visitedDecls));
3102  }
3103  }
3104  // Check return value
3105  auto retQualType = GetPointeeTypeIfPossible(methodIt->getReturnType());
3106  if (retQualType.isNull()) continue;
3107  if (const clang::CXXRecordDecl *retCxxRcd = retQualType->getAsCXXRecordDecl()) {
3108  if (retCxxRcd->hasDefinition())
3109  headers.splice(headers.end(), RecordDecl2Headers(*retCxxRcd, interp, visitedDecls));
3110  }
3111  }
3112  }
3113 
3114  } // End template instance
3115 
3116  std::string header = ROOT::TMetaUtils::GetFileName(rcd, interp);
3117  headers.emplace_back(header);
3118  headers.reverse();
3119  return headers;
3120 
3121 }
3122 
3123 ////////////////////////////////////////////////////////////////////////////////
3124 /// Check if the class good for being an autoparse key.
3125 /// We exclude from this set stl containers of pods/strings
3126 /// TODO: we may use also __gnu_cxx::
3127 bool IsGoodForAutoParseMap(const clang::RecordDecl& rcd){
3128 
3129  // If it's not an std class, we just pick it up.
3130  if (auto dclCtxt= rcd.getDeclContext()){
3131  if (! dclCtxt->isStdNamespace()){
3132  return true;
3133  }
3134  } else {
3135  return true;
3136  }
3137 
3138  // Now, we have a stl class. We now check if it's a template. If not, we
3139  // do not take it: bitset, string and so on.
3140  auto clAsTmplSpecDecl = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(&rcd);
3141  if (!clAsTmplSpecDecl) return false;
3142 
3143  // Now we have a template in the stl. Let's see what the arguments are.
3144  // If they are not a POD or something which is good for autoparsing, we keep
3145  // them.
3146  auto& astCtxt = rcd.getASTContext();
3147  auto& templInstArgs = clAsTmplSpecDecl->getTemplateInstantiationArgs();
3148  for (auto&& arg : templInstArgs.asArray()){
3149 
3150  auto argKind = arg.getKind();
3151  if (argKind != clang::TemplateArgument::Type){
3152  if (argKind == clang::TemplateArgument::Integral) continue;
3153  else return true;
3154  }
3155 
3156  auto argQualType = arg.getAsType();
3157  auto isPOD = argQualType.isPODType(astCtxt);
3158  // This is a POD, we can inspect the next arg
3159  if (isPOD) continue;
3160 
3161  auto argType = argQualType.getTypePtr();
3162  if (auto recType = llvm::dyn_cast<clang::RecordType>(argType)){
3163  auto isArgGoodForAutoParseMap = IsGoodForAutoParseMap(*recType->getDecl());
3164  // The arg is a class but good for the map
3165  if (isArgGoodForAutoParseMap) continue;
3166  } else {
3167  // The class is not a POD nor a class we can skip
3168  return true;
3169  }
3170  }
3171 
3172  return false;
3173 }
3174 
3175 ////////////////////////////////////////////////////////////////////////////////
3176 
3178  const RScanner::TypedefColl_t tDefDecls,
3179  const RScanner::FunctionColl_t funcDecls,
3180  const RScanner::VariableColl_t varDecls,
3181  const RScanner::EnumColl_t enumDecls,
3182  HeadersDeclsMap_t &headersClassesMap,
3183  HeadersDeclsMap_t &headersDeclsMap,
3184  const cling::Interpreter &interp)
3185 {
3186  std::set<const clang::CXXRecordDecl *> visitedDecls;
3187  std::unordered_set<std::string> buffer;
3188  std::string autoParseKey;
3189 
3190  // Add some manip of headers
3191  for (auto & annotatedRcd : annotatedRcds) {
3192  if (const clang::CXXRecordDecl *cxxRcd =
3193  llvm::dyn_cast_or_null<clang::CXXRecordDecl>(annotatedRcd.GetRecordDecl())) {
3194  autoParseKey = "";
3195  visitedDecls.clear();
3196  std::list<std::string> headers(RecordDecl2Headers(*cxxRcd, interp, visitedDecls));
3197  // remove duplicates, also if not subsequent
3198  buffer.clear();
3199  headers.remove_if([&buffer](const std::string & s) {
3200  return !buffer.insert(s).second;
3201  });
3202  GetMostExternalEnclosingClassName(*cxxRcd, autoParseKey, interp);
3203  if (autoParseKey.empty()) autoParseKey = annotatedRcd.GetNormalizedName();
3204  if (IsGoodForAutoParseMap(*cxxRcd)){
3205  headersDeclsMap[autoParseKey] = headers;
3206  headersDeclsMap[annotatedRcd.GetRequestedName()] = headers;
3207  } else {
3208  ROOT::TMetaUtils::Info(0, "Class %s is not included in the set of autoparse keys.\n", autoParseKey.c_str());
3209  }
3210 
3211  // Propagate to the classes map only if this is not a template.
3212  // The header is then used as autoload key and we want to avoid duplicates.
3213  if (!llvm::isa<clang::ClassTemplateSpecializationDecl>(cxxRcd)){
3214  headersClassesMap[autoParseKey] = headersDeclsMap[autoParseKey];
3215  headersClassesMap[annotatedRcd.GetRequestedName()] = headersDeclsMap[annotatedRcd.GetRequestedName()];
3216  }
3217  }
3218  }
3219 
3220  // The same for the typedefs:
3221  for (auto & tDef : tDefDecls) {
3222  if (clang::CXXRecordDecl *cxxRcd = tDef->getUnderlyingType()->getAsCXXRecordDecl()) {
3223  autoParseKey = "";
3224  visitedDecls.clear();
3225  std::list<std::string> headers(RecordDecl2Headers(*cxxRcd, interp, visitedDecls));
3226  headers.push_back(ROOT::TMetaUtils::GetFileName(*tDef, interp));
3227  // remove duplicates, also if not subsequent
3228  buffer.clear();
3229  headers.remove_if([&buffer](const std::string & s) {
3230  return !buffer.insert(s).second;
3231  });
3232  GetMostExternalEnclosingClassNameFromDecl(*tDef, autoParseKey, interp);
3233  if (autoParseKey.empty()) autoParseKey = tDef->getQualifiedNameAsString();
3234  headersDeclsMap[autoParseKey] = headers;
3235  }
3236  }
3237 
3238  // The same for the functions:
3239  for (auto & func : funcDecls) {
3240  std::list<std::string> headers = {ROOT::TMetaUtils::GetFileName(*func, interp)};
3241  headersDeclsMap[ROOT::TMetaUtils::GetQualifiedName(*func)] = headers;
3242  }
3243 
3244  // The same for the variables:
3245  for (auto & var : varDecls) {
3246  std::list<std::string> headers = {ROOT::TMetaUtils::GetFileName(*var, interp)};
3247  headersDeclsMap[ROOT::TMetaUtils::GetQualifiedName(*var)] = headers;
3248  }
3249 
3250  // The same for the enums:
3251  for (auto & en : enumDecls) {
3252  std::list<std::string> headers = {ROOT::TMetaUtils::GetFileName(*en, interp)};
3253  headersDeclsMap[ROOT::TMetaUtils::GetQualifiedName(*en)] = headers;
3254  }
3255 }
3256 
3257 ////////////////////////////////////////////////////////////////////////////////
3258 /// Generate the fwd declarations of the selected entities
3259 
3260 static std::string GenerateFwdDeclString(const RScanner &scan,
3261  const cling::Interpreter &interp)
3262 {
3263  std::string newFwdDeclString;
3264 
3265  using namespace ROOT::TMetaUtils::AST2SourceTools;
3266 
3267  std::string fwdDeclString;
3268  std::string buffer;
3269  std::unordered_set<std::string> fwdDecls;
3270 
3271  // Classes
3272 /*
3273  for (auto const & annRcd : scan.fSelectedClasses) {
3274  const auto rcdDeclPtr = annRcd.GetRecordDecl();
3275 
3276  int retCode = FwdDeclFromRcdDecl(*rcdDeclPtr, interp, buffer);
3277  if (-1 == retCode) {
3278  ROOT::TMetaUtils::Error("GenerateFwdDeclString",
3279  "Error generating fwd decl for class %s\n",
3280  annRcd.GetNormalizedName());
3281  return emptyString;
3282  }
3283  if (retCode == 0 && fwdDecls.insert(buffer).second)
3284  fwdDeclString += "\"" + buffer + "\"\n";
3285  }
3286 */
3287  // Build the input for a transaction containing all of the selected declarations
3288  // Cling will produce the fwd declaration payload.
3289 
3290  std::vector<const clang::Decl *> selectedDecls(scan.fSelectedClasses.size());
3291 
3292  // Pick only RecordDecls
3293  std::transform (scan.fSelectedClasses.begin(),
3294  scan.fSelectedClasses.end(),
3295  selectedDecls.begin(),
3296  [](const ROOT::TMetaUtils::AnnotatedRecordDecl& rcd){return rcd.GetRecordDecl();});
3297 
3298  for (auto* TD: scan.fSelectedTypedefs)
3299  selectedDecls.push_back(TD);
3300 
3301 // for (auto* VAR: scan.fSelectedVariables)
3302 // selectedDecls.push_back(VAR);
3303 
3304  // The "R\"DICTFWDDCLS(\n" ")DICTFWDDCLS\"" pieces have been moved to
3305  // TModuleGenerator to be able to make the diagnostics more telling in presence
3306  // of an issue ROOT-6752.
3307  fwdDeclString += Decls2FwdDecls(selectedDecls,IsLinkdefFile,interp);
3308 
3309  // Functions
3310 // for (auto const& fcnDeclPtr : scan.fSelectedFunctions){
3311 // int retCode = FwdDeclFromFcnDecl(*fcnDeclPtr, interp, buffer);
3312 // newFwdDeclString += Decl2FwdDecl(*fcnDeclPtr,interp);
3313 // if (-1 == retCode){
3314 // ROOT::TMetaUtils::Error("GenerateFwdDeclString",
3315 // "Error generating fwd decl for function %s\n",
3316 // fcnDeclPtr->getNameAsString().c_str());
3317 // return emptyString;
3318 // }
3319 // if (retCode == 0 && fwdDecls.insert(buffer).second)
3320 // fwdDeclString+="\""+buffer+"\"\n";
3321 // }
3322 
3323  if (fwdDeclString.empty()) fwdDeclString = "";
3324  return fwdDeclString;
3325 }
3326 
3327 ////////////////////////////////////////////////////////////////////////////////
3328 /// Generate a string for the dictionary from the headers-classes map.
3329 
3330 const std::string GenerateStringFromHeadersForClasses(const HeadersDeclsMap_t &headersClassesMap,
3331  const std::string &detectedUmbrella,
3332  bool payLoadOnly = false)
3333 {
3334  std::string headerName;
3335 
3336  if (genreflex::verbose)
3337  std::cout << "Class-headers Mapping:\n";
3338  std::string headersClassesMapString = "";
3339  for (auto const & classHeaders : headersClassesMap) {
3340  if (genreflex::verbose)
3341  std::cout << " o " << classHeaders.first << " --> ";
3342  headersClassesMapString += "\"";
3343  headersClassesMapString += classHeaders.first + "\"";
3344  for (auto const & header : classHeaders.second) {
3345  headerName = (detectedUmbrella == header || payLoadOnly) ? "payloadCode" : "\"" + header + "\"";
3346  headersClassesMapString += ", " + headerName;
3347  if (genreflex::verbose)
3348  std::cout << ", " << headerName;
3349  if (payLoadOnly)
3350  break;
3351  }
3352  if (genreflex::verbose)
3353  std::cout << std::endl;
3354  headersClassesMapString += ", \"@\",\n";
3355  }
3356  headersClassesMapString += "nullptr";
3357  return headersClassesMapString;
3358 }
3359 
3360 ////////////////////////////////////////////////////////////////////////////////
3361 
3362 bool IsImplementationName(const std::string &filename)
3363 {
3364  return !ROOT::TMetaUtils::IsHeaderName(filename);
3365 }
3366 
3367 ////////////////////////////////////////////////////////////////////////////////
3368 /// Check if the argument is a sane cling argument. Performing the following checks:
3369 /// 1) It does not start with "--" and is not the --param option.
3370 
3371 bool IsCorrectClingArgument(const std::string& argument)
3372 {
3373  if (ROOT::TMetaUtils::BeginsWith(argument,"--") && !ROOT::TMetaUtils::BeginsWith(argument,"--param")) return false;
3374  return true;
3375 }
3376 
3377 ////////////////////////////////////////////////////////////////////////////////
3378 bool NeedsSelection(const char* name)
3379 {
3380  static const std::vector<std::string> namePrfxes {
3381  "array<",
3382  "unique_ptr<"};
3383  auto pos = find_if(namePrfxes.begin(),
3384  namePrfxes.end(),
3385  [&](const std::string& str){return ROOT::TMetaUtils::BeginsWith(name,str);});
3386  return namePrfxes.end() == pos;
3387 }
3388 
3389 ////////////////////////////////////////////////////////////////////////////////
3390 
3391 bool IsSupportedClassName(const char* name)
3392 {
3393  static const std::vector<std::string> uclNamePrfxes {
3394  "chrono:",
3395  "ratio<",
3396  "shared_ptr<"};
3397  static const std::set<std::string> unsupportedClassesNormNames{
3398  "regex",
3399  "thread"};
3400  if ( unsupportedClassesNormNames.count(name) == 1) return false;
3401  auto pos = find_if(uclNamePrfxes.begin(),
3402  uclNamePrfxes.end(),
3403  [&](const std::string& str){return ROOT::TMetaUtils::BeginsWith(name,str);});
3404  return uclNamePrfxes.end() == pos;
3405 }
3406 
3407 ////////////////////////////////////////////////////////////////////////////////
3408 /// Check if the list of selected classes contains any class which is not
3409 /// supported. Return the number of unsupported classes in the selection.
3410 
3412 {
3413  int nerrors = 0;
3414  for (auto&& aRcd : annotatedRcds){
3415  auto clName = aRcd.GetNormalizedName();
3416  if (!IsSupportedClassName(clName)){
3417  std::cerr << "Error: Class " << clName << " has been selected but "
3418  << "currently the support for its I/O is not yet available. Note that "
3419  << clName << ", even if not selected, will be available for "
3420  << "interpreted code.\n";
3421  nerrors++;
3422  }
3423  if (!NeedsSelection(clName)){
3424  std::cerr << "Error: It is not necessary to explicitly select class "
3425  << clName << ". I/O is supported for it transparently.\n";
3426  nerrors++;
3427  }
3428  }
3429  return nerrors;
3430 }
3431 
3432 ////////////////////////////////////////////////////////////////////////////////
3433 
3434 class TRootClingCallbacks : public cling::InterpreterCallbacks {
3435 private:
3436  std::list<std::string>& fFilesIncludedByLinkdef;
3437  bool isLocked = false;
3438 public:
3439  TRootClingCallbacks(cling::Interpreter* interp, std::list<std::string>& filesIncludedByLinkdef):
3440  InterpreterCallbacks(interp),
3441  fFilesIncludedByLinkdef(filesIncludedByLinkdef){};
3442 
3443  ~TRootClingCallbacks(){};
3444 
3445  virtual void InclusionDirective(clang::SourceLocation /*HashLoc*/, const clang::Token & /*IncludeTok*/,
3446  llvm::StringRef FileName, bool IsAngled, clang::CharSourceRange /*FilenameRange*/,
3447  const clang::FileEntry * /*File*/, llvm::StringRef /*SearchPath*/,
3448  llvm::StringRef /*RelativePath*/, const clang::Module * /*Imported*/)
3449  {
3450  if (isLocked) return;
3451  if (IsAngled) return;
3452  auto& PP = m_Interpreter->getCI()->getPreprocessor();
3453  auto curLexer = PP.getCurrentFileLexer();
3454  if (!curLexer) return;
3455  auto fileEntry = curLexer->getFileEntry();
3456  if (!fileEntry) return;
3457  auto thisFileName = fileEntry->getName();
3458  auto fileNameAsString = FileName.str();
3459  auto isThisLinkdef = ROOT::TMetaUtils::IsLinkdefFile(thisFileName.data());
3460  if (isThisLinkdef) {
3461  auto isTheIncludedLinkdef = ROOT::TMetaUtils::IsLinkdefFile(fileNameAsString.c_str());
3462  if (isTheIncludedLinkdef) {
3463  fFilesIncludedByLinkdef.clear();
3464  isLocked = true;
3465  } else {
3466  fFilesIncludedByLinkdef.emplace_back(fileNameAsString.c_str());
3467  }
3468  }
3469  }
3470 
3471  // rootcling pre-includes things such as Rtypes.h. This means that ACLiC can
3472  // call rootcling asking it to create a module for a file with no #includes
3473  // but relying on things from Rtypes.h such as the ClassDef macro.
3474  //
3475  // When rootcling starts building a module, it becomes resilient to the
3476  // outside environment and pre-included files have no effect. This hook
3477  // informs rootcling when a new submodule is being built so that it can
3478  // make Core.Rtypes.h visible.
3479  virtual void EnteredSubmodule(clang::Module* M,
3480  clang::SourceLocation ImportLoc,
3481  bool ForPragma) {
3482  assert(M);
3483  using namespace clang;
3484  if (llvm::StringRef(M->Name).endswith("ACLiC_dict")) {
3485  Preprocessor& PP = m_Interpreter->getCI()->getPreprocessor();
3486  HeaderSearch& HS = PP.getHeaderSearchInfo();
3487  // FIXME: Reduce to Core.Rtypes.h.
3488  Module* CoreModule = HS.lookupModule("Core", /*AllowSearch*/false);
3489  assert(M && "Must have module Core");
3490  PP.makeModuleVisible(CoreModule, ImportLoc);
3491  }
3492  }
3493 };
3494 
3495 static llvm::cl::list<std::string>
3496 gOptModuleByproducts("mByproduct", llvm::cl::ZeroOrMore,
3497  llvm::cl::Hidden,
3498  llvm::cl::desc("The list of the expected implicit modules build as part of building the current module."),
3499  llvm::cl::cat(gRootclingOptions));
3500 static llvm::cl::opt<std::string>
3501 gOptDictionaryFileName(llvm::cl::Positional, llvm::cl::Required,
3502  llvm::cl::desc("<output dictionary file>"),
3503  llvm::cl::cat(gRootclingOptions));
3504 
3505 ////////////////////////////////////////////////////////////////////////////////
3506 /// Custom diag client for clang that verifies that each implicitly build module
3507 /// is a system module. If not, it will let the current rootcling invocation
3508 /// fail with an error. All other diags beside module build remarks will be
3509 /// forwarded to the passed child diag client.
3510 ///
3511 /// The reason why we need this is that if we built implicitly a C++ module
3512 /// that belongs to a ROOT dictionary, then we will miss information generated
3513 /// by rootcling in this file (e.g. the source code comments to annotation
3514 /// attributes transformation will be missing in the module file).
3515 class CheckModuleBuildClient : public clang::DiagnosticConsumer {
3516  clang::DiagnosticConsumer *fChild;
3517  bool fOwnsChild;
3518  clang::ModuleMap &fMap;
3519 
3520 public:
3521  CheckModuleBuildClient(clang::DiagnosticConsumer *Child, bool OwnsChild, clang::ModuleMap &Map)
3522  : fChild(Child), fOwnsChild(OwnsChild), fMap(Map)
3523  {
3524  }
3525 
3526  ~CheckModuleBuildClient()
3527  {
3528  if (fOwnsChild)
3529  delete fChild;
3530  }
3531 
3532  virtual void HandleDiagnostic(clang::DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &Info) override
3533  {
3534  using namespace clang::diag;
3535 
3536  // This method catches the module_build remark from clang and checks if
3537  // the implicitly built module is a system module or not. We only support
3538  // building system modules implicitly.
3539 
3540  std::string moduleName;
3541  const clang::Module *module = nullptr;
3542 
3543  // Extract the module from the diag argument with index 0.
3544  const auto &ID = Info.getID();
3545  if (ID == remark_module_build || ID == remark_module_build_done) {
3546  moduleName = Info.getArgStdStr(0);
3547  module = fMap.findModule(moduleName);
3548  // We should never be able to build a module without having it in the
3549  // modulemap. Still, let's print a warning that we at least tell the
3550  // user that this could lead to problems.
3551  if (!module) {
3553  "Couldn't find module %s in the available modulemaps. This"
3554  "prevents us from correctly diagnosing wrongly built modules.\n",
3555  moduleName.c_str());
3556  }
3557  }
3558 
3559  // A dictionary module could build implicitly a set of implicit modules.
3560  // For example, the Core module builds libc.pcm and std.pcm implicitly.
3561  // Those modules do not require I/O information and it is okay to build
3562  // them as part of another module.
3563  // However, we can build a module which requires I/O implictly which is
3564  // an error because rootcling is not able to generate the corresponding
3565  // dictionary.
3566  // If we build a I/O requiring module implicitly we should display
3567  // an error unless the -mByproduct was specified.
3568  bool isByproductModule
3569  = module && std::find(gOptModuleByproducts.begin(), gOptModuleByproducts.end(), moduleName) != gOptModuleByproducts.end();
3570  if (!isByproductModule)
3571  fChild->HandleDiagnostic(DiagLevel, Info);
3572 
3573  if (ID == remark_module_build && !isByproductModule) {
3575  "Building module '%s' implicitly. If '%s' requires a \n"
3576  "dictionary please specify build dependency: '%s' depends on '%s'.\n"
3577  "Otherwise, specify '-mByproduct %s' to disable this diagnostic.\n",
3578  moduleName.c_str(), moduleName.c_str(), gOptDictionaryFileName.c_str(),
3579  moduleName.c_str(), moduleName.c_str());
3580  }
3581  }
3582 
3583  // All methods below just forward to the child and the default method.
3584  virtual void clear() override
3585  {
3586  fChild->clear();
3587  DiagnosticConsumer::clear();
3588  }
3589 
3590  virtual void BeginSourceFile(const clang::LangOptions &LangOpts, const clang::Preprocessor *PP) override
3591  {
3592  fChild->BeginSourceFile(LangOpts, PP);
3593  DiagnosticConsumer::BeginSourceFile(LangOpts, PP);
3594  }
3595 
3596  virtual void EndSourceFile() override
3597  {
3598  fChild->EndSourceFile();
3599  DiagnosticConsumer::EndSourceFile();
3600  }
3601 
3602  virtual void finish() override
3603  {
3604  fChild->finish();
3605  DiagnosticConsumer::finish();
3606  }
3607 
3608  virtual bool IncludeInDiagnosticCounts() const override { return fChild->IncludeInDiagnosticCounts(); }
3609 };
3610 
3612 #if defined(_WIN32) && defined(_MSC_VER)
3613  // Suppress error dialogs to avoid hangs on build nodes.
3614  // One can use an environment variable (Cling_GuiOnAssert) to enable
3615  // the error dialogs.
3616  const char *EnablePopups = getenv("Cling_GuiOnAssert");
3617  if (EnablePopups == nullptr || EnablePopups[0] == '0') {
3618  ::_set_error_mode(_OUT_TO_STDERR);
3619  _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
3620  _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
3621  _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
3622  _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
3623  _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
3624  _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
3625  }
3626 #endif
3627 }
3628 
3629 static llvm::cl::opt<bool> gOptForce("f", llvm::cl::desc("Overwrite <file>s."),
3630  llvm::cl::cat(gRootclingOptions));
3631 static llvm::cl::opt<bool> gOptRootBuild("rootbuild", llvm::cl::desc("If we are building ROOT."),
3632  llvm::cl::Hidden,
3633  llvm::cl::cat(gRootclingOptions));
3637  v1 = v,
3641 };
3642 static llvm::cl::opt<VerboseLevel>
3643 gOptVerboseLevel(llvm::cl::desc("Choose verbosity level:"),
3644  llvm::cl::values(clEnumVal(v, "Show errors."),
3645  clEnumVal(v0, "Show only fatal errors."),
3646  clEnumVal(v1, "Show errors (the same as -v)."),
3647  clEnumVal(v2, "Show warnings (default)."),
3648  clEnumVal(v3, "Show notes."),
3649  clEnumVal(v4, "Show information.")),
3650  llvm::cl::init(v2),
3651  llvm::cl::cat(gRootclingOptions));
3652 
3653 static llvm::cl::opt<bool>
3654 gOptCint("cint", llvm::cl::desc("Deprecated, legacy flag which is ignored."),
3655  llvm::cl::Hidden,
3656  llvm::cl::cat(gRootclingOptions));
3657 static llvm::cl::opt<bool>
3658 gOptReflex("reflex", llvm::cl::desc("Deprecated, legacy flag which is ignored."),
3659  llvm::cl::Hidden,
3660  llvm::cl::cat(gRootclingOptions));
3661 static llvm::cl::opt<bool>
3662 gOptGccXml("gccxml", llvm::cl::desc("Deprecated, legacy flag which is ignored."),
3663  llvm::cl::Hidden,
3664  llvm::cl::cat(gRootclingOptions));
3665 static llvm::cl::opt<std::string>
3666 gOptLibListPrefix("lib-list-prefix",
3667  llvm::cl::desc("An ACLiC feature which exports the list of dependent libraries."),
3668  llvm::cl::Hidden,
3669  llvm::cl::cat(gRootclingOptions));
3670 static llvm::cl::opt<bool>
3671 gOptGeneratePCH("generate-pch",
3672  llvm::cl::desc("Generates a pch file from a predefined set of headers. See makepch.py."),
3673  llvm::cl::Hidden,
3674  llvm::cl::cat(gRootclingOptions));
3675 static llvm::cl::opt<bool>
3676 gOptC("c", llvm::cl::desc("Deprecated, legacy flag which is ignored."),
3677  llvm::cl::cat(gRootclingOptions));
3678 static llvm::cl::opt<bool>
3679 gOptP("p", llvm::cl::desc("Deprecated, legacy flag which is ignored."),
3680  llvm::cl::cat(gRootclingOptions));
3681 static llvm::cl::list<std::string>
3682 gOptRootmapLibNames("rml", llvm::cl::ZeroOrMore,
3683  llvm::cl::desc("Generate rootmap file."),
3684  llvm::cl::cat(gRootclingOptions));
3685 static llvm::cl::opt<std::string>
3687  llvm::cl::desc("Generate a rootmap file with the specified name."),
3688  llvm::cl::cat(gRootclingOptions));
3689 static llvm::cl::opt<bool>
3690 gOptCxxModule("cxxmodule",
3691  llvm::cl::desc("Generate a C++ module."),
3692  llvm::cl::cat(gRootclingOptions));
3693 static llvm::cl::list<std::string>
3694 gOptModuleMapFiles("moduleMapFile",
3695  llvm::cl::desc("Specify a C++ modulemap file."),
3696  llvm::cl::cat(gRootclingOptions));
3697 // FIXME: Figure out how to combine the code of -umbrellaHeader and inlineInputHeader
3698 static llvm::cl::opt<bool>
3699 gOptUmbrellaInput("umbrellaHeader",
3700  llvm::cl::desc("A single header including all headers instead of specifying them on the command line."),
3701  llvm::cl::cat(gRootclingOptions));
3702 static llvm::cl::opt<bool>
3703 gOptMultiDict("multiDict",
3704  llvm::cl::desc("If this library has multiple separate LinkDef files."),
3705  llvm::cl::cat(gRootclingOptions));
3706 static llvm::cl::opt<bool>
3707 gOptNoGlobalUsingStd("noGlobalUsingStd",
3708  llvm::cl::desc("Do not declare {using namespace std} in dictionary global scope."),
3709  llvm::cl::cat(gRootclingOptions));
3710 static llvm::cl::opt<bool>
3711 gOptInterpreterOnly("interpreteronly",
3712  llvm::cl::desc("Generate minimal dictionary for interactivity (without IO information)."),
3713  llvm::cl::cat(gRootclingOptions));
3714 static llvm::cl::opt<bool>
3715 gOptSplit("split",
3716  llvm::cl::desc("Split the dictionary into two parts: one containing the IO (ClassDef)\
3717 information and another the interactivity support."),
3718  llvm::cl::cat(gRootclingOptions));
3719 static llvm::cl::opt<bool>
3720 gOptNoDictSelection("noDictSelection",
3721  llvm::cl::Hidden,
3722  llvm::cl::desc("Do not run the selection rules. Useful when in -onepcm mode."),
3723  llvm::cl::cat(gRootclingOptions));
3724 static llvm::cl::opt<std::string>
3726  llvm::cl::desc("The path to the library of the built dictionary."),
3727  llvm::cl::cat(gRootclingOptions));
3728 static llvm::cl::list<std::string>
3730  llvm::cl::desc("The list of dependent modules of the dictionary."),
3731  llvm::cl::cat(gRootclingOptions));
3732 static llvm::cl::list<std::string>
3733 gOptExcludePaths("excludePath", llvm::cl::ZeroOrMore,
3734  llvm::cl::desc("Do not store the <path> in the dictionary."),
3735  llvm::cl::cat(gRootclingOptions));
3736 // FIXME: This does not seem to work. We have one use of -inlineInputHeader in
3737 // ROOT and it does not produce the expected result.
3738 static llvm::cl::opt<bool>
3739 gOptInlineInput("inlineInputHeader",
3740  llvm::cl::desc("Does not generate #include <header> but expands the header content."),
3741  llvm::cl::cat(gRootclingOptions));
3742 // FIXME: This is totally the wrong concept. We should not expose an interface
3743 // to be able to tell which component is in the pch and which needs extra
3744 // scaffolding for interactive use. Moreover, some of the ROOT components are
3745 // partially in the pch and this option makes it impossible to express that.
3746 // We should be able to get the list of headers in the pch early and scan
3747 // through them.
3748 static llvm::cl::opt<bool>
3749 gOptWriteEmptyRootPCM("writeEmptyRootPCM",
3750  llvm::cl::Hidden,
3751  llvm::cl::desc("Does not include the header files as it assumes they exist in the pch."),
3752  llvm::cl::cat(gRootclingOptions));
3753 static llvm::cl::opt<bool>
3755  llvm::cl::desc("Check the selection syntax only."),
3756  llvm::cl::cat(gRootclingOptions));
3757 static llvm::cl::opt<bool>
3758 gOptFailOnWarnings("failOnWarnings",
3759  llvm::cl::desc("Fail if there are warnings."),
3760  llvm::cl::cat(gRootclingOptions));
3761 static llvm::cl::opt<bool>
3762 gOptNoIncludePaths("noIncludePaths",
3763  llvm::cl::desc("Do not store include paths but rely on the env variable ROOT_INCLUDE_PATH."),
3764  llvm::cl::cat(gRootclingOptions));
3765 static llvm::cl::opt<std::string>
3766 gOptISysRoot("isysroot", llvm::cl::Prefix, llvm::cl::Hidden,
3767  llvm::cl::desc("Specify an isysroot."),
3768  llvm::cl::cat(gRootclingOptions),
3769  llvm::cl::init("-"));
3770 static llvm::cl::list<std::string>
3771 gOptIncludePaths("I", llvm::cl::Prefix, llvm::cl::ZeroOrMore,
3772  llvm::cl::desc("Specify an include path."),
3773  llvm::cl::cat(gRootclingOptions));
3774 static llvm::cl::list<std::string>
3775 gOptPPDefines("D", llvm::cl::Prefix, llvm::cl::ZeroOrMore,
3776  llvm::cl::desc("Specify defined macros."),
3777  llvm::cl::cat(gRootclingOptions));
3778 static llvm::cl::list<std::string>
3779 gOptPPUndefines("U", llvm::cl::Prefix, llvm::cl::ZeroOrMore,
3780  llvm::cl::desc("Specify undefined macros."),
3781  llvm::cl::cat(gRootclingOptions));
3782 static llvm::cl::list<std::string>
3783 gOptWDiags("W", llvm::cl::Prefix, llvm::cl::ZeroOrMore,
3784  llvm::cl::desc("Specify compiler diagnostics options."),
3785  llvm::cl::cat(gRootclingOptions));
3786 static llvm::cl::list<std::string>
3787 gOptDictionaryHeaderFiles(llvm::cl::Positional, llvm::cl::OneOrMore,
3788  llvm::cl::desc("<list of dictionary header files> <LinkDef file>"),
3789  llvm::cl::cat(gRootclingOptions));
3790 static llvm::cl::list<std::string>
3791 gOptSink(llvm::cl::ZeroOrMore, llvm::cl::Sink,
3792  llvm::cl::desc("Consumes all unrecognized options."),
3793  llvm::cl::cat(gRootclingOptions));
3794 
3795 static llvm::cl::SubCommand
3796 gBareClingSubcommand("bare-cling", "Call directly cling and exit.");
3797 
3798 static llvm::cl::list<std::string>
3799 gOptBareClingSink(llvm::cl::OneOrMore, llvm::cl::Sink,
3800  llvm::cl::desc("Consumes options and sends them to cling."),
3801  llvm::cl::cat(gRootclingOptions), llvm::cl::sub(gBareClingSubcommand));
3802 
3803 ////////////////////////////////////////////////////////////////////////////////
3804 /// Returns true iff a given module (and its submodules) contains all headers
3805 /// needed by the given ModuleGenerator.
3806 /// The names of all header files that are needed by the ModuleGenerator but are
3807 /// not in the given module will be inserted into the MissingHeader variable.
3808 /// Returns true iff the PCH was successfully generated.
3809 static bool ModuleContainsHeaders(TModuleGenerator &modGen, clang::Module *module,
3810  std::vector<std::string> &missingHeaders)
3811 {
3812  // Now we collect all header files from the previously collected modules.
3813  std::vector<clang::Module::Header> moduleHeaders;
3815  [&moduleHeaders](const clang::Module::Header &h) { moduleHeaders.push_back(h); });
3816 
3817  bool foundAllHeaders = true;
3818 
3819  // Go through the list of headers that are required by the ModuleGenerator
3820  // and check for each header if it's in one of the modules we loaded.
3821  // If not, make sure we fail at the end and mark the header as missing.
3822  for (const std::string &header : modGen.GetHeaders()) {
3823  bool headerFound = false;
3824  for (const clang::Module::Header &moduleHeader : moduleHeaders) {
3825  if (header == moduleHeader.NameAsWritten) {
3826  headerFound = true;
3827  break;
3828  }
3829  }
3830  if (!headerFound) {
3831  missingHeaders.push_back(header);
3832  foundAllHeaders = false;
3833  }
3834  }
3835  return foundAllHeaders;
3836 }
3837 
3838 ////////////////////////////////////////////////////////////////////////////////
3839 /// Check moduleName validity from modulemap. Check if this module is defined or not.
3840 static bool CheckModuleValid(TModuleGenerator &modGen, const std::string &resourceDir, cling::Interpreter &interpreter,
3841  StringRef LinkdefPath, const std::string &moduleName)
3842 {
3843  clang::CompilerInstance *CI = interpreter.getCI();
3844  clang::HeaderSearch &headerSearch = CI->getPreprocessor().getHeaderSearchInfo();
3845  headerSearch.loadTopLevelSystemModules();
3846 
3847  // Actually lookup the module on the computed module name.
3848  clang::Module *module = headerSearch.lookupModule(StringRef(moduleName));
3849 
3850  // Inform the user and abort if we can't find a module with a given name.
3851  if (!module) {
3852  ROOT::TMetaUtils::Error("CheckModuleValid", "Couldn't find module with name '%s' in modulemap!\n",
3853  moduleName.c_str());
3854  return false;
3855  }
3856 
3857  // Check if the loaded module covers all headers that were specified
3858  // by the user on the command line. This is an integrity check to
3859  // ensure that our used module map is
3860  std::vector<std::string> missingHeaders;
3861  if (!ModuleContainsHeaders(modGen, module, missingHeaders)) {
3862  // FIXME: Upgrade this to an error once modules are stable.
3863  std::stringstream msgStream;
3864  msgStream << "warning: Couldn't find in "
3865  << module->PresumedModuleMapFile
3866  << " the following specified headers in "
3867  << "the module " << module->Name << ":\n";
3868  for (auto &H : missingHeaders) {
3869  msgStream << " " << H << "\n";
3870  }
3871  std::string warningMessage = msgStream.str();
3872 
3873  bool maybeUmbrella = modGen.GetHeaders().size() == 1;
3874  // We may have an umbrella and forgot to add the flag. Downgrade the
3875  // warning into an information message.
3876  // FIXME: We should open the umbrella, extract the set of header files
3877  // and check if they exist in the modulemap.
3878  // FIXME: We should also check if the header files are specified in the
3879  // modulemap file as they appeared in the rootcling invocation, i.e.
3880  // if we passed rootcling ... -I/some/path somedir/some/header, the
3881  // modulemap should contain module M { header "somedir/some/header" }
3882  // This way we will make sure the module is properly activated.
3883  if (!gOptUmbrellaInput && maybeUmbrella) {
3884  ROOT::TMetaUtils::Info("CheckModuleValid, %s. You can silence this message by adding %s to the invocation.",
3885  warningMessage.c_str(),
3886  gOptUmbrellaInput.ArgStr.data());
3887  return true;
3888  }
3889 
3890  ROOT::TMetaUtils::Warning("CheckModuleValid", warningMessage.c_str());
3891  // We include the missing headers to fix the module for the user.
3892  if (!IncludeHeaders(missingHeaders, interpreter)) {
3893  ROOT::TMetaUtils::Error("CheckModuleValid", "Couldn't include missing module headers for module '%s'!\n",
3894  module->Name.c_str());
3895  }
3896  }
3897 
3898  return true;
3899 }
3900 
3901 static llvm::StringRef GetModuleNameFromRdictName(llvm::StringRef rdictName)
3902 {
3903  // Try to get the module name in the modulemap based on the filepath.
3904  llvm::StringRef moduleName = llvm::sys::path::filename(rdictName);
3905  moduleName.consume_front("lib");
3906  moduleName.consume_back(".pcm");
3907  moduleName.consume_back("_rdict");
3908  return moduleName;
3909 }
3910 
3911 ////////////////////////////////////////////////////////////////////////////////
3912 
3913 int RootClingMain(int argc,
3914  char **argv,
3915  bool isGenreflex = false)
3916 {
3917  // Define Options aliasses
3918  auto &opts = llvm::cl::getRegisteredOptions();
3919  auto &optHelp = *opts["help"];
3920  llvm::cl::alias optHelpAlias1("h",
3921  llvm::cl::desc("Alias for -help"),
3922  llvm::cl::aliasopt(optHelp));
3923  llvm::cl::alias optHelpAlias2("?",
3924  llvm::cl::desc("Alias for -help"),
3925  llvm::cl::aliasopt(optHelp));
3926 
3927  // Copied from cling driver.
3928  // FIXME: Uncomment once we fix ROOT's teardown order.
3929  //llvm::llvm_shutdown_obj shutdownTrigger;
3930 
3931  const char *executableFileName = argv[0];
3932 
3933  llvm::sys::PrintStackTraceOnErrorSignal(executableFileName);
3934  llvm::PrettyStackTraceProgram X(argc, argv);
3936 
3937 #if defined(R__WIN32) && !defined(R__WINGCC)
3938  // FIXME: This is terrible hack allocating and changing the argument set.
3939  // We should remove it and use standard llvm facilities to convert the paths.
3940  // cygwin's make is presenting us some cygwin paths even though
3941  // we are windows native. Convert them as good as we can.
3942  for (int iic = 1 /* ignore binary file name in argv[0] */; iic < argc; ++iic) {
3943  std::string iiarg(argv[iic]);
3944  if (FromCygToNativePath(iiarg)) {
3945  size_t len = iiarg.length();
3946  // yes, we leak.
3947  char *argviic = new char[len + 1];
3948  strlcpy(argviic, iiarg.c_str(), len + 1);
3949  argv[iic] = argviic;
3950  }
3951  }
3952 #endif
3953 
3954  // Hide options from llvm which we got from static initialization of libCling.
3955  llvm::cl::HideUnrelatedOptions(/*keep*/gRootclingOptions);
3956 
3957  llvm::cl::ParseCommandLineOptions(argc, argv, "rootcling");
3958 
3959  std::string llvmResourceDir = std::string(gDriverConfig->fTROOT__GetEtcDir()) + "/cling";
3960  if (gBareClingSubcommand) {
3961  std::vector<const char *> clingArgsC;
3962  clingArgsC.push_back(executableFileName);
3963  // Help cling finds its runtime (RuntimeUniverse.h and such).
3964  clingArgsC.push_back("-I");
3965  clingArgsC.push_back(gDriverConfig->fTROOT__GetEtcDir());
3966 
3967  //clingArgsC.push_back("-resource-dir");
3968  //clingArgsC.push_back(llvmResourceDir.c_str());
3969 
3970  for (const std::string& Opt : gOptBareClingSink)
3971  clingArgsC.push_back(Opt.c_str());
3972 
3973  auto interp = llvm::make_unique<cling::Interpreter>(clingArgsC.size(),
3974  &clingArgsC[0],
3975  llvmResourceDir.c_str());
3976  // FIXME: Diagnose when we have misspelled a flag. Currently we show no
3977  // diagnostic and report exit as success.
3978  return interp->getDiagnostics().hasFatalErrorOccurred();
3979  }
3980 
3981  std::string dictname;
3982 
3984  if (gOptRootBuild) {
3985  // running rootcling as part of the ROOT build for ROOT libraries.
3986  gBuildingROOT = true;
3987  }
3988  }
3989 
3990  if (!gOptModuleMapFiles.empty() && !gOptCxxModule) {
3991  ROOT::TMetaUtils::Error("", "Option %s can be used only when option %s is specified.\n",
3992  gOptModuleMapFiles.ArgStr.str().c_str(),
3993  gOptCxxModule.ArgStr.str().c_str());
3994  std::cout << "\n";
3995  llvm::cl::PrintHelpMessage();
3996  return 1;
3997  }
3998 
3999  // Set the default verbosity
4001  if (gOptVerboseLevel == v4)
4002  genreflex::verbose = true;
4003 
4004  if (gOptReflex)
4005  isGenreflex = true;
4006 
4007  if (!gOptLibListPrefix.empty()) {
4008  string filein = gOptLibListPrefix + ".in";
4009  FILE *fp;
4010  if ((fp = fopen(filein.c_str(), "r")) == 0) {
4011  ROOT::TMetaUtils::Error(0, "%s: The input list file %s does not exist\n", executableFileName, filein.c_str());
4012  return 1;
4013  }
4014  fclose(fp);
4015  }
4016 
4018  FILE *fp;
4019  if (!gOptIgnoreExistingDict && (fp = fopen(gOptDictionaryFileName.c_str(), "r")) != 0) {
4020  fclose(fp);
4021  if (!gOptForce) {
4022  ROOT::TMetaUtils::Error(0, "%s: output file %s already exists\n", executableFileName, gOptDictionaryFileName.c_str());
4023  return 1;
4024  }
4025  }
4026 
4027  // remove possible pathname to get the dictionary name
4028  if (gOptDictionaryFileName.size() > (PATH_MAX - 1)) {
4029  ROOT::TMetaUtils::Error(0, "rootcling: dictionary name too long (more than %d characters): %s\n",
4030  (PATH_MAX - 1), gOptDictionaryFileName.c_str());
4031  return 1;
4032  }
4033 
4034  dictname = llvm::sys::path::filename(gOptDictionaryFileName);
4035  }
4036 
4037  if (gOptForce && dictname.empty()) {
4038  ROOT::TMetaUtils::Error(0, "Inconsistent set of arguments detected: overwrite of dictionary file forced but no filename specified.\n");
4039  llvm::cl::PrintHelpMessage();
4040  return 1;
4041  }
4042 
4043  std::vector<std::string> clingArgs;
4044  clingArgs.push_back(executableFileName);
4045  clingArgs.push_back("-iquote.");
4046 
4047  bool dictSelection = !gOptNoDictSelection;
4048 
4049  // Collect the diagnostic pragmas linked to the usage of -W
4050  // Workaround for ROOT-5656
4051  std::list<std::string> diagnosticPragmas = {"#pragma clang diagnostic ignored \"-Wdeprecated-declarations\""};
4052 
4053  if (gOptFailOnWarnings) {
4054  using namespace ROOT::TMetaUtils;
4055  // If warnings are disabled with the current verbosity settings, lower
4056  // it so that the user sees the warning that caused the failure.
4057  if (GetErrorIgnoreLevel() > kWarning)
4059  GetWarningsAreErrors() = true;
4060  }
4061 
4062  if (gOptISysRoot != "-") {
4063  if (gOptISysRoot.empty()) {
4064  ROOT::TMetaUtils::Error("", "isysroot specified without a value.\n");
4065  return 1;
4066  }
4067  clingArgs.push_back(gOptISysRoot.ArgStr);
4068  clingArgs.push_back(gOptISysRoot.ValueStr);
4069  }
4070 
4071  // Check if we have a multi dict request but no target library
4072  if (gOptMultiDict && gOptSharedLibFileName.empty()) {
4073  ROOT::TMetaUtils::Error("", "Multidict requested but no target library. Please specify one with the -s argument.\n");
4074  return 1;
4075  }
4076 
4077  for (const std::string &PPDefine : gOptPPDefines)
4078  clingArgs.push_back(std::string("-D") + PPDefine);
4079 
4080  for (const std::string &PPUndefine : gOptPPUndefines)
4081  clingArgs.push_back(std::string("-U") + PPUndefine);
4082 
4083  for (const std::string &IncludePath : gOptIncludePaths)
4084  clingArgs.push_back(std::string("-I") + llvm::sys::path::convert_to_slash(IncludePath));
4085 
4086  for (const std::string &WDiag : gOptWDiags) {
4087  const std::string FullWDiag = std::string("-W") + WDiag;
4088  // Suppress warning when compiling the dictionary, eg. gcc G__xxx.cxx
4089  CheckForMinusW(FullWDiag, diagnosticPragmas);
4090  // Suppress warning when compiling the input headers by cling.
4091  clingArgs.push_back(FullWDiag);
4092  }
4093 
4094  std::string includeDir = llvm::sys::path::convert_to_slash(gDriverConfig->fTROOT__GetIncludeDir());
4095  clingArgs.push_back(std::string("-I") + includeDir);
4096 
4097  std::vector<std::string> pcmArgs;
4098  for (size_t parg = 0, n = clingArgs.size(); parg < n; ++parg) {
4099  auto thisArg = clingArgs[parg];
4100  auto isInclude = ROOT::TMetaUtils::BeginsWith(thisArg,"-I");
4101  if (thisArg == "-c" ||
4102  (gOptNoIncludePaths && isInclude)) continue;
4103  // We now check if the include directories are not excluded
4104  if (isInclude) {
4105  unsigned int offset = 2; // -I is two characters. Now account for spaces
4106  char c = thisArg[offset];
4107  while (c == ' ') c = thisArg[++offset];
4108  auto excludePathsEnd = gOptExcludePaths.end();
4109  auto excludePathPos = std::find_if(gOptExcludePaths.begin(),
4110  excludePathsEnd,
4111  [&](const std::string& path){
4112  return ROOT::TMetaUtils::BeginsWith(&thisArg[offset], path);});
4113  if (excludePathsEnd != excludePathPos) continue;
4114  }
4115  pcmArgs.push_back(thisArg);
4116  }
4117 
4118  // cling-only arguments
4119  clingArgs.push_back(std::string("-I") + llvm::sys::path::convert_to_slash(gDriverConfig->fTROOT__GetEtcDir()));
4120  // We do not want __ROOTCLING__ in the pch!
4121  if (!gOptGeneratePCH) {
4122  clingArgs.push_back("-D__ROOTCLING__");
4123  }
4124 #ifdef R__MACOSX
4125  clingArgs.push_back("-DSYSTEM_TYPE_macosx");
4126 #elif defined(R__WIN32)
4127  clingArgs.push_back("-DSYSTEM_TYPE_winnt");
4128 
4129  // Prevent the following #error: The C++ Standard Library forbids macroizing keywords.
4130  clingArgs.push_back("-D_XKEYCHECK_H");
4131  // Tell windows.h not to #define min and max, it clashes with numerical_limits.
4132  clingArgs.push_back("-DNOMINMAX");
4133 #else // assume UNIX
4134  clingArgs.push_back("-DSYSTEM_TYPE_unix");
4135 #endif
4136 
4137  clingArgs.push_back("-fsyntax-only");
4138 #ifndef R__WIN32
4139  clingArgs.push_back("-fPIC");
4140 #endif
4141  clingArgs.push_back("-Xclang");
4142  clingArgs.push_back("-fmodules-embed-all-files");
4143  clingArgs.push_back("-Xclang");
4144  clingArgs.push_back("-main-file-name");
4145  clingArgs.push_back("-Xclang");
4146  clingArgs.push_back((dictname + ".h").c_str());
4147 
4149 
4150  // FIXME: This line is from TModuleGenerator, but we can't reuse this code
4151  // at this point because TModuleGenerator needs a CompilerInstance (and we
4152  // currently create the arguments for creating said CompilerInstance).
4153  bool isPCH = (gOptDictionaryFileName.getValue() == "allDict.cxx");
4154  std::string outputFile;
4155  // Data is in 'outputFile', therefore in the same scope.
4156  StringRef moduleName;
4157  std::string vfsArg;
4158  // Adding -fmodules to the args will break lexing with __CINT__ defined,
4159  // and we actually do lex with __CINT__ and reuse this variable later,
4160  // we have to copy it now.
4161  auto clingArgsInterpreter = clingArgs;
4162 
4163  if (gOptSharedLibFileName.empty()) {
4165  }
4166 
4167  if (!isPCH && gOptCxxModule) {
4168  // We just pass -fmodules, the CIFactory will do the rest and configure
4169  // clang correctly once it sees this flag.
4170  clingArgsInterpreter.push_back("-fmodules");
4171  clingArgsInterpreter.push_back("-fno-implicit-module-maps");
4172 
4173  for (const std::string &modulemap : gOptModuleMapFiles)
4174  clingArgsInterpreter.push_back("-fmodule-map-file=" + modulemap);
4175 
4176  clingArgsInterpreter.push_back("-fmodule-map-file=" +
4177  std::string(gDriverConfig->fTROOT__GetIncludeDir()) +
4178  "/module.modulemap");
4179  std::string ModuleMapCWD = ROOT::FoundationUtils::GetCurrentDir() + "/module.modulemap";
4180  if (llvm::sys::fs::exists(ModuleMapCWD))
4181  clingArgsInterpreter.push_back("-fmodule-map-file=" + ModuleMapCWD);
4182 
4183  // Specify the module name that we can lookup the module in the modulemap.
4184  outputFile = llvm::sys::path::stem(gOptSharedLibFileName).str();
4185  // Try to get the module name in the modulemap based on the filepath.
4186  moduleName = GetModuleNameFromRdictName(outputFile);
4187 
4188  clingArgsInterpreter.push_back("-fmodule-name");
4189  clingArgsInterpreter.push_back(moduleName.str());
4190 
4191  std::string moduleCachePath = llvm::sys::path::parent_path(gOptSharedLibFileName).str();
4192  // FIXME: This is a horrible workaround to fix the incremental builds.
4193  // The enumerated modules are built by clang impicitly based on #include of
4194  // a header which is contained within that module. The build system has
4195  // no way to track dependencies on them and trigger a rebuild.
4196  // A possible solution can be to disable completely the implicit build of
4197  // modules and each module to be built by rootcling. We need to teach
4198  // rootcling how to build modules with no IO support.
4199  if (moduleName == "Core") {
4201  remove((moduleCachePath + llvm::sys::path::get_separator() + "_Builtin_intrinsics.pcm").str().c_str());
4202  remove((moduleCachePath + llvm::sys::path::get_separator() + "_Builtin_stddef_max_align_t.pcm").str().c_str());
4203  remove((moduleCachePath + llvm::sys::path::get_separator() + "Cling_Runtime.pcm").str().c_str());
4204  remove((moduleCachePath + llvm::sys::path::get_separator() + "Cling_Runtime_Extra.pcm").str().c_str());
4205 #ifdef R__WIN32
4206  remove((moduleCachePath + llvm::sys::path::get_separator() + "vcruntime.pcm").str().c_str());
4207  remove((moduleCachePath + llvm::sys::path::get_separator() + "services.pcm").str().c_str());
4208 #endif
4209 
4210 #ifdef R__MACOSX
4211  remove((moduleCachePath + llvm::sys::path::get_separator() + "Darwin.pcm").str().c_str());
4212 #else
4213  remove((moduleCachePath + llvm::sys::path::get_separator() + "libc.pcm").str().c_str());
4214 #endif
4215  remove((moduleCachePath + llvm::sys::path::get_separator() + "std.pcm").str().c_str());
4216  remove((moduleCachePath + llvm::sys::path::get_separator() + "cuda.pcm").str().c_str());
4217  remove((moduleCachePath + llvm::sys::path::get_separator() + "boost.pcm").str().c_str());
4218  remove((moduleCachePath + llvm::sys::path::get_separator() + "tinyxml2.pcm").str().c_str());
4219  remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Config.pcm").str().c_str());
4220  remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Rtypes.pcm").str().c_str());
4221  remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Foundation_C.pcm").str().c_str());
4222  remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Foundation_Stage1_NoRTTI.pcm").str().c_str());
4223  }
4224 
4225  // Set the C++ modules output directory to the directory where we generate
4226  // the shared library.
4227  clingArgsInterpreter.push_back("-fmodules-cache-path=" + moduleCachePath);
4228  }
4229 
4230  if (gOptVerboseLevel == v4)
4231  clingArgsInterpreter.push_back("-v");
4232 
4233  // Convert arguments to a C array and check if they are sane
4234  std::vector<const char *> clingArgsC;
4235  for (auto const &clingArg : clingArgsInterpreter) {
4236  if (!IsCorrectClingArgument(clingArg)){
4237  std::cerr << "Argument \""<< clingArg << "\" is not a supported cling argument. "
4238  << "This could be mistyped rootcling argument. Please check the commandline.\n";
4239  return 1;
4240  }
4241  clingArgsC.push_back(clingArg.c_str());
4242  }
4243 
4244 
4245  std::unique_ptr<cling::Interpreter> owningInterpPtr;
4246  cling::Interpreter* interpPtr = nullptr;
4247 
4248  std::list<std::string> filesIncludedByLinkdef;
4250 #ifdef R__FAST_MATH
4251  // Same setting as in TCling.cxx.
4252  clingArgsC.push_back("-ffast-math");
4253 #endif
4254 
4255  owningInterpPtr.reset(new cling::Interpreter(clingArgsC.size(), &clingArgsC[0],
4256  llvmResourceDir.c_str()));
4257  interpPtr = owningInterpPtr.get();
4258  } else {
4259  // Pass the interpreter arguments to TCling's interpreter:
4260  clingArgsC.push_back("-resource-dir");
4261  clingArgsC.push_back(llvmResourceDir.c_str());
4262  clingArgsC.push_back(0); // signal end of array
4263  const char ** &extraArgs = *gDriverConfig->fTROOT__GetExtraInterpreterArgs();
4264  extraArgs = &clingArgsC[1]; // skip binary name
4265  interpPtr = gDriverConfig->fTCling__GetInterpreter();
4266  if (!isGenreflex && !gOptGeneratePCH) {
4267  std::unique_ptr<TRootClingCallbacks> callBacks (new TRootClingCallbacks(interpPtr, filesIncludedByLinkdef));
4268  interpPtr->setCallbacks(std::move(callBacks));
4269  }
4270  }
4271  cling::Interpreter &interp = *interpPtr;
4272  clang::CompilerInstance *CI = interp.getCI();
4273  // FIXME: Remove this once we switch cling to use the driver. This would handle -fmodules-embed-all-files for us.
4274  CI->getFrontendOpts().ModulesEmbedAllFiles = true;
4275  CI->getSourceManager().setAllFilesAreTransient(true);
4276 
4277  clang::Preprocessor &PP = CI->getPreprocessor();
4278  clang::HeaderSearch &headerSearch = PP.getHeaderSearchInfo();
4279  clang::ModuleMap &moduleMap = headerSearch.getModuleMap();
4280  auto &diags = interp.getDiagnostics();
4281 
4282  // Manually enable the module build remarks. We don't enable them via the
4283  // normal clang command line arg because otherwise we would get remarks for
4284  // building STL/libc when starting the interpreter in rootcling_stage1.
4285  // We can't prevent these diags in any other way because we can only attach
4286  // our own diag client now after the interpreter has already started.
4287  diags.setSeverity(clang::diag::remark_module_build, clang::diag::Severity::Remark, clang::SourceLocation());
4288 
4289  // Attach our own diag client that listens to the module_build remarks from
4290  // clang to check that we don't build dictionary C++ modules implicitly.
4291  auto recordingClient = new CheckModuleBuildClient(diags.getClient(), diags.ownsClient(), moduleMap);
4292  diags.setClient(recordingClient, true);
4293 
4295  ROOT::TMetaUtils::Info(0, "\n");
4296  ROOT::TMetaUtils::Info(0, "==== INTERPRETER CONFIGURATION ====\n");
4297  ROOT::TMetaUtils::Info(0, "== Include paths\n");
4298  interp.DumpIncludePath();
4299  printf("\n\n");
4300  fflush(stdout);
4301 
4302  ROOT::TMetaUtils::Info(0, "== Included files\n");
4303  interp.printIncludedFiles(llvm::outs());
4304  llvm::outs() << "\n\n";
4305  llvm::outs().flush();
4306 
4307  ROOT::TMetaUtils::Info(0, "== Language Options\n");
4308  const clang::LangOptions& LangOpts
4309  = interp.getCI()->getASTContext().getLangOpts();
4310 #define LANGOPT(Name, Bits, Default, Description) \
4311  ROOT::TMetaUtils::Info(0, "%s = %d // %s\n", #Name, (int)LangOpts.Name, Description);
4312 #define ENUM_LANGOPT(Name, Type, Bits, Default, Description)
4313 #include "clang/Basic/LangOptions.def"
4314  ROOT::TMetaUtils::Info(0, "==== END interpreter configuration ====\n\n");
4315  }
4316 
4317  interp.getOptions().ErrorOut = true;
4318  interp.enableRawInput(true);
4319 
4320  if (gOptCxxModule) {
4321  for (llvm::StringRef DepMod : gOptModuleDependencies) {
4322  if (DepMod.endswith("_rdict.pcm")) {
4323  ROOT::TMetaUtils::Warning(0, "'%s' value is deprecated. Please use [<fullpath>]%s.pcm\n",
4324  DepMod.data(),
4325  GetModuleNameFromRdictName(DepMod).str().data());
4326  }
4327  DepMod = GetModuleNameFromRdictName(DepMod);
4328  // We might deserialize.
4329  cling::Interpreter::PushTransactionRAII RAII(&interp);
4330  if (!interp.loadModule(DepMod, /*complain*/false)) {
4331  ROOT::TMetaUtils::Error(0, "Module '%s' failed to load.\n",
4332  DepMod.data());
4333  }
4334  }
4335  }
4336 
4337  if (!isGenreflex) { // rootcling
4338  // ROOTCINT uses to define a few header implicitly, we need to do it explicitly.
4339  if (interp.declare("#include <assert.h>\n"
4340  "#include \"Rtypes.h\"\n"
4341  "#include \"TObject.h\"") != cling::Interpreter::kSuccess
4342  ) {
4343  // There was an error.
4344  ROOT::TMetaUtils::Error(0, "Error loading the default rootcling header files.\n");
4345  return 1;
4346  }
4347  }
4348 
4349  if (interp.declare("#include <string>\n" // For the list of 'opaque' typedef to also include string.
4350  "#include <RtypesCore.h>\n" // For initializing TNormalizedCtxt.
4351  "namespace std {} using namespace std;") != cling::Interpreter::kSuccess) {
4352  ROOT::TMetaUtils::Error(0, "Error loading the default header files.\n");
4353  return 1;
4354  }
4355 
4356  // We are now ready (enough is loaded) to init the list of opaque typedefs.
4357  ROOT::TMetaUtils::TNormalizedCtxt normCtxt(interp.getLookupHelper());
4358  ROOT::TMetaUtils::TClingLookupHelper helper(interp, normCtxt, 0, 0, nullptr);
4359  TClassEdit::Init(&helper);
4360 
4361  // flags used only for the pragma parser:
4362  clingArgs.push_back("-D__CINT__");
4363  clingArgs.push_back("-D__MAKECINT__");
4364 
4365  AddPlatformDefines(clingArgs);
4366 
4367  std::string currentDirectory = ROOT::FoundationUtils::GetCurrentDir();
4368 
4369  std::string interpPragmaSource;
4370  std::string includeForSource;
4371  std::string interpreterDeclarations;
4372  std::string linkdef;
4373 
4374  for (size_t i = 0, e = gOptDictionaryHeaderFiles.size(); i < e; ++i) {
4375  const std::string& optHeaderFileName = gOptDictionaryHeaderFiles[i];
4376  bool isSelectionFile = IsSelectionFile(optHeaderFileName.c_str());
4377 
4378  if (isSelectionFile) {
4379  if (i == e - 1) {
4380  linkdef = optHeaderFileName;
4381  } else { // if the linkdef was not last, issue an error.
4382  ROOT::TMetaUtils::Error(0, "%s: %s must be last file on command line\n",
4383  executableFileName, optHeaderFileName.c_str());
4384  return 1;
4385  }
4386  }
4387 
4388  // coverity[tainted_data] The OS should already limit the argument size, so we are safe here
4389  std::string fullheader(optHeaderFileName);
4390  // Strip any trailing + which is only used by GeneratedLinkdef.h which currently
4391  // use directly argv.
4392  if (fullheader[fullheader.length() - 1] == '+') {
4393  fullheader.erase(fullheader.length() - 1);
4394  }
4395  std::string header(
4396  isSelectionFile ? fullheader : ROOT::FoundationUtils::MakePathRelative(fullheader, currentDirectory, gBuildingROOT));
4397 
4398  interpPragmaSource += std::string("#include \"") + header + "\"\n";
4399  if (!isSelectionFile) {
4400  // In order to not have to add the equivalent to -I${PWD} to the
4401  // command line, include the complete file name, even if it is a
4402  // full pathname, when we write it down in the dictionary.
4403  // Note: have -I${PWD} means in that (at least in the case of
4404  // ACLiC) we inadvertently pick local file that have the same
4405  // name as system header (e.g. new or list) and -iquote has not
4406  // equivalent on some platforms.
4407  includeForSource += std::string("#include \"") + fullheader + "\"\n";
4408  pcmArgs.push_back(header);
4409  } else if (!IsSelectionXml(optHeaderFileName.c_str())) {
4410  interpreterDeclarations += std::string("#include \"") + header + "\"\n";
4411  }
4412  }
4413 
4414  if (gOptUmbrellaInput) {
4415  bool hasSelectionFile = !linkdef.empty();
4416  unsigned expectedHeaderFilesSize = 1 + hasSelectionFile;
4417  if (gOptDictionaryHeaderFiles.size() > expectedHeaderFilesSize)
4418  ROOT::TMetaUtils::Error(0, "Option %s used but more than one header file specified.\n",
4419  gOptUmbrellaInput.ArgStr.data());
4420  }
4421 
4422  // We have a multiDict request. This implies generating a pcm which is of the form
4423  // dictName_libname_rdict.pcm
4424  if (gOptMultiDict) {
4425 
4426  std::string newName = llvm::sys::path::parent_path(gOptSharedLibFileName).str();
4427  if (!newName.empty())
4428  newName += gPathSeparator;
4429  newName += llvm::sys::path::stem(gOptSharedLibFileName);
4430  newName += "_";
4431  newName += llvm::sys::path::stem(gOptDictionaryFileName);
4433  gOptSharedLibFileName = newName;
4434  }
4435 
4436  // Until the module are actually enabled in ROOT, we need to register
4437  // the 'current' directory to make it relocatable (i.e. have a way
4438  // to find the headers).
4440  string incCurDir = "-I";
4441  incCurDir += currentDirectory;
4442  pcmArgs.push_back(incCurDir);
4443  }
4444 
4445  // Add the diagnostic pragmas distilled from the -Wno-xyz
4446  {
4447  std::stringstream res;
4448  const char* delim="\n";
4449  std::copy(diagnosticPragmas.begin(),
4450  diagnosticPragmas.end(),
4451  std::ostream_iterator<std::string>(res, delim));
4452  if (interp.declare(res.str()) != cling::Interpreter::kSuccess) {
4453  ROOT::TMetaUtils::Error(0, "Failed to parse -Wno-xyz flags as pragmas:\n%s", res.str().c_str());
4454  return 1;
4455  }
4456  }
4457 
4458  class IgnoringPragmaHandler: public clang::PragmaNamespace {
4459  public:
4460  IgnoringPragmaHandler(const char* pragma):
4461  clang::PragmaNamespace(pragma) {}
4462  void HandlePragma(clang::Preprocessor &PP,
4463  clang::PragmaIntroducerKind Introducer,
4464  clang::Token &tok) {
4465  PP.DiscardUntilEndOfDirective();
4466  }
4467  };
4468 
4469  // Ignore these #pragmas to suppress "unknown pragma" warnings.
4470  // See LinkdefReader.cxx.
4471  PP.AddPragmaHandler(new IgnoringPragmaHandler("link"));
4472  PP.AddPragmaHandler(new IgnoringPragmaHandler("extra_include"));
4473  PP.AddPragmaHandler(new IgnoringPragmaHandler("read"));
4474  PP.AddPragmaHandler(new IgnoringPragmaHandler("create"));
4475 
4476  if (!interpreterDeclarations.empty() &&
4477  interp.declare(interpreterDeclarations) != cling::Interpreter::kSuccess) {
4478  ROOT::TMetaUtils::Error(0, "%s: Linkdef compilation failure\n", executableFileName);
4479  return 1;
4480  }
4481 
4482 
4483  TModuleGenerator modGen(interp.getCI(),
4487 
4488  if (!gDriverConfig->fBuildingROOTStage1 && !filesIncludedByLinkdef.empty()) {
4489  pcmArgs.push_back(linkdef);
4490  }
4491 
4492  modGen.ParseArgs(pcmArgs);
4493 
4495  // Forward the -I, -D, -U
4496  for (const std::string & inclPath : modGen.GetIncludePaths()) {
4497  interp.AddIncludePath(inclPath);
4498  }
4499  std::stringstream definesUndefinesStr;
4500  modGen.WritePPDefines(definesUndefinesStr);
4501  modGen.WritePPUndefines(definesUndefinesStr);
4502  if (!definesUndefinesStr.str().empty()) {
4503  if (interp.declare(definesUndefinesStr.str()) != cling::Interpreter::kSuccess) {
4504  ROOT::TMetaUtils::Error(0, "Failed to parse -D, -U flags as preprocessor directives:\n%s", definesUndefinesStr.str().c_str());
4505  return 1;
4506  }
4507  }
4508  }
4509 
4510  if (!InjectModuleUtilHeader(executableFileName, modGen, interp, true)
4511  || !InjectModuleUtilHeader(executableFileName, modGen, interp, false)) {
4512  return 1;
4513  }
4514 
4515  if (linkdef.empty()) {
4516  // Generate autolinkdef
4517  GenerateLinkdef(gOptDictionaryHeaderFiles, interpPragmaSource);
4518  }
4519 
4520  // Check if code goes to stdout or rootcling file
4521  std::ofstream fileout;
4522  string main_dictname(gOptDictionaryFileName.getValue());
4523  std::ostream *splitDictStream = nullptr;
4524  std::unique_ptr<std::ostream> splitDeleter(nullptr);
4525  // Store the temp files
4526  tempFileNamesCatalog tmpCatalog;
4527  if (!gOptIgnoreExistingDict) {
4528  if (!gOptDictionaryFileName.empty()) {
4529  tmpCatalog.addFileName(gOptDictionaryFileName.getValue());
4530  fileout.open(gOptDictionaryFileName.c_str());
4531  if (!fileout) {
4532  ROOT::TMetaUtils::Error(0, "rootcling: failed to open %s in main\n",
4533  gOptDictionaryFileName.c_str());
4534  return 1;
4535  }
4536  }
4537  }
4538 
4539  std::ostream &dictStream = (!gOptIgnoreExistingDict && !gOptDictionaryFileName.empty()) ? fileout : std::cout;
4540 
4541  if (!gOptIgnoreExistingDict) {
4542  // Now generate a second stream for the split dictionary if it is necessary
4543  if (gOptSplit) {
4544  splitDictStream = CreateStreamPtrForSplitDict(gOptDictionaryFileName.getValue(), tmpCatalog);
4545  splitDeleter.reset(splitDictStream);
4546  } else {
4547  splitDictStream = &dictStream;
4548  }
4549 
4550  size_t dh = main_dictname.rfind('.');
4551  if (dh != std::string::npos) {
4552  main_dictname.erase(dh);
4553  }
4554  // Need to replace all the characters not allowed in a symbol ...
4555  std::string main_dictname_copy(main_dictname);
4556  TMetaUtils::GetCppName(main_dictname, main_dictname_copy.c_str());
4557 
4558  CreateDictHeader(dictStream, main_dictname);
4559  if (gOptSplit)
4560  CreateDictHeader(*splitDictStream, main_dictname);
4561 
4562  if (!gOptNoGlobalUsingStd) {
4563  AddNamespaceSTDdeclaration(dictStream);
4564  if (gOptSplit) {
4565  AddNamespaceSTDdeclaration(*splitDictStream);
4566  }
4567  }
4568  }
4569 
4570  //---------------------------------------------------------------------------
4571  // Parse the linkdef or selection.xml file.
4572  /////////////////////////////////////////////////////////////////////////////
4573 
4574  string linkdefFilename;
4575  if (linkdef.empty()) {
4576  linkdefFilename = "in memory";
4577  } else {
4578  bool found = Which(interp, linkdef.c_str(), linkdefFilename);
4579  if (!found) {
4580  ROOT::TMetaUtils::Error(0, "%s: cannot open linkdef file %s\n", executableFileName, linkdef.c_str());
4581  return 1;
4582  }
4583  }
4584 
4585  // Exclude string not to re-generate the dictionary
4586  std::vector<std::pair<std::string, std::string>> namesForExclusion;
4587  if (!gBuildingROOT) {
4588  namesForExclusion.push_back(std::make_pair(ROOT::TMetaUtils::propNames::name, "std::string"));
4589  namesForExclusion.push_back(std::make_pair(ROOT::TMetaUtils::propNames::pattern, "ROOT::Meta::Selection*"));
4590  }
4591 
4592  SelectionRules selectionRules(interp, normCtxt, namesForExclusion);
4593 
4594  std::string extraIncludes;
4595 
4596  ROOT::TMetaUtils::RConstructorTypes constructorTypes;
4597 
4598  // Select using DictSelection
4599  const unsigned int selRulesInitialSize = selectionRules.Size();
4600  if (dictSelection && !gOptGeneratePCH)
4601  ROOT::Internal::DictSelectionReader dictSelReader(interp, selectionRules, CI->getASTContext(), normCtxt);
4602 
4603  bool dictSelRulesPresent = selectionRules.Size() > selRulesInitialSize;
4604 
4605  bool isSelXML = IsSelectionXml(linkdefFilename.c_str());
4606 
4607  int rootclingRetCode(0);
4608 
4609  if (linkdef.empty()) {
4610  // There is no linkdef file, we added the 'default' #pragma to
4611  // interpPragmaSource.
4612 
4613  LinkdefReader ldefr(interp, constructorTypes);
4614  clingArgs.push_back("-Ietc/cling/cint"); // For multiset and multimap
4615 
4616  if (!ldefr.Parse(selectionRules, interpPragmaSource, clingArgs,
4617  llvmResourceDir.c_str())) {
4618  ROOT::TMetaUtils::Error(0, "Parsing #pragma failed %s\n", linkdefFilename.c_str());
4619  rootclingRetCode += 1;
4620  } else {
4621  ROOT::TMetaUtils::Info(0, "#pragma successfully parsed.\n");
4622  }
4623 
4624  if (!ldefr.LoadIncludes(extraIncludes)) {
4625  ROOT::TMetaUtils::Error(0, "Error loading the #pragma extra_include.\n");
4626  return 1;
4627  }
4628 
4629  } else if (isSelXML) {
4630 
4632 
4633  std::ifstream file(linkdefFilename.c_str());
4634  if (file.is_open()) {
4635  ROOT::TMetaUtils::Info(0, "Selection XML file\n");
4636 
4637  XMLReader xmlr(interp);
4638  if (!xmlr.Parse(linkdefFilename.c_str(), selectionRules)) {
4639  ROOT::TMetaUtils::Error(0, "Parsing XML file %s\n", linkdefFilename.c_str());
4640  return 1; // Return here to propagate the failure up to the build system
4641  } else {
4642  ROOT::TMetaUtils::Info(0, "XML file successfully parsed\n");
4643  }
4644  file.close();
4645  } else {
4646  ROOT::TMetaUtils::Error(0, "XML file %s couldn't be opened!\n", linkdefFilename.c_str());
4647  }
4648 
4649  } else if (ROOT::TMetaUtils::IsLinkdefFile(linkdefFilename.c_str())) {
4650 
4651  std::ifstream file(linkdefFilename.c_str());
4652  if (file.is_open()) {
4653  ROOT::TMetaUtils::Info(0, "Using linkdef file: %s\n", linkdefFilename.c_str());
4654  file.close();
4655  } else {
4656  ROOT::TMetaUtils::Error(0, "Linkdef file %s couldn't be opened!\n", linkdefFilename.c_str());
4657  }
4658 
4660 
4661  LinkdefReader ldefr(interp, constructorTypes);
4662  clingArgs.push_back("-Ietc/cling/cint"); // For multiset and multimap
4663 
4664  if (!ldefr.Parse(selectionRules, interpPragmaSource, clingArgs,
4665  llvmResourceDir.c_str())) {
4666  ROOT::TMetaUtils::Error(0, "Parsing Linkdef file %s\n", linkdefFilename.c_str());
4667  rootclingRetCode += 1;
4668  } else {
4669  ROOT::TMetaUtils::Info(0, "Linkdef file successfully parsed.\n");
4670  }
4671 
4672  if (! ldefr.LoadIncludes(extraIncludes)) {
4673  ROOT::TMetaUtils::Error(0, "Error loading the #pragma extra_include.\n");
4674  return 1;
4675  }
4676 
4677  } else {
4678 
4679  ROOT::TMetaUtils::Error(0, "Unrecognized selection file: %s\n", linkdefFilename.c_str());
4680 
4681  }
4682 
4683  // Speed up the operations with rules
4684  selectionRules.FillCache();
4685  selectionRules.Optimize();
4686 
4687  if (isGenreflex){
4688  if (0 != selectionRules.CheckDuplicates()){
4689  return 1;
4690  }
4691  }
4692 
4693  // If we want to validate the selection only, we just quit.
4695  return 0;
4696 
4697  //---------------------------------------------------------------------------
4698  // Write schema evolution related headers and declarations
4699  /////////////////////////////////////////////////////////////////////////////
4700 
4701  if ((!ROOT::gReadRules.empty() || !ROOT::gReadRawRules.empty()) && !gOptIgnoreExistingDict) {
4702  dictStream << "#include \"TBuffer.h\"\n"
4703  << "#include \"TVirtualObject.h\"\n"
4704  << "#include <vector>\n"
4705  << "#include \"TSchemaHelper.h\"\n\n";
4706 
4707  std::list<std::string> includes;
4708  GetRuleIncludes(includes);
4709  for (auto & incFile : includes) {
4710  dictStream << "#include <" << incFile << ">" << std::endl;
4711  }
4712  dictStream << std::endl;
4713  }
4714 
4715  selectionRules.SearchNames(interp);
4716 
4717  int scannerVerbLevel = 0;
4718  {
4719  using namespace ROOT::TMetaUtils;
4720  scannerVerbLevel = GetErrorIgnoreLevel() == kInfo; // 1 if true, 0 if false
4721  if (isGenreflex){
4722  scannerVerbLevel = GetErrorIgnoreLevel() < kWarning;
4723  }
4724  }
4725 
4726  // Select the type of scan
4727  auto scanType = RScanner::EScanType::kNormal;
4728  if (gOptGeneratePCH)
4729  scanType = RScanner::EScanType::kOnePCM;
4730  if (dictSelection)
4732 
4733  RScanner scan(selectionRules,
4734  scanType,
4735  interp,
4736  normCtxt,
4737  scannerVerbLevel);
4738 
4739  // If needed initialize the autoloading hook
4740  if (!gOptLibListPrefix.empty()) {
4743  }
4744 
4745  scan.Scan(CI->getASTContext());
4746 
4747  bool has_input_error = false;
4748 
4749  if (genreflex::verbose)
4750  selectionRules.PrintSelectionRules();
4751 
4753  !gOptGeneratePCH &&
4754  !dictSelRulesPresent &&
4755  !selectionRules.AreAllSelectionRulesUsed()) {
4756  ROOT::TMetaUtils::Warning(0, "Not all selection rules are used!\n");
4757  }
4758 
4759  if (!gOptGeneratePCH){
4760  rootclingRetCode += CheckForUnsupportedClasses(scan.fSelectedClasses);
4761  if (rootclingRetCode) return rootclingRetCode;
4762  }
4763 
4764  // SELECTION LOOP
4765  // Check for error in the class layout before doing anything else.
4766  for (auto const & annRcd : scan.fSelectedClasses) {
4767  if (ROOT::TMetaUtils::ClassInfo__HasMethod(annRcd, "Streamer", interp)) {
4768  if (annRcd.RequestNoInputOperator()) {
4769  int version = ROOT::TMetaUtils::GetClassVersion(annRcd, interp);
4770  if (version != 0) {
4771  // Only Check for input operator is the object is I/O has
4772  // been requested.
4773  has_input_error |= CheckInputOperator(annRcd, interp);
4774  }
4775  }
4776  }
4777  has_input_error |= !CheckClassDef(*annRcd, interp);
4778  }
4779 
4780  if (has_input_error) {
4781  // Be a little bit makefile friendly and remove the dictionary in case of error.
4782  // We could add an option -k to keep the file even in case of error.
4783  exit(1);
4784  }
4785 
4786  //---------------------------------------------------------------------------
4787  // Write all the necessary #include
4788  /////////////////////////////////////////////////////////////////////////////
4790  for (auto &&includedFromLinkdef : filesIncludedByLinkdef) {
4791  includeForSource += "#include \"" + includedFromLinkdef + "\"\n";
4792  }
4793  }
4794 
4795  if (!gOptGeneratePCH) {
4796  if (!gOptIgnoreExistingDict) {
4797  GenerateNecessaryIncludes(dictStream, includeForSource, extraIncludes);
4798  if (gOptSplit) {
4799  GenerateNecessaryIncludes(*splitDictStream, includeForSource, extraIncludes);
4800  }
4801  }
4804  }
4805 
4806  // The order of addition to the list of constructor type
4807  // is significant. The list is sorted by with the highest
4808  // priority first.
4809  if (!gOptInterpreterOnly) {
4810  constructorTypes.emplace_back("TRootIOCtor", interp);
4811  constructorTypes.emplace_back("__void__", interp); // ROOT-7723
4812  constructorTypes.emplace_back("", interp);
4813  }
4814  }
4816  AddNamespaceSTDdeclaration(dictStream);
4817 
4818  if (gOptSplit && splitDictStream) {
4819  AddNamespaceSTDdeclaration(*splitDictStream);
4820  }
4821  }
4822 
4823  if (gOptGeneratePCH) {
4824  AnnotateAllDeclsForPCH(interp, scan);
4825  } else if (gOptInterpreterOnly) {
4826  rootclingRetCode += CheckClassesForInterpreterOnlyDicts(interp, scan);
4827  // generate an empty pcm nevertheless for consistency
4828  // Negate as true is 1 and true is returned in case of success.
4830  rootclingRetCode += FinalizeStreamerInfoWriting(interp);
4831  }
4832  } else {
4833  rootclingRetCode += GenerateFullDict(*splitDictStream,
4834  interp,
4835  scan,
4836  constructorTypes,
4837  gOptSplit,
4838  isGenreflex,
4840  }
4841 
4842  if (rootclingRetCode != 0) {
4843  return rootclingRetCode;
4844  }
4845 
4846  // Now we have done all our looping and thus all the possible
4847  // annotation, let's write the pcms.
4848  HeadersDeclsMap_t headersClassesMap;
4849  HeadersDeclsMap_t headersDeclsMap;
4850  if (!gOptIgnoreExistingDict) {
4851  const std::string fwdDeclnArgsToKeepString(GetFwdDeclnArgsToKeepString(normCtxt, interp));
4852 
4854  scan.fSelectedTypedefs,
4855  scan.fSelectedFunctions,
4856  scan.fSelectedVariables,
4857  scan.fSelectedEnums,
4858  headersClassesMap,
4859  headersDeclsMap,
4860  interp);
4861 
4862  std::string detectedUmbrella;
4863  for (auto & arg : pcmArgs) {
4865  detectedUmbrella = arg;
4866  break;
4867  }
4868  }
4869 
4870  if (gOptWriteEmptyRootPCM){
4871  headersDeclsMap.clear();
4872  }
4873 
4874 
4875  std::string headersClassesMapString = "\"\"";
4876  std::string fwdDeclsString = "\"\"";
4877  if (!gOptCxxModule) {
4878  headersClassesMapString = GenerateStringFromHeadersForClasses(headersDeclsMap,
4879  detectedUmbrella,
4880  true);
4882  if (!gOptWriteEmptyRootPCM)
4883  fwdDeclsString = GenerateFwdDeclString(scan, interp);
4884  }
4885  }
4886  modGen.WriteRegistrationSource(dictStream, fwdDeclnArgsToKeepString, headersClassesMapString, fwdDeclsString,
4887  extraIncludes, gOptCxxModule);
4888  // If we just want to inline the input header, we don't need
4889  // to generate any files.
4890  if (!gOptInlineInput) {
4891  // Write the module/PCH depending on what mode we are on
4892  if (modGen.IsPCH()) {
4893  if (!GenerateAllDict(modGen, CI, currentDirectory)) return 1;
4894  } else if (gOptCxxModule) {
4895  if (!CheckModuleValid(modGen, llvmResourceDir, interp, linkdefFilename, moduleName.str()))
4896  return 1;
4897  }
4898  }
4899  }
4900 
4901 
4902  if (!gOptLibListPrefix.empty()) {
4903  string liblist_filename = gOptLibListPrefix + ".out";
4904 
4905  ofstream outputfile(liblist_filename.c_str(), ios::out);
4906  if (!outputfile) {
4907  ROOT::TMetaUtils::Error(0, "%s: Unable to open output lib file %s\n",
4908  executableFileName, liblist_filename.c_str());
4909  } else {
4910  const size_t endStr = gLibsNeeded.find_last_not_of(" \t");
4911  outputfile << gLibsNeeded.substr(0, endStr + 1) << endl;
4912  // Add explicit delimiter
4913  outputfile << "# Now the list of classes\n";
4914  // SELECTION LOOP
4915  for (auto const & annRcd : scan.fSelectedClasses) {
4916  // Shouldn't it be GetLong64_Name( cl_input.GetNormalizedName() )
4917  // or maybe we should be normalizing to turn directly all long long into Long64_t
4918  outputfile << annRcd.GetNormalizedName() << endl;
4919  }
4920  }
4921  }
4922 
4923  // Check for errors in module generation
4924  rootclingRetCode += modGen.GetErrorCount();
4925  if (0 != rootclingRetCode) return rootclingRetCode;
4926 
4927  // Create the rootmap file
4928  std::string rootmapLibName = std::accumulate(gOptRootmapLibNames.begin(),
4929  gOptRootmapLibNames.end(),
4930  std::string(),
4931  [](const std::string & a, const std::string & b) -> std::string {
4932  if (a.empty()) return b;
4933  else return a + " " + b;
4934  });
4935 
4936  bool rootMapNeeded = !gOptRootMapFileName.empty() || !rootmapLibName.empty();
4937 
4938  std::list<std::string> classesNames;
4939  std::list<std::string> classesNamesForRootmap;
4940  std::list<std::string> classesDefsList;
4941 
4942  rootclingRetCode = ExtractClassesListAndDeclLines(scan,
4943  classesNames,
4944  classesNamesForRootmap,
4945  classesDefsList,
4946  interp);
4947 
4948  std::list<std::string> enumNames;
4949  rootclingRetCode += ExtractAutoloadKeys(enumNames,
4950  scan.fSelectedEnums,
4951  interp);
4952 
4953  std::list<std::string> varNames;
4954  rootclingRetCode += ExtractAutoloadKeys(varNames,
4955  scan.fSelectedVariables,
4956  interp);
4957 
4958  if (0 != rootclingRetCode) return rootclingRetCode;
4959 
4960  // Create the rootmapfile if needed
4961  if (rootMapNeeded) {
4962 
4963  std::list<std::string> nsNames;
4964 
4965  ExtractSelectedNamespaces(scan, nsNames);
4966 
4968  rootmapLibName);
4969 
4970  ROOT::TMetaUtils::Info(0, "Rootmap file name %s and lib name(s) \"%s\"\n",
4971  gOptRootMapFileName.c_str(),
4972  rootmapLibName.c_str());
4973 
4974  tmpCatalog.addFileName(gOptRootMapFileName);
4975  std::unordered_set<std::string> headersToIgnore;
4976  if (gOptInlineInput)
4977  for (const std::string& optHeaderFileName : gOptDictionaryHeaderFiles)
4978  headersToIgnore.insert(optHeaderFileName.c_str());
4979 
4980  std::list<std::string> typedefsRootmapLines;
4981  rootclingRetCode += ExtractAutoloadKeys(typedefsRootmapLines,
4982  scan.fSelectedTypedefs,
4983  interp);
4984 
4985  rootclingRetCode = CreateNewRootMapFile(gOptRootMapFileName,
4986  rootmapLibName,
4987  classesDefsList,
4988  classesNamesForRootmap,
4989  nsNames,
4990  typedefsRootmapLines,
4991  enumNames,
4992  varNames,
4993  headersClassesMap,
4994  headersToIgnore);
4995 
4996  if (0 != rootclingRetCode) return 1;
4997  }
4998 
4999  if (genreflex::verbose)
5000  tmpCatalog.dump();
5001 
5002  // Manually call end of translation unit because we never call the
5003  // appropriate deconstructors in the interpreter. This writes out the C++
5004  // module file that we currently generate.
5005  {
5006  cling::Interpreter::PushTransactionRAII RAII(&interp);
5007  CI->getSema().getASTConsumer().HandleTranslationUnit(CI->getSema().getASTContext());
5008  }
5009 
5010  // Add the warnings
5011  rootclingRetCode += ROOT::TMetaUtils::GetNumberOfErrors();
5012 
5013  // make sure the file is closed before committing
5014  fileout.close();
5015 
5016  // Before returning, rename the files if no errors occurred
5017  // otherwise clean them to avoid remnants (see ROOT-10015)
5018  if(rootclingRetCode == 0) {
5019  rootclingRetCode += tmpCatalog.commit();
5020  } else {
5021  tmpCatalog.clean();
5022  }
5023 
5024  return rootclingRetCode;
5025 
5026 }
5027 
5028 namespace genreflex {
5029 
5030 ////////////////////////////////////////////////////////////////////////////////
5031 /// Loop on arguments: stop at the first which starts with -
5032 
5033  unsigned int checkHeadersNames(std::vector<std::string> &headersNames)
5034  {
5035  unsigned int numberOfHeaders = 0;
5036  for (std::vector<std::string>::iterator it = headersNames.begin();
5037  it != headersNames.end(); ++it) {
5038  const std::string headername(*it);
5039  if (ROOT::TMetaUtils::IsHeaderName(headername)) {
5040  numberOfHeaders++;
5041  } else {
5043  "*** genreflex: %s is not a valid header name (.h and .hpp extensions expected)!\n",
5044  headername.c_str());
5045  }
5046  }
5047  return numberOfHeaders;
5048  }
5049 
5050 ////////////////////////////////////////////////////////////////////////////////
5051 /// Extract the arguments from the command line
5052 
5053  unsigned int extractArgs(int argc, char **argv, std::vector<std::string> &args)
5054  {
5055  // loop on argv, spot strings which are not preceded by something
5056  unsigned int argvCounter = 0;
5057  for (int i = 1; i < argc; ++i) {
5058  if (!ROOT::TMetaUtils::BeginsWith(argv[i - 1], "-") && // so, if preceding element starts with -, this is a value for an option
5059  !ROOT::TMetaUtils::BeginsWith(argv[i], "-")) { // and the element itself is not an option
5060  args.push_back(argv[i]);
5061  argvCounter++;
5062  } else if (argvCounter) {
5063  argv[i - argvCounter] = argv[i];
5064  }
5065  }
5066 
5067  // Some debug
5068  if (genreflex::verbose) {
5069  int i = 0;
5070  std::cout << "Args: \n";
5071  for (std::vector<std::string>::iterator it = args.begin();
5072  it < args.end(); ++it) {
5073  std::cout << i << ") " << *it << std::endl;
5074  ++i;
5075  }
5076 
5077  }
5078 
5079  return argvCounter;
5080  }
5081 
5082 ////////////////////////////////////////////////////////////////////////////////
5083 
5084  void changeExtension(std::string &filename, const std::string &newExtension)
5085  {
5086  size_t result = filename.find_last_of('.');
5087  if (std::string::npos != result) {
5088  filename.erase(result);
5089  filename.append(newExtension);
5090  }
5091 
5092  }
5093 
5094 ////////////////////////////////////////////////////////////////////////////////
5095 /// The caller is responsible for deleting the string!
5096 
5097  char *string2charptr(const std::string &str)
5098  {
5099  const unsigned int size(str.size());
5100  char *a = new char[size + 1];
5101  a[size] = 0;
5102  memcpy(a, str.c_str(), size);
5103  return a;
5104  }
5105 
5106 ////////////////////////////////////////////////////////////////////////////////
5107 /// Replace the extension with "_rflx.cpp"
5108 
5109  void header2outputName(std::string &fileName)
5110  {
5111  changeExtension(fileName, "_rflx.cpp");
5112  }
5113 
5114 ////////////////////////////////////////////////////////////////////////////////
5115 /// Get a proper name for the output file
5116 
5117  void headers2outputsNames(const std::vector<std::string> &headersNames,
5118  std::vector<std::string> &ofilesnames)
5119  {
5120  ofilesnames.reserve(headersNames.size());
5121 
5122  for (std::vector<std::string>::const_iterator it = headersNames.begin();
5123  it != headersNames.end(); ++it) {
5124  std::string ofilename(*it);
5125  header2outputName(ofilename);
5126  ofilesnames.push_back(ofilename);
5127  }
5128  }
5129 
5130 ////////////////////////////////////////////////////////////////////////////////
5131 
5132  void AddToArgVector(std::vector<char *> &argvVector,
5133  const std::vector<std::string> &argsToBeAdded,
5134  const std::string &optName = "")
5135  {
5136  for (std::vector<std::string>::const_iterator it = argsToBeAdded.begin();
5137  it != argsToBeAdded.end(); ++it) {
5138  argvVector.push_back(string2charptr(optName + *it));
5139  }
5140  }
5141 
5142 ////////////////////////////////////////////////////////////////////////////////
5143 
5144  void AddToArgVectorSplit(std::vector<char *> &argvVector,
5145  const std::vector<std::string> &argsToBeAdded,
5146  const std::string &optName = "")
5147  {
5148  for (std::vector<std::string>::const_iterator it = argsToBeAdded.begin();
5149  it != argsToBeAdded.end(); ++it) {
5150  if (optName.length()) {
5151  argvVector.push_back(string2charptr(optName));
5152  }
5153  argvVector.push_back(string2charptr(*it));
5154  }
5155  }
5156 
5157 ////////////////////////////////////////////////////////////////////////////////
5158 
5159  int invokeRootCling(const std::string &verbosity,
5160  const std::string &selectionFileName,
5161  const std::string &targetLibName,
5162  bool multiDict,
5163  const std::vector<std::string> &pcmsNames,
5164  const std::vector<std::string> &includes,
5165  const std::vector<std::string> &preprocDefines,
5166  const std::vector<std::string> &preprocUndefines,
5167  const std::vector<std::string> &warnings,
5168  const std::string &rootmapFileName,
5169  const std::string &rootmapLibName,
5170  bool interpreteronly,
5171  bool doSplit,
5172  bool isCxxmodule,
5173  bool writeEmptyRootPCM,
5174  bool selSyntaxOnly,
5175  bool noIncludePaths,
5176  bool noGlobalUsingStd,
5177  const std::vector<std::string> &headersNames,
5178  bool failOnWarnings,
5179  const std::string &ofilename)
5180  {
5181  // Prepare and invoke the commandline to invoke rootcling
5182 
5183  std::vector<char *> argvVector;
5184 
5185  argvVector.push_back(string2charptr("rootcling"));
5186  argvVector.push_back(string2charptr(verbosity));
5187  argvVector.push_back(string2charptr("-f"));
5188  argvVector.push_back(string2charptr(ofilename));
5189 
5190  if (isCxxmodule)
5191  argvVector.push_back(string2charptr("-cxxmodule"));
5192 
5193  // Extract the path to the dictionary
5194  std::string dictLocation;
5195  ExtractFilePath(ofilename, dictLocation);
5196 
5197  // Rootmaps
5198 
5199  // Prepare the correct rootmap libname if not already set.
5200  std::string newRootmapLibName(rootmapLibName);
5201  if (!rootmapFileName.empty() && newRootmapLibName.empty()) {
5202  if (headersNames.size() != 1) {
5204  "*** genreflex: No rootmap lib and several header specified!\n");
5205  }
5206  std::string cleanHeaderName = ExtractFileName(headersNames[0]);
5207  newRootmapLibName = "lib";
5208  newRootmapLibName += cleanHeaderName;
5209  changeExtension(newRootmapLibName, gLibraryExtension);
5210  }
5211 
5212  // Prepend to the rootmap the designed directory of the dictionary
5213  // if no path is specified for the rootmap itself
5214  std::string newRootmapFileName(rootmapFileName);
5215  if (!newRootmapFileName.empty() && !HasPath(newRootmapFileName)) {
5216  newRootmapFileName = dictLocation + newRootmapFileName;
5217  }
5218 
5219 
5220  // RootMap filename
5221  if (!newRootmapFileName.empty()) {
5222  argvVector.push_back(string2charptr("-rmf"));
5223  argvVector.push_back(string2charptr(newRootmapFileName));
5224  }
5225 
5226  // RootMap Lib filename
5227  if (!newRootmapLibName.empty()) {
5228  argvVector.push_back(string2charptr("-rml"));
5229  argvVector.push_back(string2charptr(newRootmapLibName));
5230  }
5231 
5232  // Interpreter only dictionaries
5233  if (interpreteronly)
5234  argvVector.push_back(string2charptr("-interpreteronly"));
5235 
5236  // Split dictionaries
5237  if (doSplit)
5238  argvVector.push_back(string2charptr("-split"));
5239 
5240  // Targetlib
5241  if (!targetLibName.empty()) {
5242  argvVector.push_back(string2charptr("-s"));
5243  argvVector.push_back(string2charptr(targetLibName));
5244  }
5245 
5246  // Multidict support
5247  if (multiDict)
5248  argvVector.push_back(string2charptr("-multiDict"));
5249 
5250  // Don't declare "using namespace std"
5251  if (noGlobalUsingStd)
5252  argvVector.push_back(string2charptr("-noGlobalUsingStd"));
5253 
5254 
5255  AddToArgVectorSplit(argvVector, pcmsNames, "-m");
5256 
5257  // Inline the input header
5258  argvVector.push_back(string2charptr("-inlineInputHeader"));
5259 
5260  // Write empty root pcms
5261  if (writeEmptyRootPCM)
5262  argvVector.push_back(string2charptr("-writeEmptyRootPCM"));
5263 
5264  // Just test the syntax of the selection file
5265  if (selSyntaxOnly)
5266  argvVector.push_back(string2charptr("-selSyntaxOnly"));
5267 
5268  // No include paths
5269  if (noIncludePaths)
5270  argvVector.push_back(string2charptr("-noIncludePaths"));
5271 
5272  // Fail on warnings
5273  if (failOnWarnings)
5274  argvVector.push_back(string2charptr("-failOnWarnings"));
5275 
5276  // Clingargs
5277  AddToArgVector(argvVector, includes, "-I");
5278  AddToArgVector(argvVector, preprocDefines, "-D");
5279  AddToArgVector(argvVector, preprocUndefines, "-U");
5280  AddToArgVector(argvVector, warnings, "-W");
5281 
5282  AddToArgVector(argvVector, headersNames);
5283 
5284  if (!selectionFileName.empty()) {
5285  argvVector.push_back(string2charptr(selectionFileName));
5286  }
5287 
5288  const int argc = argvVector.size();
5289 
5290  // Output commandline for rootcling
5291  if (genreflex::verbose) {
5292  std::cout << "Rootcling commandline:\n";
5293  for (int i = 0; i < argc; i++)
5294  std::cout << i << ") " << argvVector[i] << std::endl;
5295  }
5296 
5297  char **argv = & (argvVector[0]);
5298  int rootclingReturnCode = RootClingMain(argc,
5299  argv,
5300  /*isGenReflex=*/true);
5301 
5302  for (int i = 0; i < argc; i++)
5303  delete [] argvVector[i];
5304 
5305  return rootclingReturnCode;
5306 
5307  }
5308 
5309 ////////////////////////////////////////////////////////////////////////////////
5310 /// Get the right ofilenames and invoke several times rootcling
5311 /// One invokation per header
5312 
5313  int invokeManyRootCling(const std::string &verbosity,
5314  const std::string &selectionFileName,
5315  const std::string &targetLibName,
5316  bool multiDict,
5317  const std::vector<std::string> &pcmsNames,
5318  const std::vector<std::string> &includes,
5319  const std::vector<std::string> &preprocDefines,
5320  const std::vector<std::string> &preprocUndefines,
5321  const std::vector<std::string> &warnings,
5322  const std::string &rootmapFileName,
5323  const std::string &rootmapLibName,
5324  bool interpreteronly,
5325  bool doSplit,
5326  bool isCxxmodule,
5327  bool writeEmptyRootPCM,
5328  bool selSyntaxOnly,
5329  bool noIncludePaths,
5330  bool noGlobalUsingStd,
5331  const std::vector<std::string> &headersNames,
5332  bool failOnWarnings,
5333  const std::string &outputDirName_const = "")
5334  {
5335  std::string outputDirName(outputDirName_const);
5336 
5337  std::vector<std::string> ofilesNames;
5338  headers2outputsNames(headersNames, ofilesNames);
5339 
5340  if (!outputDirName.empty() && !ROOT::TMetaUtils::EndsWith(outputDirName, gPathSeparator)) {
5341  outputDirName += gPathSeparator;
5342  }
5343 
5344  std::vector<std::string> namesSingleton(1);
5345  for (unsigned int i = 0; i < headersNames.size(); ++i) {
5346  namesSingleton[0] = headersNames[i];
5347  std::string ofilenameFullPath(ofilesNames[i]);
5348  if (llvm::sys::path::parent_path(ofilenameFullPath) == "")
5349  ofilenameFullPath = outputDirName + ofilenameFullPath;
5350  int returnCode = invokeRootCling(verbosity,
5351  selectionFileName,
5352  targetLibName,
5353  multiDict,
5354  pcmsNames,
5355  includes,
5356  preprocDefines,
5357  preprocUndefines,
5358  warnings,
5359  rootmapFileName,
5360  rootmapLibName,
5361  interpreteronly,
5362  doSplit,
5363  isCxxmodule,
5364  writeEmptyRootPCM,
5365  selSyntaxOnly,
5366  noIncludePaths,
5367  noGlobalUsingStd,
5368  namesSingleton,
5369  failOnWarnings,
5370  ofilenameFullPath);
5371  if (returnCode != 0)
5372  return returnCode;
5373  }
5374 
5375  return 0;
5376  }
5377 
5378 
5379 } // end genreflex namespace
5380 
5381 ////////////////////////////////////////////////////////////////////////////////
5382 /// Extract from options multiple values with the same option
5383 
5384 int extractMultipleOptions(std::vector<ROOT::option::Option> &options,
5385  int oIndex,
5386  std::vector<std::string> &values)
5387 {
5388  int nValues = 0;
5389  if (options[oIndex]) {
5390  const int nVals = options[oIndex].count();
5391  values.reserve(nVals);
5392  int optionIndex = 0;
5393  for (ROOT::option::Option *opt = options[oIndex]; opt; opt = opt->next()) {
5394  if (genreflex::verbose) std::cout << "Extracting multiple args: "
5395  << optionIndex << "/" << nVals << " "
5396  << opt->arg << std::endl;
5397  optionIndex++;
5398  values.push_back(opt->arg);
5399  nValues++;
5400  }
5401  }
5402  return nValues;
5403 }
5404 
5405 ////////////////////////////////////////////////////////////////////////////////
5406 
5407 void RiseWarningIfPresent(std::vector<ROOT::option::Option> &options,
5408  int optionIndex,
5409  const char *descriptor)
5410 {
5411  if (options[optionIndex]) {
5413  "*** genereflex: %s is not supported anymore.\n",
5414  descriptor);
5415  }
5416 }
5417 
5418 ////////////////////////////////////////////////////////////////////////////////
5419 
5420 bool IsGoodLibraryName(const std::string &name)
5421 {
5422 
5423 
5425 #ifdef __APPLE__
5426  isGood |= ROOT::TMetaUtils::EndsWith(name, ".dylib");
5427 #endif
5428  return isGood;
5429 }
5430 
5431 ////////////////////////////////////////////////////////////////////////////////
5432 /// Translate the arguments of genreflex into rootcling ones and forward them
5433 /// to the RootCling function.
5434 /// These are two typical genreflex and rootcling commandlines
5435 /// 1) genreflex header1.h [header2.h ...] [options] [preprocessor options]
5436 /// 2) rootcling [-v] [-v0-4] [-f] [out.cxx] [-s sharedlib.so] [-m pcmfilename]
5437 /// header1.h[{+,-}][!] ..headerN.h[{+,-}][!] [{LinkDef.h,selectionRules.xml}]
5438 /// The rules with which the arguments are translated are (1st column genreflex):
5439 /// --debug -v4
5440 /// --quiet -v0
5441 /// -o ofile positional arg after -f
5442 /// -s selection file Last argument of the call
5443 /// --fail_on_warning Wrap ROOT::TMetaUtils::Warning and throw if selected
5444 ///
5445 /// New arguments:
5446 /// -l --library targetLib name (new) -s targetLib name
5447 /// -m pcmname (can be many -m) (new) -m pcmname (can be many -m)
5448 /// --rootmap -rmf (new)
5449 /// --rootmap-lib -rml (new)
5450 ///
5451 /// genreflex options which rise warnings (feedback is desirable)
5452 /// --no_membertypedefs (it should be irrelevant)
5453 /// --no_templatetypedefs (it should be irrelevant)
5454 ///
5455 /// genreflex options which are ignored (know for sure they are not needed)
5456 /// --pool, --dataonly
5457 /// --interpreteronly
5458 /// --gccxml{path,opt,post}
5459 ///
5460 ///
5461 /// Exceptions
5462 /// The --deep option of genreflex is passed as function parameter to rootcling
5463 /// since it's not needed at the moment there.
5464 
5465 int GenReflexMain(int argc, char **argv)
5466 {
5467  using namespace genreflex;
5468 
5469  // Setup the options parser
5470  enum optionIndex { UNKNOWN,
5471  OFILENAME,
5472  TARGETLIB,
5473  MULTIDICT,
5474  NOGLOBALUSINGSTD,
5475  SELECTIONFILENAME,
5476  ROOTMAP,
5477  ROOTMAPLIB,
5478  PCMFILENAME,
5479  DEEP,
5480  DEBUG,
5481  VERBOSE,
5482  QUIET,
5483  SILENT,
5484  CXXMODULE,
5485  WRITEEMPTYROOTPCM,
5486  HELP,
5487  FAILONWARNINGS,
5488  SELSYNTAXONLY,
5489  INTERPRETERONLY,
5490  SPLIT,
5491  NOMEMBERTYPEDEFS,
5492  NOTEMPLATETYPEDEFS,
5493  NOINCLUDEPATHS,
5494  // Don't show up in the help
5495  PREPROCDEFINE,
5496  PREPROCUNDEFINE,
5497  INCLUDE,
5498  WARNING
5499  };
5500 
5501  enum optionTypes { NOTYPE, STRING } ;
5502 
5503  // Some long help strings
5504  const char *genreflexUsage =
5505  "Generates dictionary sources and related ROOT pcm starting from an header.\n"
5506  "Usage: genreflex headerfile.h [opts] [preproc. opts]\n\n"
5507  "Options:\n";
5508 
5509  const char *selectionFilenameUsage =
5510  "-s, --selection_file\tSelection filename\n"
5511  " Class selection file to specify for which classes the dictionary\n"
5512  " will be generated. The final set can be crafted with exclusion and\n"
5513  " exclusion rules.\n"
5514  " Properties can be specified. Some have special meaning:\n"
5515  " - name [string] name of the entity to select with an exact matching\n"
5516  " - pattern [string] name with wildcards (*) to select entities\n"
5517  " - file_name/file_pattern [string]: as name/pattern but referring to\n"
5518  " file where the C++ entities reside and not to C++ entities themselves.\n"
5519  " - transient/persistent [string: true/false] The fields to which they are\n"
5520  " applied will not be persistified if requested.\n"
5521  " - comment [string]: what you could write in code after an inline comment\n"
5522  " without \"//\". For example comment=\"!\" or \"||\".\n"
5523  " - noStreamer [true/false]: turns off streamer generation if set to 'true.'\n"
5524  " Default value is 'false'\n"
5525  " - noInputOperator [true/false]: turns off input operator generation if set\n"
5526  " to 'true'. Default value is 'false'\n"
5527  " Example XML:\n"
5528  " <lcgdict>\n"
5529  " [<selection>]\n"
5530  " <class [name=\"classname\"] [pattern=\"wildname\"]\n"
5531  " [file_name=\"filename\"] [file_pattern=\"wildname\"]\n"
5532  " [id=\"xxxx\"] [noStreamer=\"true/false\"]\n"
5533  " [noInputOperator=\"true/false\"] />\n"
5534  " <class name=\"classname\" >\n"
5535  " <field name=\"m_transient\" transient=\"true\"/>\n"
5536  " <field name=\"m_anothertransient\" persistent=\"false\"/>\n"
5537  " <field name=\"m_anothertransient\" comment=\"||\"/>\n"
5538  " <properties prop1=\"value1\" [prop2=\"value2\"]/>\n"
5539  " </class>\n"
5540  " <function [name=\"funcname\"] [pattern=\"wildname\"] />\n"
5541  " <enum [name=\"enumname\"] [pattern=\"wildname\"] />\n"
5542  " <variable [name=\"varname\"] [pattern=\"wildname\"] />\n"
5543  " [</selection>]\n"
5544  " <exclusion>\n"
5545  " <class [name=\"classname\"] [pattern=\"wildname\"] />\n"
5546  " <method name=\"unwanted\" />\n"
5547  " </class>\n"
5548  " ...\n"
5549  " </lcgdict>\n"
5550  "\n"
5551  " If no selection file is specified, the class with the filename without\n"
5552  " extension will be selected, i.e. myClass.h as argument without any\n"
5553  " selection xml comes with an implicit selection rule for class \"myClass\".\n";
5554 
5555  const char *outputFilenameUsage =
5556  "-o, --output\tOutput filename\n"
5557  " Output file name. If an existing directory is specified instead of a file,\n"
5558  " then a filename will be build using the name of the input file and will\n"
5559  " be placed in the given directory. <headerfile>_rflx.cpp.\n"
5560  " NOTA BENE: the dictionaries that will be used within the same project must\n"
5561  " have unique names.\n";
5562 
5563 
5564  const char *targetLib =
5565  "-l, --library\tTarget library\n"
5566  " The flag -l must be followed by the name of the library that will\n"
5567  " contain the object file corresponding to the dictionary produced by\n"
5568  " this invocation of genreflex.\n"
5569  " The name takes priority over the one specified for the rootmapfile.\n"
5570  " The name influences the name of the created pcm:\n"
5571  " 1) If it is not specified, the pcm is called libINPUTHEADER_rdict.pcm\n"
5572  " 2) If it is specified, the pcm is called libTARGETLIBRARY_rdict.pcm\n"
5573  " Any \"liblib\" occurence is transformed in the expected \"lib\".\n"
5574  " 3) If this is specified in conjunction with --multiDict, the output is\n"
5575  " libTARGETLIBRARY_DICTIONARY_rdict.pcm\n";
5576 
5577  const char *rootmapUsage =
5578  "--rootmap\tGenerate the rootmap file to be used by ROOT.\n"
5579  " This file lists the autoload keys. For example classes for which the\n"
5580  " reflection information is provided.\n"
5581  " The format of the rootmap is the following:\n"
5582  " - Forward declarations section\n"
5583  " - Libraries sections\n"
5584  " Rootmaps can be concatenated together, for example with the cat util.\n"
5585  " In order for ROOT to pick up the information in the rootmaps, they\n"
5586  " have to be located in the library path and have the .rootmap extension.\n"
5587  " An example rootmap file could be:\n"
5588  " { decls }\n"
5589  " template <class T> class A;\n"
5590  " [ libMyLib.so ]\n"
5591  " class A<double>\n"
5592  " class B\n"
5593  " typedef C\n"
5594  " header H.h\n";
5595 
5596  const char *rootmapLibUsage =
5597  "--rootmap-lib\tLibrary name for the rootmap file.\n";
5598 
5599  // The Descriptor
5600  const ROOT::option::Descriptor genreflexUsageDescriptor[] = {
5601  {
5602  UNKNOWN,
5603  NOTYPE,
5604  "", "",
5606  genreflexUsage
5607  },
5608 
5609  {
5610  OFILENAME,
5611  STRING ,
5612  "o" , "output" ,
5614  outputFilenameUsage
5615  },
5616 
5617  {
5618  TARGETLIB,
5619  STRING ,
5620  "l" , "library" ,
5622  targetLib
5623  },
5624 
5625  {
5626  MULTIDICT,
5627  NOTYPE ,
5628  "" , "multiDict" ,
5630  "--multiDict\tSupport for many dictionaries in one library\n"
5631  " Form correct pcm names if multiple dictionaries will be in the same\n"
5632  " library (needs target library switch. See its documentation).\n"
5633  },
5634 
5635 
5636  {
5637  NOGLOBALUSINGSTD,
5638  NOTYPE ,
5639  "" , "noGlobalUsingStd" ,
5641  "--noGlobalUsingStd\tDo not declare {using namespace std} in the dictionary global scope\n"
5642  " All header files must have sumbols from std:: namespace fully qualified\n"
5643  },
5644 
5645  {
5646  SELECTIONFILENAME,
5647  STRING ,
5648  "s" , "selection_file" ,
5650  selectionFilenameUsage
5651  },
5652 
5653  {
5654  ROOTMAP,
5655  STRING ,
5656  "" , "rootmap" ,
5658  rootmapUsage
5659  },
5660 
5661  {
5662  ROOTMAPLIB,
5663  STRING ,
5664  "" , "rootmap-lib" ,
5666  rootmapLibUsage
5667  },
5668 
5669  {
5670  INTERPRETERONLY,
5671  NOTYPE,
5672  "" , "interpreteronly",
5674  "--interpreteronly\tDo not generate I/O related information.\n"
5675  " Generate minimal dictionary required for interactivity.\n"
5676  },
5677 
5678  {
5679  SPLIT,
5680  NOTYPE,
5681  "" , "split",
5683  "--split\tSplit the dictionary\n"
5684  " Split in two the dictionary, isolating the part with\n"
5685  " ClassDef related functions in a separate file.\n"
5686  },
5687 
5688  {
5689  PCMFILENAME,
5690  STRING ,
5691  "m" , "" ,
5693  "-m \tPcm file loaded before any header (option can be repeated).\n"
5694  },
5695 
5696  {
5697  VERBOSE,
5698  NOTYPE ,
5699  "-v" , "verbose",
5701  "-v, --verbose\tPrint some debug information.\n"
5702  },
5703 
5704  {
5705  DEBUG,
5706  NOTYPE ,
5707  "" , "debug",
5709  "--debug\tPrint all debug information.\n"
5710  },
5711 
5712  {
5713  QUIET,
5714  NOTYPE ,
5715  "" , "quiet",
5717  "--quiet\tPrint only warnings and errors (default).\n"
5718  },
5719 
5720  {
5721  SILENT,
5722  NOTYPE ,
5723  "" , "silent",
5725  "--silent\tPrint no information at all.\n"
5726  },
5727 
5728  {
5729  WRITEEMPTYROOTPCM,
5730  NOTYPE ,
5731  "" , "writeEmptyPCM",
5733  "--writeEmptyPCM\tWrite an empty ROOT pcm.\n"
5734  },
5735 
5736  {
5737  CXXMODULE,
5738  NOTYPE ,
5739  "" , "cxxmodule",
5741  "--cxxmodule\tGenerates a PCM for C++ Modules.\n"
5742  },
5743 
5744 
5745  {
5746  HELP,
5747  NOTYPE,
5748  "h" , "help",
5750  "--help\tPrint usage and exit.\n"
5751  },
5752 
5753  {
5754  FAILONWARNINGS,
5755  NOTYPE,
5756  "", "fail_on_warnings",
5758  "--fail_on_warnings\tFail on warnings and errors.\n"
5759  },
5760 
5761  {
5762  SELSYNTAXONLY,
5763  NOTYPE,
5764  "", "selSyntaxOnly",
5766  "--selSyntaxOnly\tValidate selection file w/o generating the dictionary.\n"
5767  },
5768 
5769  {
5770  NOINCLUDEPATHS,
5771  NOTYPE ,
5772  "" , "noIncludePaths",
5774  "--noIncludePaths\tDo not store the headers' directories in the dictionary. Instead, rely on the environment variable $ROOT_INCLUDE_PATH at runtime.\n"
5775  },
5776 
5777  // Left intentionally empty not to be shown in the help, like in the first genreflex
5778  {
5779  INCLUDE,
5780  STRING ,
5781  "I" , "" ,
5783  ""
5784  },
5785 
5786  {
5787  PREPROCDEFINE,
5788  STRING ,
5789  "D" , "" ,
5791  ""
5792  },
5793 
5794  {
5795  PREPROCUNDEFINE,
5796  STRING ,
5797  "U" , "" ,
5799  ""
5800  },
5801 
5802  {
5803  WARNING,
5804  STRING ,
5805  "W" , "" ,
5807  ""
5808  },
5809 
5810  {
5811  NOMEMBERTYPEDEFS, // Option which is not meant for the user: deprecated
5812  STRING ,
5813  "" , "no_membertypedefs" ,
5815  ""
5816  },
5817 
5818  {
5819  NOTEMPLATETYPEDEFS, // Option which is not meant for the user: deprecated
5820  STRING ,
5821  "" , "no_templatetypedefs" ,
5823  ""
5824  },
5825 
5826  {0, 0, 0, 0, 0, 0}
5827  };
5828 
5829  std::vector<std::string> headersNames;
5830  const int originalArgc = argc;
5831  // The only args are the headers here
5832  const int extractedArgs = extractArgs(argc, argv, headersNames);
5833 
5834  const int offset = 1; // skip argv[0]
5835  argc -= offset + extractedArgs;
5836  argv += offset;
5837 
5838  // Parse the options
5839  ROOT::option::Stats stats(genreflexUsageDescriptor, argc, argv);
5840  std::vector<ROOT::option::Option> options(stats.options_max);// non POD var size arrays are not C++!
5841  std::vector<ROOT::option::Option> buffer(stats.buffer_max);
5842  // The 4 is the minimum size of the abbreviation length.
5843  // For example, --selection_file can be abbreviated with --sele at least.
5844 
5845  ROOT::option::Parser parse(genreflexUsageDescriptor, argc, argv, &options[0], &buffer[0], 5);
5846 
5847  if (parse.error()) {
5848  ROOT::TMetaUtils::Error(0, "Argument parsing error!\n");
5849  return 1;
5850  }
5851 
5852  // Print help if needed
5853  if (options[HELP] || originalArgc == 1) {
5854  ROOT::option::printUsage(std::cout, genreflexUsageDescriptor);
5855  return 0;
5856  }
5857  // See if no header was provided
5858  int numberOfHeaders = checkHeadersNames(headersNames);
5859  if (0 == numberOfHeaders) {
5860  ROOT::TMetaUtils::Error(0, "No valid header was provided!\n");
5861  return 1;
5862  }
5863 
5865 
5866  if (options[DEEP])
5867  ROOT::TMetaUtils::Warning(0, "--deep has no effect. Please remove the deprecated flag!\n");
5868  // The verbosity: debug wins over quiet
5869  //std::string verbosityOption("-v4"); // To be uncommented for the testing phase. It should be -v
5870  std::string verbosityOption("-v2");
5871  if (options[SILENT]) verbosityOption = "-v0";
5872  if (options[VERBOSE] || getenv ("VERBOSE")) verbosityOption = "-v3";
5873  if (options[DEBUG]) verbosityOption = "-v4";
5874 
5875  genreflex::verbose = verbosityOption == "-v4";
5876 
5877  // The selection file
5878  std::string selectionFileName;
5879  if (options[SELECTIONFILENAME]) {
5880  selectionFileName = options[SELECTIONFILENAME].arg;
5881  if (!ROOT::TMetaUtils::EndsWith(selectionFileName, ".xml")) {
5883  "Invalid selection file extension: filename is %s and extension .xml is expected!\n",
5884  selectionFileName.c_str());
5885  return 1;
5886  }
5887  }
5888 
5889 // // Warn if a selection file is not present and exit
5890 // if (NULL==options[SELECTIONFILENAME].arg){
5891 // ROOT::TMetaUtils::Warning(0,"The usage of genreflex without a selection file is not yet supported.\n");
5892 // return 1;
5893 // }
5894 
5895 
5896  // Set the parameters for the rootmap file. If the libname is not set,
5897  // it will be set according to the header in invokeRootCling.
5898  // FIXME: treatment of directories
5899  std::string rootmapFileName(options[ROOTMAP].arg ? options[ROOTMAP].arg :