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