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  } else {
1970  modGen.WriteContentHeader(out);
1971  }
1972  if (interp.declare(out.str()) != cling::Interpreter::kSuccess) {
1973  const std::string &hdrName
1974  = umbrella ? modGen.GetUmbrellaName() : modGen.GetContentName();
1975  ROOT::TMetaUtils::Error(0, "%s: compilation failure (%s)\n", argv0,
1976  hdrName.c_str());
1977  return false;
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>
3686 gOptRootMapFileName("rmf",
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>
3754 gOptCheckSelectionSyntax("selSyntaxOnly",
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 #if defined(_MSC_VER) && (_MSC_VER >= 1926)
4081  // FIXME: Silly workaround for rootcling not being able to parse the STL
4082  // headers anymore after the update of Visual Studio v16.7.0
4083  // To be checked/removed after the upgrade of LLVM & Clang
4084  clingArgs.push_back(std::string("-D__CUDACC__"));
4085 #endif
4086 
4087  for (const std::string &PPUndefine : gOptPPUndefines)
4088  clingArgs.push_back(std::string("-U") + PPUndefine);
4089 
4090  for (const std::string &IncludePath : gOptIncludePaths)
4091  clingArgs.push_back(std::string("-I") + llvm::sys::path::convert_to_slash(IncludePath));
4092 
4093  for (const std::string &WDiag : gOptWDiags) {
4094  const std::string FullWDiag = std::string("-W") + WDiag;
4095  // Suppress warning when compiling the dictionary, eg. gcc G__xxx.cxx
4096  CheckForMinusW(FullWDiag, diagnosticPragmas);
4097  // Suppress warning when compiling the input headers by cling.
4098  clingArgs.push_back(FullWDiag);
4099  }
4100 
4101  std::string includeDir = llvm::sys::path::convert_to_slash(gDriverConfig->fTROOT__GetIncludeDir());
4102  clingArgs.push_back(std::string("-I") + includeDir);
4103 
4104  std::vector<std::string> pcmArgs;
4105  for (size_t parg = 0, n = clingArgs.size(); parg < n; ++parg) {
4106  auto thisArg = clingArgs[parg];
4107  auto isInclude = ROOT::TMetaUtils::BeginsWith(thisArg,"-I");
4108  if (thisArg == "-c" ||
4109  (gOptNoIncludePaths && isInclude)) continue;
4110  // We now check if the include directories are not excluded
4111  if (isInclude) {
4112  unsigned int offset = 2; // -I is two characters. Now account for spaces
4113  char c = thisArg[offset];
4114  while (c == ' ') c = thisArg[++offset];
4115  auto excludePathsEnd = gOptExcludePaths.end();
4116  auto excludePathPos = std::find_if(gOptExcludePaths.begin(),
4117  excludePathsEnd,
4118  [&](const std::string& path){
4119  return ROOT::TMetaUtils::BeginsWith(&thisArg[offset], path);});
4120  if (excludePathsEnd != excludePathPos) continue;
4121  }
4122  pcmArgs.push_back(thisArg);
4123  }
4124 
4125  // cling-only arguments
4126  clingArgs.push_back(std::string("-I") + llvm::sys::path::convert_to_slash(gDriverConfig->fTROOT__GetEtcDir()));
4127  // We do not want __ROOTCLING__ in the pch!
4128  if (!gOptGeneratePCH) {
4129  clingArgs.push_back("-D__ROOTCLING__");
4130  }
4131 #ifdef R__MACOSX
4132  clingArgs.push_back("-DSYSTEM_TYPE_macosx");
4133 #elif defined(R__WIN32)
4134  clingArgs.push_back("-DSYSTEM_TYPE_winnt");
4135 
4136  // Prevent the following #error: The C++ Standard Library forbids macroizing keywords.
4137  clingArgs.push_back("-D_XKEYCHECK_H");
4138  // Tell windows.h not to #define min and max, it clashes with numerical_limits.
4139  clingArgs.push_back("-DNOMINMAX");
4140 #else // assume UNIX
4141  clingArgs.push_back("-DSYSTEM_TYPE_unix");
4142 #endif
4143 
4144  clingArgs.push_back("-fsyntax-only");
4145 #ifndef R__WIN32
4146  clingArgs.push_back("-fPIC");
4147 #endif
4148  clingArgs.push_back("-Xclang");
4149  clingArgs.push_back("-fmodules-embed-all-files");
4150  clingArgs.push_back("-Xclang");
4151  clingArgs.push_back("-main-file-name");
4152  clingArgs.push_back("-Xclang");
4153  clingArgs.push_back((dictname + ".h").c_str());
4154 
4156 
4157  // FIXME: This line is from TModuleGenerator, but we can't reuse this code
4158  // at this point because TModuleGenerator needs a CompilerInstance (and we
4159  // currently create the arguments for creating said CompilerInstance).
4160  bool isPCH = (gOptDictionaryFileName.getValue() == "allDict.cxx");
4161  std::string outputFile;
4162  // Data is in 'outputFile', therefore in the same scope.
4163  StringRef moduleName;
4164  std::string vfsArg;
4165  // Adding -fmodules to the args will break lexing with __CINT__ defined,
4166  // and we actually do lex with __CINT__ and reuse this variable later,
4167  // we have to copy it now.
4168  auto clingArgsInterpreter = clingArgs;
4169 
4170  if (gOptSharedLibFileName.empty()) {
4172  }
4173 
4174  if (!isPCH && gOptCxxModule) {
4175  // We just pass -fmodules, the CIFactory will do the rest and configure
4176  // clang correctly once it sees this flag.
4177  clingArgsInterpreter.push_back("-fmodules");
4178  clingArgsInterpreter.push_back("-fno-implicit-module-maps");
4179 
4180  for (const std::string &modulemap : gOptModuleMapFiles)
4181  clingArgsInterpreter.push_back("-fmodule-map-file=" + modulemap);
4182 
4183  clingArgsInterpreter.push_back("-fmodule-map-file=" +
4184  std::string(gDriverConfig->fTROOT__GetIncludeDir()) +
4185  "/module.modulemap");
4186  std::string ModuleMapCWD = ROOT::FoundationUtils::GetCurrentDir() + "/module.modulemap";
4187  if (llvm::sys::fs::exists(ModuleMapCWD))
4188  clingArgsInterpreter.push_back("-fmodule-map-file=" + ModuleMapCWD);
4189 
4190  // Specify the module name that we can lookup the module in the modulemap.
4191  outputFile = llvm::sys::path::stem(gOptSharedLibFileName).str();
4192  // Try to get the module name in the modulemap based on the filepath.
4193  moduleName = GetModuleNameFromRdictName(outputFile);
4194 
4195  clingArgsInterpreter.push_back("-fmodule-name");
4196  clingArgsInterpreter.push_back(moduleName.str());
4197 
4198  std::string moduleCachePath = llvm::sys::path::parent_path(gOptSharedLibFileName).str();
4199  // FIXME: This is a horrible workaround to fix the incremental builds.
4200  // The enumerated modules are built by clang impicitly based on #include of
4201  // a header which is contained within that module. The build system has
4202  // no way to track dependencies on them and trigger a rebuild.
4203  // A possible solution can be to disable completely the implicit build of
4204  // modules and each module to be built by rootcling. We need to teach
4205  // rootcling how to build modules with no IO support.
4206  if (moduleName == "Core") {
4208  remove((moduleCachePath + llvm::sys::path::get_separator() + "_Builtin_intrinsics.pcm").str().c_str());
4209  remove((moduleCachePath + llvm::sys::path::get_separator() + "_Builtin_stddef_max_align_t.pcm").str().c_str());
4210  remove((moduleCachePath + llvm::sys::path::get_separator() + "Cling_Runtime.pcm").str().c_str());
4211  remove((moduleCachePath + llvm::sys::path::get_separator() + "Cling_Runtime_Extra.pcm").str().c_str());
4212 #ifdef R__WIN32
4213  remove((moduleCachePath + llvm::sys::path::get_separator() + "vcruntime.pcm").str().c_str());
4214  remove((moduleCachePath + llvm::sys::path::get_separator() + "services.pcm").str().c_str());
4215 #endif
4216 
4217 #ifdef R__MACOSX
4218  remove((moduleCachePath + llvm::sys::path::get_separator() + "Darwin.pcm").str().c_str());
4219 #else
4220  remove((moduleCachePath + llvm::sys::path::get_separator() + "libc.pcm").str().c_str());
4221 #endif
4222  remove((moduleCachePath + llvm::sys::path::get_separator() + "std.pcm").str().c_str());
4223  remove((moduleCachePath + llvm::sys::path::get_separator() + "cuda.pcm").str().c_str());
4224  remove((moduleCachePath + llvm::sys::path::get_separator() + "boost.pcm").str().c_str());
4225  remove((moduleCachePath + llvm::sys::path::get_separator() + "tinyxml2.pcm").str().c_str());
4226  remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Config.pcm").str().c_str());
4227  remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Rtypes.pcm").str().c_str());
4228  remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Foundation_C.pcm").str().c_str());
4229  remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Foundation_Stage1_NoRTTI.pcm").str().c_str());
4230  }
4231 
4232  // Set the C++ modules output directory to the directory where we generate
4233  // the shared library.
4234  clingArgsInterpreter.push_back("-fmodules-cache-path=" + moduleCachePath);
4235  }
4236 
4237  if (gOptVerboseLevel == v4)
4238  clingArgsInterpreter.push_back("-v");
4239 
4240  // Convert arguments to a C array and check if they are sane
4241  std::vector<const char *> clingArgsC;
4242  for (auto const &clingArg : clingArgsInterpreter) {
4243  if (!IsCorrectClingArgument(clingArg)){
4244  std::cerr << "Argument \""<< clingArg << "\" is not a supported cling argument. "
4245  << "This could be mistyped rootcling argument. Please check the commandline.\n";
4246  return 1;
4247  }
4248  clingArgsC.push_back(clingArg.c_str());
4249  }
4250 
4251 
4252  std::unique_ptr<cling::Interpreter> owningInterpPtr;
4253  cling::Interpreter* interpPtr = nullptr;
4254 
4255  std::list<std::string> filesIncludedByLinkdef;
4257 #ifdef R__FAST_MATH
4258  // Same setting as in TCling.cxx.
4259  clingArgsC.push_back("-ffast-math");
4260 #endif
4261 
4262  owningInterpPtr.reset(new cling::Interpreter(clingArgsC.size(), &clingArgsC[0],
4263  llvmResourceDir.c_str()));
4264  interpPtr = owningInterpPtr.get();
4265  } else {
4266  // Pass the interpreter arguments to TCling's interpreter:
4267  clingArgsC.push_back("-resource-dir");
4268  clingArgsC.push_back(llvmResourceDir.c_str());
4269  clingArgsC.push_back(0); // signal end of array
4270  const char ** &extraArgs = *gDriverConfig->fTROOT__GetExtraInterpreterArgs();
4271  extraArgs = &clingArgsC[1]; // skip binary name
4272  interpPtr = gDriverConfig->fTCling__GetInterpreter();
4273  if (!isGenreflex && !gOptGeneratePCH) {
4274  std::unique_ptr<TRootClingCallbacks> callBacks (new TRootClingCallbacks(interpPtr, filesIncludedByLinkdef));
4275  interpPtr->setCallbacks(std::move(callBacks));
4276  }
4277  }
4278  cling::Interpreter &interp = *interpPtr;
4279  clang::CompilerInstance *CI = interp.getCI();
4280  // FIXME: Remove this once we switch cling to use the driver. This would handle -fmodules-embed-all-files for us.
4281  CI->getFrontendOpts().ModulesEmbedAllFiles = true;
4282  CI->getSourceManager().setAllFilesAreTransient(true);
4283 
4284  clang::Preprocessor &PP = CI->getPreprocessor();
4285  clang::HeaderSearch &headerSearch = PP.getHeaderSearchInfo();
4286  clang::ModuleMap &moduleMap = headerSearch.getModuleMap();
4287  auto &diags = interp.getDiagnostics();
4288 
4289  // Manually enable the module build remarks. We don't enable them via the
4290  // normal clang command line arg because otherwise we would get remarks for
4291  // building STL/libc when starting the interpreter in rootcling_stage1.
4292  // We can't prevent these diags in any other way because we can only attach
4293  // our own diag client now after the interpreter has already started.
4294  diags.setSeverity(clang::diag::remark_module_build, clang::diag::Severity::Remark, clang::SourceLocation());
4295 
4296  // Attach our own diag client that listens to the module_build remarks from
4297  // clang to check that we don't build dictionary C++ modules implicitly.
4298  auto recordingClient = new CheckModuleBuildClient(diags.getClient(), diags.ownsClient(), moduleMap);
4299  diags.setClient(recordingClient, true);
4300 
4302  ROOT::TMetaUtils::Info(0, "\n");
4303  ROOT::TMetaUtils::Info(0, "==== INTERPRETER CONFIGURATION ====\n");
4304  ROOT::TMetaUtils::Info(0, "== Include paths\n");
4305  interp.DumpIncludePath();
4306  printf("\n\n");
4307  fflush(stdout);
4308 
4309  ROOT::TMetaUtils::Info(0, "== Included files\n");
4310  interp.printIncludedFiles(llvm::outs());
4311  llvm::outs() << "\n\n";
4312  llvm::outs().flush();
4313 
4314  ROOT::TMetaUtils::Info(0, "== Language Options\n");
4315  const clang::LangOptions& LangOpts
4316  = interp.getCI()->getASTContext().getLangOpts();
4317 #define LANGOPT(Name, Bits, Default, Description) \
4318  ROOT::TMetaUtils::Info(0, "%s = %d // %s\n", #Name, (int)LangOpts.Name, Description);
4319 #define ENUM_LANGOPT(Name, Type, Bits, Default, Description)
4320 #include "clang/Basic/LangOptions.def"
4321  ROOT::TMetaUtils::Info(0, "==== END interpreter configuration ====\n\n");
4322  }
4323 
4324  interp.getOptions().ErrorOut = true;
4325  interp.enableRawInput(true);
4326 
4327  if (gOptCxxModule) {
4328  for (llvm::StringRef DepMod : gOptModuleDependencies) {
4329  if (DepMod.endswith("_rdict.pcm")) {
4330  ROOT::TMetaUtils::Warning(0, "'%s' value is deprecated. Please use [<fullpath>]%s.pcm\n",
4331  DepMod.data(),
4332  GetModuleNameFromRdictName(DepMod).str().data());
4333  }
4334  DepMod = GetModuleNameFromRdictName(DepMod);
4335  // We might deserialize.
4336  cling::Interpreter::PushTransactionRAII RAII(&interp);
4337  if (!interp.loadModule(DepMod, /*complain*/false)) {
4338  ROOT::TMetaUtils::Error(0, "Module '%s' failed to load.\n",
4339  DepMod.data());
4340  }
4341  }
4342  }
4343 
4344  if (interp.declare("namespace std {} using namespace std;") != cling::Interpreter::kSuccess) {
4345  ROOT::TMetaUtils::Error(0, "Error loading the default header files.\n");
4346  return 1;
4347  }
4348  if (!isGenreflex) { // rootcling
4349  // ROOTCINT uses to define a few header implicitly, we need to do it explicitly.
4350  if (interp.declare("#include <assert.h>\n") != cling::Interpreter::kSuccess
4351  || interp.declare("#include \"Rtypes.h\"\n"
4352  "#include \"TObject.h\"") != cling::Interpreter::kSuccess
4353  ) {
4354  // There was an error.
4355  ROOT::TMetaUtils::Error(0, "Error loading the default header files.\n");
4356  return 1;
4357  }
4358  }
4359 
4360  // For the list of 'opaque' typedef to also include string, we have to include it now.
4361  interp.declare("#include <string>");
4362  // For initializing TNormalizedCtxt.
4363  interp.declare("#include <RtypesCore.h>");
4364 
4365  // We are now ready (enough is loaded) to init the list of opaque typedefs.
4366  ROOT::TMetaUtils::TNormalizedCtxt normCtxt(interp.getLookupHelper());
4367  ROOT::TMetaUtils::TClingLookupHelper helper(interp, normCtxt, 0, 0, nullptr);
4368  TClassEdit::Init(&helper);
4369 
4370  // flags used only for the pragma parser:
4371  clingArgs.push_back("-D__CINT__");
4372  clingArgs.push_back("-D__MAKECINT__");
4373 
4374  AddPlatformDefines(clingArgs);
4375 
4376  std::string currentDirectory = ROOT::FoundationUtils::GetCurrentDir();
4377 
4378  std::string interpPragmaSource;
4379  std::string includeForSource;
4380  std::string interpreterDeclarations;
4381  std::string linkdef;
4382 
4383  for (size_t i = 0, e = gOptDictionaryHeaderFiles.size(); i < e; ++i) {
4384  const std::string& optHeaderFileName = gOptDictionaryHeaderFiles[i];
4385  bool isSelectionFile = IsSelectionFile(optHeaderFileName.c_str());
4386 
4387  if (isSelectionFile) {
4388  if (i == e - 1) {
4389  linkdef = optHeaderFileName;
4390  } else { // if the linkdef was not last, issue an error.
4391  ROOT::TMetaUtils::Error(0, "%s: %s must be last file on command line\n",
4392  executableFileName, optHeaderFileName.c_str());
4393  return 1;
4394  }
4395  }
4396 
4397  // coverity[tainted_data] The OS should already limit the argument size, so we are safe here
4398  std::string fullheader(optHeaderFileName);
4399  // Strip any trailing + which is only used by GeneratedLinkdef.h which currently
4400  // use directly argv.
4401  if (fullheader[fullheader.length() - 1] == '+') {
4402  fullheader.erase(fullheader.length() - 1);
4403  }
4404  std::string header(
4405  isSelectionFile ? fullheader : ROOT::FoundationUtils::MakePathRelative(fullheader, currentDirectory, gBuildingROOT));
4406 
4407  interpPragmaSource += std::string("#include \"") + header + "\"\n";
4408  if (!isSelectionFile) {
4409  // In order to not have to add the equivalent to -I${PWD} to the
4410  // command line, include the complete file name, even if it is a
4411  // full pathname, when we write it down in the dictionary.
4412  // Note: have -I${PWD} means in that (at least in the case of
4413  // ACLiC) we inadvertently pick local file that have the same
4414  // name as system header (e.g. new or list) and -iquote has not
4415  // equivalent on some platforms.
4416  includeForSource += std::string("#include \"") + fullheader + "\"\n";
4417  pcmArgs.push_back(header);
4418  } else if (!IsSelectionXml(optHeaderFileName.c_str())) {
4419  interpreterDeclarations += std::string("#include \"") + header + "\"\n";
4420  }
4421  }
4422 
4423  if (gOptUmbrellaInput) {
4424  bool hasSelectionFile = !linkdef.empty();
4425  unsigned expectedHeaderFilesSize = 1 + hasSelectionFile;
4426  if (gOptDictionaryHeaderFiles.size() > expectedHeaderFilesSize)
4427  ROOT::TMetaUtils::Error(0, "Option %s used but more than one header file specified.\n",
4428  gOptUmbrellaInput.ArgStr.data());
4429  }
4430 
4431  // We have a multiDict request. This implies generating a pcm which is of the form
4432  // dictName_libname_rdict.pcm
4433  if (gOptMultiDict) {
4434 
4435  std::string newName = llvm::sys::path::parent_path(gOptSharedLibFileName).str();
4436  if (!newName.empty())
4437  newName += gPathSeparator;
4438  newName += llvm::sys::path::stem(gOptSharedLibFileName);
4439  newName += "_";
4440  newName += llvm::sys::path::stem(gOptDictionaryFileName);
4442  gOptSharedLibFileName = newName;
4443  }
4444 
4445  // Until the module are actually enabled in ROOT, we need to register
4446  // the 'current' directory to make it relocatable (i.e. have a way
4447  // to find the headers).
4449  string incCurDir = "-I";
4450  incCurDir += currentDirectory;
4451  pcmArgs.push_back(incCurDir);
4452  }
4453 
4454  // Add the diagnostic pragmas distilled from the -Wno-xyz
4455  {
4456  std::stringstream res;
4457  const char* delim="\n";
4458  std::copy(diagnosticPragmas.begin(),
4459  diagnosticPragmas.end(),
4460  std::ostream_iterator<std::string>(res, delim));
4461  interp.declare(res.str());
4462  }
4463 
4464  class IgnoringPragmaHandler: public clang::PragmaNamespace {
4465  public:
4466  IgnoringPragmaHandler(const char* pragma):
4467  clang::PragmaNamespace(pragma) {}
4468  void HandlePragma(clang::Preprocessor &PP,
4469  clang::PragmaIntroducerKind Introducer,
4470  clang::Token &tok) {
4471  PP.DiscardUntilEndOfDirective();
4472  }
4473  };
4474 
4475  // Ignore these #pragmas to suppress "unknown pragma" warnings.
4476  // See LinkdefReader.cxx.
4477  PP.AddPragmaHandler(new IgnoringPragmaHandler("link"));
4478  PP.AddPragmaHandler(new IgnoringPragmaHandler("extra_include"));
4479  PP.AddPragmaHandler(new IgnoringPragmaHandler("read"));
4480  PP.AddPragmaHandler(new IgnoringPragmaHandler("create"));
4481 
4482  if (!interpreterDeclarations.empty() &&
4483  interp.declare(interpreterDeclarations) != cling::Interpreter::kSuccess) {
4484  ROOT::TMetaUtils::Error(0, "%s: Linkdef compilation failure\n", executableFileName);
4485  return 1;
4486  }
4487 
4488 
4489  TModuleGenerator modGen(interp.getCI(),
4493 
4494  if (!gDriverConfig->fBuildingROOTStage1 && !filesIncludedByLinkdef.empty()) {
4495  pcmArgs.push_back(linkdef);
4496  }
4497 
4498  modGen.ParseArgs(pcmArgs);
4499 
4501  // Forward the -I, -D, -U
4502  for (const std::string & inclPath : modGen.GetIncludePaths()) {
4503  interp.AddIncludePath(inclPath);
4504  }
4505  std::stringstream definesUndefinesStr;
4506  modGen.WritePPDefines(definesUndefinesStr);
4507  modGen.WritePPUndefines(definesUndefinesStr);
4508  if (!definesUndefinesStr.str().empty())
4509  interp.declare(definesUndefinesStr.str());
4510  }
4511 
4512  if (!InjectModuleUtilHeader(executableFileName, modGen, interp, true)
4513  || !InjectModuleUtilHeader(executableFileName, modGen, interp, false)) {
4514  return 1;
4515  }
4516 
4517  if (linkdef.empty()) {
4518  // Generate autolinkdef
4519  GenerateLinkdef(gOptDictionaryHeaderFiles, interpPragmaSource);
4520  }
4521 
4522  // Check if code goes to stdout or rootcling file
4523  std::ofstream fileout;
4524  string main_dictname(gOptDictionaryFileName.getValue());
4525  std::ostream *splitDictStream = nullptr;
4526  std::unique_ptr<std::ostream> splitDeleter(nullptr);
4527  // Store the temp files
4528  tempFileNamesCatalog tmpCatalog;
4529  if (!gOptIgnoreExistingDict) {
4530  if (!gOptDictionaryFileName.empty()) {
4531  tmpCatalog.addFileName(gOptDictionaryFileName.getValue());
4532  fileout.open(gOptDictionaryFileName.c_str());
4533  if (!fileout) {
4534  ROOT::TMetaUtils::Error(0, "rootcling: failed to open %s in main\n",
4535  gOptDictionaryFileName.c_str());
4536  return 1;
4537  }
4538  }
4539  }
4540 
4541  std::ostream &dictStream = (!gOptIgnoreExistingDict && !gOptDictionaryFileName.empty()) ? fileout : std::cout;
4542 
4543  if (!gOptIgnoreExistingDict) {
4544  // Now generate a second stream for the split dictionary if it is necessary
4545  if (gOptSplit) {
4546  splitDictStream = CreateStreamPtrForSplitDict(gOptDictionaryFileName.getValue(), tmpCatalog);
4547  splitDeleter.reset(splitDictStream);
4548  } else {
4549  splitDictStream = &dictStream;
4550  }
4551 
4552  size_t dh = main_dictname.rfind('.');
4553  if (dh != std::string::npos) {
4554  main_dictname.erase(dh);
4555  }
4556  // Need to replace all the characters not allowed in a symbol ...
4557  std::string main_dictname_copy(main_dictname);
4558  TMetaUtils::GetCppName(main_dictname, main_dictname_copy.c_str());
4559 
4560  CreateDictHeader(dictStream, main_dictname);
4561  if (gOptSplit)
4562  CreateDictHeader(*splitDictStream, main_dictname);
4563 
4564  if (!gOptNoGlobalUsingStd) {
4565  AddNamespaceSTDdeclaration(dictStream);
4566  if (gOptSplit) {
4567  AddNamespaceSTDdeclaration(*splitDictStream);
4568  }
4569  }
4570  }
4571 
4572  //---------------------------------------------------------------------------
4573  // Parse the linkdef or selection.xml file.
4574  /////////////////////////////////////////////////////////////////////////////
4575 
4576  string linkdefFilename;
4577  if (linkdef.empty()) {
4578  linkdefFilename = "in memory";
4579  } else {
4580  bool found = Which(interp, linkdef.c_str(), linkdefFilename);
4581  if (!found) {
4582  ROOT::TMetaUtils::Error(0, "%s: cannot open linkdef file %s\n", executableFileName, linkdef.c_str());
4583  return 1;
4584  }
4585  }
4586 
4587  // Exclude string not to re-generate the dictionary
4588  std::vector<std::pair<std::string, std::string>> namesForExclusion;
4589  if (!gBuildingROOT) {
4590  namesForExclusion.push_back(std::make_pair(ROOT::TMetaUtils::propNames::name, "std::string"));
4591  namesForExclusion.push_back(std::make_pair(ROOT::TMetaUtils::propNames::pattern, "ROOT::Meta::Selection*"));
4592  }
4593 
4594  SelectionRules selectionRules(interp, normCtxt, namesForExclusion);
4595 
4596  std::string extraIncludes;
4597 
4598  ROOT::TMetaUtils::RConstructorTypes constructorTypes;
4599 
4600  // Select using DictSelection
4601  const unsigned int selRulesInitialSize = selectionRules.Size();
4602  if (dictSelection && !gOptGeneratePCH)
4603  ROOT::Internal::DictSelectionReader dictSelReader(interp, selectionRules, CI->getASTContext(), normCtxt);
4604 
4605  bool dictSelRulesPresent = selectionRules.Size() > selRulesInitialSize;
4606 
4607  bool isSelXML = IsSelectionXml(linkdefFilename.c_str());
4608 
4609  int rootclingRetCode(0);
4610 
4611  if (linkdef.empty()) {
4612  // There is no linkdef file, we added the 'default' #pragma to
4613  // interpPragmaSource.
4614 
4615  LinkdefReader ldefr(interp, constructorTypes);
4616  clingArgs.push_back("-Ietc/cling/cint"); // For multiset and multimap
4617 
4618  if (!ldefr.Parse(selectionRules, interpPragmaSource, clingArgs,
4619  llvmResourceDir.c_str())) {
4620  ROOT::TMetaUtils::Error(0, "Parsing #pragma failed %s\n", linkdefFilename.c_str());
4621  rootclingRetCode += 1;
4622  } else {
4623  ROOT::TMetaUtils::Info(0, "#pragma successfully parsed.\n");
4624  }
4625 
4626  if (!ldefr.LoadIncludes(extraIncludes)) {
4627  ROOT::TMetaUtils::Error(0, "Error loading the #pragma extra_include.\n");
4628  return 1;
4629  }
4630 
4631  } else if (isSelXML) {
4632 
4634 
4635  std::ifstream file(linkdefFilename.c_str());
4636  if (file.is_open()) {
4637  ROOT::TMetaUtils::Info(0, "Selection XML file\n");
4638 
4639  XMLReader xmlr(interp);
4640  if (!xmlr.Parse(linkdefFilename.c_str(), selectionRules)) {
4641  ROOT::TMetaUtils::Error(0, "Parsing XML file %s\n", linkdefFilename.c_str());
4642  return 1; // Return here to propagate the failure up to the build system
4643  } else {
4644  ROOT::TMetaUtils::Info(0, "XML file successfully parsed\n");
4645  }
4646  file.close();
4647  } else {
4648  ROOT::TMetaUtils::Error(0, "XML file %s couldn't be opened!\n", linkdefFilename.c_str());
4649  }
4650 
4651  } else if (ROOT::TMetaUtils::IsLinkdefFile(linkdefFilename.c_str())) {
4652 
4653  std::ifstream file(linkdefFilename.c_str());
4654  if (file.is_open()) {
4655  ROOT::TMetaUtils::Info(0, "Using linkdef file: %s\n", linkdefFilename.c_str());
4656  file.close();
4657  } else {
4658  ROOT::TMetaUtils::Error(0, "Linkdef file %s couldn't be opened!\n", linkdefFilename.c_str());
4659  }
4660 
4662 
4663  LinkdefReader ldefr(interp, constructorTypes);
4664  clingArgs.push_back("-Ietc/cling/cint"); // For multiset and multimap
4665 
4666  if (!ldefr.Parse(selectionRules, interpPragmaSource, clingArgs,
4667  llvmResourceDir.c_str())) {
4668  ROOT::TMetaUtils::Error(0, "Parsing Linkdef file %s\n", linkdefFilename.c_str());
4669  rootclingRetCode += 1;
4670  } else {
4671  ROOT::TMetaUtils::Info(0, "Linkdef file successfully parsed.\n");
4672  }
4673 
4674  if (! ldefr.LoadIncludes(extraIncludes)) {
4675  ROOT::TMetaUtils::Error(0, "Error loading the #pragma extra_include.\n");
4676  return 1;
4677  }
4678 
4679  } else {
4680 
4681  ROOT::TMetaUtils::Error(0, "Unrecognized selection file: %s\n", linkdefFilename.c_str());
4682 
4683  }
4684 
4685  // Speed up the operations with rules
4686  selectionRules.FillCache();
4687  selectionRules.Optimize();
4688 
4689  if (isGenreflex){
4690  if (0 != selectionRules.CheckDuplicates()){
4691  return 1;
4692  }
4693  }
4694 
4695  // If we want to validate the selection only, we just quit.
4697  return 0;
4698 
4699  //---------------------------------------------------------------------------
4700  // Write schema evolution related headers and declarations
4701  /////////////////////////////////////////////////////////////////////////////
4702 
4703  if ((!ROOT::gReadRules.empty() || !ROOT::gReadRawRules.empty()) && !gOptIgnoreExistingDict) {
4704  dictStream << "#include \"TBuffer.h\"\n"
4705  << "#include \"TVirtualObject.h\"\n"
4706  << "#include <vector>\n"
4707  << "#include \"TSchemaHelper.h\"\n\n";
4708 
4709  std::list<std::string> includes;
4710  GetRuleIncludes(includes);
4711  for (auto & incFile : includes) {
4712  dictStream << "#include <" << incFile << ">" << std::endl;
4713  }
4714  dictStream << std::endl;
4715  }
4716 
4717  selectionRules.SearchNames(interp);
4718 
4719  int scannerVerbLevel = 0;
4720  {
4721  using namespace ROOT::TMetaUtils;
4722  scannerVerbLevel = GetErrorIgnoreLevel() == kInfo; // 1 if true, 0 if false
4723  if (isGenreflex){
4724  scannerVerbLevel = GetErrorIgnoreLevel() < kWarning;
4725  }
4726  }
4727 
4728  // Select the type of scan
4729  auto scanType = RScanner::EScanType::kNormal;
4730  if (gOptGeneratePCH)
4731  scanType = RScanner::EScanType::kOnePCM;
4732  if (dictSelection)
4734 
4735  RScanner scan(selectionRules,
4736  scanType,
4737  interp,
4738  normCtxt,
4739  scannerVerbLevel);
4740 
4741  // If needed initialize the autoloading hook
4742  if (!gOptLibListPrefix.empty()) {
4745  }
4746 
4747  scan.Scan(CI->getASTContext());
4748 
4749  bool has_input_error = false;
4750 
4751  if (genreflex::verbose)
4752  selectionRules.PrintSelectionRules();
4753 
4755  !gOptGeneratePCH &&
4756  !dictSelRulesPresent &&
4757  !selectionRules.AreAllSelectionRulesUsed()) {
4758  ROOT::TMetaUtils::Warning(0, "Not all selection rules are used!\n");
4759  }
4760 
4761  if (!gOptGeneratePCH){
4762  rootclingRetCode += CheckForUnsupportedClasses(scan.fSelectedClasses);
4763  if (rootclingRetCode) return rootclingRetCode;
4764  }
4765 
4766  // SELECTION LOOP
4767  // Check for error in the class layout before doing anything else.
4768  for (auto const & annRcd : scan.fSelectedClasses) {
4769  if (ROOT::TMetaUtils::ClassInfo__HasMethod(annRcd, "Streamer", interp)) {
4770  if (annRcd.RequestNoInputOperator()) {
4771  int version = ROOT::TMetaUtils::GetClassVersion(annRcd, interp);
4772  if (version != 0) {
4773  // Only Check for input operator is the object is I/O has
4774  // been requested.
4775  has_input_error |= CheckInputOperator(annRcd, interp);
4776  }
4777  }
4778  }
4779  has_input_error |= !CheckClassDef(*annRcd, interp);
4780  }
4781 
4782  if (has_input_error) {
4783  // Be a little bit makefile friendly and remove the dictionary in case of error.
4784  // We could add an option -k to keep the file even in case of error.
4785  exit(1);
4786  }
4787 
4788  //---------------------------------------------------------------------------
4789  // Write all the necessary #include
4790  /////////////////////////////////////////////////////////////////////////////
4792  for (auto &&includedFromLinkdef : filesIncludedByLinkdef) {
4793  includeForSource += "#include \"" + includedFromLinkdef + "\"\n";
4794  }
4795  }
4796 
4797  if (!gOptGeneratePCH) {
4798  if (!gOptIgnoreExistingDict) {
4799  GenerateNecessaryIncludes(dictStream, includeForSource, extraIncludes);
4800  if (gOptSplit) {
4801  GenerateNecessaryIncludes(*splitDictStream, includeForSource, extraIncludes);
4802  }
4803  }
4806  }
4807 
4808  // The order of addition to the list of constructor type
4809  // is significant. The list is sorted by with the highest
4810  // priority first.
4811  if (!gOptInterpreterOnly) {
4812  constructorTypes.emplace_back("TRootIOCtor", interp);
4813  constructorTypes.emplace_back("__void__", interp); // ROOT-7723
4814  constructorTypes.emplace_back("", interp);
4815  }
4816  }
4818  AddNamespaceSTDdeclaration(dictStream);
4819 
4820  if (gOptSplit && splitDictStream) {
4821  AddNamespaceSTDdeclaration(*splitDictStream);
4822  }
4823  }
4824 
4825  if (gOptGeneratePCH) {
4826  AnnotateAllDeclsForPCH(interp, scan);
4827  } else if (gOptInterpreterOnly) {
4828  rootclingRetCode += CheckClassesForInterpreterOnlyDicts(interp, scan);
4829  // generate an empty pcm nevertheless for consistency
4830  // Negate as true is 1 and true is returned in case of success.
4832  rootclingRetCode += FinalizeStreamerInfoWriting(interp);
4833  }
4834  } else {
4835  rootclingRetCode += GenerateFullDict(*splitDictStream,
4836  interp,
4837  scan,
4838  constructorTypes,
4839  gOptSplit,
4840  isGenreflex,
4842  }
4843 
4844  if (rootclingRetCode != 0) {
4845  return rootclingRetCode;
4846  }
4847 
4848  // Now we have done all our looping and thus all the possible
4849  // annotation, let's write the pcms.
4850  HeadersDeclsMap_t headersClassesMap;
4851  HeadersDeclsMap_t headersDeclsMap;
4852  if (!gOptIgnoreExistingDict) {
4853  const std::string fwdDeclnArgsToKeepString(GetFwdDeclnArgsToKeepString(normCtxt, interp));
4854 
4856  scan.fSelectedTypedefs,
4857  scan.fSelectedFunctions,
4858  scan.fSelectedVariables,
4859  scan.fSelectedEnums,
4860  headersClassesMap,
4861  headersDeclsMap,
4862  interp);
4863 
4864  std::string detectedUmbrella;
4865  for (auto & arg : pcmArgs) {
4867  detectedUmbrella = arg;
4868  break;
4869  }
4870  }
4871 
4872  if (gOptWriteEmptyRootPCM){
4873  headersDeclsMap.clear();
4874  }
4875 
4876 
4877  std::string headersClassesMapString = "\"\"";
4878  std::string fwdDeclsString = "\"\"";
4879  if (!gOptCxxModule) {
4880  headersClassesMapString = GenerateStringFromHeadersForClasses(headersDeclsMap,
4881  detectedUmbrella,
4882  true);
4884  if (!gOptWriteEmptyRootPCM)
4885  fwdDeclsString = GenerateFwdDeclString(scan, interp);
4886  }
4887  }
4888  modGen.WriteRegistrationSource(dictStream, fwdDeclnArgsToKeepString, headersClassesMapString, fwdDeclsString,
4889  extraIncludes, gOptCxxModule);
4890  // If we just want to inline the input header, we don't need
4891  // to generate any files.
4892  if (!gOptInlineInput) {
4893  // Write the module/PCH depending on what mode we are on
4894  if (modGen.IsPCH()) {
4895  if (!GenerateAllDict(modGen, CI, currentDirectory)) return 1;
4896  } else if (gOptCxxModule) {
4897  if (!CheckModuleValid(modGen, llvmResourceDir, interp, linkdefFilename, moduleName.str()))
4898  return 1;
4899  }
4900  }
4901  }
4902 
4903 
4904  if (!gOptLibListPrefix.empty()) {
4905  string liblist_filename = gOptLibListPrefix + ".out";
4906 
4907  ofstream outputfile(liblist_filename.c_str(), ios::out);
4908  if (!outputfile) {
4909  ROOT::TMetaUtils::Error(0, "%s: Unable to open output lib file %s\n",
4910  executableFileName, liblist_filename.c_str());
4911  } else {
4912  const size_t endStr = gLibsNeeded.find_last_not_of(" \t");
4913  outputfile << gLibsNeeded.substr(0, endStr + 1) << endl;
4914  // Add explicit delimiter
4915  outputfile << "# Now the list of classes\n";
4916  // SELECTION LOOP
4917  for (auto const & annRcd : scan.fSelectedClasses) {
4918  // Shouldn't it be GetLong64_Name( cl_input.GetNormalizedName() )
4919  // or maybe we should be normalizing to turn directly all long long into Long64_t
4920  outputfile << annRcd.GetNormalizedName() << endl;
4921  }
4922  }
4923  }
4924 
4925  // Check for errors in module generation
4926  rootclingRetCode += modGen.GetErrorCount();
4927  if (0 != rootclingRetCode) return rootclingRetCode;
4928 
4929  // Create the rootmap file
4930  std::string rootmapLibName = std::accumulate(gOptRootmapLibNames.begin(),
4931  gOptRootmapLibNames.end(),
4932  std::string(),
4933  [](const std::string & a, const std::string & b) -> std::string {
4934  if (a.empty()) return b;
4935  else return a + " " + b;
4936  });
4937 
4938  bool rootMapNeeded = !gOptRootMapFileName.empty() || !rootmapLibName.empty();
4939 
4940  std::list<std::string> classesNames;
4941  std::list<std::string> classesNamesForRootmap;
4942  std::list<std::string> classesDefsList;
4943 
4944  rootclingRetCode = ExtractClassesListAndDeclLines(scan,
4945  classesNames,
4946  classesNamesForRootmap,
4947  classesDefsList,
4948  interp);
4949 
4950  std::list<std::string> enumNames;
4951  rootclingRetCode += ExtractAutoloadKeys(enumNames,
4952  scan.fSelectedEnums,
4953  interp);
4954 
4955  std::list<std::string> varNames;
4956  rootclingRetCode += ExtractAutoloadKeys(varNames,
4957  scan.fSelectedVariables,
4958  interp);
4959 
4960  if (0 != rootclingRetCode) return rootclingRetCode;
4961 
4962  // Create the rootmapfile if needed
4963  if (rootMapNeeded) {
4964 
4965  std::list<std::string> nsNames;
4966 
4967  ExtractSelectedNamespaces(scan, nsNames);
4968 
4970  rootmapLibName);
4971 
4972  ROOT::TMetaUtils::Info(0, "Rootmap file name %s and lib name(s) \"%s\"\n",
4973  gOptRootMapFileName.c_str(),
4974  rootmapLibName.c_str());
4975 
4976  tmpCatalog.addFileName(gOptRootMapFileName);
4977  std::unordered_set<std::string> headersToIgnore;
4978  if (gOptInlineInput)
4979  for (const std::string& optHeaderFileName : gOptDictionaryHeaderFiles)
4980  headersToIgnore.insert(optHeaderFileName.c_str());
4981 
4982  std::list<std::string> typedefsRootmapLines;
4983  rootclingRetCode += ExtractAutoloadKeys(typedefsRootmapLines,
4984  scan.fSelectedTypedefs,
4985  interp);
4986 
4987  rootclingRetCode = CreateNewRootMapFile(gOptRootMapFileName,
4988  rootmapLibName,
4989  classesDefsList,
4990  classesNamesForRootmap,
4991  nsNames,
4992  typedefsRootmapLines,
4993  enumNames,
4994  varNames,
4995  headersClassesMap,
4996  headersToIgnore);
4997 
4998  if (0 != rootclingRetCode) return 1;
4999  }
5000 
5001  if (genreflex::verbose)
5002  tmpCatalog.dump();
5003 
5004  // Manually call end of translation unit because we never call the
5005  // appropriate deconstructors in the interpreter. This writes out the C++
5006  // module file that we currently generate.
5007  {
5008  cling::Interpreter::PushTransactionRAII RAII(&interp);
5009  CI->getSema().getASTConsumer().HandleTranslationUnit(CI->getSema().getASTContext());
5010  }
5011 
5012  // Add the warnings
5013  rootclingRetCode += ROOT::TMetaUtils::GetNumberOfErrors();
5014 
5015  // make sure the file is closed before committing
5016  fileout.close();
5017 
5018  // Before returning, rename the files if no errors occurred
5019  // otherwise clean them to avoid remnants (see ROOT-10015)
5020  if(rootclingRetCode == 0) {
5021  rootclingRetCode += tmpCatalog.commit();
5022  } else {
5023  tmpCatalog.clean();
5024  }
5025 
5026  return rootclingRetCode;
5027 
5028 }
5029 
5030 namespace genreflex {
5031 
5032 ////////////////////////////////////////////////////////////////////////////////
5033 /// Loop on arguments: stop at the first which starts with -
5034 
5035  unsigned int checkHeadersNames(std::vector<std::string> &headersNames)
5036  {
5037  unsigned int numberOfHeaders = 0;
5038  for (std::vector<std::string>::iterator it = headersNames.begin();
5039  it != headersNames.end(); ++it) {
5040  const std::string headername(*it);
5041  if (ROOT::TMetaUtils::IsHeaderName(headername)) {
5042  numberOfHeaders++;
5043  } else {
5045  "*** genreflex: %s is not a valid header name (.h and .hpp extensions expected)!\n",
5046  headername.c_str());
5047  }
5048  }
5049  return numberOfHeaders;
5050  }
5051 
5052 ////////////////////////////////////////////////////////////////////////////////
5053 /// Extract the arguments from the command line
5054 
5055  unsigned int extractArgs(int argc, char **argv, std::vector<std::string> &args)
5056  {
5057  // loop on argv, spot strings which are not preceded by something
5058  unsigned int argvCounter = 0;
5059  for (int i = 1; i < argc; ++i) {
5060  if (!ROOT::TMetaUtils::BeginsWith(argv[i - 1], "-") && // so, if preceding element starts with -, this is a value for an option
5061  !ROOT::TMetaUtils::BeginsWith(argv[i], "-")) { // and the element itself is not an option
5062  args.push_back(argv[i]);
5063  argvCounter++;
5064  } else if (argvCounter) {
5065  argv[i - argvCounter] = argv[i];
5066  }
5067  }
5068 
5069  // Some debug
5070  if (genreflex::verbose) {
5071  int i = 0;
5072  std::cout << "Args: \n";
5073  for (std::vector<std::string>::iterator it = args.begin();
5074  it < args.end(); ++it) {
5075  std::cout << i << ") " << *it << std::endl;
5076  ++i;
5077  }
5078 
5079  }
5080 
5081  return argvCounter;
5082  }
5083 
5084 ////////////////////////////////////////////////////////////////////////////////
5085 
5086  void changeExtension(std::string &filename, const std::string &newExtension)
5087  {
5088  size_t result = filename.find_last_of('.');
5089  if (std::string::npos != result) {
5090  filename.erase(result);
5091  filename.append(newExtension);
5092  }
5093 
5094  }
5095 
5096 ////////////////////////////////////////////////////////////////////////////////
5097 /// The caller is responsible for deleting the string!
5098 
5099  char *string2charptr(const std::string &str)
5100  {
5101  const unsigned int size(str.size());
5102  char *a = new char[size + 1];
5103  a[size] = 0;
5104  memcpy(a, str.c_str(), size);
5105  return a;
5106  }
5107 
5108 ////////////////////////////////////////////////////////////////////////////////
5109 /// Replace the extension with "_rflx.cpp"
5110 
5111  void header2outputName(std::string &fileName)
5112  {
5113  changeExtension(fileName, "_rflx.cpp");
5114  }
5115 
5116 ////////////////////////////////////////////////////////////////////////////////
5117 /// Get a proper name for the output file
5118 
5119  void headers2outputsNames(const std::vector<std::string> &headersNames,
5120  std::vector<std::string> &ofilesnames)
5121  {
5122  ofilesnames.reserve(headersNames.size());
5123 
5124  for (std::vector<std::string>::const_iterator it = headersNames.begin();
5125  it != headersNames.end(); ++it) {
5126  std::string ofilename(*it);
5127  header2outputName(ofilename);
5128  ofilesnames.push_back(ofilename);
5129  }
5130  }
5131 
5132 ////////////////////////////////////////////////////////////////////////////////
5133 
5134  void AddToArgVector(std::vector<char *> &argvVector,
5135  const std::vector<std::string> &argsToBeAdded,
5136  const std::string &optName = "")
5137  {
5138  for (std::vector<std::string>::const_iterator it = argsToBeAdded.begin();
5139  it != argsToBeAdded.end(); ++it) {
5140  argvVector.push_back(string2charptr(optName + *it));
5141  }
5142  }
5143 
5144 ////////////////////////////////////////////////////////////////////////////////
5145 
5146  void AddToArgVectorSplit(std::vector<char *> &argvVector,
5147  const std::vector<std::string> &argsToBeAdded,
5148  const std::string &optName = "")
5149  {
5150  for (std::vector<std::string>::const_iterator it = argsToBeAdded.begin();
5151  it != argsToBeAdded.end(); ++it) {
5152  if (optName.length()) {
5153  argvVector.push_back(string2charptr(optName));
5154  }
5155  argvVector.push_back(string2charptr(*it));
5156  }
5157  }
5158 
5159 ////////////////////////////////////////////////////////////////////////////////
5160 
5161  int invokeRootCling(const std::string &verbosity,
5162  const std::string &selectionFileName,
5163  const std::string &targetLibName,
5164  bool multiDict,
5165  const std::vector<std::string> &pcmsNames,
5166  const std::vector<std::string> &includes,
5167  const std::vector<std::string> &preprocDefines,
5168  const std::vector<std::string> &preprocUndefines,
5169  const std::vector<std::string> &warnings,
5170  const std::string &rootmapFileName,
5171  const std::string &rootmapLibName,
5172  bool interpreteronly,
5173  bool doSplit,
5174  bool isCxxmodule,
5175  bool writeEmptyRootPCM,
5176  bool selSyntaxOnly,
5177  bool noIncludePaths,
5178  bool noGlobalUsingStd,
5179  const std::vector<std::string> &headersNames,
5180  bool failOnWarnings,
5181  const std::string &ofilename)
5182  {
5183  // Prepare and invoke the commandline to invoke rootcling
5184 
5185  std::vector<char *> argvVector;
5186 
5187  argvVector.push_back(string2charptr("rootcling"));
5188  argvVector.push_back(string2charptr(verbosity));
5189  argvVector.push_back(string2charptr("-f"));
5190  argvVector.push_back(string2charptr(ofilename));
5191 
5192  if (isCxxmodule)
5193  argvVector.push_back(string2charptr("-cxxmodule"));
5194 
5195  // Extract the path to the dictionary
5196  std::string dictLocation;
5197  ExtractFilePath(ofilename, dictLocation);
5198 
5199  // Rootmaps
5200 
5201  // Prepare the correct rootmap libname if not already set.
5202  std::string newRootmapLibName(rootmapLibName);
5203  if (!rootmapFileName.empty() && newRootmapLibName.empty()) {
5204  if (headersNames.size() != 1) {
5206  "*** genreflex: No rootmap lib and several header specified!\n");
5207  }
5208  std::string cleanHeaderName = ExtractFileName(headersNames[0]);
5209  newRootmapLibName = "lib";
5210  newRootmapLibName += cleanHeaderName;
5211  changeExtension(newRootmapLibName, gLibraryExtension);
5212  }
5213 
5214  // Prepend to the rootmap the designed directory of the dictionary
5215  // if no path is specified for the rootmap itself
5216  std::string newRootmapFileName(rootmapFileName);
5217  if (!newRootmapFileName.empty() && !HasPath(newRootmapFileName)) {
5218  newRootmapFileName = dictLocation + newRootmapFileName;
5219  }
5220 
5221 
5222  // RootMap filename
5223  if (!newRootmapFileName.empty()) {
5224  argvVector.push_back(string2charptr("-rmf"));
5225  argvVector.push_back(string2charptr(newRootmapFileName));
5226  }
5227 
5228  // RootMap Lib filename
5229  if (!newRootmapLibName.empty()) {
5230  argvVector.push_back(string2charptr("-rml"));
5231  argvVector.push_back(string2charptr(newRootmapLibName));
5232  }
5233 
5234  // Interpreter only dictionaries
5235  if (interpreteronly)
5236  argvVector.push_back(string2charptr("-interpreteronly"));
5237 
5238  // Split dictionaries
5239  if (doSplit)
5240  argvVector.push_back(string2charptr("-split"));
5241 
5242  // Targetlib
5243  if (!targetLibName.empty()) {
5244  argvVector.push_back(string2charptr("-s"));
5245  argvVector.push_back(string2charptr(targetLibName));
5246  }
5247 
5248  // Multidict support
5249  if (multiDict)
5250  argvVector.push_back(string2charptr("-multiDict"));
5251 
5252  // Don't declare "using namespace std"
5253  if (noGlobalUsingStd)
5254  argvVector.push_back(string2charptr("-noGlobalUsingStd"));
5255 
5256 
5257  AddToArgVectorSplit(argvVector, pcmsNames, "-m");
5258 
5259  // Inline the input header
5260  argvVector.push_back(string2charptr("-inlineInputHeader"));
5261 
5262  // Write empty root pcms
5263  if (writeEmptyRootPCM)
5264  argvVector.push_back(string2charptr("-writeEmptyRootPCM"));
5265 
5266  // Just test the syntax of the selection file
5267  if (selSyntaxOnly)
5268  argvVector.push_back(string2charptr("-selSyntaxOnly"));
5269 
5270  // No include paths
5271  if (noIncludePaths)
5272  argvVector.push_back(string2charptr("-noIncludePaths"));
5273 
5274  // Fail on warnings
5275  if (failOnWarnings)
5276  argvVector.push_back(string2charptr("-failOnWarnings"));
5277 
5278  // Clingargs
5279  AddToArgVector(argvVector, includes, "-I");
5280  AddToArgVector(argvVector, preprocDefines, "-D");
5281  AddToArgVector(argvVector, preprocUndefines, "-U");
5282  AddToArgVector(argvVector, warnings, "-W");
5283 
5284  AddToArgVector(argvVector, headersNames);
5285 
5286  if (!selectionFileName.empty()) {
5287  argvVector.push_back(string2charptr(selectionFileName));
5288  }
5289 
5290  const int argc = argvVector.size();
5291 
5292  // Output commandline for rootcling
5293  if (genreflex::verbose) {
5294  std::cout << "Rootcling commandline:\n";
5295  for (int i = 0; i < argc; i++)
5296  std::cout << i << ") " << argvVector[i] << std::endl;
5297  }
5298 
5299  char **argv = & (argvVector[0]);
5300  int rootclingReturnCode = RootClingMain(argc,
5301  argv,
5302  /*isGenReflex=*/true);
5303 
5304  for (int i = 0; i < argc; i++)
5305  delete [] argvVector[i];
5306 
5307  return rootclingReturnCode;
5308 
5309  }
5310 
5311 ////////////////////////////////////////////////////////////////////////////////
5312 /// Get the right ofilenames and invoke several times rootcling
5313 /// One invokation per header
5314 
5315  int invokeManyRootCling(const std::string &verbosity,
5316  const std::string &selectionFileName,
5317  const std::string &targetLibName,
5318  bool multiDict,
5319  const std::vector<std::string> &pcmsNames,
5320  const std::vector<std::string> &includes,
5321  const std::vector<std::string> &preprocDefines,
5322  const std::vector<std::string> &preprocUndefines,
5323  const std::vector<std::string> &warnings,
5324  const std::string &rootmapFileName,
5325  const std::string &rootmapLibName,
5326  bool interpreteronly,
5327  bool doSplit,
5328  bool isCxxmodule,
5329  bool writeEmptyRootPCM,
5330  bool selSyntaxOnly,
5331  bool noIncludePaths,
5332  bool noGlobalUsingStd,
5333  const std::vector<std::string> &headersNames,
5334  bool failOnWarnings,
5335  const std::string &outputDirName_const = "")
5336  {
5337  std::string outputDirName(outputDirName_const);
5338 
5339  std::vector<std::string> ofilesNames;
5340  headers2outputsNames(headersNames, ofilesNames);
5341 
5342  if (!outputDirName.empty() && !ROOT::TMetaUtils::EndsWith(outputDirName, gPathSeparator)) {
5343  outputDirName += gPathSeparator;
5344  }
5345 
5346  std::vector<std::string> namesSingleton(1);
5347  for (unsigned int i = 0; i < headersNames.size(); ++i) {
5348  namesSingleton[0] = headersNames[i];
5349  std::string ofilenameFullPath(ofilesNames[i]);
5350  if (llvm::sys::path::parent_path(ofilenameFullPath) == "")
5351  ofilenameFullPath = outputDirName + ofilenameFullPath;
5352  int returnCode = invokeRootCling(verbosity,
5353  selectionFileName,
5354  targetLibName,
5355  multiDict,
5356  pcmsNames,
5357  includes,
5358  preprocDefines,
5359  preprocUndefines,
5360  warnings,
5361  rootmapFileName,
5362  rootmapLibName,
5363  interpreteronly,
5364  doSplit,
5365  isCxxmodule,
5366  writeEmptyRootPCM,
5367  selSyntaxOnly,
5368  noIncludePaths,
5369  noGlobalUsingStd,
5370  namesSingleton,
5371  failOnWarnings,
5372  ofilenameFullPath);
5373  if (returnCode != 0)
5374  return returnCode;
5375  }
5376 
5377  return 0;
5378  }
5379 
5380 
5381 } // end genreflex namespace
5382 
5383 ////////////////////////////////////////////////////////////////////////////////
5384 /// Extract from options multiple values with the same option
5385 
5386 int extractMultipleOptions(std::vector<ROOT::option::Option> &options,
5387  int oIndex,
5388  std::vector<std::string> &values)
5389 {
5390  int nValues = 0;
5391  if (options[oIndex]) {
5392  const int nVals = options[oIndex].count();
5393  values.reserve(nVals);
5394  int optionIndex = 0;
5395  for (ROOT::option::Option *opt = options[oIndex]; opt; opt = opt->next()) {
5396  if (genreflex::verbose) std::cout << "Extracting multiple args: "
5397  << optionIndex << "/" << nVals << " "
5398  << opt->arg << std::endl;
5399  optionIndex++;
5400  values.push_back(opt->arg);
5401  nValues++;
5402  }
5403  }
5404  return nValues;
5405 }
5406 
5407 ////////////////////////////////////////////////////////////////////////////////
5408 
5409 void RiseWarningIfPresent(std::vector<ROOT::option::Option> &options,
5410  int optionIndex,
5411  const char *descriptor)
5412 {
5413  if (options[optionIndex]) {
5415  "*** genereflex: %s is not supported anymore.\n",
5416  descriptor);
5417  }
5418 }
5419 
5420 ////////////////////////////////////////////////////////////////////////////////
5421 
5422 bool IsGoodLibraryName(const std::string &name)
5423 {
5424 
5425 
5427 #ifdef __APPLE__
5428  isGood |= ROOT::TMetaUtils::EndsWith(name, ".dylib");
5429 #endif
5430  return isGood;
5431 }
5432 
5433 ////////////////////////////////////////////////////////////////////////////////
5434 /// Translate the arguments of genreflex into rootcling ones and forward them
5435 /// to the RootCling function.
5436 /// These are two typical genreflex and rootcling commandlines
5437 /// 1) genreflex header1.h [header2.h ...] [options] [preprocessor options]
5438 /// 2) rootcling [-v] [-v0-4] [-f] [out.cxx] [-s sharedlib.so] [-m pcmfilename]
5439 /// header1.h[{+,-}][!] ..headerN.h[{+,-}][!] [{LinkDef.h,selectionRules.xml}]
5440 /// The rules with which the arguments are translated are (1st column genreflex):
5441 /// --debug -v4
5442 /// --quiet -v0
5443 /// -o ofile positional arg after -f
5444 /// -s selection file Last argument of the call
5445 /// --fail_on_warning Wrap ROOT::TMetaUtils::Warning and throw if selected
5446 ///
5447 /// New arguments:
5448 /// -l --library targetLib name (new) -s targetLib name
5449 /// -m pcmname (can be many -m) (new) -m pcmname (can be many -m)
5450 /// --rootmap -rmf (new)
5451 /// --rootmap-lib -rml (new)
5452 ///
5453 /// genreflex options which rise warnings (feedback is desirable)
5454 /// --no_membertypedefs (it should be irrelevant)
5455 /// --no_templatetypedefs (it should be irrelevant)
5456 ///
5457 /// genreflex options which are ignored (know for sure they are not needed)
5458 /// --pool, --dataonly
5459 /// --interpreteronly
5460 /// --gccxml{path,opt,post}
5461 ///
5462 ///
5463 /// Exceptions
5464 /// The --deep option of genreflex is passed as function parameter to rootcling
5465 /// since it's not needed at the moment there.
5466 
5467 int GenReflexMain(int argc, char **argv)
5468 {
5469  using namespace genreflex;
5470 
5471  // Setup the options parser
5472  enum optionIndex { UNKNOWN,
5473  OFILENAME,
5474  TARGETLIB,
5475  MULTIDICT,
5476  NOGLOBALUSINGSTD,
5477  SELECTIONFILENAME,
5478  ROOTMAP,
5479  ROOTMAPLIB,
5480  PCMFILENAME,
5481  DEEP,
5482  DEBUG,
5483  VERBOSE,
5484  QUIET,
5485  SILENT,
5486  CXXMODULE,
5487  WRITEEMPTYROOTPCM,
5488  HELP,
5489  FAILONWARNINGS,
5490  SELSYNTAXONLY,
5491  INTERPRETERONLY,
5492  SPLIT,
5493  NOMEMBERTYPEDEFS,
5494  NOTEMPLATETYPEDEFS,
5495  NOINCLUDEPATHS,
5496  // Don't show up in the help
5497  PREPROCDEFINE,
5498  PREPROCUNDEFINE,
5499  INCLUDE,
5500  WARNING
5501  };
5502 
5503  enum optionTypes { NOTYPE, STRING } ;
5504 
5505  // Some long help strings
5506  const char *genreflexUsage =
5507  "Generates dictionary sources and related ROOT pcm starting from an header.\n"
5508  "Usage: genreflex headerfile.h [opts] [preproc. opts]\n\n"
5509  "Options:\n";
5510 
5511  const char *selectionFilenameUsage =
5512  "-s, --selection_file\tSelection filename\n"
5513  " Class selection file to specify for which classes the dictionary\n"
5514  " will be generated. The final set can be crafted with exclusion and\n"
5515  " exclusion rules.\n"
5516  " Properties can be specified. Some have special meaning:\n"
5517  " - name [string] name of the entity to select with an exact matching\n"
5518  " - pattern [string] name with wildcards (*) to select entities\n"
5519  " - file_name/file_pattern [string]: as name/pattern but referring to\n"
5520  " file where the C++ entities reside and not to C++ entities themselves.\n"
5521  " - transient/persistent [string: true/false] The fields to which they are\n"
5522  " applied will not be persistified if requested.\n"
5523  " - comment [string]: what you could write in code after an inline comment\n"
5524  " without \"//\". For example comment=\"!\" or \"||\".\n"
5525  " - noStreamer [true/false]: turns off streamer generation if set to 'true.'\n"
5526  " Default value is 'false'\n"
5527  " - noInputOperator [true/false]: turns off input operator generation if set\n"
5528  " to 'true'. Default value is 'false'\n"
5529  " Example XML:\n"
5530  " <lcgdict>\n"
5531  " [<selection>]\n"
5532  " <class [name=\"classname\"] [pattern=\"wildname\"]\n"
5533  " [file_name=\"filename\"] [file_pattern=\"wildname\"]\n"
5534  " [id=\"xxxx\"] [noStreamer=\"true/false\"]\n"
5535  " [noInputOperator=\"true/false\"] />\n"
5536  " <class name=\"classname\" >\n"
5537  " <field name=\"m_transient\" transient=\"true\"/>\n"
5538  " <field name=\"m_anothertransient\" persistent=\"false\"/>\n"
5539  " <field name=\"m_anothertransient\" comment=\"||\"/>\n"
5540  " <properties prop1=\"value1\" [prop2=\"value2\"]/>\n"
5541  " </class>\n"
5542  " <function [name=\"funcname\"] [pattern=\"wildname\"] />\n"
5543  " <enum [name=\"enumname\"] [pattern=\"wildname\"] />\n"
5544  " <variable [name=\"varname\"] [pattern=\"wildname\"] />\n"
5545  " [</selection>]\n"
5546  " <exclusion>\n"
5547  " <class [name=\"classname\"] [pattern=\"wildname\"] />\n"
5548  " <method name=\"unwanted\" />\n"
5549  " </class>\n"
5550  " ...\n"
5551  " </lcgdict>\n"
5552  "\n"
5553  " If no selection file is specified, the class with the filename without\n"
5554  " extension will be selected, i.e. myClass.h as argument without any\n"
5555  " selection xml comes with an implicit selection rule for class \"myClass\".\n";
5556 
5557  const char *outputFilenameUsage =
5558  "-o, --output\tOutput filename\n"
5559  " Output file name. If an existing directory is specified instead of a file,\n"
5560  " then a filename will be build using the name of the input file and will\n"
5561  " be placed in the given directory. <headerfile>_rflx.cpp.\n"
5562  " NOTA BENE: the dictionaries that will be used within the same project must\n"
5563  " have unique names.\n";
5564 
5565 
5566  const char *targetLib =
5567  "-l, --library\tTarget library\n"
5568  " The flag -l must be followed by the name of the library that will\n"
5569  " contain the object file corresponding to the dictionary produced by\n"
5570  " this invocation of genreflex.\n"
5571  " The name takes priority over the one specified for the rootmapfile.\n"
5572  " The name influences the name of the created pcm:\n"
5573  " 1) If it is not specified, the pcm is called libINPUTHEADER_rdict.pcm\n"
5574  " 2) If it is specified, the pcm is called libTARGETLIBRARY_rdict.pcm\n"
5575  " Any \"liblib\" occurence is transformed in the expected \"lib\".\n"
5576  " 3) If this is specified in conjunction with --multiDict, the output is\n"
5577  " libTARGETLIBRARY_DICTIONARY_rdict.pcm\n";
5578 
5579  const char *rootmapUsage =
5580  "--rootmap\tGenerate the rootmap file to be used by ROOT.\n"
5581  " This file lists the autoload keys. For example classes for which the\n"
5582  " reflection information is provided.\n"
5583  " The format of the rootmap is the following:\n"
5584  " - Forward declarations section\n"
5585  " - Libraries sections\n"
5586  " Rootmaps can be concatenated together, for example with the cat util.\n"
5587  " In order for ROOT to pick up the information in the rootmaps, they\n"
5588  " have to be located in the library path and have the .rootmap extension.\n"
5589  " An example rootmap file could be:\n"
5590  " { decls }\n"
5591  " template <class T> class A;\n"
5592  " [ libMyLib.so ]\n"
5593  " class A<double>\n"
5594  " class B\n"
5595  " typedef C\n"
5596  " header H.h\n";
5597 
5598  const char *rootmapLibUsage =
5599  "--rootmap-lib\tLibrary name for the rootmap file.\n";
5600 
5601  // The Descriptor
5602  const ROOT::option::Descriptor genreflexUsageDescriptor[] = {
5603  {
5604  UNKNOWN,
5605  NOTYPE,
5606  "", "",
5608  genreflexUsage
5609  },
5610 
5611  {
5612  OFILENAME,
5613  STRING ,
5614  "o" , "output" ,
5616  outputFilenameUsage
5617  },
5618 
5619  {
5620  TARGETLIB,
5621  STRING ,
5622  "l" , "library" ,
5624  targetLib
5625  },
5626 
5627  {
5628  MULTIDICT,
5629  NOTYPE ,
5630  "" , "multiDict" ,
5632  "--multiDict\tSupport for many dictionaries in one library\n"
5633  " Form correct pcm names if multiple dictionaries will be in the same\n"
5634  " library (needs target library switch. See its documentation).\n"
5635  },
5636 
5637 
5638  {
5639  NOGLOBALUSINGSTD,
5640  NOTYPE ,
5641  "" , "noGlobalUsingStd" ,
5643  "--noGlobalUsingStd\tDo not declare {using namespace std} in the dictionary global scope\n"
5644  " All header files must have sumbols from std:: namespace fully qualified\n"
5645  },
5646 
5647  {
5648  SELECTIONFILENAME,
5649  STRING ,
5650  "s" , "selection_file" ,
5652  selectionFilenameUsage
5653  },
5654 
5655  {
5656  ROOTMAP,
5657  STRING ,
5658  "" , "rootmap" ,
5660  rootmapUsage
5661  },
5662 
5663  {
5664  ROOTMAPLIB,
5665  STRING ,
5666  "" , "rootmap-lib" ,
5668  rootmapLibUsage
5669  },
5670 
5671  {
5672  INTERPRETERONLY,
5673  NOTYPE,
5674  "" , "interpreteronly",
5676  "--interpreteronly\tDo not generate I/O related information.\n"
5677  " Generate minimal dictionary required for interactivity.\n"
5678  },
5679 
5680  {
5681  SPLIT,
5682  NOTYPE,
5683  "" , "split",
5685  "--split\tSplit the dictionary\n"
5686  " Split in two the dictionary, isolating the part with\n"
5687  " ClassDef related functions in a separate file.\n"
5688  },
5689 
5690  {
5691  PCMFILENAME,
5692  STRING ,
5693  "m" , "" ,
5695  "-m \tPcm file loaded before any header (option can be repeated).\n"
5696  },
5697 
5698  {
5699  VERBOSE,
5700  NOTYPE ,
5701  "-v" , "verbose",
5703  "-v, --verbose\tPrint some debug information.\n"
5704  },
5705 
5706  {
5707  DEBUG,
5708  NOTYPE ,
5709  "" , "debug",
5711  "--debug\tPrint all debug information.\n"
5712  },
5713 
5714  {
5715  QUIET,
5716  NOTYPE ,
5717  "" , "quiet",
5719  "--quiet\tPrint only warnings and errors (default).\n"
5720  },
5721 
5722  {
5723  SILENT,
5724  NOTYPE ,
5725  "" , "silent",
5727  "--silent\tPrint no information at all.\n"
5728  },
5729 
5730  {
5731  WRITEEMPTYROOTPCM,
5732  NOTYPE ,
5733  "" , "writeEmptyPCM",
5735  "--writeEmptyPCM\tWrite an empty ROOT pcm.\n"
5736  },
5737 
5738  {
5739  CXXMODULE,
5740  NOTYPE ,
5741  "" , "cxxmodule",
5743  "--cxxmodule\tGenerates a PCM for C++ Modules.\n"
5744  },
5745 
5746 
5747  {
5748  HELP,
5749  NOTYPE,
5750  "h" , "help",
5752  "--help\tPrint usage and exit.\n"
5753  },
5754 
5755  {
5756  FAILONWARNINGS,
5757  NOTYPE,
5758  "", "fail_on_warnings",
5760  "--fail_on_warnings\tFail on warnings and errors.\n"
5761  },
5762 
5763  {
5764  SELSYNTAXONLY,
5765  NOTYPE,
5766  "", "selSyntaxOnly",
5768  "--selSyntaxOnly\tValidate selection file w/o generating the dictionary.\n"
5769  },
5770 
5771  {
5772  NOINCLUDEPATHS,
5773  NOTYPE ,
5774  "" , "noIncludePaths",
5776  "--noIncludePaths\tDo not store the headers' directories in the dictionary. Instead, rely on the environment variable $ROOT_INCLUDE_PATH at runtime.\n"
5777  },
5778 
5779  // Left intentionally empty not to be shown in the help, like in the first genreflex
5780  {
5781  INCLUDE,
5782  STRING ,
5783  "I" , "" ,
5785  ""
5786  },
5787 
5788  {
5789  PREPROCDEFINE,
5790  STRING ,
5791  "D" , "" ,
5793  ""
5794  },
5795 
5796  {
5797  PREPROCUNDEFINE,
5798  STRING ,
5799  "U" , "" ,
5801  ""
5802  },
5803 
5804  {
5805  WARNING,
5806  STRING ,
5807  "W" , "" ,
5809  ""
5810  },
5811 
5812  {
5813  NOMEMBERTYPEDEFS, // Option which is not meant for the user: deprecated
5814  STRING ,
5815  "" , "no_membertypedefs" ,
5817  ""
5818  },
5819 
5820  {
5821  NOTEMPLATETYPEDEFS, // Option which is not meant for the user: deprecated
5822  STRING ,
5823  "" , "no_templatetypedefs" ,
5825  ""
5826  },
5827 
5828  {0, 0, 0, 0, 0, 0}
5829  };
5830 
5831  std::vector<std::string> headersNames;
5832  const int originalArgc = argc;
5833  // The only args are the headers here
5834  const int extractedArgs = extractArgs(argc, argv, headersNames);
5835 
5836  const int offset = 1; // skip argv[0]
5837  argc -= offset + extractedArgs;
5838  argv += offset;
5839 
5840  // Parse the options
5841  ROOT::option::Stats stats(genreflexUsageDescriptor, argc, argv);
5842  std::vector<ROOT::option::Option> options(stats.options_max);// non POD var size arrays are not C++!
5843  std::vector<ROOT::option::Option> buffer(stats.buffer_max);
5844  // The 4 is the minimum size of the abbreviation length.
5845  // For example, --selection_file can be abbreviated with --sele at least.
5846 
5847  ROOT::option::Parser parse(genreflexUsageDescriptor, argc, argv, &options[0], &buffer[0], 5);
5848 
5849  if (parse.error()) {
5850  ROOT::TMetaUtils::Error(0, "Argument parsing error!\n");
5851  return 1;
5852  }
5853 
5854  // Print help if needed
5855  if (options[HELP] || originalArgc == 1) {
5856  ROOT::option::printUsage(std::cout, genreflexUsageDescriptor);
5857  return 0;
5858  }
5859  // See if no header was provided
5860  int numberOfHeaders = checkHeadersNames(headersNames);
5861  if (0 == numberOfHeaders) {
5862  ROOT::TMetaUtils::Error(0, "No valid header was provided!\n");
5863  return 1;
5864  }
5865 
5867 
5868  if (options[DEEP])
5869  ROOT::TMetaUtils::Warning(0, "--deep has no effect. Please remove the deprecated flag!\n");
5870  // The verbosity: debug wins over quiet
5871  //std::string verbosityOption("-v4"); // To be uncommented for the testing phase. It should be -v
5872  std::string verbosityOption("-v2");
5873  if (options[SILENT]) verbosityOption = "-v0";
5874  if (options[VERBOSE] || getenv ("VERBOSE")) verbosityOption = "-v3";
5875  if (options[DEBUG]) verbosityOption = "-v4";
5876 
5877  genreflex::verbose = verbosityOption == "-v4";
5878 
5879  // The selection file
5880  std::string selectionFileName;
5881  if (options[SELECTIONFILENAME]) {
5882  selectionFileName = options[SELECTIONFILENAME].arg;
5883  if (!ROOT::TMetaUtils::EndsWith(selectionFileName, ".xml")) {
5885  "Invalid selection file extension: filename is %s and extension .xml is expected!\n",
5886  selectionFileName.c_str());
5887  return 1;
5888  }
5889  }
5890 
5891 // // Warn if a selection file is not present and exit
5892 // if (NULL==options[SELECTIONFILENAME].arg){
5893 // ROOT::TMetaUtils::Warning(0,"The usage of genreflex without a selection file is not yet supported.\n");
5894 // return 1;
5895 // }
5896 
5897 
5898  // Set the parameters for the rootmap file. If the libname is not set,
5899  // it will be set according to the header in invokeRootCling.
5900  // FIXME: treatment of directories
5901  std::string rootmapFileName(options[ROOTMAP].arg ? options[ROOTMAP].arg : "");
5902  std::string rootmapLibName(options[ROOTMAPLIB].arg ? options[ROOTMAPLIB].arg : "");
5903 
5904  // The target lib name
5905  std::string targetLibName;
5906  if (options[TARGETLIB]) {
5907  targetLibName = options[TARGETLIB].arg;
5908  if (!IsGoodLibraryName(targetLibName)) {
5910  "Invalid target library extension: filename is %s and extension %s is expected!\n",
5911  targetLibName.c_str(),
5912  gLibraryExtension.c_str());
5913  }
5914  // Target lib has precedence over rootmap lib
5915  if (options[ROOTMAP]) {
5916  rootmapLibName = ExtractFileName(options[TARGETLIB].arg);
5917  }
5918  }
5919 
5920  bool isCxxmodule = options[CXXMODULE];
5921 
5922  bool multidict = false;
5923  if (options[MULTIDICT]) multidict = true;
5924 
5925  bool noGlobalUsingStd = false;
5926  if (options[NOGLOBALUSINGSTD]) noGlobalUsingStd = true;