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