Logo ROOT   master
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 const char *shortHelp =
12  "Usage: rootcling [-v][-v0-4] [-f] [out.cxx] [opts] "
13  "file1.h[+][-][!] file2.h[+][-][!] ...[LinkDef.h]\n";
14 
15 
16 
17 #include "rootcling_impl.h"
18 #include "rootclingCommandLineOptionsHelp.h"
19 
20 #include "RConfigure.h"
21 #include <ROOT/RConfig.hxx>
22 #include <ROOT/FoundationUtils.hxx>
23 
24 #include <iostream>
25 #include <iomanip>
26 #include <memory>
27 #include <vector>
28 #include <algorithm>
29 #include <stdio.h>
30 
31 #include <errno.h>
32 #include <string>
33 #include <list>
34 #include <sstream>
35 #include <map>
36 #include <fstream>
37 #include <sys/stat.h>
38 #include <unordered_map>
39 #include <unordered_set>
40 #include <numeric>
41 
42 
43 #ifdef _WIN32
44 #ifdef system
45 #undef system
46 #endif
47 #undef UNICODE
48 #include <windows.h>
49 #include <Tlhelp32.h> // for MAX_MODULE_NAME32
50 #include <process.h>
51 #define PATH_MAX _MAX_PATH
52 #ifdef interface
53 // prevent error coming from clang/AST/Attrs.inc
54 #undef interface
55 #endif
56 #endif
57 
58 #ifdef __APPLE__
59 #include <mach-o/dyld.h>
60 #endif
61 
62 #if !defined(R__WIN32)
63 #include <limits.h>
64 #include <unistd.h>
65 #endif
66 
67 
68 #include "cling/Interpreter/Interpreter.h"
69 #include "cling/Interpreter/InterpreterCallbacks.h"
70 #include "cling/Interpreter/LookupHelper.h"
71 #include "cling/Interpreter/Value.h"
72 #include "clang/AST/CXXInheritance.h"
73 #include "clang/AST/Mangle.h"
74 #include "clang/Basic/Diagnostic.h"
75 #include "clang/Basic/MemoryBufferCache.h"
76 #include "clang/Frontend/CompilerInstance.h"
77 #include "clang/Frontend/FrontendActions.h"
78 #include "clang/Frontend/FrontendDiagnostic.h"
79 #include "clang/Lex/HeaderSearch.h"
80 #include "clang/Lex/Preprocessor.h"
81 #include "clang/Lex/ModuleMap.h"
82 #include "clang/Lex/Pragma.h"
83 #include "clang/Sema/Sema.h"
84 #include "clang/Serialization/ASTWriter.h"
85 #include "cling/Utils/AST.h"
86 
87 #include "llvm/Bitcode/BitstreamWriter.h"
88 #include "llvm/Support/CommandLine.h"
89 #include "llvm/Support/Path.h"
90 #include "llvm/Support/PrettyStackTrace.h"
91 #include "llvm/Support/Signals.h"
92 
93 #include "RtypesCore.h"
94 #include "TModuleGenerator.h"
95 #include "TClassEdit.h"
96 #include "TClingUtils.h"
97 #include "RStl.h"
98 #include "XMLReader.h"
99 #include "LinkdefReader.h"
100 #include "DictSelectionReader.h"
101 #include "SelectionRules.h"
102 #include "Scanner.h"
103 #include "strlcpy.h"
104 
105 #include "OptionParser.h"
106 
107 #ifdef WIN32
108 const std::string gLibraryExtension(".dll");
109 #else
110 const std::string gLibraryExtension(".so"); // no dylib for the moment
111 #endif
113 
114 #ifdef __APPLE__
115 #include <mach-o/dyld.h>
116 #endif
117 
118 #if defined(R__WIN32)
119 #include "cygpath.h"
120 #define strcasecmp _stricmp
121 #define strncasecmp _strnicmp
122 #else
123 #include <unistd.h>
124 #endif
125 
126 bool gBuildingROOT = false;
128 
129 
130 // Maybe too ugly? let's see how it performs.
131 using HeadersDeclsMap_t = std::map<std::string, std::list<std::string>>;
132 
133 using namespace ROOT;
134 using namespace TClassEdit;
135 
136 using namespace std;
137 
138 namespace genreflex {
139  bool verbose = false;
140 }
141 
142 ////////////////////////////////////////////////////////////////////////////////
143 
144 static llvm::cl::OptionCategory gRootclingOptions("rootcling common options");
145 
146  // FIXME: We should remove after removal of r flag.
147 static llvm::cl::opt<bool>
149  llvm::cl::desc("Deprecated. Similar to -f but it ignores the dictionary generation. \
150 When -r is present rootcling becomes a tool to generate rootmaps (and capability files)."),
151  llvm::cl::Hidden,
152  llvm::cl::cat(gRootclingOptions));
153 
154 ////////////////////////////////////////////////////////////////////////////////
155 
156 void SetRootSys();
157 
159  // rootcling's libCore needs "our" ROOTSYS:
160  SetRootSys();
161 };
162 
163 ////////////////////////////////////////////////////////////////////////////////
164 
165 void EmitStreamerInfo(const char *normName)
166 {
169 }
170 static void EmitTypedefs(const std::vector<const clang::TypedefNameDecl *> &tdvec)
171 {
173  return;
174  for (const auto td : tdvec)
175  gDriverConfig->fAddTypedefToROOTFile(td->getQualifiedNameAsString().c_str());
176 }
177 static void EmitEnums(const std::vector<const clang::EnumDecl *> &enumvec)
178 {
180  return;
181  for (const auto en : enumvec) {
182  // Enums within tag decls are processed as part of the tag.
183  if (clang::isa<clang::TranslationUnitDecl>(en->getDeclContext())
184  || clang::isa<clang::LinkageSpecDecl>(en->getDeclContext())
185  || clang::isa<clang::NamespaceDecl>(en->getDeclContext()))
186  gDriverConfig->fAddEnumToROOTFile(en->getQualifiedNameAsString().c_str());
187  }
188 }
189 
190 ////////////////////////////////////////////////////////////////////////////////
191 /// Returns the executable path name, used e.g. by SetRootSys().
192 
193 const char *GetExePath()
194 {
195  static std::string exepath;
196  if (exepath == "") {
197 #ifdef __APPLE__
198  exepath = _dyld_get_image_name(0);
199 #endif
200 #if defined(__linux) || defined(__linux__)
201  char linkname[PATH_MAX]; // /proc/<pid>/exe
202  char buf[PATH_MAX]; // exe path name
203  pid_t pid;
204 
205  // get our pid and build the name of the link in /proc
206  pid = getpid();
207  snprintf(linkname, PATH_MAX, "/proc/%i/exe", pid);
208  int ret = readlink(linkname, buf, 1024);
209  if (ret > 0 && ret < 1024) {
210  buf[ret] = 0;
211  exepath = buf;
212  }
213 #endif
214 #ifdef _WIN32
215  char *buf = new char[MAX_MODULE_NAME32 + 1];
216  ::GetModuleFileName(NULL, buf, MAX_MODULE_NAME32 + 1);
217  char *p = buf;
218  while ((p = strchr(p, '\\')))
219  * (p++) = '/';
220  exepath = buf;
221  delete[] buf;
222 #endif
223  }
224  return exepath.c_str();
225 }
226 
227 ////////////////////////////////////////////////////////////////////////////////
228 
229 bool Namespace__HasMethod(const clang::NamespaceDecl *cl, const char *name,
230  const cling::Interpreter &interp)
231 {
232  return ROOT::TMetaUtils::ClassInfo__HasMethod(cl, name, interp);
233 }
234 
235 ////////////////////////////////////////////////////////////////////////////////
236 
237 static void AnnotateFieldDecl(clang::FieldDecl &decl,
238  const std::list<VariableSelectionRule> &fieldSelRules)
239 {
240  using namespace ROOT::TMetaUtils;
241  // See if in the VariableSelectionRules there are attributes and names with
242  // which we can annotate.
243  // We may look for a smarter algorithm.
244 
245  // Nothing to do then ...
246  if (fieldSelRules.empty()) return;
247 
248  clang::ASTContext &C = decl.getASTContext();
249  clang::SourceRange commentRange; // Empty: this is a fake comment
250 
251  const std::string declName(decl.getNameAsString());
252  std::string varName;
253  for (std::list<VariableSelectionRule>::const_iterator it = fieldSelRules.begin();
254  it != fieldSelRules.end(); ++it) {
255  if (! it->GetAttributeValue(propNames::name, varName)) continue;
256  if (declName == varName) { // we have the rule!
257  // Let's extract the attributes
258  BaseSelectionRule::AttributesMap_t attrMap(it->GetAttributes());
259  BaseSelectionRule::AttributesMap_t::iterator iter;
260  std::string userDefinedProperty;
261  for (iter = attrMap.begin(); iter != attrMap.end(); ++iter) {
262  const std::string &name = iter->first;
263  const std::string &value = iter->second;
264 
265  if (name == propNames::name) continue;
266 
267  /* This test is here since in ROOT5, when using genreflex,
268  * for pods, iotype is ignored */
269 
270  if (name == propNames::iotype &&
271  (decl.getType()->isArrayType() || decl.getType()->isPointerType())) {
272  const char *msg = "Data member \"%s\" is an array or a pointer. "
273  "It is not possible to assign to it the iotype \"%s\". "
274  "This transformation is possible only with data members "
275  "which are not pointers or arrays.\n";
276  ROOT::TMetaUtils::Error("AnnotateFieldDecl",
277  msg, varName.c_str(), value.c_str());
278  continue;
279  }
280 
281 
282  // These lines are here to use the root pcms. Indeed we need to annotate the AST
283  // before persisting the ProtoClasses in the root pcms.
284  // BEGIN ROOT PCMS
285  if (name == propNames::comment) {
286  decl.addAttr(new(C) clang::AnnotateAttr(commentRange, C, value, 0));
287  }
288  // END ROOT PCMS
289 
290  if ((name == propNames::transient && value == "true") ||
291  (name == propNames::persistent && value == "false")) { // special case
292  userDefinedProperty = propNames::comment + propNames::separator + "!";
293  // This next line is here to use the root pcms. Indeed we need to annotate the AST
294  // before persisting the ProtoClasses in the root pcms.
295  // BEGIN ROOT PCMS
296  decl.addAttr(new(C) clang::AnnotateAttr(commentRange, C, "!", 0));
297  // END ROOT PCMS
298  // The rest of the lines are not changed to leave in place the system which
299  // works with bulk header parsing on library load.
300  } else {
301  userDefinedProperty = name + propNames::separator + value;
302  }
303  ROOT::TMetaUtils::Info(0, "%s %s\n", varName.c_str(), userDefinedProperty.c_str());
304  decl.addAttr(new(C) clang::AnnotateAttr(commentRange, C, userDefinedProperty, 0));
305 
306  }
307  }
308  }
309 }
310 
311 ////////////////////////////////////////////////////////////////////////////////
312 
313 void AnnotateDecl(clang::CXXRecordDecl &CXXRD,
314  const RScanner::DeclsSelRulesMap_t &declSelRulesMap,
315  cling::Interpreter &interpreter,
316  bool isGenreflex)
317 {
318  // In order to store the meaningful for the IO comments we have to transform
319  // the comment into annotation of the given decl.
320  // This works only with comments in the headers, so no selection rules in an
321  // xml file.
322 
323  using namespace clang;
324  SourceLocation commentSLoc;
325  llvm::StringRef comment;
326 
327  ASTContext &C = CXXRD.getASTContext();
328  Sema &S = interpreter.getCI()->getSema();
329 
330  SourceRange commentRange;
331 
332  // Fetch the selection rule associated to this class
333  clang::Decl *declBaseClassPtr = static_cast<clang::Decl *>(&CXXRD);
334  auto declSelRulePair = declSelRulesMap.find(declBaseClassPtr->getCanonicalDecl());
335  if (declSelRulePair == declSelRulesMap.end()){
336  const std::string thisClassName(CXXRD.getName());
337  ROOT::TMetaUtils::Error("AnnotateDecl","Cannot find class %s in the list of selected classes.\n",thisClassName.c_str());
338  return;
339  }
340  const BaseSelectionRule *thisClassBaseSelectionRule = declSelRulePair->second;
341  // If the rule is there
342  if (thisClassBaseSelectionRule) {
343  // Fetch and loop over Class attributes
344  // if the name of the attribute is not "name", add attr to the ast.
345  BaseSelectionRule::AttributesMap_t::iterator iter;
346  std::string userDefinedProperty;
347  for (auto const & attr : thisClassBaseSelectionRule->GetAttributes()) {
348  const std::string &name = attr.first;
349  if (name == ROOT::TMetaUtils::propNames::name) continue;
350  const std::string &value = attr.second;
351  userDefinedProperty = name + ROOT::TMetaUtils::propNames::separator + value;
352  if (genreflex::verbose) std::cout << " * " << userDefinedProperty << std::endl;
353  CXXRD.addAttr(new(C) AnnotateAttr(commentRange, C, userDefinedProperty, 0));
354  }
355  }
356 
357  // See if the rule is a class selection rule (FIX dynamic_cast)
358  const ClassSelectionRule *thisClassSelectionRule = reinterpret_cast<const ClassSelectionRule *>(thisClassBaseSelectionRule);
359 
360  for (CXXRecordDecl::decl_iterator I = CXXRD.decls_begin(),
361  E = CXXRD.decls_end(); I != E; ++I) {
362 
363  // CXXMethodDecl,FieldDecl and VarDecl inherit from NamedDecl
364  // See: http://clang.llvm.org/doxygen/classclang_1_1DeclaratorDecl.html
365  if (!(*I)->isImplicit()
366  && (isa<CXXMethodDecl>(*I) || isa<FieldDecl>(*I) || isa<VarDecl>(*I))) {
367 
368 
369  // For now we allow only a special macro (ClassDef) to have meaningful comments
370  SourceLocation maybeMacroLoc = (*I)->getLocation();
371  bool isClassDefMacro = maybeMacroLoc.isMacroID() && S.findMacroSpelling(maybeMacroLoc, "ClassDef");
372  if (isClassDefMacro) {
373  while (isa<NamedDecl>(*I) && cast<NamedDecl>(*I)->getName() != "DeclFileLine") {
374  ++I;
375  }
376  }
377 
378  comment = ROOT::TMetaUtils::GetComment(**I, &commentSLoc);
379  if (comment.size()) {
380  // Keep info for the source range of the comment in case we want to issue
381  // nice warnings, eg. empty comment and so on.
382  commentRange = SourceRange(commentSLoc, commentSLoc.getLocWithOffset(comment.size()));
383  // The ClassDef annotation is for the class itself
384  if (isClassDefMacro) {
385  CXXRD.addAttr(new(C) AnnotateAttr(commentRange, C, comment.str(), 0));
386  } else if (!isGenreflex) {
387  // Here we check if we are in presence of a selection file so that
388  // the comment does not ends up as a decoration in the AST,
389  // Nevertheless, w/o PCMS this has no effect, since the headers
390  // are parsed at runtime and the information in the AST dumped by
391  // rootcling is not relevant.
392  (*I)->addAttr(new(C) AnnotateAttr(commentRange, C, comment.str(), 0));
393  }
394  }
395  // Match decls with sel rules if we are in presence of a selection file
396  // and the cast was successful
397  if (isGenreflex && thisClassSelectionRule != 0) {
398  const std::list<VariableSelectionRule> &fieldSelRules = thisClassSelectionRule->GetFieldSelectionRules();
399 
400  // This check is here to avoid asserts in debug mode (LLVMDEV env variable set)
401  if (FieldDecl *fieldDecl = dyn_cast<FieldDecl>(*I)) {
402  AnnotateFieldDecl(*fieldDecl, fieldSelRules);
403  }
404  } // End presence of XML selection file
405  }
406  }
407 }
408 
409 ////////////////////////////////////////////////////////////////////////////////
410 
411 size_t GetFullArrayLength(const clang::ConstantArrayType *arrayType)
412 {
413  llvm::APInt len = arrayType->getSize();
414  while (const clang::ConstantArrayType *subArrayType = llvm::dyn_cast<clang::ConstantArrayType>(arrayType->getArrayElementTypeNoTypeQual())) {
415  len *= subArrayType->getSize();
416  arrayType = subArrayType;
417  }
418  return len.getLimitedValue();
419 }
420 
421 ////////////////////////////////////////////////////////////////////////////////
422 
423 bool InheritsFromTObject(const clang::RecordDecl *cl,
424  const cling::Interpreter &interp)
425 {
426  static const clang::CXXRecordDecl *TObject_decl
427  = ROOT::TMetaUtils::ScopeSearch("TObject", interp, true /*diag*/, 0);
428 
429  const clang::CXXRecordDecl *clxx = llvm::dyn_cast<clang::CXXRecordDecl>(cl);
430  return ROOT::TMetaUtils::IsBase(clxx, TObject_decl, nullptr, interp);
431 }
432 
433 ////////////////////////////////////////////////////////////////////////////////
434 
435 bool InheritsFromTSelector(const clang::RecordDecl *cl,
436  const cling::Interpreter &interp)
437 {
438  static const clang::CXXRecordDecl *TObject_decl
439  = ROOT::TMetaUtils::ScopeSearch("TSelector", interp, false /*diag*/, 0);
440 
441  return ROOT::TMetaUtils::IsBase(llvm::dyn_cast<clang::CXXRecordDecl>(cl), TObject_decl, nullptr, interp);
442 }
443 
444 ////////////////////////////////////////////////////////////////////////////////
445 
446 bool IsSelectionXml(const char *filename)
447 {
448  size_t len = strlen(filename);
449  size_t xmllen = 4; /* strlen(".xml"); */
450  if (strlen(filename) >= xmllen) {
451  return (0 == strcasecmp(filename + (len - xmllen), ".xml"));
452  } else {
453  return false;
454  }
455 }
456 
457 ////////////////////////////////////////////////////////////////////////////////
458 
459 bool IsLinkdefFile(const clang::PresumedLoc& PLoc)
460 {
461  return ROOT::TMetaUtils::IsLinkdefFile(PLoc.getFilename());
462 }
463 
464 ////////////////////////////////////////////////////////////////////////////////
465 
466 bool IsSelectionFile(const char *filename)
467 {
468  return ROOT::TMetaUtils::IsLinkdefFile(filename) || IsSelectionXml(filename);
469 }
470 
471 ////////////////////////////////////////////////////////////////////////////////
472 /// Set the ROOTSYS env var based on the executable location.
473 
475 {
476  const char *exepath = GetExePath();
477  if (exepath && *exepath) {
478 #if !defined(_WIN32)
479  char *ep = new char[PATH_MAX];
480  if (!realpath(exepath, ep)) {
481  fprintf(stderr, "rootcling: error getting realpath of rootcling!");
482  strlcpy(ep, exepath, PATH_MAX);
483  }
484 #else
485  int nche = strlen(exepath) + 1;
486  char *ep = new char[nche];
487  strlcpy(ep, exepath, nche);
488 #endif
489  char *s;
490 
491  if ((s = strrchr(ep, '/'))) {
492  // $ROOTSYS/bin/rootcling
493  int removesubdirs = 2;
494  if (!strncmp(s + 1, "rootcling_stage1.exe", 20)) {
495  // $ROOTSYS/bin/rootcling_stage1.exe
496  removesubdirs = 2;
497  gBuildingROOT = true;
498  } else if (!strncmp(s + 1, "rootcling_stage1", 16)) {
499  // $ROOTSYS/core/rootcling_stage1/src/rootcling_stage1
500  removesubdirs = 4;
501  gBuildingROOT = true;
502  }
503  for (int i = 1; s && i < removesubdirs; ++i) {
504  *s = 0;
505  s = strrchr(ep, '/');
506  }
507  if (s) *s = 0;
508  } else {
509  // There was no slashes at all let now change ROOTSYS
510  delete [] ep;
511  return;
512  }
513 
514  if (!gBuildingROOT) {
515  delete [] ep;
516  return; // don't mess with user's ROOTSYS.
517  }
518 
519  int ncha = strlen(ep) + 10;
520  char *env = new char[ncha];
521  snprintf(env, ncha, "ROOTSYS=%s", ep);
522 
523  if (gDriverConfig) {
524  // After the putenv below, gRootDir might point to the old ROOTSYS
525  // entry, i.e. to deleted memory. Update it.
526  const char** pRootDir = gDriverConfig->fPRootDir;
527  if (pRootDir) {
528  *pRootDir = env + 8;
529  }
530  }
531 
532  putenv(env);
533  // intentionally not call delete [] env, while GLIBC keep use pointer
534  delete [] ep;
535  }
536 }
537 
538 ////////////////////////////////////////////////////////////////////////////////
539 /// Check whether the #pragma line contains expectedTokens (0-terminated array).
540 
541 bool ParsePragmaLine(const std::string &line,
542  const char *expectedTokens[],
543  size_t *end = 0)
544 {
545  if (end) *end = 0;
546  if (line[0] != '#') return false;
547  size_t pos = 1;
548  for (const char **iToken = expectedTokens; *iToken; ++iToken) {
549  while (isspace(line[pos])) ++pos;
550  size_t lenToken = strlen(*iToken);
551  if (line.compare(pos, lenToken, *iToken)) {
552  if (end) *end = pos;
553  return false;
554  }
555  pos += lenToken;
556  }
557  if (end) *end = pos;
558  return true;
559 }
560 
561 
562 map<string, string> gAutoloads;
563 string gLibsNeeded;
564 
565 ////////////////////////////////////////////////////////////////////////////////
566 
567 void RecordDeclCallback(const clang::RecordDecl* recordDecl)
568 {
569  std::string need;
570  if (recordDecl->hasOwningModule()) {
571  clang::Module *M = recordDecl->getOwningModule()->getTopLevelModule();
572  need = "lib" + M->Name + gLibraryExtension;
573  } else {
574  std::string qual_name;
575  RScanner::GetDeclQualName(recordDecl, qual_name);
576 
577  need = gAutoloads[qual_name];
578  }
579 
580  if (need.length() && gLibsNeeded.find(need) == string::npos) {
581  gLibsNeeded += " " + need;
582  }
583 }
584 
585 ////////////////////////////////////////////////////////////////////////////////
586 
587 void CheckClassNameForRootMap(const std::string &classname, map<string, string> &autoloads)
588 {
589  if (classname.find(':') == std::string::npos) return;
590 
591  // We have a namespace and we have to check it first
592  int slen = classname.size();
593  for (int k = 0; k < slen; ++k) {
594  if (classname[k] == ':') {
595  if (k + 1 >= slen || classname[k + 1] != ':') {
596  // we expected another ':'
597  break;
598  }
599  if (k) {
600  string base = classname.substr(0, k);
601  if (base == "std") {
602  // std is not declared but is also ignored by CINT!
603  break;
604  } else {
605  autoloads[base] = ""; // We never load namespaces on their own.
606  }
607  ++k;
608  }
609  } else if (classname[k] == '<') {
610  // We do not want to look at the namespace inside the template parameters!
611  break;
612  }
613  }
614 }
615 
616 ////////////////////////////////////////////////////////////////////////////////
617 /// Parse the rootmap and add entries to the autoload map
618 
619 void ParseRootMapFile(ifstream &file, map<string, string> &autoloads)
620 {
621  std::string classname;
622  std::string line;
623  while (file >> line) {
624 
625  if (line.find("Library.") != 0) continue;
626 
627  int pos = line.find(":", 8);
628  classname = line.substr(8, pos - 8);
629 
630  ROOT::TMetaUtils::ReplaceAll(classname, "@@", "::");
631  ROOT::TMetaUtils::ReplaceAll(classname, "-", " ");
632 
633  getline(file, line, '\n');
634  while (line[0] == ' ') line.replace(0, 1, "");
635 
636  CheckClassNameForRootMap(classname, autoloads);
637 
638  if (classname == "ROOT::TImpProxy") {
639  // Do not register the ROOT::TImpProxy so that they can be instantiated.
640  continue;
641  }
642  autoloads[classname] = line;
643  }
644 
645 }
646 
647 ////////////////////////////////////////////////////////////////////////////////
648 /// Parse the rootmap and add entries to the autoload map, using the new format
649 
650 void ParseRootMapFileNewFormat(ifstream &file, map<string, string> &autoloads)
651 {
652  std::string keyname;
653  std::string libs;
654  std::string line;
655 
656  // For "class ", "namespace " and "typedef " respectively
657  const std::unordered_map<char, unsigned int> keyLenMap = {{'c', 6}, {'n', 10}, {'t', 8}};
658 
659  while (getline(file, line, '\n')) {
660  if (line == "{ decls }") {
661  while (getline(file, line, '\n')) {
662  if (line[0] == '[') break;
663  }
664  }
665  const char firstChar = line[0];
666  if (firstChar == '[') {
667  // new section
668  libs = line.substr(1, line.find(']') - 1);
669  while (libs[0] == ' ') libs.replace(0, 1, "");
670  } else if (0 != keyLenMap.count(firstChar)) {
671  unsigned int keyLen = keyLenMap.at(firstChar);
672  keyname = line.substr(keyLen, line.length() - keyLen);
673  CheckClassNameForRootMap(keyname, autoloads);
674  autoloads[keyname] = libs;
675  }
676  }
677 
678 }
679 
680 ////////////////////////////////////////////////////////////////////////////////
681 /// Fill the map of libraries to be loaded in presence of a class
682 /// Transparently support the old and new rootmap file format
683 
684 void LoadLibraryMap(const std::string &fileListName, map<string, string> &autoloads)
685 {
686  std::ifstream filelist(fileListName.c_str());
687 
688  std::string filename;
689  std::string line;
690 
691  while (filelist >> filename) {
692 
693  if (llvm::sys::fs::is_directory(filename)) continue;
694 
695  ifstream file(filename.c_str());
696 
697  // Check which format is this
698  file >> line;
699  bool new_format = (line[0] == '[' || line[0] == '{') ;
700  file.clear();
701  file.seekg(0, std::ios::beg);
702 
703  // Now act
704  if (new_format) {
705  ParseRootMapFileNewFormat(file, autoloads);
706  } else {
707  ParseRootMapFile(file, autoloads);
708  }
709 
710  file.close();
711 
712  } // end loop on files
713  filelist.close();
714 }
715 
716 ////////////////////////////////////////////////////////////////////////////////
717 /// Check if the specified operator (what) has been properly declared if the user has
718 /// requested a custom version.
719 
720 bool CheckInputOperator(const char *what,
721  const char *proto,
722  const string &fullname,
723  const clang::RecordDecl *cl,
724  cling::Interpreter &interp)
725 {
726 
727  const clang::FunctionDecl *method
728  = ROOT::TMetaUtils::GetFuncWithProto(llvm::dyn_cast<clang::Decl>(cl->getDeclContext()), what, proto, interp,
729  false /*diags*/);
730  if (!method) {
731  // This intended to find the global scope.
732  clang::TranslationUnitDecl *TU =
733  cl->getASTContext().getTranslationUnitDecl();
734  method = ROOT::TMetaUtils::GetFuncWithProto(TU, what, proto, interp,
735  false /*diags*/);
736  }
737  bool has_input_error = false;
738  if (method != 0 && (method->getAccess() == clang::AS_public || method->getAccess() == clang::AS_none)) {
739  std::string filename = ROOT::TMetaUtils::GetFileName(*method, interp);
740  if (strstr(filename.c_str(), "TBuffer.h") != 0 ||
741  strstr(filename.c_str(), "Rtypes.h") != 0) {
742 
743  has_input_error = true;
744  }
745  } else {
746  has_input_error = true;
747  }
748  if (has_input_error) {
749  // We don't want to generate duplicated error messages in several dictionaries (when generating temporaries)
750  const char *maybeconst = "";
751  const char *mayberef = "&";
752  if (what[strlen(what) - 1] == '<') {
753  maybeconst = "const ";
754  mayberef = "";
755  }
757  "in this version of ROOT, the option '!' used in a linkdef file\n"
758  " implies the actual existence of customized operators.\n"
759  " The following declaration is now required:\n"
760  " TBuffer &%s(TBuffer &,%s%s *%s);\n", what, maybeconst, fullname.c_str(), mayberef);
761  }
762  return has_input_error;
763 
764 }
765 
766 ////////////////////////////////////////////////////////////////////////////////
767 /// Check if the operator>> has been properly declared if the user has
768 /// requested a custom version.
769 
770 bool CheckInputOperator(const clang::RecordDecl *cl, cling::Interpreter &interp)
771 {
772  string fullname;
773  ROOT::TMetaUtils::GetQualifiedName(fullname, *cl);
774  int ncha = fullname.length() + 13;
775  char *proto = new char[ncha];
776  snprintf(proto, ncha, "TBuffer&,%s*&", fullname.c_str());
777 
778  ROOT::TMetaUtils::Info(0, "Class %s: Do not generate operator>>()\n",
779  fullname.c_str());
780 
781  // We do want to call both CheckInputOperator all the times.
782  bool has_input_error = CheckInputOperator("operator>>", proto, fullname, cl, interp);
783  has_input_error = CheckInputOperator("operator<<", proto, fullname, cl, interp) || has_input_error;
784 
785  delete [] proto;
786 
787  return has_input_error;
788 }
789 
790 ////////////////////////////////////////////////////////////////////////////////
791 /// Return false if the class does not have ClassDef even-though it should.
792 
793 bool CheckClassDef(const clang::RecordDecl &cl, const cling::Interpreter &interp)
794 {
795 
796  // Detect if the class has a ClassDef
797  bool hasClassDef = ROOT::TMetaUtils::ClassInfo__HasMethod(&cl, "Class_Version", interp);
798 
799  const clang::CXXRecordDecl *clxx = llvm::dyn_cast<clang::CXXRecordDecl>(&cl);
800  if (!clxx) {
801  return false;
802  }
803  bool isAbstract = clxx->isAbstract();
804 
805  if (!isAbstract && InheritsFromTObject(clxx, interp) && !InheritsFromTSelector(clxx, interp) && !hasClassDef) {
806  std::string qualName;
808  const char *qualName_c = qualName.c_str();
809  ROOT::TMetaUtils::Warning(qualName_c, "The data members of %s will not be stored, "
810  "because it inherits from TObject but does not "
811  "have its own ClassDef.\n",
812  qualName_c);
813  }
814 
815  return true;
816 }
817 
818 ////////////////////////////////////////////////////////////////////////////////
819 /// Return the name of the data member so that it can be used
820 /// by non-const operation (so it includes a const_cast if necessary).
821 
822 string GetNonConstMemberName(const clang::FieldDecl &m, const string &prefix = "")
823 {
824  if (m.getType().isConstQualified()) {
825  string ret = "const_cast< ";
826  string type_name;
827  ROOT::TMetaUtils::GetQualifiedName(type_name, m.getType(), m);
828  if (type_name.substr(0,6)=="const ") {
829  ret += type_name.c_str()+6;
830  } else {
831  ret += type_name;
832  }
833  ret += " &>( ";
834  ret += prefix;
835  ret += m.getName().str();
836  ret += " )";
837  return ret;
838  } else {
839  return prefix + m.getName().str();
840  }
841 }
842 
843 ////////////////////////////////////////////////////////////////////////////////
844 /// Create Streamer code for an STL container. Returns 1 if data member
845 /// was an STL container and if Streamer code has been created, 0 otherwise.
846 
847 int STLContainerStreamer(const clang::FieldDecl &m,
848  int rwmode,
849  const cling::Interpreter &interp,
850  const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt,
851  std::ostream &dictStream)
852 {
854  std::string mTypename;
855  ROOT::TMetaUtils::GetQualifiedName(mTypename, m.getType(), m);
856 
857  const clang::CXXRecordDecl *clxx = llvm::dyn_cast_or_null<clang::CXXRecordDecl>(ROOT::TMetaUtils::GetUnderlyingRecordDecl(m.getType()));
858 
859  if (stltype == ROOT::kNotSTL) {
860  return 0;
861  }
862  // fprintf(stderr,"Add %s (%d) which is also %s\n",
863  // m.Type()->Name(), stltype, m.Type()->TrueName() );
864  clang::QualType utype(ROOT::TMetaUtils::GetUnderlyingType(m.getType()), 0);
865  Internal::RStl::Instance().GenerateTClassFor(utype, interp, normCtxt);
866 
867  if (clxx->getTemplateSpecializationKind() == clang::TSK_Undeclared) return 0;
868 
869  const clang::ClassTemplateSpecializationDecl *tmplt_specialization = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl> (clxx);
870  if (!tmplt_specialization) return 0;
871 
872 
873  string stlType(ROOT::TMetaUtils::ShortTypeName(mTypename.c_str()));
874  string stlName;
875  stlName = ROOT::TMetaUtils::ShortTypeName(m.getName().str().c_str());
876 
877  string fulName1, fulName2;
878  const char *tcl1 = 0, *tcl2 = 0;
879  const clang::TemplateArgument &arg0(tmplt_specialization->getTemplateArgs().get(0));
880  clang::QualType ti = arg0.getAsType();
881 
882  if (ROOT::TMetaUtils::ElementStreamer(dictStream, m, ti, 0, rwmode, interp)) {
883  tcl1 = "R__tcl1";
884  fulName1 = ti.getAsString(); // Should we be passing a context?
885  }
886  if (stltype == kSTLmap || stltype == kSTLmultimap) {
887  const clang::TemplateArgument &arg1(tmplt_specialization->getTemplateArgs().get(1));
888  clang::QualType tmplti = arg1.getAsType();
889  if (ROOT::TMetaUtils::ElementStreamer(dictStream, m, tmplti, 0, rwmode, interp)) {
890  tcl2 = "R__tcl2";
891  fulName2 = tmplti.getAsString(); // Should we be passing a context?
892  }
893  }
894 
895  int isArr = 0;
896  int len = 1;
897  int pa = 0;
898  const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(m.getType().getTypePtr());
899  if (arrayType) {
900  isArr = 1;
901  len = GetFullArrayLength(arrayType);
902  pa = 1;
903  while (arrayType) {
904  if (arrayType->getArrayElementTypeNoTypeQual()->isPointerType()) {
905  pa = 3;
906  break;
907  }
908  arrayType = llvm::dyn_cast<clang::ConstantArrayType>(arrayType->getArrayElementTypeNoTypeQual());
909  }
910  } else if (m.getType()->isPointerType()) {
911  pa = 2;
912  }
913  if (rwmode == 0) {
914  // create read code
915  dictStream << " {" << std::endl;
916  if (isArr) {
917  dictStream << " for (Int_t R__l = 0; R__l < " << len << "; R__l++) {" << std::endl;
918  }
919 
920  switch (pa) {
921  case 0: //No pointer && No array
922  dictStream << " " << stlType.c_str() << " &R__stl = " << stlName.c_str() << ";" << std::endl;
923  break;
924  case 1: //No pointer && array
925  dictStream << " " << stlType.c_str() << " &R__stl = " << stlName.c_str() << "[R__l];" << std::endl;
926  break;
927  case 2: //pointer && No array
928  dictStream << " delete *" << stlName.c_str() << ";" << std::endl
929  << " *" << stlName.c_str() << " = new " << stlType.c_str() << ";" << std::endl
930  << " " << stlType.c_str() << " &R__stl = **" << stlName.c_str() << ";" << std::endl;
931  break;
932  case 3: //pointer && array
933  dictStream << " delete " << stlName.c_str() << "[R__l];" << std::endl
934  << " " << stlName.c_str() << "[R__l] = new " << stlType.c_str() << ";" << std::endl
935  << " " << stlType.c_str() << " &R__stl = *" << stlName.c_str() << "[R__l];" << std::endl;
936  break;
937  }
938 
939  dictStream << " R__stl.clear();" << std::endl;
940 
941  if (tcl1) {
942  dictStream << " TClass *R__tcl1 = TBuffer::GetClass(typeid(" << fulName1.c_str() << "));" << std::endl
943  << " if (R__tcl1==0) {" << std::endl
944  << " Error(\"" << stlName.c_str() << " streamer\",\"Missing the TClass object for "
945  << fulName1.c_str() << "!\");" << std::endl
946  << " return;" << std::endl
947  << " }" << std::endl;
948  }
949  if (tcl2) {
950  dictStream << " TClass *R__tcl2 = TBuffer::GetClass(typeid(" << fulName2.c_str() << "));" << std::endl
951  << " if (R__tcl2==0) {" << std::endl
952  << " Error(\"" << stlName.c_str() << " streamer\",\"Missing the TClass object for "
953  << fulName2.c_str() << "!\");" << std::endl
954  << " return;" << std::endl
955  << " }" << std::endl;
956  }
957 
958  dictStream << " int R__i, R__n;" << std::endl
959  << " R__b >> R__n;" << std::endl;
960 
961  if (stltype == kSTLvector) {
962  dictStream << " R__stl.reserve(R__n);" << std::endl;
963  }
964  dictStream << " for (R__i = 0; R__i < R__n; R__i++) {" << std::endl;
965 
966  ROOT::TMetaUtils::ElementStreamer(dictStream, m, arg0.getAsType(), "R__t", rwmode, interp, tcl1);
967  if (stltype == kSTLmap || stltype == kSTLmultimap) { //Second Arg
968  const clang::TemplateArgument &arg1(tmplt_specialization->getTemplateArgs().get(1));
969  ROOT::TMetaUtils::ElementStreamer(dictStream, m, arg1.getAsType(), "R__t2", rwmode, interp, tcl2);
970  }
971 
972  /* Need to go from
973  type R__t;
974  R__t.Stream;
975  vec.push_back(R__t);
976  to
977  vec.push_back(type());
978  R__t_p = &(vec.last());
979  *R__t_p->Stream;
980 
981  */
982  switch (stltype) {
983 
984  case kSTLmap:
985  case kSTLmultimap:
986  case kSTLunorderedmap:
987  case kSTLunorderedmultimap:{
988  std::string keyName(ti.getAsString());
989  dictStream << " typedef " << keyName << " Value_t;" << std::endl
990  << " std::pair<Value_t const, " << tmplt_specialization->getTemplateArgs().get(1).getAsType().getAsString() << " > R__t3(R__t,R__t2);" << std::endl
991  << " R__stl.insert(R__t3);" << std::endl;
992  //fprintf(fp, " R__stl.insert(%s::value_type(R__t,R__t2));\n",stlType.c_str());
993  break;
994  }
995  case kSTLset:
996  case kSTLunorderedset:
998  case kSTLmultiset:
999  dictStream << " R__stl.insert(R__t);" << std::endl;
1000  break;
1001  case kSTLvector:
1002  case kSTLlist:
1003  case kSTLdeque:
1004  dictStream << " R__stl.push_back(R__t);" << std::endl;
1005  break;
1006  case kSTLforwardlist:
1007  dictStream << " R__stl.push_front(R__t);" << std::endl;
1008  break;
1009  default:
1010  assert(0);
1011  }
1012  dictStream << " }" << std::endl
1013  << " }" << std::endl;
1014  if (isArr) dictStream << " }" << std::endl;
1015 
1016  } else {
1017 
1018  // create write code
1019  if (isArr) {
1020  dictStream << " for (Int_t R__l = 0; R__l < " << len << "; R__l++) {" << std::endl;
1021  }
1022  dictStream << " {" << std::endl;
1023  switch (pa) {
1024  case 0: //No pointer && No array
1025  dictStream << " " << stlType.c_str() << " &R__stl = " << stlName.c_str() << ";" << std::endl;
1026  break;
1027  case 1: //No pointer && array
1028  dictStream << " " << stlType.c_str() << " &R__stl = " << stlName.c_str() << "[R__l];" << std::endl;
1029  break;
1030  case 2: //pointer && No array
1031  dictStream << " " << stlType.c_str() << " &R__stl = **" << stlName.c_str() << ";" << std::endl;
1032  break;
1033  case 3: //pointer && array
1034  dictStream << " " << stlType.c_str() << " &R__stl = *" << stlName.c_str() << "[R__l];" << std::endl;
1035  break;
1036  }
1037 
1038  dictStream << " int R__n=int(R__stl.size());" << std::endl
1039  << " R__b << R__n;" << std::endl
1040  << " if(R__n) {" << std::endl;
1041 
1042  if (tcl1) {
1043  dictStream << " TClass *R__tcl1 = TBuffer::GetClass(typeid(" << fulName1.c_str() << "));" << std::endl
1044  << " if (R__tcl1==0) {" << std::endl
1045  << " Error(\"" << stlName.c_str() << " streamer\",\"Missing the TClass object for "
1046  << fulName1.c_str() << "!\");" << std::endl
1047  << " return;" << std::endl
1048  << " }" << std::endl;
1049  }
1050  if (tcl2) {
1051  dictStream << " TClass *R__tcl2 = TBuffer::GetClass(typeid(" << fulName2.c_str() << "));" << std::endl
1052  << " if (R__tcl2==0) {" << std::endl
1053  << " Error(\"" << stlName.c_str() << "streamer\",\"Missing the TClass object for " << fulName2.c_str() << "!\");" << std::endl
1054  << " return;" << std::endl
1055  << " }" << std::endl;
1056  }
1057 
1058  dictStream << " " << stlType.c_str() << "::iterator R__k;" << std::endl
1059  << " for (R__k = R__stl.begin(); R__k != R__stl.end(); ++R__k) {" << std::endl;
1060  if (stltype == kSTLmap || stltype == kSTLmultimap) {
1061  const clang::TemplateArgument &arg1(tmplt_specialization->getTemplateArgs().get(1));
1062  clang::QualType tmplti = arg1.getAsType();
1063  ROOT::TMetaUtils::ElementStreamer(dictStream, m, ti, "((*R__k).first )", rwmode, interp, tcl1);
1064  ROOT::TMetaUtils::ElementStreamer(dictStream, m, tmplti, "((*R__k).second)", rwmode, interp, tcl2);
1065  } else {
1066  ROOT::TMetaUtils::ElementStreamer(dictStream, m, ti, "(*R__k)" , rwmode, interp, tcl1);
1067  }
1068 
1069  dictStream << " }" << std::endl
1070  << " }" << std::endl
1071  << " }" << std::endl;
1072  if (isArr) dictStream << " }" << std::endl;
1073  }
1074  return 1;
1075 }
1076 
1077 ////////////////////////////////////////////////////////////////////////////////
1078 /// Create Streamer code for a standard string object. Returns 1 if data
1079 /// member was a standard string and if Streamer code has been created,
1080 /// 0 otherwise.
1081 
1082 int STLStringStreamer(const clang::FieldDecl &m, int rwmode, std::ostream &dictStream)
1083 {
1084  std::string mTypenameStr;
1085  ROOT::TMetaUtils::GetQualifiedName(mTypenameStr, m.getType(), m);
1086  // Note: here we could to a direct type comparison!
1087  const char *mTypeName = ROOT::TMetaUtils::ShortTypeName(mTypenameStr.c_str());
1088  if (!strcmp(mTypeName, "string")) {
1089 
1090  std::string fieldname = m.getName().str();
1091  if (rwmode == 0) {
1092  // create read mode
1093  if (m.getType()->isConstantArrayType()) {
1094  if (m.getType().getTypePtr()->getArrayElementTypeNoTypeQual()->isPointerType()) {
1095  dictStream << "// Array of pointer to std::string are not supported (" << fieldname << "\n";
1096  } else {
1097  std::stringstream fullIdx;
1098  const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(m.getType().getTypePtr());
1099  int dim = 0;
1100  while (arrayType) {
1101  dictStream << " for (int R__i" << dim << "=0; R__i" << dim << "<"
1102  << arrayType->getSize().getLimitedValue() << "; ++R__i" << dim << " )" << std::endl;
1103  fullIdx << "[R__i" << dim << "]";
1104  arrayType = llvm::dyn_cast<clang::ConstantArrayType>(arrayType->getArrayElementTypeNoTypeQual());
1105  ++dim;
1106  }
1107  dictStream << " { TString R__str; R__str.Streamer(R__b); "
1108  << fieldname << fullIdx.str() << " = R__str.Data();}" << std::endl;
1109  }
1110  } else {
1111  dictStream << " { TString R__str; R__str.Streamer(R__b); ";
1112  if (m.getType()->isPointerType())
1113  dictStream << "if (*" << fieldname << ") delete *" << fieldname << "; (*"
1114  << fieldname << " = new string(R__str.Data())); }" << std::endl;
1115  else
1116  dictStream << fieldname << " = R__str.Data(); }" << std::endl;
1117  }
1118  } else {
1119  // create write mode
1120  if (m.getType()->isPointerType())
1121  dictStream << " { TString R__str; if (*" << fieldname << ") R__str = (*"
1122  << fieldname << ")->c_str(); R__str.Streamer(R__b);}" << std::endl;
1123  else if (m.getType()->isConstantArrayType()) {
1124  std::stringstream fullIdx;
1125  const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(m.getType().getTypePtr());
1126  int dim = 0;
1127  while (arrayType) {
1128  dictStream << " for (int R__i" << dim << "=0; R__i" << dim << "<"
1129  << arrayType->getSize().getLimitedValue() << "; ++R__i" << dim << " )" << std::endl;
1130  fullIdx << "[R__i" << dim << "]";
1131  arrayType = llvm::dyn_cast<clang::ConstantArrayType>(arrayType->getArrayElementTypeNoTypeQual());
1132  ++dim;
1133  }
1134  dictStream << " { TString R__str(" << fieldname << fullIdx.str() << ".c_str()); R__str.Streamer(R__b);}" << std::endl;
1135  } else
1136  dictStream << " { TString R__str = " << fieldname << ".c_str(); R__str.Streamer(R__b);}" << std::endl;
1137  }
1138  return 1;
1139  }
1140  return 0;
1141 }
1142 
1143 ////////////////////////////////////////////////////////////////////////////////
1144 
1145 bool isPointerToPointer(const clang::FieldDecl &m)
1146 {
1147  if (m.getType()->isPointerType()) {
1148  if (m.getType()->getPointeeType()->isPointerType()) {
1149  return true;
1150  }
1151  }
1152  return false;
1153 }
1154 
1155 ////////////////////////////////////////////////////////////////////////////////
1156 /// Write "[0]" for all but the 1st dimension.
1157 
1158 void WriteArrayDimensions(const clang::QualType &type, std::ostream &dictStream)
1159 {
1160  const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(type.getTypePtr());
1161  if (arrayType) {
1162  arrayType = llvm::dyn_cast<clang::ConstantArrayType>(arrayType->getArrayElementTypeNoTypeQual());
1163  while (arrayType) {
1164  dictStream << "[0]";
1165  arrayType = llvm::dyn_cast<clang::ConstantArrayType>(arrayType->getArrayElementTypeNoTypeQual());
1166  }
1167  }
1168 }
1169 
1170 ////////////////////////////////////////////////////////////////////////////////
1171 /// Write the code to set the class name and the initialization object.
1172 
1173 void WriteClassFunctions(const clang::CXXRecordDecl *cl, std::ostream &dictStream, bool autoLoad = false)
1174 {
1175  bool add_template_keyword = ROOT::TMetaUtils::NeedTemplateKeyword(cl);
1176 
1177  string fullname;
1178  string clsname;
1179  string nsname;
1180  int enclSpaceNesting = 0;
1181 
1182  if (ROOT::TMetaUtils::GetNameWithinNamespace(fullname, clsname, nsname, cl)) {
1183  enclSpaceNesting = ROOT::TMetaUtils::WriteNamespaceHeader(dictStream, cl);
1184  }
1185 
1186  if (autoLoad)
1187  dictStream << "#include \"TInterpreter.h\"\n";
1188 
1189  dictStream << "//_______________________________________"
1190  << "_______________________________________" << std::endl;
1191  if (add_template_keyword) dictStream << "template <> ";
1192  dictStream << "atomic_TClass_ptr " << clsname << "::fgIsA(0); // static to hold class pointer" << std::endl
1193  << std::endl
1194 
1195  << "//_______________________________________"
1196  << "_______________________________________" << std::endl;
1197  if (add_template_keyword) dictStream << "template <> ";
1198  dictStream << "const char *" << clsname << "::Class_Name()" << std::endl << "{" << std::endl
1199  << " return \"" << fullname << "\";" << std::endl << "}" << std::endl << std::endl;
1200 
1201  dictStream << "//_______________________________________"
1202  << "_______________________________________" << std::endl;
1203  if (add_template_keyword) dictStream << "template <> ";
1204  dictStream << "const char *" << clsname << "::ImplFileName()" << std::endl << "{" << std::endl
1205  << " return ::ROOT::GenerateInitInstanceLocal((const ::" << fullname
1206  << "*)0x0)->GetImplFileName();" << std::endl << "}" << std::endl << std::endl
1207 
1208  << "//_______________________________________"
1209  << "_______________________________________" << std::endl;
1210  if (add_template_keyword) dictStream << "template <> ";
1211  dictStream << "int " << clsname << "::ImplFileLine()" << std::endl << "{" << std::endl
1212  << " return ::ROOT::GenerateInitInstanceLocal((const ::" << fullname
1213  << "*)0x0)->GetImplFileLine();" << std::endl << "}" << std::endl << std::endl
1214 
1215  << "//_______________________________________"
1216  << "_______________________________________" << std::endl;
1217  if (add_template_keyword) dictStream << "template <> ";
1218  dictStream << "TClass *" << clsname << "::Dictionary()" << std::endl << "{" << std::endl;
1219 
1220  // Trigger autoloading if dictionary is split
1221  if (autoLoad)
1222  dictStream << " gInterpreter->AutoLoad(\"" << fullname << "\");\n";
1223  dictStream << " fgIsA = ::ROOT::GenerateInitInstanceLocal((const ::" << fullname
1224  << "*)0x0)->GetClass();" << std::endl
1225  << " return fgIsA;\n"
1226  << "}" << std::endl << std::endl
1227 
1228  << "//_______________________________________"
1229  << "_______________________________________" << std::endl;
1230  if (add_template_keyword) dictStream << "template <> ";
1231  dictStream << "TClass *" << clsname << "::Class()" << std::endl << "{" << std::endl;
1232  if (autoLoad) {
1233  dictStream << " Dictionary();\n";
1234  } else {
1235  dictStream << " if (!fgIsA.load()) { R__LOCKGUARD(gInterpreterMutex); fgIsA = ::ROOT::GenerateInitInstanceLocal((const ::";
1236  dictStream << fullname << "*)0x0)->GetClass(); }" << std::endl;
1237  }
1238  dictStream << " return fgIsA;" << std::endl
1239  << "}" << std::endl << std::endl;
1240 
1241  while (enclSpaceNesting) {
1242  dictStream << "} // namespace " << nsname << std::endl;
1243  --enclSpaceNesting;
1244  }
1245 }
1246 
1247 ////////////////////////////////////////////////////////////////////////////////
1248 /// Write the code to initialize the namespace name and the initialization object.
1249 
1250 void WriteNamespaceInit(const clang::NamespaceDecl *cl,
1251  cling::Interpreter &interp,
1252  std::ostream &dictStream)
1253 {
1254  if (cl->isAnonymousNamespace()) {
1255  // Don't write a GenerateInitInstance for the anonymous namespaces.
1256  return;
1257  }
1258 
1259  // coverity[fun_call_w_exception] - that's just fine.
1260  string classname = ROOT::TMetaUtils::GetQualifiedName(*cl).c_str();
1261  string mappedname;
1262  TMetaUtils::GetCppName(mappedname, classname.c_str());
1263 
1264  int nesting = 0;
1265  // We should probably unwind the namespace to properly nest it.
1266  if (classname != "ROOT") {
1267  nesting = ROOT::TMetaUtils::WriteNamespaceHeader(dictStream,cl);
1268  }
1269 
1270  dictStream << " namespace ROOT {" << std::endl;
1271 
1272 #if !defined(R__AIX)
1273  dictStream << " inline ::ROOT::TGenericClassInfo *GenerateInitInstance();" << std::endl;
1274 #endif
1275 
1276  if (!Namespace__HasMethod(cl, "Dictionary", interp))
1277  dictStream << " static TClass *" << mappedname.c_str() << "_Dictionary();" << std::endl;
1278  dictStream << std::endl
1279 
1280  << " // Function generating the singleton type initializer" << std::endl
1281 
1282 #if !defined(R__AIX)
1283  << " inline ::ROOT::TGenericClassInfo *GenerateInitInstance()" << std::endl
1284  << " {" << std::endl
1285 #else
1286  << " ::ROOT::TGenericClassInfo *GenerateInitInstance()" << std::endl
1287  << " {" << std::endl
1288 #endif
1289 
1290  << " static ::ROOT::TGenericClassInfo " << std::endl
1291 
1292  << " instance(\"" << classname.c_str() << "\", ";
1293 
1294  if (Namespace__HasMethod(cl, "Class_Version", interp)) {
1295  dictStream << "::" << classname.c_str() << "::Class_Version(), ";
1296  } else {
1297  dictStream << "0 /*version*/, ";
1298  }
1299 
1300  std::string filename = ROOT::TMetaUtils::GetFileName(*cl, interp);
1301  for (unsigned int i = 0; i < filename.length(); i++) {
1302  if (filename[i] == '\\') filename[i] = '/';
1303  }
1304  dictStream << "\"" << filename << "\", " << ROOT::TMetaUtils::GetLineNumber(cl) << "," << std::endl
1305  << " ::ROOT::Internal::DefineBehavior((void*)0,(void*)0)," << std::endl
1306  << " ";
1307 
1308  if (Namespace__HasMethod(cl, "Dictionary", interp)) {
1309  dictStream << "&::" << classname.c_str() << "::Dictionary, ";
1310  } else {
1311  dictStream << "&" << mappedname.c_str() << "_Dictionary, ";
1312  }
1313 
1314  dictStream << 0 << ");" << std::endl
1315 
1316  << " return &instance;" << std::endl
1317  << " }" << std::endl
1318  << " // Insure that the inline function is _not_ optimized away by the compiler\n"
1319  << " ::ROOT::TGenericClassInfo *(*_R__UNIQUE_DICT_(InitFunctionKeeper))() = &GenerateInitInstance; " << std::endl
1320  << " // Static variable to force the class initialization" << std::endl
1321  // must be one long line otherwise R__UseDummy does not work
1322  << " static ::ROOT::TGenericClassInfo *_R__UNIQUE_DICT_(Init) = GenerateInitInstance();"
1323  << " R__UseDummy(_R__UNIQUE_DICT_(Init));" << std::endl;
1324 
1325  if (!Namespace__HasMethod(cl, "Dictionary", interp)) {
1326  dictStream << std::endl << " // Dictionary for non-ClassDef classes" << std::endl
1327  << " static TClass *" << mappedname.c_str() << "_Dictionary() {" << std::endl
1328  << " return GenerateInitInstance()->GetClass();" << std::endl
1329  << " }" << std::endl << std::endl;
1330  }
1331 
1332  dictStream << " }" << std::endl;
1333  while (nesting--) {
1334  dictStream << "}" << std::endl;
1335  }
1336  dictStream << std::endl;
1337 }
1338 
1339 ////////////////////////////////////////////////////////////////////////////////
1340 /// GrabIndex returns a static string (so use it or copy it immediately, do not
1341 /// call GrabIndex twice in the same expression) containing the size of the
1342 /// array data member.
1343 /// In case of error, or if the size is not specified, GrabIndex returns 0.
1344 
1345 llvm::StringRef GrabIndex(const clang::FieldDecl &member, int printError)
1346 {
1347  int error;
1348  llvm::StringRef where;
1349 
1350  llvm::StringRef index = ROOT::TMetaUtils::DataMemberInfo__ValidArrayIndex(member, &error, &where);
1351  if (index.size() == 0 && printError) {
1352  const char *errorstring;
1353  switch (error) {
1354  case TMetaUtils::NOT_INT:
1355  errorstring = "is not an integer";
1356  break;
1357  case TMetaUtils::NOT_DEF:
1358  errorstring = "has not been defined before the array";
1359  break;
1361  errorstring = "is a private member of a parent class";
1362  break;
1363  case TMetaUtils::UNKNOWN:
1364  errorstring = "is not known";
1365  break;
1366  default:
1367  errorstring = "UNKNOWN ERROR!!!!";
1368  }
1369 
1370  if (where.size() == 0) {
1371  ROOT::TMetaUtils::Error(0, "*** Datamember %s::%s: no size indication!\n",
1372  member.getParent()->getName().str().c_str(), member.getName().str().c_str());
1373  } else {
1374  ROOT::TMetaUtils::Error(0, "*** Datamember %s::%s: size of array (%s) %s!\n",
1375  member.getParent()->getName().str().c_str(), member.getName().str().c_str(), where.str().c_str(), errorstring);
1376  }
1377  }
1378  return index;
1379 }
1380 
1381 ////////////////////////////////////////////////////////////////////////////////
1382 
1384  const cling::Interpreter &interp,
1385  const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt,
1386  std::ostream &dictStream)
1387 {
1388  const clang::CXXRecordDecl *clxx = llvm::dyn_cast<clang::CXXRecordDecl>(cl.GetRecordDecl());
1389  if (clxx == 0) return;
1390 
1391  bool add_template_keyword = ROOT::TMetaUtils::NeedTemplateKeyword(clxx);
1392 
1393  string fullname;
1394  string clsname;
1395  string nsname;
1396  int enclSpaceNesting = 0;
1397 
1398  if (ROOT::TMetaUtils::GetNameWithinNamespace(fullname, clsname, nsname, clxx)) {
1399  enclSpaceNesting = ROOT::TMetaUtils::WriteNamespaceHeader(dictStream, cl);
1400  }
1401 
1402  dictStream << "//_______________________________________"
1403  << "_______________________________________" << std::endl;
1404  if (add_template_keyword) dictStream << "template <> ";
1405  dictStream << "void " << clsname << "::Streamer(TBuffer &R__b)" << std::endl << "{" << std::endl
1406  << " // Stream an object of class " << fullname << "." << std::endl << std::endl;
1407 
1408  // In case of VersionID<=0 write dummy streamer only calling
1409  // its base class Streamer(s). If no base class(es) let Streamer
1410  // print error message, i.e. this Streamer should never have been called.
1411  int version = ROOT::TMetaUtils::GetClassVersion(clxx, interp);
1412  if (version <= 0) {
1413  // We also need to look at the base classes.
1414  int basestreamer = 0;
1415  for (clang::CXXRecordDecl::base_class_const_iterator iter = clxx->bases_begin(), end = clxx->bases_end();
1416  iter != end;
1417  ++iter) {
1418  if (ROOT::TMetaUtils::ClassInfo__HasMethod(iter->getType()->getAsCXXRecordDecl(), "Streamer", interp)) {
1419  string base_fullname;
1420  ROOT::TMetaUtils::GetQualifiedName(base_fullname, * iter->getType()->getAsCXXRecordDecl());
1421 
1422  if (strstr(base_fullname.c_str(), "::")) {
1423  // there is a namespace involved, trigger MS VC bug workaround
1424  dictStream << " //This works around a msvc bug and should be harmless on other platforms" << std::endl
1425  << " typedef " << base_fullname << " baseClass" << basestreamer << ";" << std::endl
1426  << " baseClass" << basestreamer << "::Streamer(R__b);" << std::endl;
1427  } else {
1428  dictStream << " " << base_fullname << "::Streamer(R__b);" << std::endl;
1429  }
1430  basestreamer++;
1431  }
1432  }
1433  if (!basestreamer) {
1434  dictStream << " ::Error(\"" << fullname << "::Streamer\", \"version id <=0 in ClassDef,"
1435  " dummy Streamer() called\"); if (R__b.IsReading()) { }" << std::endl;
1436  }
1437  dictStream << "}" << std::endl << std::endl;
1438  while (enclSpaceNesting) {
1439  dictStream << "} // namespace " << nsname.c_str() << std::endl;
1440  --enclSpaceNesting;
1441  }
1442  return;
1443  }
1444 
1445  // loop twice: first time write reading code, second time writing code
1446  string classname = fullname;
1447  if (strstr(fullname.c_str(), "::")) {
1448  // there is a namespace involved, trigger MS VC bug workaround
1449  dictStream << " //This works around a msvc bug and should be harmless on other platforms" << std::endl
1450  << " typedef ::" << fullname << " thisClass;" << std::endl;
1451  classname = "thisClass";
1452  }
1453  for (int i = 0; i < 2; i++) {
1454 
1455  int decli = 0;
1456 
1457  if (i == 0) {
1458  dictStream << " UInt_t R__s, R__c;" << std::endl;
1459  dictStream << " if (R__b.IsReading()) {" << std::endl;
1460  dictStream << " Version_t R__v = R__b.ReadVersion(&R__s, &R__c); if (R__v) { }" << std::endl;
1461  } else {
1462  dictStream << " R__b.CheckByteCount(R__s, R__c, " << classname.c_str() << "::IsA());" << std::endl;
1463  dictStream << " } else {" << std::endl;
1464  dictStream << " R__c = R__b.WriteVersion(" << classname.c_str() << "::IsA(), kTRUE);" << std::endl;
1465  }
1466 
1467  // Stream base class(es) when they have the Streamer() method
1468  int base = 0;
1469  for (clang::CXXRecordDecl::base_class_const_iterator iter = clxx->bases_begin(), end = clxx->bases_end();
1470  iter != end;
1471  ++iter) {
1472  if (ROOT::TMetaUtils::ClassInfo__HasMethod(iter->getType()->getAsCXXRecordDecl(), "Streamer", interp)) {
1473  string base_fullname;
1474  ROOT::TMetaUtils::GetQualifiedName(base_fullname, * iter->getType()->getAsCXXRecordDecl());
1475 
1476  if (strstr(base_fullname.c_str(), "::")) {
1477  // there is a namespace involved, trigger MS VC bug workaround
1478  dictStream << " //This works around a msvc bug and should be harmless on other platforms" << std::endl
1479  << " typedef " << base_fullname << " baseClass" << base << ";" << std::endl
1480  << " baseClass" << base << "::Streamer(R__b);" << std::endl;
1481  ++base;
1482  } else {
1483  dictStream << " " << base_fullname << "::Streamer(R__b);" << std::endl;
1484  }
1485  }
1486  }
1487  // Stream data members
1488  // Loop over the non static data member.
1489  for (clang::RecordDecl::field_iterator field_iter = clxx->field_begin(), end = clxx->field_end();
1490  field_iter != end;
1491  ++field_iter) {
1492  const char *comment = ROOT::TMetaUtils::GetComment(**field_iter).data();
1493 
1494  clang::QualType type = field_iter->getType();
1495  std::string type_name = type.getAsString(clxx->getASTContext().getPrintingPolicy());
1496 
1497  const clang::Type *underling_type = ROOT::TMetaUtils::GetUnderlyingType(type);
1498 
1499  // we skip:
1500  // - static members
1501  // - members with an ! as first character in the title (comment) field
1502 
1503  //special case for Float16_t
1504  int isFloat16 = 0;
1505  if (strstr(type_name.c_str(), "Float16_t")) isFloat16 = 1;
1506 
1507  //special case for Double32_t
1508  int isDouble32 = 0;
1509  if (strstr(type_name.c_str(), "Double32_t")) isDouble32 = 1;
1510 
1511  // No need to test for static, there are not in this list.
1512  if (strncmp(comment, "!", 1)) {
1513 
1514  // fundamental type: short, int, long, etc....
1515  if (underling_type->isFundamentalType() || underling_type->isEnumeralType()) {
1516  if (type.getTypePtr()->isConstantArrayType() &&
1517  type.getTypePtr()->getArrayElementTypeNoTypeQual()->isPointerType()) {
1518  const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(type.getTypePtr());
1519  int s = GetFullArrayLength(arrayType);
1520 
1521  if (!decli) {
1522  dictStream << " int R__i;" << std::endl;
1523  decli = 1;
1524  }
1525  dictStream << " for (R__i = 0; R__i < " << s << "; R__i++)" << std::endl;
1526  if (i == 0) {
1527  ROOT::TMetaUtils::Error(0, "*** Datamember %s::%s: array of pointers to fundamental type (need manual intervention)\n", fullname.c_str(), field_iter->getName().str().c_str());
1528  dictStream << " ;//R__b.ReadArray(" << field_iter->getName().str() << ");" << std::endl;
1529  } else {
1530  dictStream << " ;//R__b.WriteArray(" << field_iter->getName().str() << ", __COUNTER__);" << std::endl;
1531  }
1532  } else if (type.getTypePtr()->isPointerType()) {
1533  llvm::StringRef indexvar = GrabIndex(**field_iter, i == 0);
1534  if (indexvar.size() == 0) {
1535  if (i == 0) {
1536  ROOT::TMetaUtils::Error(0, "*** Datamember %s::%s: pointer to fundamental type (need manual intervention)\n", fullname.c_str(), field_iter->getName().str().c_str());
1537  dictStream << " //R__b.ReadArray(" << field_iter->getName().str() << ");" << std::endl;
1538  } else {
1539  dictStream << " //R__b.WriteArray(" << field_iter->getName().str() << ", __COUNTER__);" << std::endl;
1540  }
1541  } else {
1542  if (i == 0) {
1543  dictStream << " delete [] " << field_iter->getName().str() << ";" << std::endl
1544  << " " << GetNonConstMemberName(**field_iter) << " = new "
1545  << ROOT::TMetaUtils::ShortTypeName(**field_iter) << "[" << indexvar.str() << "];" << std::endl;
1546  if (isFloat16) {
1547  dictStream << " R__b.ReadFastArrayFloat16(" << GetNonConstMemberName(**field_iter)
1548  << "," << indexvar.str() << ");" << std::endl;
1549  } else if (isDouble32) {
1550  dictStream << " R__b.ReadFastArrayDouble32(" << GetNonConstMemberName(**field_iter)
1551  << "," << indexvar.str() << ");" << std::endl;
1552  } else {
1553  dictStream << " R__b.ReadFastArray(" << GetNonConstMemberName(**field_iter)
1554  << "," << indexvar.str() << ");" << std::endl;
1555  }
1556  } else {
1557  if (isFloat16) {
1558  dictStream << " R__b.WriteFastArrayFloat16("
1559  << field_iter->getName().str() << "," << indexvar.str() << ");" << std::endl;
1560  } else if (isDouble32) {
1561  dictStream << " R__b.WriteFastArrayDouble32("
1562  << field_iter->getName().str() << "," << indexvar.str() << ");" << std::endl;
1563  } else {
1564  dictStream << " R__b.WriteFastArray("
1565  << field_iter->getName().str() << "," << indexvar.str() << ");" << std::endl;
1566  }
1567  }
1568  }
1569  } else if (type.getTypePtr()->isArrayType()) {
1570  if (i == 0) {
1571  if (type.getTypePtr()->getArrayElementTypeNoTypeQual()->isArrayType()) { // if (m.ArrayDim() > 1) {
1572  if (underling_type->isEnumeralType())
1573  dictStream << " R__b.ReadStaticArray((Int_t*)" << field_iter->getName().str() << ");" << std::endl;
1574  else {
1575  if (isFloat16) {
1576  dictStream << " R__b.ReadStaticArrayFloat16((" << ROOT::TMetaUtils::TrueName(**field_iter)
1577  << "*)" << field_iter->getName().str() << ");" << std::endl;
1578  } else if (isDouble32) {
1579  dictStream << " R__b.ReadStaticArrayDouble32((" << ROOT::TMetaUtils::TrueName(**field_iter)
1580  << "*)" << field_iter->getName().str() << ");" << std::endl;
1581  } else {
1582  dictStream << " R__b.ReadStaticArray((" << ROOT::TMetaUtils::TrueName(**field_iter)
1583  << "*)" << field_iter->getName().str() << ");" << std::endl;
1584  }
1585  }
1586  } else {
1587  if (underling_type->isEnumeralType()) {
1588  dictStream << " R__b.ReadStaticArray((Int_t*)" << field_iter->getName().str() << ");" << std::endl;
1589  } else {
1590  if (isFloat16) {
1591  dictStream << " R__b.ReadStaticArrayFloat16(" << field_iter->getName().str() << ");" << std::endl;
1592  } else if (isDouble32) {
1593  dictStream << " R__b.ReadStaticArrayDouble32(" << field_iter->getName().str() << ");" << std::endl;
1594  } else {
1595  dictStream << " R__b.ReadStaticArray((" << ROOT::TMetaUtils::TrueName(**field_iter)
1596  << "*)" << field_iter->getName().str() << ");" << std::endl;
1597  }
1598  }
1599  }
1600  } else {
1601  const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(type.getTypePtr());
1602  int s = GetFullArrayLength(arrayType);
1603 
1604  if (type.getTypePtr()->getArrayElementTypeNoTypeQual()->isArrayType()) {// if (m.ArrayDim() > 1) {
1605  if (underling_type->isEnumeralType())
1606  dictStream << " R__b.WriteArray((Int_t*)" << field_iter->getName().str() << ", "
1607  << s << ");" << std::endl;
1608  else if (isFloat16) {
1609  dictStream << " R__b.WriteArrayFloat16((" << ROOT::TMetaUtils::TrueName(**field_iter)
1610  << "*)" << field_iter->getName().str() << ", " << s << ");" << std::endl;
1611  } else if (isDouble32) {
1612  dictStream << " R__b.WriteArrayDouble32((" << ROOT::TMetaUtils::TrueName(**field_iter)
1613  << "*)" << field_iter->getName().str() << ", " << s << ");" << std::endl;
1614  } else {
1615  dictStream << " R__b.WriteArray((" << ROOT::TMetaUtils::TrueName(**field_iter)
1616  << "*)" << field_iter->getName().str() << ", " << s << ");" << std::endl;
1617  }
1618  } else {
1619  if (underling_type->isEnumeralType())
1620  dictStream << " R__b.WriteArray((Int_t*)" << field_iter->getName().str() << ", " << s << ");" << std::endl;
1621  else if (isFloat16) {
1622  dictStream << " R__b.WriteArrayFloat16(" << field_iter->getName().str() << ", " << s << ");" << std::endl;
1623  } else if (isDouble32) {
1624  dictStream << " R__b.WriteArrayDouble32(" << field_iter->getName().str() << ", " << s << ");" << std::endl;
1625  } else {
1626  dictStream << " R__b.WriteArray(" << field_iter->getName().str() << ", " << s << ");" << std::endl;
1627  }
1628  }
1629  }
1630  } else if (underling_type->isEnumeralType()) {
1631  if (i == 0) {
1632  dictStream << " void *ptr_" << field_iter->getName().str() << " = (void*)&" << field_iter->getName().str() << ";\n";
1633  dictStream << " R__b >> *reinterpret_cast<Int_t*>(ptr_" << field_iter->getName().str() << ");" << std::endl;
1634  } else
1635  dictStream << " R__b << (Int_t)" << field_iter->getName().str() << ";" << std::endl;
1636  } else {
1637  if (isFloat16) {
1638  if (i == 0)
1639  dictStream << " {float R_Dummy; R__b >> R_Dummy; " << GetNonConstMemberName(**field_iter)
1640  << "=Float16_t(R_Dummy);}" << std::endl;
1641  else
1642  dictStream << " R__b << float(" << GetNonConstMemberName(**field_iter) << ");" << std::endl;
1643  } else if (isDouble32) {
1644  if (i == 0)
1645  dictStream << " {float R_Dummy; R__b >> R_Dummy; " << GetNonConstMemberName(**field_iter)
1646  << "=Double32_t(R_Dummy);}" << std::endl;
1647  else
1648  dictStream << " R__b << float(" << GetNonConstMemberName(**field_iter) << ");" << std::endl;
1649  } else {
1650  if (i == 0)
1651  dictStream << " R__b >> " << GetNonConstMemberName(**field_iter) << ";" << std::endl;
1652  else
1653  dictStream << " R__b << " << GetNonConstMemberName(**field_iter) << ";" << std::endl;
1654  }
1655  }
1656  } else {
1657  // we have an object...
1658 
1659  // check if object is a standard string
1660  if (STLStringStreamer(**field_iter, i, dictStream))
1661  continue;
1662 
1663  // check if object is an STL container
1664  if (STLContainerStreamer(**field_iter, i, interp, normCtxt, dictStream))
1665  continue;
1666 
1667  // handle any other type of objects
1668  if (type.getTypePtr()->isConstantArrayType() &&
1669  type.getTypePtr()->getArrayElementTypeNoTypeQual()->isPointerType()) {
1670  const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(type.getTypePtr());
1671  int s = GetFullArrayLength(arrayType);
1672 
1673  if (!decli) {
1674  dictStream << " int R__i;" << std::endl;
1675  decli = 1;
1676  }
1677  dictStream << " for (R__i = 0; R__i < " << s << "; R__i++)" << std::endl;
1678  if (i == 0)
1679  dictStream << " R__b >> " << GetNonConstMemberName(**field_iter);
1680  else {
1681  if (ROOT::TMetaUtils::IsBase(**field_iter, "TObject", interp) && ROOT::TMetaUtils::IsBase(**field_iter, "TArray", interp))
1682  dictStream << " R__b << (TObject*)" << field_iter->getName().str();
1683  else
1684  dictStream << " R__b << " << GetNonConstMemberName(**field_iter);
1685  }
1686  WriteArrayDimensions(field_iter->getType(), dictStream);
1687  dictStream << "[R__i];" << std::endl;
1688  } else if (type.getTypePtr()->isPointerType()) {
1689  // This is always good. However, in case of a pointer
1690  // to an object that is guaranteed to be there and not
1691  // being referenced by other objects we could use
1692  // xx->Streamer(b);
1693  // Optimize this with control statement in title.
1694  if (isPointerToPointer(**field_iter)) {
1695  if (i == 0) {
1696  ROOT::TMetaUtils::Error(0, "*** Datamember %s::%s: pointer to pointer (need manual intervention)\n", fullname.c_str(), field_iter->getName().str().c_str());
1697  dictStream << " //R__b.ReadArray(" << field_iter->getName().str() << ");" << std::endl;
1698  } else {
1699  dictStream << " //R__b.WriteArray(" << field_iter->getName().str() << ", __COUNTER__);";
1700  }
1701  } else {
1702  if (ROOT::TMetaUtils::GetQualifiedName(*ROOT::TMetaUtils::GetUnderlyingType(field_iter->getType()), **field_iter) == "TClonesArray") {
1703  dictStream << " " << field_iter->getName().str() << "->Streamer(R__b);" << std::endl;
1704  } else {
1705  if (i == 0) {
1706  // The following:
1707  // if (strncmp(m.Title(),"->",2) != 0) fprintf(fp, " delete %s;\n", GetNonConstMemberName(**field_iter).c_str());
1708  // could be used to prevent a memory leak since the next statement could possibly create a new object.
1709  // In the TStreamerInfo based I/O we made the previous statement conditional on TStreamerInfo::CanDelete
1710  // to allow the user to prevent some inadvisable deletions. So we should be offering this flexibility
1711  // here to and should not (technically) rely on TStreamerInfo for it, so for now we leave it as is.
1712  // Note that the leak should happen from here only if the object is stored in an unsplit object
1713  // and either the user request an old branch or the streamer has been customized.
1714  dictStream << " R__b >> " << GetNonConstMemberName(**field_iter) << ";" << std::endl;
1715  } else {
1716  if (ROOT::TMetaUtils::IsBase(**field_iter, "TObject", interp) && ROOT::TMetaUtils::IsBase(**field_iter, "TArray", interp))
1717  dictStream << " R__b << (TObject*)" << field_iter->getName().str() << ";" << std::endl;
1718  else
1719  dictStream << " R__b << " << GetNonConstMemberName(**field_iter) << ";" << std::endl;
1720  }
1721  }
1722  }
1723  } else if (const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(type.getTypePtr())) {
1724  int s = GetFullArrayLength(arrayType);
1725 
1726  if (!decli) {
1727  dictStream << " int R__i;" << std::endl;
1728  decli = 1;
1729  }
1730  dictStream << " for (R__i = 0; R__i < " << s << "; R__i++)" << std::endl;
1731  std::string mTypeNameStr;
1732  ROOT::TMetaUtils::GetQualifiedName(mTypeNameStr, field_iter->getType(), **field_iter);
1733  const char *mTypeName = mTypeNameStr.c_str();
1734  const char *constwd = "const ";
1735  if (strncmp(constwd, mTypeName, strlen(constwd)) == 0) {
1736  mTypeName += strlen(constwd);
1737  dictStream << " const_cast< " << mTypeName << " &>(" << field_iter->getName().str();
1738  WriteArrayDimensions(field_iter->getType(), dictStream);
1739  dictStream << "[R__i]).Streamer(R__b);" << std::endl;
1740  } else {
1741  dictStream << " " << GetNonConstMemberName(**field_iter);
1742  WriteArrayDimensions(field_iter->getType(), dictStream);
1743  dictStream << "[R__i].Streamer(R__b);" << std::endl;
1744  }
1745  } else {
1746  if (ROOT::TMetaUtils::ClassInfo__HasMethod(ROOT::TMetaUtils::GetUnderlyingRecordDecl(field_iter->getType()), "Streamer", interp))
1747  dictStream << " " << GetNonConstMemberName(**field_iter) << ".Streamer(R__b);" << std::endl;
1748  else {
1749  dictStream << " R__b.StreamObject(&(" << field_iter->getName().str() << "),typeid("
1750  << field_iter->getName().str() << "));" << std::endl; //R__t.Streamer(R__b);\n");
1751  //VP if (i == 0)
1752  //VP Error(0, "*** Datamember %s::%s: object has no Streamer() method (need manual intervention)\n",
1753  //VP fullname, field_iter->getName().str());
1754  //VP fprintf(fp, " //%s.Streamer(R__b);\n", m.Name());
1755  }
1756  }
1757  }
1758  }
1759  }
1760  }
1761  dictStream << " R__b.SetByteCount(R__c, kTRUE);" << std::endl
1762  << " }" << std::endl
1763  << "}" << std::endl << std::endl;
1764 
1765  while (enclSpaceNesting) {
1766  dictStream << "} // namespace " << nsname.c_str() << std::endl;
1767  --enclSpaceNesting;
1768  }
1769 }
1770 
1771 ////////////////////////////////////////////////////////////////////////////////
1772 
1774  const cling::Interpreter &interp,
1775  const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt,
1776  std::ostream &dictStream)
1777 {
1778  // Write Streamer() method suitable for automatic schema evolution.
1779 
1780  const clang::CXXRecordDecl *clxx = llvm::dyn_cast<clang::CXXRecordDecl>(cl.GetRecordDecl());
1781  if (clxx == 0) return;
1782 
1783  bool add_template_keyword = ROOT::TMetaUtils::NeedTemplateKeyword(clxx);
1784 
1785  // We also need to look at the base classes.
1786  for (clang::CXXRecordDecl::base_class_const_iterator iter = clxx->bases_begin(), end = clxx->bases_end();
1787  iter != end;
1788  ++iter) {
1789  int k = ROOT::TMetaUtils::IsSTLContainer(*iter);
1790  if (k != 0) {
1791  Internal::RStl::Instance().GenerateTClassFor(iter->getType(), interp, normCtxt);
1792  }
1793  }
1794 
1795  string fullname;
1796  string clsname;
1797  string nsname;
1798  int enclSpaceNesting = 0;
1799 
1800  if (ROOT::TMetaUtils::GetNameWithinNamespace(fullname, clsname, nsname, clxx)) {
1801  enclSpaceNesting = ROOT::TMetaUtils::WriteNamespaceHeader(dictStream, cl);
1802  }
1803 
1804  dictStream << "//_______________________________________"
1805  << "_______________________________________" << std::endl;
1806  if (add_template_keyword) dictStream << "template <> ";
1807  dictStream << "void " << clsname << "::Streamer(TBuffer &R__b)" << std::endl
1808  << "{" << std::endl
1809  << " // Stream an object of class " << fullname << "." << std::endl << std::endl
1810  << " if (R__b.IsReading()) {" << std::endl
1811  << " R__b.ReadClassBuffer(" << fullname << "::Class(),this);" << std::endl
1812  << " } else {" << std::endl
1813  << " R__b.WriteClassBuffer(" << fullname << "::Class(),this);" << std::endl
1814  << " }" << std::endl
1815  << "}" << std::endl << std::endl;
1816 
1817  while (enclSpaceNesting) {
1818  dictStream << "} // namespace " << nsname << std::endl;
1819  --enclSpaceNesting;
1820  }
1821 }
1822 
1823 ////////////////////////////////////////////////////////////////////////////////
1824 
1826  const cling::Interpreter &interp,
1827  const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt,
1828  std::ostream &dictStream,
1829  bool isAutoStreamer)
1830 {
1831  if (isAutoStreamer) {
1832  WriteAutoStreamer(cl, interp, normCtxt, dictStream);
1833  } else {
1834  WriteStreamer(cl, interp, normCtxt, dictStream);
1835  }
1836 }
1837 
1838 ////////////////////////////////////////////////////////////////////////////////
1839 
1840 void GenerateLinkdef(llvm::cl::list<std::string> &InputFiles,
1841  std::string &code_for_parser)
1842 {
1843  code_for_parser += "#ifdef __CINT__\n\n";
1844  code_for_parser += "#pragma link off all globals;\n";
1845  code_for_parser += "#pragma link off all classes;\n";
1846  code_for_parser += "#pragma link off all functions;\n\n";
1847 
1848  for (std::string& arg : InputFiles) {
1849  char trail[3];
1850  int nostr = 0, noinp = 0, bcnt = 0, l = arg.length() - 1;
1851  for (int j = 0; j < 3; j++) {
1852  if (arg[l] == '-') {
1853  arg[l] = '\0';
1854  nostr = 1;
1855  l--;
1856  }
1857  if (arg[l] == '!') {
1858  arg[l] = '\0';
1859  noinp = 1;
1860  l--;
1861  }
1862  if (arg[l] == '+') {
1863  arg[l] = '\0';
1864  bcnt = 1;
1865  l--;
1866  }
1867  }
1868  if (nostr || noinp) {
1869  trail[0] = 0;
1870  if (nostr) strlcat(trail, "-", 3);
1871  if (noinp) strlcat(trail, "!", 3);
1872  }
1873  if (bcnt) {
1874  strlcpy(trail, "+", 3);
1875  if (nostr)
1876  ROOT::TMetaUtils::Error(0, "option + mutual exclusive with -\n");
1877  }
1878  llvm::SmallString<256> filestem = llvm::sys::path::filename(arg);
1879  llvm::sys::path::replace_extension(filestem, "");
1880 
1881  code_for_parser += "#pragma link C++ class ";
1882  code_for_parser += filestem.str().str();
1883  if (nostr || noinp || bcnt)
1884  code_for_parser += trail;
1885  code_for_parser += ";\n";
1886  }
1887 
1888  code_for_parser += "\n#endif\n";
1889 }
1890 
1891 ////////////////////////////////////////////////////////////////////////////////
1892 /// Find file name in path specified via -I statements to Cling.
1893 /// Return false if the file can not be found.
1894 /// If the file is found, set pname to the full path name and return true.
1895 
1896 bool Which(cling::Interpreter &interp, const char *fname, string &pname)
1897 {
1898  FILE *fp = 0;
1899 
1900 #ifdef WIN32
1901  static const char *fopenopts = "rb";
1902 #else
1903  static const char *fopenopts = "r";
1904 #endif
1905 
1906  pname = fname;
1907  fp = fopen(pname.c_str(), fopenopts);
1908  if (fp) {
1909  fclose(fp);
1910  return true;
1911  }
1912 
1913  llvm::SmallVector<std::string, 10> includePaths;//Why 10? Hell if I know.
1914  //false - no system header, false - with flags.
1915  interp.GetIncludePaths(includePaths, false, false);
1916 
1917  const size_t nPaths = includePaths.size();
1918  for (size_t i = 0; i < nPaths; i += 1 /* 2 */) {
1919 
1920  pname = includePaths[i].c_str() + gPathSeparator + fname;
1921 
1922  fp = fopen(pname.c_str(), fopenopts);
1923  if (fp) {
1924  fclose(fp);
1925  return true;
1926  }
1927  }
1928  pname = "";
1929  return false;
1930 }
1931 
1932 ////////////////////////////////////////////////////////////////////////////////
1933 /// If the argument starts with MODULE/inc, strip it
1934 /// to make it the name we can use in #includes.
1935 
1936 const char *CopyArg(const char *original)
1937 {
1938  if (!gBuildingROOT)
1939  return original;
1940 
1941  if (IsSelectionFile(original))
1942  return original;
1943 
1944  const char *inc = strstr(original, "\\inc\\");
1945  if (!inc)
1946  inc = strstr(original, "/inc/");
1947  if (inc && strlen(inc) > 5)
1948  return inc + 5;
1949  return original;
1950 }
1951 
1952 ////////////////////////////////////////////////////////////////////////////////
1953 /// Copy the command line argument, stripping MODULE/inc if
1954 /// necessary.
1955 
1956 void StrcpyArg(string &dest, const char *original)
1957 {
1958  dest = CopyArg(original);
1959 }
1960 
1961 ////////////////////////////////////////////////////////////////////////////////
1962 /// Write the extra header injected into the module:
1963 /// umbrella header if (umbrella) else content header.
1964 
1965 static bool InjectModuleUtilHeader(const char *argv0,
1966  TModuleGenerator &modGen,
1967  cling::Interpreter &interp,
1968  bool umbrella)
1969 {
1970  std::ostringstream out;
1971  if (umbrella) {
1972  // This will duplicate the -D,-U from clingArgs - but as they are surrounded
1973  // by #ifndef there is no problem here.
1974  modGen.WriteUmbrellaHeader(out);
1975  } else {
1976  modGen.WriteContentHeader(out);
1977  }
1978  if (interp.declare(out.str()) != cling::Interpreter::kSuccess) {
1979  const std::string &hdrName
1980  = umbrella ? modGen.GetUmbrellaName() : modGen.GetContentName();
1981  ROOT::TMetaUtils::Error(0, "%s: compilation failure (%s)\n", argv0,
1982  hdrName.c_str());
1983  return false;
1984  }
1985  return true;
1986 }
1987 
1988 ////////////////////////////////////////////////////////////////////////////////
1989 /// Write the AST of the given CompilerInstance to the given File while
1990 /// respecting the given isysroot.
1991 /// If module is not a null pointer, we only write the given module to the
1992 /// given file and not the whole AST.
1993 /// Returns true if the AST was successfully written.
1994 static bool WriteAST(StringRef fileName, clang::CompilerInstance *compilerInstance, StringRef iSysRoot,
1995  clang::Module *module = nullptr)
1996 {
1997  // From PCHGenerator and friends:
1998  llvm::SmallVector<char, 128> buffer;
1999  llvm::BitstreamWriter stream(buffer);
2000  clang::ASTWriter writer(stream, buffer, compilerInstance->getPCMCache(), /*Extensions=*/{});
2001  std::unique_ptr<llvm::raw_ostream> out =
2002  compilerInstance->createOutputFile(fileName, /*Binary=*/true,
2003  /*RemoveFileOnSignal=*/false, /*InFile*/ "",
2004  /*Extension=*/"", /*useTemporary=*/false,
2005  /*CreateMissingDirectories*/ false);
2006  if (!out) {
2007  ROOT::TMetaUtils::Error("WriteAST", "Couldn't open output stream to '%s'!\n", fileName.data());
2008  return false;
2009  }
2010 
2011  compilerInstance->getFrontendOpts().RelocatablePCH = true;
2012 
2013  writer.WriteAST(compilerInstance->getSema(), fileName, module, iSysRoot);
2014 
2015  // Write the generated bitstream to "Out".
2016  out->write(&buffer.front(), buffer.size());
2017 
2018  // Make sure it hits disk now.
2019  out->flush();
2020 
2021  return true;
2022 }
2023 
2024 ////////////////////////////////////////////////////////////////////////////////
2025 /// Generates a PCH from the given ModuleGenerator and CompilerInstance.
2026 /// Returns true iff the PCH was successfully generated.
2027 static bool GenerateAllDict(TModuleGenerator &modGen, clang::CompilerInstance *compilerInstance,
2028  const std::string &currentDirectory)
2029 {
2030  assert(modGen.IsPCH() && "modGen must be in PCH mode");
2031 
2032  std::string iSysRoot("/DUMMY_SYSROOT/include/");
2033  if (gBuildingROOT) iSysRoot = (currentDirectory + "/");
2034  return WriteAST(modGen.GetModuleFileName(), compilerInstance, iSysRoot);
2035 }
2036 
2037 ////////////////////////////////////////////////////////////////////////////////
2038 /// Includes all given headers in the interpreter. Returns true when we could
2039 /// include the headers and otherwise false on an error when including.
2040 static bool IncludeHeaders(const std::vector<std::string> &headers, cling::Interpreter &interpreter)
2041 {
2042  // If no headers are given, this is a no-op.
2043  if (headers.empty())
2044  return true;
2045 
2046  // Turn every header name into an include and parse it in the interpreter.
2047  std::stringstream includes;
2048  for (const std::string &header : headers) {
2049  includes << "#include \"" << header << "\"\n";
2050  }
2051  std::string includeListStr = includes.str();
2052  auto result = interpreter.declare(includeListStr);
2053  return result == cling::Interpreter::CompilationResult::kSuccess;
2054 }
2055 
2056 
2057 ////////////////////////////////////////////////////////////////////////////////
2058 
2059 void AddPlatformDefines(std::vector<std::string> &clingArgs)
2060 {
2061  char platformDefines[64] = {0};
2062 #ifdef __INTEL_COMPILER
2063  snprintf(platformDefines, 64, "-DG__INTEL_COMPILER=%ld", (long)__INTEL_COMPILER);
2064  clingArgs.push_back(platformDefines);
2065 #endif
2066 #ifdef __xlC__
2067  snprintf(platformDefines, 64, "-DG__xlC=%ld", (long)__xlC__);
2068  clingArgs.push_back(platformDefines);
2069 #endif
2070 #ifdef __GNUC__
2071  snprintf(platformDefines, 64, "-DG__GNUC=%ld", (long)__GNUC__);
2072  snprintf(platformDefines, 64, "-DG__GNUC_VER=%ld", (long)__GNUC__ * 1000 + __GNUC_MINOR__);
2073  clingArgs.push_back(platformDefines);
2074 #endif
2075 #ifdef __GNUC_MINOR__
2076  snprintf(platformDefines, 64, "-DG__GNUC_MINOR=%ld", (long)__GNUC_MINOR__);
2077  clingArgs.push_back(platformDefines);
2078 #endif
2079 #ifdef __HP_aCC
2080  snprintf(platformDefines, 64, "-DG__HP_aCC=%ld", (long)__HP_aCC);
2081  clingArgs.push_back(platformDefines);
2082 #endif
2083 #ifdef __sun
2084  snprintf(platformDefines, 64, "-DG__sun=%ld", (long)__sun);
2085  clingArgs.push_back(platformDefines);
2086 #endif
2087 #ifdef __SUNPRO_CC
2088  snprintf(platformDefines, 64, "-DG__SUNPRO_CC=%ld", (long)__SUNPRO_CC);
2089  clingArgs.push_back(platformDefines);
2090 #endif
2091 #ifdef _STLPORT_VERSION
2092  // stlport version, used on e.g. SUN
2093  snprintf(platformDefines, 64, "-DG__STLPORT_VERSION=%ld", (long)_STLPORT_VERSION);
2094  clingArgs.push_back(platformDefines);
2095 #endif
2096 #ifdef __ia64__
2097  snprintf(platformDefines, 64, "-DG__ia64=%ld", (long)__ia64__);
2098  clingArgs.push_back(platformDefines);
2099 #endif
2100 #ifdef __x86_64__
2101  snprintf(platformDefines, 64, "-DG__x86_64=%ld", (long)__x86_64__);
2102  clingArgs.push_back(platformDefines);
2103 #endif
2104 #ifdef __i386__
2105  snprintf(platformDefines, 64, "-DG__i386=%ld", (long)__i386__);
2106  clingArgs.push_back(platformDefines);
2107 #endif
2108 #ifdef __arm__
2109  snprintf(platformDefines, 64, "-DG__arm=%ld", (long)__arm__);
2110  clingArgs.push_back(platformDefines);
2111 #endif
2112 #ifdef _WIN32
2113  snprintf(platformDefines, 64, "-DG__WIN32=%ld", (long)_WIN32);
2114  clingArgs.push_back(platformDefines);
2115 #else
2116 # ifdef WIN32
2117  snprintf(platformDefines, 64, "-DG__WIN32=%ld", (long)WIN32);
2118  clingArgs.push_back(platformDefines);
2119 # endif
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(0, "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(0, "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) ProcessAndAppendIfNotThere(fwdDeclaration, fwdDeclarationsList, availableFwdDecls);
2485  }
2486 
2487 
2488  // Loop on attributes, if rootmap=false, don't put it in the list!
2489  for (auto ait = rDecl->attr_begin(); ait != rDecl->attr_end(); ++ait) {
2490  if (0 == ROOT::TMetaUtils::extractPropertyNameVal(*ait, attrName, attrValue) &&
2491  attrName == "rootmap" &&
2492  attrValue == "false") {
2493  attrName = attrValue = "";
2494  isClassSelected = false;
2495  break;
2496  }
2497  }
2498  if (isClassSelected) {
2499  // Now, check if this is an internal class. If yes, we check the name of the outermost one
2500  // This is because of ROOT-6517. On the other hand, we exclude from this treatment
2501  // classes which are template instances which are nested in classes. For example:
2502  // class A{
2503  // class B{};
2504  // };
2505  // selection: <class name="A::B" />
2506  // Will result in a rootmap entry like "class A"
2507  // On the other hand, taking
2508  // class A{
2509  // public:
2510  // template <class T> class B{};
2511  // };
2512  // selection: <class name="A::B<int>" />
2513  // Would result in an entry like "class A::B<int>"
2514  std::string outerMostClassName;
2515  GetMostExternalEnclosingClassName(*rDecl, outerMostClassName, interpreter);
2516  if (!outerMostClassName.empty() &&
2517  !llvm::isa<clang::ClassTemplateSpecializationDecl>(rDecl) &&
2518  classesSet.insert(outerMostClassName).second &&
2519  outerMostClassesSet.insert(outerMostClassName).second) {
2520  classesListForRootmap.push_back(outerMostClassName);
2521  } else {
2522  classesListForRootmap.push_back(normalizedName);
2523  if (reqName != nullptr && 0 != strcmp(reqName, "") && reqName != normalizedName) {
2524  classesListForRootmap.push_back(reqName);
2525  }
2526 
2527  // Also register typeinfo::name(), unless we have pseudo-strong typedefs:
2528  if (normalizedName.find("Double32_t") == std::string::npos
2529  && normalizedName.find("Float16_t") == std::string::npos) {
2530  std::unique_ptr<clang::MangleContext> mangleCtx(rDecl->getASTContext().createMangleContext());
2531  std::string mangledName;
2532  {
2533  llvm::raw_string_ostream sstr(mangledName);
2534  if (const clang::TypeDecl* TD = llvm::dyn_cast<clang::TypeDecl>(rDecl)) {
2535  mangleCtx->mangleCXXRTTI(clang::QualType(TD->getTypeForDecl(), 0), sstr);
2536  }
2537  }
2538  if (!mangledName.empty()) {
2539  int errDemangle = 0;
2540 #ifdef WIN32
2541  if (mangledName[0] == '\01')
2542  mangledName.erase(0, 1);
2543  char *demangledTIName = TClassEdit::DemangleName(mangledName.c_str(), errDemangle);
2544  if (!errDemangle && demangledTIName) {
2545  static const char typeinfoNameFor[] = " `RTTI Type Descriptor'";
2546  if (strstr(demangledTIName, typeinfoNameFor)) {
2547  std::string demangledName = demangledTIName;
2548  demangledName.erase(demangledName.end() - strlen(typeinfoNameFor), demangledName.end());
2549 #else
2550  char* demangledTIName = TClassEdit::DemangleName(mangledName.c_str(), errDemangle);
2551  if (!errDemangle && demangledTIName) {
2552  static const char typeinfoNameFor[] = "typeinfo for ";
2553  if (!strncmp(demangledTIName, typeinfoNameFor, strlen(typeinfoNameFor))) {
2554  std::string demangledName = demangledTIName + strlen(typeinfoNameFor);
2555 #endif
2556  // See the operations in TCling::AutoLoad(type_info)
2558  splitname.ShortType(demangledName, TClassEdit::kDropStlDefault | TClassEdit::kDropStd);
2559 
2560  if (demangledName != normalizedName && (!reqName || demangledName != reqName)) {
2561  classesListForRootmap.push_back(demangledName);
2562  } // if demangledName != other name
2563  } else {
2564 #ifdef WIN32
2565  ROOT::TMetaUtils::Error("ExtractClassesListAndDeclLines",
2566  "Demangled typeinfo name '%s' does not contain `RTTI Type Descriptor'\n",
2567  demangledTIName);
2568 #else
2569  ROOT::TMetaUtils::Error("ExtractClassesListAndDeclLines",
2570  "Demangled typeinfo name '%s' does not start with 'typeinfo for'\n",
2571  demangledTIName);
2572 #endif
2573  } // if demangled type_info starts with "typeinfo for "
2574  } // if demangling worked
2575  free(demangledTIName);
2576  } // if mangling worked
2577  } // if no pseudo-strong typedef involved
2578  }
2579  }
2580  }
2581  classesListForRootmap.sort();
2582 
2583  // Disable for the moment
2584  // fwdDeclarationsList = CollapseIdenticalNamespaces(fwdDeclarationsList);
2585 
2586  return 0;
2587 }
2588 
2589 ////////////////////////////////////////////////////////////////////////////////
2590 /// Loop on selected classes and put them in a list
2591 
2592 void ExtractSelectedNamespaces(RScanner &scan, std::list<std::string> &nsList)
2593 {
2594  for (RScanner::NamespaceColl_t::const_iterator selNsIter = scan.fSelectedNamespaces.begin();
2595  selNsIter != scan.fSelectedNamespaces.end(); ++selNsIter) {
2596  nsList.push_back(ROOT::TMetaUtils::GetQualifiedName(* selNsIter->GetNamespaceDecl()));
2597  }
2598 }
2599 
2600 ////////////////////////////////////////////////////////////////////////////////
2601 /// We need annotations even in the PCH: // !, // || etc.
2602 
2603 void AnnotateAllDeclsForPCH(cling::Interpreter &interp,
2604  RScanner &scan)
2605 {
2606  auto const & declSelRulesMap = scan.GetDeclsSelRulesMap();
2607  for (auto const & selClass : scan.fSelectedClasses) {
2608  // Very important: here we decide if we want to attach attributes to the decl.
2609  if (clang::CXXRecordDecl *CXXRD =
2610  llvm::dyn_cast<clang::CXXRecordDecl>(const_cast<clang::RecordDecl *>(selClass.GetRecordDecl()))) {
2611  AnnotateDecl(*CXXRD, declSelRulesMap, interp, false);
2612  }
2613  }
2614 }
2615 
2616 ////////////////////////////////////////////////////////////////////////////////
2617 
2618 int CheckClassesForInterpreterOnlyDicts(cling::Interpreter &interp,
2619  RScanner &scan)
2620 {
2621  for (auto const & selClass : scan.fSelectedClasses) {
2622  if (!selClass.GetRecordDecl()->isCompleteDefinition() || selClass.RequestOnlyTClass()) {
2623  continue;
2624  }
2625  const clang::CXXRecordDecl *cxxdecl = llvm::dyn_cast<clang::CXXRecordDecl>(selClass.GetRecordDecl());
2626  if (cxxdecl && ROOT::TMetaUtils::ClassInfo__HasMethod(selClass, "Class_Name", interp)) {
2627  ROOT::TMetaUtils::Error("CheckClassesForInterpreterOnlyDicts",
2628  "Interactivity only dictionaries are not supported for classes with ClassDef\n");
2629  return 1;
2630  }
2631  }
2632  return 0;
2633 }
2634 
2635 ////////////////////////////////////////////////////////////////////////////////
2636 /// Make up for skipping RegisterModule, now that dictionary parsing
2637 /// is done and these headers cannot be selected anymore.
2638 
2639 int FinalizeStreamerInfoWriting(cling::Interpreter &interp, bool writeEmptyRootPCM=false)
2640 {
2642  return 0;
2643 
2644  if (interp.parseForModule("#include \"TStreamerInfo.h\"\n"
2645  "#include \"TFile.h\"\n"
2646  "#include \"TObjArray.h\"\n"
2647  "#include \"TVirtualArray.h\"\n"
2648  "#include \"TStreamerElement.h\"\n"
2649  "#include \"TProtoClass.h\"\n"
2650  "#include \"TBaseClass.h\"\n"
2651  "#include \"TListOfDataMembers.h\"\n"
2652  "#include \"TListOfEnums.h\"\n"
2653  "#include \"TListOfEnumsWithLock.h\"\n"
2654  "#include \"TDataMember.h\"\n"
2655  "#include \"TEnum.h\"\n"
2656  "#include \"TEnumConstant.h\"\n"
2657  "#include \"TDictAttributeMap.h\"\n"
2658  "#include \"TMessageHandler.h\"\n"
2659  "#include \"TArray.h\"\n"
2660  "#include \"TRefArray.h\"\n"
2661  "#include \"root_std_complex.h\"\n")
2662  != cling::Interpreter::kSuccess)
2663  return 1;
2664  if (!gDriverConfig->fCloseStreamerInfoROOTFile(writeEmptyRootPCM)) {
2665  return 1;
2666  }
2667  return 0;
2668 }
2669 
2670 ////////////////////////////////////////////////////////////////////////////////
2671 
2672 int GenerateFullDict(std::ostream &dictStream,
2673  cling::Interpreter &interp,
2674  RScanner &scan,
2675  const ROOT::TMetaUtils::RConstructorTypes &ctorTypes,
2676  bool isSplit,
2677  bool isGenreflex,
2678  bool writeEmptyRootPCM)
2679 {
2680  ROOT::TMetaUtils::TNormalizedCtxt normCtxt(interp.getLookupHelper());
2681 
2682  bool needsCollectionProxy = false;
2683 
2684  //
2685  // We will loop over all the classes several times.
2686  // In order we will call
2687  //
2688  // WriteClassInit (code to create the TGenericClassInfo)
2689  // check for constructor and operator input
2690  // WriteClassFunctions (declared in ClassDef)
2691  // WriteClassCode (Streamer,ShowMembers,Auxiliary functions)
2692  //
2693 
2694 
2695  //
2696  // Loop over all classes and create Streamer() & Showmembers() methods
2697  //
2698 
2699  // SELECTION LOOP
2700  for (auto const & ns : scan.fSelectedNamespaces) {
2701  if (!gOptIgnoreExistingDict) {
2702  WriteNamespaceInit(ns, interp, dictStream);
2703  }
2704  auto nsName = ns.GetNamespaceDecl()->getQualifiedNameAsString();
2705  if (nsName.find("(anonymous)") == std::string::npos)
2706  EmitStreamerInfo(nsName.c_str());
2707  }
2708 
2709  for (auto const & selClass : scan.fSelectedClasses) {
2710  if (!selClass.GetRecordDecl()->isCompleteDefinition()) {
2711  ROOT::TMetaUtils::Error(0, "A dictionary has been requested for %s but there is no declaration!\n", ROOT::TMetaUtils::GetQualifiedName(selClass).c_str());
2712  continue;
2713  }
2714  if (selClass.RequestOnlyTClass()) {
2715  // fprintf(stderr,"rootcling: Skipping class %s\n",R__GetQualifiedName(* selClass.GetRecordDecl()).c_str());
2716  // For now delay those for later.
2717  continue;
2718  }
2719 
2720  // Very important: here we decide if we want to attach attributes to the decl.
2721 
2722  if (clang::CXXRecordDecl *CXXRD =
2723  llvm::dyn_cast<clang::CXXRecordDecl>(const_cast<clang::RecordDecl *>(selClass.GetRecordDecl()))) {
2724  AnnotateDecl(*CXXRD, scan.GetDeclsSelRulesMap() , interp, isGenreflex);
2725  }
2726 
2727  const clang::CXXRecordDecl *CRD = llvm::dyn_cast<clang::CXXRecordDecl>(selClass.GetRecordDecl());
2728 
2729  if (CRD) {
2730  ROOT::TMetaUtils::Info(0, "Generating code for class %s\n", selClass.GetNormalizedName());
2731  if (TMetaUtils::IsStdClass(*CRD) && 0 != TClassEdit::STLKind(CRD->getName().str() /* unqualified name without template argument */)) {
2732  // Register the collections
2733  // coverity[fun_call_w_exception] - that's just fine.
2734  Internal::RStl::Instance().GenerateTClassFor(selClass.GetNormalizedName(), CRD, interp, normCtxt);
2735  } else {
2736  if (!gOptIgnoreExistingDict) {
2737  ROOT::TMetaUtils::WriteClassInit(dictStream, selClass, CRD, interp, normCtxt, ctorTypes,
2738  needsCollectionProxy);
2739  }
2740  EmitStreamerInfo(selClass.GetNormalizedName());
2741  }
2742  }
2743  }
2744 
2745  //
2746  // Write all TBuffer &operator>>(...), Class_Name(), Dictionary(), etc.
2747  // first to allow template specialisation to occur before template
2748  // instantiation (STK)
2749  //
2750  // SELECTION LOOP
2751  for (auto const & selClass : scan.fSelectedClasses) {
2752 
2753  if (!selClass.GetRecordDecl()->isCompleteDefinition() || selClass.RequestOnlyTClass()) {
2754  // For now delay those for later.
2755  continue;
2756  }
2757  const clang::CXXRecordDecl *cxxdecl = llvm::dyn_cast<clang::CXXRecordDecl>(selClass.GetRecordDecl());
2758  if (cxxdecl && ROOT::TMetaUtils::ClassInfo__HasMethod(selClass, "Class_Name", interp) && !gOptIgnoreExistingDict) {
2759  WriteClassFunctions(cxxdecl, dictStream, isSplit);
2760  }
2761  }
2762 
2763  // LINKDEF SELECTION LOOP
2764  // Loop to get the shadow class for the class marked 'RequestOnlyTClass' (but not the
2765  // STL class which is done via Internal::RStl::Instance().WriteClassInit(0);
2766  // and the ClassInit
2767 
2768  for (auto const & selClass : scan.fSelectedClasses) {
2769  if (!selClass.GetRecordDecl()->isCompleteDefinition() || !selClass.RequestOnlyTClass()) {
2770  continue;
2771  }
2772 
2773  const clang::CXXRecordDecl *CRD = llvm::dyn_cast<clang::CXXRecordDecl>(selClass.GetRecordDecl());
2774 
2775  if (!ROOT::TMetaUtils::IsSTLContainer(selClass)) {
2776  if (!gOptIgnoreExistingDict) {
2777  ROOT::TMetaUtils::WriteClassInit(dictStream, selClass, CRD, interp, normCtxt, ctorTypes,
2778  needsCollectionProxy);
2779  }
2780  EmitStreamerInfo(selClass.GetNormalizedName());
2781  }
2782  }
2783  // Loop to write all the ClassCode
2784  if (!gOptIgnoreExistingDict) {
2785  for (auto const &selClass : scan.fSelectedClasses) {
2787  selClass,
2788  interp,
2789  normCtxt,
2790  dictStream,
2791  ctorTypes,
2792  isGenreflex);
2793  }
2794 
2795  // Loop on the registered collections internally
2796  // coverity[fun_call_w_exception] - that's just fine.
2797  ROOT::Internal::RStl::Instance().WriteClassInit(dictStream, interp, normCtxt, ctorTypes, needsCollectionProxy,
2799  }
2800 
2803  EmitEnums(scan.fSelectedEnums);
2804  // Make up for skipping RegisterModule, now that dictionary parsing
2805  // is done and these headers cannot be selected anymore.
2806  int finRetCode = FinalizeStreamerInfoWriting(interp, writeEmptyRootPCM);
2807  if (finRetCode != 0) return finRetCode;
2808  }
2809 
2810  return 0;
2811 }
2812 
2813 ////////////////////////////////////////////////////////////////////////////////
2814 
2815 void CreateDictHeader(std::ostream &dictStream, const std::string &main_dictname)
2816 {
2817  dictStream << "// Do NOT change. Changes will be lost next time file is generated\n\n"
2818  << "#define R__DICTIONARY_FILENAME " << main_dictname << std::endl
2819 
2820  // We do not want deprecation warnings to fire in dictionaries
2821  << "#define R__NO_DEPRECATION" << std::endl
2822 
2823  // Now that CINT is not longer there to write the header file,
2824  // write one and include in there a few things for backward
2825  // compatibility.
2826  << "\n/*******************************************************************/\n"
2827  << "#include <stddef.h>\n"
2828  << "#include <stdio.h>\n"
2829  << "#include <stdlib.h>\n"
2830  << "#include <string.h>\n"
2831  << "#include <assert.h>\n"
2832  << "#define G__DICTIONARY\n"
2833  << "#include \"RConfig.h\"\n"
2834  << "#include \"TClass.h\"\n"
2835  << "#include \"TDictAttributeMap.h\"\n"
2836  << "#include \"TInterpreter.h\"\n"
2837  << "#include \"TROOT.h\"\n"
2838  << "#include \"TBuffer.h\"\n"
2839  << "#include \"TMemberInspector.h\"\n"
2840  << "#include \"TInterpreter.h\"\n"
2841  << "#include \"TVirtualMutex.h\"\n"
2842  << "#include \"TError.h\"\n\n"
2843  << "#ifndef G__ROOT\n"
2844  << "#define G__ROOT\n"
2845  << "#endif\n\n"
2846  << "#include \"RtypesImp.h\"\n"
2847  << "#include \"TIsAProxy.h\"\n"
2848  << "#include \"TFileMergeInfo.h\"\n"
2849  << "#include <algorithm>\n"
2850  << "#include \"TCollectionProxyInfo.h\"\n"
2851  << "/*******************************************************************/\n\n"
2852  << "#include \"TDataMember.h\"\n\n"; // To set their transiency
2853 }
2854 
2855 ////////////////////////////////////////////////////////////////////////////////
2856 
2857 void AddNamespaceSTDdeclaration(std::ostream &dictStream)
2858 {
2859  dictStream << "// The generated code does not explicitly qualifies STL entities\n"
2860  << "namespace std {} using namespace std;\n\n";
2861 }
2862 
2863 ////////////////////////////////////////////////////////////////////////////////
2864 
2865 void GenerateNecessaryIncludes(std::ostream &dictStream,
2866  const std::string &includeForSource,
2867  const std::string &extraIncludes)
2868 {
2869  dictStream << "// Header files passed as explicit arguments\n"
2870  << includeForSource << std::endl
2871  << "// Header files passed via #pragma extra_include\n"
2872  << extraIncludes << std::endl;
2873 }
2874 
2875 //______________________________________________________________________________
2876 
2877 // cross-compiling for iOS and iOS simulator (assumes host is Intel Mac OS X)
2878 #if defined(R__IOSSIM) || defined(R__IOS)
2879 #ifdef __x86_64__
2880 #undef __x86_64__
2881 #endif
2882 #ifdef __i386__
2883 #undef __i386__
2884 #endif
2885 #ifdef R__IOSSIM
2886 #define __i386__ 1
2887 #endif
2888 #ifdef R__IOS
2889 #define __arm__ 1
2890 #endif
2891 #endif
2892 
2893 ////////////////////////////////////////////////////////////////////////////////
2894 /// Little helper class to bookkeep the files names which we want to make
2895 /// temporary.
2896 
2897 class tempFileNamesCatalog {
2898 public:
2899  //______________________________________________
2900  tempFileNamesCatalog(): m_size(0), m_emptyString("") {};
2901 
2902  std::string getTmpFileName(const std::string &filename) {
2903  return filename + "_tmp_" + std::to_string(getpid());
2904  }
2905  /////////////////////////////////////////////////////////////////////////////
2906  /// Adds the name and the associated temp name to the catalog.
2907  /// Changes the name into the temp name
2908 
2909  void addFileName(std::string &nameStr) {
2910  if (nameStr.empty()) return;
2911 
2912  std::string tmpNameStr(getTmpFileName(nameStr));
2913 
2914  // For brevity
2915  const char *name(nameStr.c_str());
2916  const char *tmpName(tmpNameStr.c_str());
2917 
2918  m_names.push_back(nameStr);
2919  m_tempNames.push_back(tmpNameStr);
2920  ROOT::TMetaUtils::Info(0, "File %s added to the tmp catalog.\n", name);
2921 
2922  // This is to allow update of existing files
2923  if (0 == std::rename(name , tmpName)) {
2924  ROOT::TMetaUtils::Info(0, "File %s existing. Preserved as %s.\n", name, tmpName);
2925  }
2926 
2927  // To change the name to its tmp version
2928  nameStr = tmpNameStr;
2929 
2930  m_size++;
2931 
2932  }
2933 
2934  /////////////////////////////////////////////////////////////////////////////
2935 
2936  int clean() {
2937  int retval = 0;
2938  // rename the temp files into the normal ones
2939  for (unsigned int i = 0; i < m_size; ++i) {
2940  const char *tmpName = m_tempNames[i].c_str();
2941  // Check if the file exists
2942  std::ifstream ifile(tmpName);
2943  if (!ifile)
2944  ROOT::TMetaUtils::Error(0, "Cannot find %s!\n", tmpName);
2945 
2946  if (0 != std::remove(tmpName)) {
2947  ROOT::TMetaUtils::Error(0, "Removing %s!\n", tmpName);
2948  retval++;
2949  }
2950  }
2951  return retval;
2952  }
2953 
2954  /////////////////////////////////////////////////////////////////////////////
2955 
2956  int commit() {
2957  int retval = 0;
2958  // rename the temp files into the normal ones
2959  for (unsigned int i = 0; i < m_size; ++i) {
2960  const char *tmpName = m_tempNames[i].c_str();
2961  const char *name = m_names[i].c_str();
2962  // Check if the file exists
2963  std::ifstream ifile(tmpName);
2964  if (!ifile)
2965  ROOT::TMetaUtils::Error(0, "Cannot find %s!\n", tmpName);
2966 #ifdef WIN32
2967  // Sometimes files cannot be renamed on Windows if they don't have
2968  // been released by the system. So just copy them and try to delete
2969  // the old one afterwards.
2970  if (ifile.is_open())
2971  ifile.close();
2972  if (0 != std::rename(tmpName , name)) {
2973  if (llvm::sys::fs::copy_file(tmpName , name)) {
2974  llvm::sys::fs::remove(tmpName);
2975  }
2976  }
2977 #else
2978  if (0 != std::rename(tmpName , name)) {
2979  ROOT::TMetaUtils::Error(0, "Renaming %s into %s!\n", tmpName, name);
2980  retval++;
2981  }
2982 #endif
2983  }
2984  return retval;
2985  }
2986 
2987  /////////////////////////////////////////////////////////////////////////////
2988 
2989  const std::string &getFileName(const std::string &tmpFileName) {
2990  size_t i = std::distance(m_tempNames.begin(),
2991  find(m_tempNames.begin(), m_tempNames.end(), tmpFileName));
2992  if (i == m_tempNames.size()) return m_emptyString;
2993  return m_names[i];
2994  }
2995 
2996  /////////////////////////////////////////////////////////////////////////////
2997 
2998  void dump() {
2999  std::cout << "Restoring files in temporary file catalog:\n";
3000  for (unsigned int i = 0; i < m_size; ++i) {
3001  std::cout << m_tempNames[i] << " --> " << m_names[i] << std::endl;
3002  }
3003  }
3004 
3005 private:
3006  unsigned int m_size;
3007  const std::string m_emptyString;
3008  std::vector<std::string> m_names;
3009  std::vector<std::string> m_tempNames;
3010 };
3011 
3012 ////////////////////////////////////////////////////////////////////////////////
3013 /// Transform name of dictionary
3014 
3015 std::ostream *CreateStreamPtrForSplitDict(const std::string &dictpathname,
3016  tempFileNamesCatalog &tmpCatalog)
3017 {
3018  std::string splitDictName(tmpCatalog.getFileName(dictpathname));
3019  const size_t dotPos = splitDictName.find_last_of(".");
3020  splitDictName.insert(dotPos, "_classdef");
3021  tmpCatalog.addFileName(splitDictName);
3022  return new std::ofstream(splitDictName.c_str());
3023 }
3024 
3025 ////////////////////////////////////////////////////////////////////////////////
3026 /// Transform -W statements in diagnostic pragmas for cling reacting on "-Wno-"
3027 /// For example
3028 /// -Wno-deprecated-declarations --> #pragma clang diagnostic ignored "-Wdeprecated-declarations"
3029 
3030 static void CheckForMinusW(std::string arg,
3031  std::list<std::string> &diagnosticPragmas)
3032 {
3033  static const std::string pattern("-Wno-");
3034 
3035  if (arg.find(pattern) != 0)
3036  return;
3037  if (arg == "-Wno-noexcept-type") {
3038  // GCC7 warning not supported by clang 3.9
3039  return;
3040  }
3041 
3042  ROOT::TMetaUtils::ReplaceAll(arg, pattern, "#pragma clang diagnostic ignored \"-W");
3043  arg += "\"";
3044  diagnosticPragmas.push_back(arg);
3045 }
3046 
3047 ////////////////////////////////////////////////////////////////////////////////
3048 
3050  cling::Interpreter &interp)
3051 {
3052  using namespace ROOT::TMetaUtils::AST2SourceTools;
3053  std::string fwdDecl;
3054  std::string initStr("{");
3055  auto &fwdDeclnArgsToSkipColl = normCtxt.GetTemplNargsToKeepMap();
3056  for (auto & strigNargsToKeepPair : fwdDeclnArgsToSkipColl) {
3057  auto &clTemplDecl = *strigNargsToKeepPair.first;
3058  FwdDeclFromTmplDecl(clTemplDecl , interp, fwdDecl);
3059  initStr += "{\"" +
3060  fwdDecl + "\", "
3061  + std::to_string(strigNargsToKeepPair.second)
3062  + "},";
3063  }
3064  if (!fwdDeclnArgsToSkipColl.empty())
3065  initStr.pop_back();
3066  initStr += "}";
3067  return initStr;
3068 }
3069 
3070 ////////////////////////////////////////////////////////////////////////////////
3071 /// Get the pointee type if possible
3072 
3073 clang::QualType GetPointeeTypeIfPossible(const clang::QualType &qt)
3074 {
3075  if (qt.isNull()) return qt;
3076  clang::QualType thisQt(qt);
3077  while (thisQt->isPointerType() ||
3078  thisQt->isReferenceType()) {
3079  thisQt = thisQt->getPointeeType();
3080  }
3081  return thisQt;
3082 
3083 }
3084 
3085 ////////////////////////////////////////////////////////////////////////////////
3086 /// Extract the list of headers necessary for the Decl
3087 
3088 std::list<std::string> RecordDecl2Headers(const clang::CXXRecordDecl &rcd,
3089  const cling::Interpreter &interp,
3090  std::set<const clang::CXXRecordDecl *> &visitedDecls)
3091 {
3092  std::list<std::string> headers;
3093 
3094  // We push a new transaction because we could deserialize decls here
3095  cling::Interpreter::PushTransactionRAII RAII(&interp);
3096 
3097  // Avoid infinite recursion
3098  if (!visitedDecls.insert(rcd.getCanonicalDecl()).second)
3099  return headers;
3100 
3101  // If this is a template
3102  if (const clang::ClassTemplateSpecializationDecl *tsd = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(&rcd)) {
3103 
3104  // Loop on the template args
3105  for (auto & tArg : tsd->getTemplateArgs().asArray()) {
3106  if (clang::TemplateArgument::ArgKind::Type != tArg.getKind()) continue;
3107  auto tArgQualType = GetPointeeTypeIfPossible(tArg.getAsType());
3108  if (tArgQualType.isNull()) continue;
3109  if (const clang::CXXRecordDecl *tArgCxxRcd = tArgQualType->getAsCXXRecordDecl()) {
3110  headers.splice(headers.end(), RecordDecl2Headers(*tArgCxxRcd, interp, visitedDecls));
3111  }
3112  }
3113 
3114  if (!ROOT::TMetaUtils::IsStdClass(rcd) && rcd.hasDefinition()) {
3115 
3116  // Loop on base classes - with a newer llvm, range based possible
3117  for (auto baseIt = tsd->bases_begin(); baseIt != tsd->bases_end(); baseIt++) {
3118  auto baseQualType = GetPointeeTypeIfPossible(baseIt->getType());
3119  if (baseQualType.isNull()) continue;
3120  if (const clang::CXXRecordDecl *baseRcdPtr = baseQualType->getAsCXXRecordDecl()) {
3121  headers.splice(headers.end(), RecordDecl2Headers(*baseRcdPtr, interp, visitedDecls));
3122  }
3123  }
3124 
3125  // Loop on the data members - with a newer llvm, range based possible
3126  for (auto declIt = tsd->decls_begin(); declIt != tsd->decls_end(); ++declIt) {
3127  if (const clang::FieldDecl *fieldDecl = llvm::dyn_cast<clang::FieldDecl>(*declIt)) {
3128  auto fieldQualType = GetPointeeTypeIfPossible(fieldDecl->getType());
3129  if (fieldQualType.isNull()) continue ;
3130  if (const clang::CXXRecordDecl *fieldCxxRcd = fieldQualType->getAsCXXRecordDecl()) {
3131  if (fieldCxxRcd->hasDefinition())
3132  headers.splice(headers.end(), RecordDecl2Headers(*fieldCxxRcd, interp, visitedDecls));
3133  }
3134  }
3135  }
3136 
3137  // Loop on methods
3138  for (auto methodIt = tsd->method_begin(); methodIt != tsd->method_end(); ++methodIt) {
3139  // Check arguments
3140  for (auto & fPar : methodIt->parameters()) {
3141  auto fParQualType = GetPointeeTypeIfPossible(fPar->getOriginalType());
3142  if (fParQualType.isNull()) continue;
3143  if (const clang::CXXRecordDecl *fParCxxRcd = fParQualType->getAsCXXRecordDecl()) {
3144  if (fParCxxRcd->hasDefinition())
3145  headers.splice(headers.end(), RecordDecl2Headers(*fParCxxRcd, interp, visitedDecls));
3146  }
3147  }
3148  // Check return value
3149  auto retQualType = GetPointeeTypeIfPossible(methodIt->getReturnType());
3150  if (retQualType.isNull()) continue;
3151  if (const clang::CXXRecordDecl *retCxxRcd = retQualType->getAsCXXRecordDecl()) {
3152  if (retCxxRcd->hasDefinition())
3153  headers.splice(headers.end(), RecordDecl2Headers(*retCxxRcd, interp, visitedDecls));
3154  }
3155  }
3156  }
3157 
3158  } // End template instance
3159 
3160  std::string header = ROOT::TMetaUtils::GetFileName(rcd, interp);
3161  headers.emplace_back(header);
3162  headers.reverse();
3163  return headers;
3164 
3165 }
3166 
3167 ////////////////////////////////////////////////////////////////////////////////
3168 /// Check if the class good for being an autoparse key.
3169 /// We exclude from this set stl containers of pods/strings
3170 /// TODO: we may use also __gnu_cxx::
3171 bool IsGoodForAutoParseMap(const clang::RecordDecl& rcd){
3172 
3173  // If it's not an std class, we just pick it up.
3174  if (auto dclCtxt= rcd.getDeclContext()){
3175  if (! dclCtxt->isStdNamespace()){
3176  return true;
3177  }
3178  } else {
3179  return true;
3180  }
3181 
3182  // Now, we have a stl class. We now check if it's a template. If not, we
3183  // do not take it: bitset, string and so on.
3184  auto clAsTmplSpecDecl = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(&rcd);
3185  if (!clAsTmplSpecDecl) return false;
3186 
3187  // Now we have a template in the stl. Let's see what the arguments are.
3188  // If they are not a POD or something which is good for autoparsing, we keep
3189  // them.
3190  auto& astCtxt = rcd.getASTContext();
3191  auto& templInstArgs = clAsTmplSpecDecl->getTemplateInstantiationArgs();
3192  for (auto&& arg : templInstArgs.asArray()){
3193 
3194  auto argKind = arg.getKind();
3195  if (argKind != clang::TemplateArgument::Type){
3196  if (argKind == clang::TemplateArgument::Integral) continue;
3197  else return true;
3198  }
3199 
3200  auto argQualType = arg.getAsType();
3201  auto isPOD = argQualType.isPODType(astCtxt);
3202  // This is a POD, we can inspect the next arg
3203  if (isPOD) continue;
3204 
3205  auto argType = argQualType.getTypePtr();
3206  if (auto recType = llvm::dyn_cast<clang::RecordType>(argType)){
3207  auto isArgGoodForAutoParseMap = IsGoodForAutoParseMap(*recType->getDecl());
3208  // The arg is a class but good for the map
3209  if (isArgGoodForAutoParseMap) continue;
3210  } else {
3211  // The class is not a POD nor a class we can skip
3212  return true;
3213  }
3214  }
3215 
3216  return false;
3217 }
3218 
3219 ////////////////////////////////////////////////////////////////////////////////
3220 
3222  const RScanner::TypedefColl_t tDefDecls,
3223  const RScanner::FunctionColl_t funcDecls,
3224  const RScanner::VariableColl_t varDecls,
3225  const RScanner::EnumColl_t enumDecls,
3226  HeadersDeclsMap_t &headersClassesMap,
3227  HeadersDeclsMap_t &headersDeclsMap,
3228  const cling::Interpreter &interp)
3229 {
3230  std::set<const clang::CXXRecordDecl *> visitedDecls;
3231  std::unordered_set<std::string> buffer;
3232  std::string autoParseKey;
3233 
3234  // Add some manip of headers
3235  for (auto & annotatedRcd : annotatedRcds) {
3236  if (const clang::CXXRecordDecl *cxxRcd =
3237  llvm::dyn_cast_or_null<clang::CXXRecordDecl>(annotatedRcd.GetRecordDecl())) {
3238  autoParseKey = "";
3239  visitedDecls.clear();
3240  std::list<std::string> headers(RecordDecl2Headers(*cxxRcd, interp, visitedDecls));
3241  // remove duplicates, also if not subsequent
3242  buffer.clear();
3243  headers.remove_if([&buffer](const std::string & s) {
3244  return !buffer.insert(s).second;
3245  });
3246  GetMostExternalEnclosingClassName(*cxxRcd, autoParseKey, interp);
3247  if (autoParseKey.empty()) autoParseKey = annotatedRcd.GetNormalizedName();
3248  if (IsGoodForAutoParseMap(*cxxRcd)){
3249  headersDeclsMap[autoParseKey] = headers;
3250  headersDeclsMap[annotatedRcd.GetRequestedName()] = headers;
3251  } else {
3252  ROOT::TMetaUtils::Info(0, "Class %s is not included in the set of autoparse keys.\n", autoParseKey.c_str());
3253  }
3254 
3255  // Propagate to the classes map only if this is not a template.
3256  // The header is then used as autoload key and we want to avoid duplicates.
3257  if (!llvm::isa<clang::ClassTemplateSpecializationDecl>(cxxRcd)){
3258  headersClassesMap[autoParseKey] = headersDeclsMap[autoParseKey];
3259  headersClassesMap[annotatedRcd.GetRequestedName()] = headersDeclsMap[annotatedRcd.GetRequestedName()];
3260  }
3261  }
3262  }
3263 
3264  // The same for the typedefs:
3265  for (auto & tDef : tDefDecls) {
3266  if (clang::CXXRecordDecl *cxxRcd = tDef->getUnderlyingType()->getAsCXXRecordDecl()) {
3267  autoParseKey = "";
3268  visitedDecls.clear();
3269  std::list<std::string> headers(RecordDecl2Headers(*cxxRcd, interp, visitedDecls));
3270  headers.push_back(ROOT::TMetaUtils::GetFileName(*tDef, interp));
3271  // remove duplicates, also if not subsequent
3272  buffer.clear();
3273  headers.remove_if([&buffer](const std::string & s) {
3274  return !buffer.insert(s).second;
3275  });
3276  GetMostExternalEnclosingClassNameFromDecl(*tDef, autoParseKey, interp);
3277  if (autoParseKey.empty()) autoParseKey = tDef->getQualifiedNameAsString();
3278  headersDeclsMap[autoParseKey] = headers;
3279  }
3280  }
3281 
3282  // The same for the functions:
3283  for (auto & func : funcDecls) {
3284  std::list<std::string> headers = {ROOT::TMetaUtils::GetFileName(*func, interp)};
3285  headersDeclsMap[ROOT::TMetaUtils::GetQualifiedName(*func)] = headers;
3286  }
3287 
3288  // The same for the variables:
3289  for (auto & var : varDecls) {
3290  std::list<std::string> headers = {ROOT::TMetaUtils::GetFileName(*var, interp)};
3291  headersDeclsMap[ROOT::TMetaUtils::GetQualifiedName(*var)] = headers;
3292  }
3293 
3294  // The same for the enums:
3295  for (auto & en : enumDecls) {
3296  std::list<std::string> headers = {ROOT::TMetaUtils::GetFileName(*en, interp)};
3297  headersDeclsMap[ROOT::TMetaUtils::GetQualifiedName(*en)] = headers;
3298  }
3299 }
3300 
3301 ////////////////////////////////////////////////////////////////////////////////
3302 /// Generate the fwd declarations of the selected entities
3303 
3304 static std::string GenerateFwdDeclString(const RScanner &scan,
3305  const cling::Interpreter &interp)
3306 {
3307  std::string newFwdDeclString;
3308 
3309  using namespace ROOT::TMetaUtils::AST2SourceTools;
3310 
3311  std::string fwdDeclString;
3312  std::string buffer;
3313  std::unordered_set<std::string> fwdDecls;
3314 
3315  // Classes
3316 /*
3317  for (auto const & annRcd : scan.fSelectedClasses) {
3318  const auto rcdDeclPtr = annRcd.GetRecordDecl();
3319 
3320  int retCode = FwdDeclFromRcdDecl(*rcdDeclPtr, interp, buffer);
3321  if (-1 == retCode) {
3322  ROOT::TMetaUtils::Error("GenerateFwdDeclString",
3323  "Error generating fwd decl for class %s\n",
3324  annRcd.GetNormalizedName());
3325  return emptyString;
3326  }
3327  if (retCode == 0 && fwdDecls.insert(buffer).second)
3328  fwdDeclString += "\"" + buffer + "\"\n";
3329  }
3330 */
3331  // Build the input for a transaction containing all of the selected declarations
3332  // Cling will produce the fwd declaration payload.
3333 
3334  std::vector<const clang::Decl *> selectedDecls(scan.fSelectedClasses.size());
3335 
3336  // Pick only RecordDecls
3337  std::transform (scan.fSelectedClasses.begin(),
3338  scan.fSelectedClasses.end(),
3339  selectedDecls.begin(),
3340  [](const ROOT::TMetaUtils::AnnotatedRecordDecl& rcd){return rcd.GetRecordDecl();});
3341 
3342  for (auto* TD: scan.fSelectedTypedefs)
3343  selectedDecls.push_back(TD);
3344 
3345 // for (auto* VAR: scan.fSelectedVariables)
3346 // selectedDecls.push_back(VAR);
3347 
3348  // The "R\"DICTFWDDCLS(\n" ")DICTFWDDCLS\"" pieces have been moved to
3349  // TModuleGenerator to be able to make the diagnostics more telling in presence
3350  // of an issue ROOT-6752.
3351  fwdDeclString += Decls2FwdDecls(selectedDecls,IsLinkdefFile,interp);
3352 
3353  // Functions
3354 // for (auto const& fcnDeclPtr : scan.fSelectedFunctions){
3355 // int retCode = FwdDeclFromFcnDecl(*fcnDeclPtr, interp, buffer);
3356 // newFwdDeclString += Decl2FwdDecl(*fcnDeclPtr,interp);
3357 // if (-1 == retCode){
3358 // ROOT::TMetaUtils::Error("GenerateFwdDeclString",
3359 // "Error generating fwd decl for function %s\n",
3360 // fcnDeclPtr->getNameAsString().c_str());
3361 // return emptyString;
3362 // }
3363 // if (retCode == 0 && fwdDecls.insert(buffer).second)
3364 // fwdDeclString+="\""+buffer+"\"\n";
3365 // }
3366 
3367  if (fwdDeclString.empty()) fwdDeclString = "";
3368  return fwdDeclString;
3369 }
3370 
3371 ////////////////////////////////////////////////////////////////////////////////
3372 /// Generate a string for the dictionary from the headers-classes map.
3373 
3374 const std::string GenerateStringFromHeadersForClasses(const HeadersDeclsMap_t &headersClassesMap,
3375  const std::string &detectedUmbrella,
3376  bool payLoadOnly = false)
3377 {
3378  std::string headerName;
3379 
3380  if (genreflex::verbose)
3381  std::cout << "Class-headers Mapping:\n";
3382  std::string headersClassesMapString = "";
3383  for (auto const & classHeaders : headersClassesMap) {
3384  if (genreflex::verbose)
3385  std::cout << " o " << classHeaders.first << " --> ";
3386  headersClassesMapString += "\"";
3387  headersClassesMapString += classHeaders.first + "\"";
3388  for (auto const & header : classHeaders.second) {
3389  headerName = (detectedUmbrella == header || payLoadOnly) ? "payloadCode" : "\"" + header + "\"";
3390  headersClassesMapString += ", " + headerName;
3391  if (genreflex::verbose)
3392  std::cout << ", " << headerName;
3393  if (payLoadOnly)
3394  break;
3395  }
3396  if (genreflex::verbose)
3397  std::cout << std::endl;
3398  headersClassesMapString += ", \"@\",\n";
3399  }
3400  headersClassesMapString += "nullptr";
3401  return headersClassesMapString;
3402 }
3403 
3404 ////////////////////////////////////////////////////////////////////////////////
3405 
3406 bool IsImplementationName(const std::string &filename)
3407 {
3408  return !ROOT::TMetaUtils::IsHeaderName(filename);
3409 }
3410 
3411 ////////////////////////////////////////////////////////////////////////////////
3412 /// Check if the argument is a sane cling argument. Performing the following checks:
3413 /// 1) It does not start with "--" and is not the --param option.
3414 
3415 bool IsCorrectClingArgument(const std::string& argument)
3416 {
3417  if (ROOT::TMetaUtils::BeginsWith(argument,"--") && !ROOT::TMetaUtils::BeginsWith(argument,"--param")) return false;
3418  return true;
3419 }
3420 
3421 ////////////////////////////////////////////////////////////////////////////////
3422 bool NeedsSelection(const char* name)
3423 {
3424  static const std::vector<std::string> namePrfxes {
3425  "array<",
3426  "unique_ptr<"};
3427  auto pos = find_if(namePrfxes.begin(),
3428  namePrfxes.end(),
3429  [&](const std::string& str){return ROOT::TMetaUtils::BeginsWith(name,str);});
3430  return namePrfxes.end() == pos;
3431 }
3432 
3433 ////////////////////////////////////////////////////////////////////////////////
3434 
3435 bool IsSupportedClassName(const char* name)
3436 {
3437  static const std::vector<std::string> uclNamePrfxes {
3438  "chrono:",
3439  "ratio<",
3440  "shared_ptr<"};
3441  static const std::set<std::string> unsupportedClassesNormNames{
3442  "regex",
3443  "thread"};
3444  if ( unsupportedClassesNormNames.count(name) == 1) return false;
3445  auto pos = find_if(uclNamePrfxes.begin(),
3446  uclNamePrfxes.end(),
3447  [&](const std::string& str){return ROOT::TMetaUtils::BeginsWith(name,str);});
3448  return uclNamePrfxes.end() == pos;
3449 }
3450 
3451 ////////////////////////////////////////////////////////////////////////////////
3452 /// Check if the list of selected classes contains any class which is not
3453 /// supported. Return the number of unsupported classes in the selection.
3454 
3456 {
3457  int nerrors = 0;
3458  for (auto&& aRcd : annotatedRcds){
3459  auto clName = aRcd.GetNormalizedName();
3460  if (!IsSupportedClassName(clName)){
3461  std::cerr << "Error: Class " << clName << " has been selected but "
3462  << "currently the support for its I/O is not yet available. Note that "
3463  << clName << ", even if not selected, will be available for "
3464  << "interpreted code.\n";
3465  nerrors++;
3466  }
3467  if (!NeedsSelection(clName)){
3468  std::cerr << "Error: It is not necessary to explicitly select class "
3469  << clName << ". I/O is supported for it transparently.\n";
3470  nerrors++;
3471  }
3472  }
3473  return nerrors;
3474 }
3475 
3476 ////////////////////////////////////////////////////////////////////////////////
3477 
3478 class TRootClingCallbacks : public cling::InterpreterCallbacks {
3479 private:
3480  std::list<std::string>& fFilesIncludedByLinkdef;
3481  bool isLocked = false;
3482 public:
3483  TRootClingCallbacks(cling::Interpreter* interp, std::list<std::string>& filesIncludedByLinkdef):
3484  InterpreterCallbacks(interp),
3485  fFilesIncludedByLinkdef(filesIncludedByLinkdef){};
3486 
3487  ~TRootClingCallbacks(){};
3488 
3489  virtual void InclusionDirective(clang::SourceLocation /*HashLoc*/, const clang::Token & /*IncludeTok*/,
3490  llvm::StringRef FileName, bool IsAngled, clang::CharSourceRange /*FilenameRange*/,
3491  const clang::FileEntry * /*File*/, llvm::StringRef /*SearchPath*/,
3492  llvm::StringRef /*RelativePath*/, const clang::Module * /*Imported*/)
3493  {
3494  if (isLocked) return;
3495  if (IsAngled) return;
3496  auto& PP = m_Interpreter->getCI()->getPreprocessor();
3497  auto curLexer = PP.getCurrentFileLexer();
3498  if (!curLexer) return;
3499  auto fileEntry = curLexer->getFileEntry();
3500  if (!fileEntry) return;
3501  auto thisFileName = fileEntry->getName();
3502  auto fileNameAsString = FileName.str();
3503  auto isThisLinkdef = ROOT::TMetaUtils::IsLinkdefFile(thisFileName.data());
3504  if (isThisLinkdef) {
3505  auto isTheIncludedLinkdef = ROOT::TMetaUtils::IsLinkdefFile(fileNameAsString.c_str());
3506  if (isTheIncludedLinkdef) {
3507  fFilesIncludedByLinkdef.clear();
3508  isLocked = true;
3509  } else {
3510  fFilesIncludedByLinkdef.emplace_back(fileNameAsString.c_str());
3511  }
3512  }
3513  }
3514 
3515  // rootcling pre-includes things such as Rtypes.h. This means that ACLiC can
3516  // call rootcling asking it to create a module for a file with no #includes
3517  // but relying on things from Rtypes.h such as the ClassDef macro.
3518  //
3519  // When rootcling starts building a module, it becomes resilient to the
3520  // outside environment and pre-included files have no effect. This hook
3521  // informs rootcling when a new submodule is being built so that it can
3522  // make Core.Rtypes.h visible.
3523  virtual void EnteredSubmodule(clang::Module* M,
3524  clang::SourceLocation ImportLoc,
3525  bool ForPragma) {
3526  assert(M);
3527  using namespace clang;
3528  if (llvm::StringRef(M->Name).endswith("ACLiC_dict")) {
3529  Preprocessor& PP = m_Interpreter->getCI()->getPreprocessor();
3530  HeaderSearch& HS = PP.getHeaderSearchInfo();
3531  // FIXME: Reduce to Core.Rtypes.h.
3532  Module* CoreModule = HS.lookupModule("Core", /*AllowSearch*/false);
3533  assert(M && "Must have module Core");
3534  PP.makeModuleVisible(CoreModule, ImportLoc);
3535  }
3536  }
3537 };
3538 
3539 static llvm::cl::list<std::string>
3540 gOptModuleByproducts("mByproduct", llvm::cl::ZeroOrMore,
3541  llvm::cl::Hidden,
3542  llvm::cl::desc("The list of the expected implicit modules build as part of building the current module."),
3543  llvm::cl::cat(gRootclingOptions));
3544 
3545 ////////////////////////////////////////////////////////////////////////////////
3546 /// Custom diag client for clang that verifies that each implicitly build module
3547 /// is a system module. If not, it will let the current rootcling invocation
3548 /// fail with an error. All other diags beside module build remarks will be
3549 /// forwarded to the passed child diag client.
3550 ///
3551 /// The reason why we need this is that if we built implicitly a C++ module
3552 /// that belongs to a ROOT dictionary, then we will miss information generated
3553 /// by rootcling in this file (e.g. the source code comments to annotation
3554 /// attributes transformation will be missing in the module file).
3555 class CheckModuleBuildClient : public clang::DiagnosticConsumer {
3556  clang::DiagnosticConsumer *fChild;
3557  bool fOwnsChild;
3558  clang::ModuleMap &fMap;
3559 
3560 public:
3561  CheckModuleBuildClient(clang::DiagnosticConsumer *Child, bool OwnsChild, clang::ModuleMap &Map)
3562  : fChild(Child), fOwnsChild(OwnsChild), fMap(Map)
3563  {
3564  }
3565 
3566  ~CheckModuleBuildClient()
3567  {
3568  if (fOwnsChild)
3569  delete fChild;
3570  }
3571 
3572  virtual void HandleDiagnostic(clang::DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &Info) override
3573  {
3574  using namespace clang::diag;
3575 
3576  // This method catches the module_build remark from clang and checks if
3577  // the implicitly built module is a system module or not. We only support
3578  // building system modules implicitly.
3579 
3580  std::string moduleName;
3581  const clang::Module *module = nullptr;
3582 
3583  // Extract the module from the diag argument with index 0.
3584  const auto &ID = Info.getID();
3585  if (ID == remark_module_build || ID == remark_module_build_done) {
3586  moduleName = Info.getArgStdStr(0);
3587  module = fMap.findModule(moduleName);
3588  // We should never be able to build a module without having it in the
3589  // modulemap. Still, let's print a warning that we at least tell the
3590  // user that this could lead to problems.
3591  if (!module) {
3593  "Couldn't find module %s in the available modulemaps. This"
3594  "prevents us from correctly diagnosing wrongly built modules.\n",
3595  moduleName.c_str());
3596  }
3597  }
3598 
3599  // A dictionary module could build implicitly a set of implicit modules.
3600  // For example, the Core module builds libc.pcm and std.pcm implicitly.
3601  // Those modules do not require I/O information and it is okay to build
3602  // them as part of another module.
3603  // However, we can build a module which requires I/O implictly which is
3604  // an error because rootcling is not able to generate the corresponding
3605  // dictionary.
3606  // If we build a I/O requiring module implicitly we should display
3607  // an error unless the -mByproduct was specified.
3608  bool isByproductModule
3609  = module && std::find(gOptModuleByproducts.begin(), gOptModuleByproducts.end(), moduleName) != gOptModuleByproducts.end();
3610  if (!isByproductModule)
3611  fChild->HandleDiagnostic(DiagLevel, Info);
3612 
3613  if (ID == remark_module_build && !isByproductModule) {
3615  "Building module '%s' implicitly. If '%s' requires a \n"
3616  "dictionary please fix the build dependencies.\n"
3617  "Otherwise, specify -mByproduct %s to disable this diagnostic.\n",
3618  moduleName.c_str(), moduleName.c_str(), moduleName.c_str());
3619  }
3620  }
3621 
3622  // All methods below just forward to the child and the default method.
3623  virtual void clear() override
3624  {
3625  fChild->clear();
3626  DiagnosticConsumer::clear();
3627  }
3628 
3629  virtual void BeginSourceFile(const clang::LangOptions &LangOpts, const clang::Preprocessor *PP) override
3630  {
3631  fChild->BeginSourceFile(LangOpts, PP);
3632  DiagnosticConsumer::BeginSourceFile(LangOpts, PP);
3633  }
3634 
3635  virtual void EndSourceFile() override
3636  {
3637  fChild->EndSourceFile();
3638  DiagnosticConsumer::EndSourceFile();
3639  }
3640 
3641  virtual void finish() override
3642  {
3643  fChild->finish();
3644  DiagnosticConsumer::finish();
3645  }
3646 
3647  virtual bool IncludeInDiagnosticCounts() const override { return fChild->IncludeInDiagnosticCounts(); }
3648 };
3649 
3651 #if defined(_WIN32) && defined(_MSC_VER)
3652  // Suppress error dialogs to avoid hangs on build nodes.
3653  // One can use an environment variable (Cling_GuiOnAssert) to enable
3654  // the error dialogs.
3655  const char *EnablePopups = getenv("Cling_GuiOnAssert");
3656  if (EnablePopups == nullptr || EnablePopups[0] == '0') {
3657  ::_set_error_mode(_OUT_TO_STDERR);
3658  _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
3659  _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
3660  _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
3661  _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
3662  _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
3663  _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
3664  }
3665 #endif
3666 }
3667 
3668 static llvm::cl::opt<bool> gOptForce("f", llvm::cl::desc("Overwrite <file>s."),
3669  llvm::cl::cat(gRootclingOptions));
3670 static llvm::cl::opt<bool> gOptRootBuild("rootbuild", llvm::cl::desc("If we are building ROOT."),
3671  llvm::cl::Hidden,
3672  llvm::cl::cat(gRootclingOptions));
3676  v1 = v,
3680 };
3681 static llvm::cl::opt<VerboseLevel>
3682 gOptVerboseLevel(llvm::cl::desc("Choose verbosity level:"),
3683  llvm::cl::values(clEnumVal(v, "Show errors."),
3684  clEnumVal(v0, "Show only fatal errors."),
3685  clEnumVal(v1, "Show errors (the same as -v)."),
3686  clEnumVal(v2, "Show warnings (default)."),
3687  clEnumVal(v3, "Show notes."),
3688  clEnumVal(v4, "Show information.")),
3689  llvm::cl::init(v2),
3690  llvm::cl::cat(gRootclingOptions));
3691 
3692 static llvm::cl::opt<bool>
3693 gOptCint("cint", llvm::cl::desc("Deprecated, legacy flag which is ignored."),
3694  llvm::cl::Hidden,
3695  llvm::cl::cat(gRootclingOptions));
3696 static llvm::cl::opt<bool>
3697 gOptReflex("reflex", llvm::cl::desc("Deprecated, legacy flag which is ignored."),
3698  llvm::cl::Hidden,
3699  llvm::cl::cat(gRootclingOptions));
3700 static llvm::cl::opt<bool>
3701 gOptGccXml("gccxml", llvm::cl::desc("Deprecated, legacy flag which is ignored."),
3702  llvm::cl::Hidden,
3703  llvm::cl::cat(gRootclingOptions));
3704 static llvm::cl::opt<std::string>
3705 gOptLibListPrefix("lib-list-prefix",
3706  llvm::cl::desc("An ACLiC feature which exports the list of dependent libraries."),
3707  llvm::cl::Hidden,
3708  llvm::cl::cat(gRootclingOptions));
3709 static llvm::cl::opt<bool>
3710 gOptGeneratePCH("generate-pch",
3711  llvm::cl::desc("Generates a pch file from a predefined set of headers. See makepch.py."),
3712  llvm::cl::Hidden,
3713  llvm::cl::cat(gRootclingOptions));
3714 static llvm::cl::opt<std::string>
3715 gOptDictionaryFileName(llvm::cl::Positional, llvm::cl::Required,
3716  llvm::cl::desc("<output dictionary file>"),
3717  llvm::cl::cat(gRootclingOptions));
3718 static llvm::cl::opt<bool>
3719 gOptC("c", llvm::cl::desc("Deprecated, legacy flag which is ignored."),
3720  llvm::cl::cat(gRootclingOptions));
3721 static llvm::cl::opt<bool>
3722 gOptP("p", llvm::cl::desc("Deprecated, legacy flag which is ignored."),
3723  llvm::cl::cat(gRootclingOptions));
3724 static llvm::cl::list<std::string>
3725 gOptRootmapLibNames("rml", llvm::cl::ZeroOrMore,
3726  llvm::cl::desc("Generate rootmap file."),
3727  llvm::cl::cat(gRootclingOptions));
3728 static llvm::cl::opt<std::string>
3729 gOptRootMapFileName("rmf",
3730  llvm::cl::desc("Generate a rootmap file with the specified name."),
3731  llvm::cl::cat(gRootclingOptions));
3732 static llvm::cl::opt<bool>
3733 gOptCxxModule("cxxmodule",
3734  llvm::cl::desc("Generate a C++ module."),
3735  llvm::cl::cat(gRootclingOptions));
3736 static llvm::cl::list<std::string>
3737 gOptModuleMapFiles("moduleMapFile",
3738  llvm::cl::desc("Specify a C++ modulemap file."),
3739  llvm::cl::cat(gRootclingOptions));
3740 // FIXME: Figure out how to combine the code of -umbrellaHeader and inlineInputHeader
3741 static llvm::cl::opt<bool>
3742 gOptUmbrellaInput("umbrellaHeader",
3743  llvm::cl::desc("A single header including all headers instead of specifying them on the command line."),
3744  llvm::cl::cat(gRootclingOptions));
3745 static llvm::cl::opt<bool>
3746 gOptMultiDict("multiDict",
3747  llvm::cl::desc("If this library has multiple separate LinkDef files."),
3748  llvm::cl::cat(gRootclingOptions));
3749 static llvm::cl::opt<bool>
3750 gOptNoGlobalUsingStd("noGlobalUsingStd",
3751  llvm::cl::desc("Do not declare {using namespace std} in dictionary global scope."),
3752  llvm::cl::cat(gRootclingOptions));
3753 static llvm::cl::opt<bool>
3754 gOptInterpreterOnly("interpreteronly",
3755  llvm::cl::desc("Generate minimal dictionary for interactivity (without IO information)."),
3756  llvm::cl::cat(gRootclingOptions));
3757 static llvm::cl::opt<bool>
3758 gOptSplit("split",
3759  llvm::cl::desc("Split the dictionary into two parts: one containing the IO (ClassDef)\
3760 information and another the interactivity support."),
3761  llvm::cl::cat(gRootclingOptions));
3762 static llvm::cl::opt<bool>
3763 gOptNoDictSelection("noDictSelection",
3764  llvm::cl::Hidden,
3765  llvm::cl::desc("Do not run the selection rules. Useful when in -onepcm mode."),
3766  llvm::cl::cat(gRootclingOptions));
3767 static llvm::cl::opt<std::string>
3769  llvm::cl::desc("The path to the library of the built dictionary."),
3770  llvm::cl::cat(gRootclingOptions));
3771 static llvm::cl::list<std::string>
3773  llvm::cl::desc("The list of dependent modules of the dictionary."),
3774  llvm::cl::cat(gRootclingOptions));
3775 static llvm::cl::list<std::string>
3776 gOptExcludePaths("excludePath", llvm::cl::ZeroOrMore,
3777  llvm::cl::desc("Do not store the <path> in the dictionary."),
3778  llvm::cl::cat(gRootclingOptions));
3779 // FIXME: This does not seem to work. We have one use of -inlineInputHeader in
3780 // ROOT and it does not produce the expected result.
3781 static llvm::cl::opt<bool>
3782 gOptInlineInput("inlineInputHeader",
3783  llvm::cl::desc("Does not generate #include <header> but expands the header content."),
3784  llvm::cl::cat(gRootclingOptions));
3785 // FIXME: This is totally the wrong concept. We should not expose an interface
3786 // to be able to tell which component is in the pch and which needs extra
3787 // scaffolding for interactive use. Moreover, some of the ROOT components are
3788 // partially in the pch and this option makes it impossible to express that.
3789 // We should be able to get the list of headers in the pch early and scan
3790 // through them.
3791 static llvm::cl::opt<bool>
3792 gOptWriteEmptyRootPCM("writeEmptyRootPCM",
3793  llvm::cl::Hidden,
3794  llvm::cl::desc("Does not include the header files as it assumes they exist in the pch."),
3795  llvm::cl::cat(gRootclingOptions));
3796 static llvm::cl::opt<bool>
3797 gOptCheckSelectionSyntax("selSyntaxOnly",
3798  llvm::cl::desc("Check the selection syntax only."),
3799  llvm::cl::cat(gRootclingOptions));
3800 static llvm::cl::opt<bool>
3801 gOptFailOnWarnings("failOnWarnings",
3802  llvm::cl::desc("Fail if there are warnings."),
3803  llvm::cl::cat(gRootclingOptions));
3804 static llvm::cl::opt<bool>
3805 gOptNoIncludePaths("noIncludePaths",
3806  llvm::cl::desc("Do not store include paths but rely on the env variable ROOT_INCLUDE_PATH."),
3807  llvm::cl::cat(gRootclingOptions));
3808 static llvm::cl::opt<std::string>
3809 gOptISysRoot("isysroot", llvm::cl::Prefix, llvm::cl::Hidden,
3810  llvm::cl::desc("Specify an isysroot."),
3811  llvm::cl::cat(gRootclingOptions),
3812  llvm::cl::init("-"));
3813 static llvm::cl::list<std::string>
3814 gOptIncludePaths("I", llvm::cl::Prefix, llvm::cl::ZeroOrMore,
3815  llvm::cl::desc("Specify an include path."),
3816  llvm::cl::cat(gRootclingOptions));
3817 static llvm::cl::list<std::string>
3818 gOptPPDefines("D", llvm::cl::Prefix, llvm::cl::ZeroOrMore,
3819  llvm::cl::desc("Specify defined macros."),
3820  llvm::cl::cat(gRootclingOptions));
3821 static llvm::cl::list<std::string>
3822 gOptPPUndefines("U", llvm::cl::Prefix, llvm::cl::ZeroOrMore,
3823  llvm::cl::desc("Specify undefined macros."),
3824  llvm::cl::cat(gRootclingOptions));
3825 static llvm::cl::list<std::string>
3826 gOptWDiags("W", llvm::cl::Prefix, llvm::cl::ZeroOrMore,
3827  llvm::cl::desc("Specify compiler diagnostics options."),
3828  llvm::cl::cat(gRootclingOptions));
3829 static llvm::cl::list<std::string>
3830 gOptDictionaryHeaderFiles(llvm::cl::Positional, llvm::cl::OneOrMore,
3831  llvm::cl::desc("<list of dictionary header files> <LinkDef file>"),
3832  llvm::cl::cat(gRootclingOptions));
3833 static llvm::cl::list<std::string>
3834 gOptSink(llvm::cl::ZeroOrMore, llvm::cl::Sink,
3835  llvm::cl::desc("Consumes all unrecognized options."),
3836  llvm::cl::cat(gRootclingOptions));
3837 
3838 static llvm::cl::SubCommand
3839 gBareClingSubcommand("bare-cling", "Call directly cling and exit.");
3840 
3841 static llvm::cl::list<std::string>
3842 gOptBareClingSink(llvm::cl::OneOrMore, llvm::cl::Sink,
3843  llvm::cl::desc("Consumes options and sends them to cling."),
3844  llvm::cl::cat(gRootclingOptions), llvm::cl::sub(gBareClingSubcommand));
3845 
3846 ////////////////////////////////////////////////////////////////////////////////
3847 /// Returns true iff a given module (and its submodules) contains all headers
3848 /// needed by the given ModuleGenerator.
3849 /// The names of all header files that are needed by the ModuleGenerator but are
3850 /// not in the given module will be inserted into the MissingHeader variable.
3851 /// Returns true iff the PCH was successfully generated.
3852 static bool ModuleContainsHeaders(TModuleGenerator &modGen, clang::Module *module,
3853  std::vector<std::string> &missingHeaders)
3854 {
3855  // Now we collect all header files from the previously collected modules.
3856  std::vector<clang::Module::Header> moduleHeaders;
3858  [&moduleHeaders](const clang::Module::Header &h) { moduleHeaders.push_back(h); });
3859 
3860  bool foundAllHeaders = true;
3861 
3862  // Go through the list of headers that are required by the ModuleGenerator
3863  // and check for each header if it's in one of the modules we loaded.
3864  // If not, make sure we fail at the end and mark the header as missing.
3865  for (const std::string &header : modGen.GetHeaders()) {
3866  bool headerFound = false;
3867  for (const clang::Module::Header &moduleHeader : moduleHeaders) {
3868  if (header == moduleHeader.NameAsWritten) {
3869  headerFound = true;
3870  break;
3871  }
3872  }
3873  if (!headerFound) {
3874  missingHeaders.push_back(header);
3875  foundAllHeaders = false;
3876  }
3877  }
3878  return foundAllHeaders;
3879 }
3880 
3881 ////////////////////////////////////////////////////////////////////////////////
3882 /// Check moduleName validity from modulemap. Check if this module is defined or not.
3883 static bool CheckModuleValid(TModuleGenerator &modGen, const std::string &resourceDir, cling::Interpreter &interpreter,
3884  StringRef LinkdefPath, const std::string &moduleName)
3885 {
3886  clang::CompilerInstance *CI = interpreter.getCI();
3887  clang::HeaderSearch &headerSearch = CI->getPreprocessor().getHeaderSearchInfo();
3888  headerSearch.loadTopLevelSystemModules();
3889 
3890  // Actually lookup the module on the computed module name.
3891  clang::Module *module = headerSearch.lookupModule(StringRef(moduleName));
3892 
3893  // Inform the user and abort if we can't find a module with a given name.
3894  if (!module) {
3895  ROOT::TMetaUtils::Error("CheckModuleValid", "Couldn't find module with name '%s' in modulemap!\n",
3896  moduleName.c_str());
3897  return false;
3898  }
3899 
3900  // Check if the loaded module covers all headers that were specified
3901  // by the user on the command line. This is an integrity check to
3902  // ensure that our used module map is
3903  std::vector<std::string> missingHeaders;
3904  if (!ModuleContainsHeaders(modGen, module, missingHeaders)) {
3905  // FIXME: Upgrade this to an error once modules are stable.
3906  std::stringstream msgStream;
3907  msgStream << "warning: Couldn't find in "
3908  << module->PresumedModuleMapFile
3909  << " the following specified headers in "
3910  << "the module " << module->Name << ":\n";
3911  for (auto &H : missingHeaders) {
3912  msgStream << " " << H << "\n";
3913  }
3914  std::string warningMessage = msgStream.str();
3915 
3916  bool maybeUmbrella = modGen.GetHeaders().size() == 1;
3917  // We may have an umbrella and forgot to add the flag. Downgrade the
3918  // warning into an information message.
3919  // FIXME: We should open the umbrella, extract the set of header files
3920  // and check if they exist in the modulemap.
3921  // FIXME: We should also check if the header files are specified in the
3922  // modulemap file as they appeared in the rootcling invocation, i.e.
3923  // if we passed rootcling ... -I/some/path somedir/some/header, the
3924  // modulemap should contain module M { header "somedir/some/header" }
3925  // This way we will make sure the module is properly activated.
3926  if (!gOptUmbrellaInput && maybeUmbrella) {
3927  ROOT::TMetaUtils::Info("CheckModuleValid, %s. You can silence this message by adding %s to the invocation.",
3928  warningMessage.c_str(),
3929  gOptUmbrellaInput.ArgStr.data());
3930  return true;
3931  }
3932 
3933  ROOT::TMetaUtils::Warning("CheckModuleValid", warningMessage.c_str());
3934  // We include the missing headers to fix the module for the user.
3935  if (!IncludeHeaders(missingHeaders, interpreter)) {
3936  ROOT::TMetaUtils::Error("CheckModuleValid", "Couldn't include missing module headers for module '%s'!\n",
3937  module->Name.c_str());
3938  }
3939  }
3940 
3941  return true;
3942 }
3943 
3944 static llvm::StringRef GetModuleNameFromRdictName(llvm::StringRef rdictName)
3945 {
3946  // Try to get the module name in the modulemap based on the filepath.
3947  llvm::StringRef moduleName = llvm::sys::path::filename(rdictName);
3948  moduleName.consume_front("lib");
3949  moduleName.consume_back(".pcm");
3950  moduleName.consume_back("_rdict");
3951  return moduleName;
3952 }
3953 
3954 ////////////////////////////////////////////////////////////////////////////////
3955 
3956 int RootClingMain(int argc,
3957  char **argv,
3958  bool isGenreflex = false)
3959 {
3960  // Define Options aliasses
3961  auto &opts = llvm::cl::getRegisteredOptions();
3962  auto &optHelp = *opts["help"];
3963  llvm::cl::alias optHelpAlias1("h",
3964  llvm::cl::desc("Alias for -help"),
3965  llvm::cl::aliasopt(optHelp));
3966  llvm::cl::alias optHelpAlias2("?",
3967  llvm::cl::desc("Alias for -help"),
3968  llvm::cl::aliasopt(optHelp));
3969 
3970  // Copied from cling driver.
3971  // FIXME: Uncomment once we fix ROOT's teardown order.
3972  //llvm::llvm_shutdown_obj shutdownTrigger;
3973 
3974  const char *executableFileName = argv[0];
3975 
3976  llvm::sys::PrintStackTraceOnErrorSignal(executableFileName);
3977  llvm::PrettyStackTraceProgram X(argc, argv);
3979 
3980 #if defined(R__WIN32) && !defined(R__WINGCC)
3981  // FIXME: This is terrible hack allocating and changing the argument set.
3982  // We should remove it and use standard llvm facilities to convert the paths.
3983  // cygwin's make is presenting us some cygwin paths even though
3984  // we are windows native. Convert them as good as we can.
3985  for (int iic = 1 /* ignore binary file name in argv[0] */; iic < argc; ++iic) {
3986  std::string iiarg(argv[iic]);
3987  if (FromCygToNativePath(iiarg)) {
3988  size_t len = iiarg.length();
3989  // yes, we leak.
3990  char *argviic = new char[len + 1];
3991  strlcpy(argviic, iiarg.c_str(), len + 1);
3992  argv[iic] = argviic;
3993  }
3994  }
3995 #endif
3996 
3997  // Hide options from llvm which we got from static initialization of libCling.
3998  llvm::cl::HideUnrelatedOptions(/*keep*/gRootclingOptions);
3999 
4000  llvm::cl::ParseCommandLineOptions(argc, argv, "rootcling");
4001 
4002  std::string llvmResourceDir = std::string(gDriverConfig->fTROOT__GetEtcDir()) + "/cling";
4003  if (gBareClingSubcommand) {
4004  std::vector<const char *> clingArgsC;
4005  clingArgsC.push_back(executableFileName);
4006  // Help cling finds its runtime (RuntimeUniverse.h and such).
4007  clingArgsC.push_back("-I");
4008  clingArgsC.push_back(gDriverConfig->fTROOT__GetEtcDir());
4009 
4010  //clingArgsC.push_back("-resource-dir");
4011  //clingArgsC.push_back(llvmResourceDir.c_str());
4012 
4013  for (const std::string& Opt : gOptBareClingSink)
4014  clingArgsC.push_back(Opt.c_str());
4015 
4016  auto interp = llvm::make_unique<cling::Interpreter>(clingArgsC.size(),
4017  &clingArgsC[0],
4018  llvmResourceDir.c_str());
4019  // FIXME: Diagnose when we have misspelled a flag. Currently we show no
4020  // diagnostic and report exit as success.
4021  return interp->getDiagnostics().hasFatalErrorOccurred();
4022  }
4023 
4024  std::string dictname;
4025 
4027  if (gOptRootBuild) {
4028  // running rootcling as part of the ROOT build for ROOT libraries.
4029  gBuildingROOT = true;
4030  }
4031  }
4032 
4033  if (!gOptModuleMapFiles.empty() && !gOptCxxModule) {
4034  ROOT::TMetaUtils::Error("", "Option %s can be used only when option %s is specified.\n",
4035  gOptModuleMapFiles.ArgStr.str().c_str(),
4036  gOptCxxModule.ArgStr.str().c_str());
4037  std::cout << "\n";
4038  llvm::cl::PrintHelpMessage();
4039  return 1;
4040  }
4041 
4042  // Set the default verbosity
4044  if (gOptVerboseLevel == v4)
4045  genreflex::verbose = true;
4046 
4047  if (gOptReflex)
4048  isGenreflex = true;
4049 
4050  if (!gOptLibListPrefix.empty()) {
4051  string filein = gOptLibListPrefix + ".in";
4052  FILE *fp;
4053  if ((fp = fopen(filein.c_str(), "r")) == 0) {
4054  ROOT::TMetaUtils::Error(0, "%s: The input list file %s does not exist\n", executableFileName, filein.c_str());
4055  return 1;
4056  }
4057  fclose(fp);
4058  }
4059 
4061  FILE *fp;
4062  if (!gOptIgnoreExistingDict && (fp = fopen(gOptDictionaryFileName.c_str(), "r")) != 0) {
4063  fclose(fp);
4064  if (!gOptForce) {
4065  ROOT::TMetaUtils::Error(0, "%s: output file %s already exists\n", executableFileName, gOptDictionaryFileName.c_str());
4066  return 1;
4067  }
4068  }
4069 
4070  // remove possible pathname to get the dictionary name
4071  if (gOptDictionaryFileName.size() > (PATH_MAX - 1)) {
4072  ROOT::TMetaUtils::Error(0, "rootcling: dictionary name too long (more than %d characters): %s\n",
4073  (PATH_MAX - 1), gOptDictionaryFileName.c_str());
4074  return 1;
4075  }
4076 
4077  dictname = llvm::sys::path::filename(gOptDictionaryFileName);
4078  }
4079 
4080  if (gOptForce && dictname.empty()) {
4081  ROOT::TMetaUtils::Error(0, "Inconsistent set of arguments detected: overwrite of dictionary file forced but no filename specified.\n");
4082  fprintf(stderr, "%s\n", shortHelp);
4083  return 1;
4084  }
4085 
4086  std::vector<std::string> clingArgs;
4087  clingArgs.push_back(executableFileName);
4088  clingArgs.push_back("-iquote.");
4089 
4090  bool dictSelection = !gOptNoDictSelection;
4091 
4092  // Collect the diagnostic pragmas linked to the usage of -W
4093  // Workaround for ROOT-5656
4094  std::list<std::string> diagnosticPragmas = {"#pragma clang diagnostic ignored \"-Wdeprecated-declarations\""};
4095 
4096  if (gOptFailOnWarnings) {
4097  using namespace ROOT::TMetaUtils;
4098  // If warnings are disabled with the current verbosity settings, lower
4099  // it so that the user sees the warning that caused the failure.
4100  if (GetErrorIgnoreLevel() > kWarning)
4102  GetWarningsAreErrors() = true;
4103  }
4104 
4105  if (gOptISysRoot != "-") {
4106  if (gOptISysRoot.empty()) {
4107  ROOT::TMetaUtils::Error("", "isysroot specified without a value.\n");
4108  return 1;
4109  }
4110  clingArgs.push_back(gOptISysRoot.ArgStr);
4111  clingArgs.push_back(gOptISysRoot.ValueStr);
4112  }
4113 
4114  // Check if we have a multi dict request but no target library
4115  if (gOptMultiDict && gOptSharedLibFileName.empty()) {
4116  ROOT::TMetaUtils::Error("", "Multidict requested but no target library. Please specify one with the -s argument.\n");
4117  return 1;
4118  }
4119 
4120  for (const std::string &PPDefine : gOptPPDefines)
4121  clingArgs.push_back(std::string("-D") + PPDefine);
4122 
4123  for (const std::string &PPUndefine : gOptPPUndefines)
4124  clingArgs.push_back(std::string("-U") + PPUndefine);
4125 
4126  for (const std::string &IncludePath : gOptIncludePaths)
4127  clingArgs.push_back(std::string("-I") + llvm::sys::path::convert_to_slash(IncludePath));
4128 
4129  for (const std::string &WDiag : gOptWDiags) {
4130  const std::string FullWDiag = std::string("-W") + WDiag;
4131  // Suppress warning when compiling the dictionary, eg. gcc G__xxx.cxx
4132  CheckForMinusW(FullWDiag, diagnosticPragmas);
4133  // Suppress warning when compiling the input headers by cling.
4134  clingArgs.push_back(FullWDiag);
4135  }
4136 
4137  std::string includeDir = llvm::sys::path::convert_to_slash(gDriverConfig->fTROOT__GetIncludeDir());
4138  clingArgs.push_back(std::string("-I") + includeDir);
4139 
4140  std::vector<std::string> pcmArgs;
4141  for (size_t parg = 0, n = clingArgs.size(); parg < n; ++parg) {
4142  auto thisArg = clingArgs[parg];
4143  auto isInclude = ROOT::TMetaUtils::BeginsWith(thisArg,"-I");
4144  if (thisArg == "-c" ||
4145  (gOptNoIncludePaths && isInclude)) continue;
4146  // We now check if the include directories are not excluded
4147  if (isInclude) {
4148  unsigned int offset = 2; // -I is two characters. Now account for spaces
4149  char c = thisArg[offset];
4150  while (c == ' ') c = thisArg[++offset];
4151  auto excludePathsEnd = gOptExcludePaths.end();
4152  auto excludePathPos = std::find_if(gOptExcludePaths.begin(),
4153  excludePathsEnd,
4154  [&](const std::string& path){
4155  return ROOT::TMetaUtils::BeginsWith(&thisArg[offset], path);});
4156  if (excludePathsEnd != excludePathPos) continue;
4157  }
4158  pcmArgs.push_back(thisArg);
4159  }
4160 
4161  // cling-only arguments
4162  clingArgs.push_back(std::string("-I") + llvm::sys::path::convert_to_slash(gDriverConfig->fTROOT__GetEtcDir()));
4163  // We do not want __ROOTCLING__ in the pch!
4164  if (!gOptGeneratePCH) {
4165  clingArgs.push_back("-D__ROOTCLING__");
4166  }
4167 #ifdef R__MACOSX
4168  clingArgs.push_back("-DSYSTEM_TYPE_macosx");
4169 #elif defined(R__WIN32)
4170  clingArgs.push_back("-DSYSTEM_TYPE_winnt");
4171 
4172  // Prevent the following #error: The C++ Standard Library forbids macroizing keywords.
4173  clingArgs.push_back("-D_XKEYCHECK_H");
4174  // Tell windows.h not to #define min and max, it clashes with numerical_limits.
4175  clingArgs.push_back("-DNOMINMAX");
4176 #else // assume UNIX
4177  clingArgs.push_back("-DSYSTEM_TYPE_unix");
4178 #endif
4179 
4180  clingArgs.push_back("-fsyntax-only");
4181 #ifndef R__WIN32
4182  clingArgs.push_back("-fPIC");
4183 #endif
4184  clingArgs.push_back("-Xclang");
4185  clingArgs.push_back("-fmodules-embed-all-files");
4186  clingArgs.push_back("-Xclang");
4187  clingArgs.push_back("-main-file-name");
4188  clingArgs.push_back("-Xclang");
4189  clingArgs.push_back((dictname + ".h").c_str());
4190 
4192 
4193  // FIXME: This line is from TModuleGenerator, but we can't reuse this code
4194  // at this point because TModuleGenerator needs a CompilerInstance (and we
4195  // currently create the arguments for creating said CompilerInstance).
4196  bool isPCH = (gOptDictionaryFileName.getValue() == "allDict.cxx");
4197  std::string outputFile;
4198  // Data is in 'outputFile', therefore in the same scope.
4199  StringRef moduleName;
4200  std::string vfsArg;
4201  // Adding -fmodules to the args will break lexing with __CINT__ defined,
4202  // and we actually do lex with __CINT__ and reuse this variable later,
4203  // we have to copy it now.
4204  auto clingArgsInterpreter = clingArgs;
4205 
4206  if (gOptSharedLibFileName.empty()) {
4208  }
4209 
4210  if (!isPCH && gOptCxxModule) {
4211  // We just pass -fmodules, the CIFactory will do the rest and configure
4212  // clang correctly once it sees this flag.
4213  clingArgsInterpreter.push_back("-fmodules");
4214  clingArgsInterpreter.push_back("-fno-implicit-module-maps");
4215 
4216  for (const std::string &modulemap : gOptModuleMapFiles)
4217  clingArgsInterpreter.push_back("-fmodule-map-file=" + modulemap);
4218 
4219  clingArgsInterpreter.push_back("-fmodule-map-file=" +
4220  std::string(gDriverConfig->fTROOT__GetIncludeDir()) +
4221  "/module.modulemap");
4222  std::string ModuleMapCWD = ROOT::FoundationUtils::GetCurrentDir() + "/module.modulemap";
4223  if (llvm::sys::fs::exists(ModuleMapCWD))
4224  clingArgsInterpreter.push_back("-fmodule-map-file=" + ModuleMapCWD);
4225 
4226  // Specify the module name that we can lookup the module in the modulemap.
4227  outputFile = llvm::sys::path::stem(gOptSharedLibFileName).str();
4228  // Try to get the module name in the modulemap based on the filepath.
4229  moduleName = GetModuleNameFromRdictName(outputFile);
4230 
4231  clingArgsInterpreter.push_back("-fmodule-name");
4232  clingArgsInterpreter.push_back(moduleName.str());
4233 
4234  std::string moduleCachePath = llvm::sys::path::parent_path(gOptSharedLibFileName).str();
4235  // FIXME: This is a horrible workaround to fix the incremental builds.
4236  // The enumerated modules are built by clang impicitly based on #include of
4237  // a header which is contained within that module. The build system has
4238  // no way to track dependencies on them and trigger a rebuild.
4239  // A possible solution can be to disable completely the implicit build of
4240  // modules and each module to be built by rootcling. We need to teach
4241  // rootcling how to build modules with no IO support.
4242  if (moduleName == "Core") {
4244  remove((moduleCachePath + llvm::sys::path::get_separator() + "_Builtin_intrinsics.pcm").str().c_str());
4245  remove((moduleCachePath + llvm::sys::path::get_separator() + "_Builtin_stddef_max_align_t.pcm").str().c_str());
4246  remove((moduleCachePath + llvm::sys::path::get_separator() + "Cling_Runtime.pcm").str().c_str());
4247  remove((moduleCachePath + llvm::sys::path::get_separator() + "Cling_Runtime_Extra.pcm").str().c_str());
4248 #ifdef R__WIN32
4249  remove((moduleCachePath + llvm::sys::path::get_separator() + "vcruntime.pcm").str().c_str());
4250  remove((moduleCachePath + llvm::sys::path::get_separator() + "services.pcm").str().c_str());
4251 #endif
4252 
4253 #ifdef R__MACOSX
4254  remove((moduleCachePath + llvm::sys::path::get_separator() + "Darwin.pcm").str().c_str());
4255 #else
4256  remove((moduleCachePath + llvm::sys::path::get_separator() + "libc.pcm").str().c_str());
4257 #endif
4258  remove((moduleCachePath + llvm::sys::path::get_separator() + "std.pcm").str().c_str());
4259  remove((moduleCachePath + llvm::sys::path::get_separator() + "cuda.pcm").str().c_str());
4260  remove((moduleCachePath + llvm::sys::path::get_separator() + "boost.pcm").str().c_str());
4261  remove((moduleCachePath + llvm::sys::path::get_separator() + "tinyxml2.pcm").str().c_str());
4262  remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Config.pcm").str().c_str());
4263  remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Rtypes.pcm").str().c_str());
4264  remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Foundation_C.pcm").str().c_str());
4265  remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Foundation_Stage1_NoRTTI.pcm").str().c_str());
4266  }
4267 
4268  // Set the C++ modules output directory to the directory where we generate
4269  // the shared library.
4270  clingArgsInterpreter.push_back("-fmodules-cache-path=" + moduleCachePath);
4271  }
4272 
4273  if (gOptVerboseLevel == v4)
4274  clingArgsInterpreter.push_back("-v");
4275 
4276  // Convert arguments to a C array and check if they are sane
4277  std::vector<const char *> clingArgsC;
4278  for (auto const &clingArg : clingArgsInterpreter) {
4279  if (!IsCorrectClingArgument(clingArg)){
4280  std::cerr << "Argument \""<< clingArg << "\" is not a supported cling argument. "
4281  << "This could be mistyped rootcling argument. Please check the commandline.\n";
4282  return 1;
4283  }
4284  clingArgsC.push_back(clingArg.c_str());
4285  }
4286 
4287 
4288  std::unique_ptr<cling::Interpreter> owningInterpPtr;
4289  cling::Interpreter* interpPtr = nullptr;
4290 
4291  std::list<std::string> filesIncludedByLinkdef;
4293  // Pass the interpreter arguments to TCling's interpreter:
4294  clingArgsC.push_back("-resource-dir");
4295  clingArgsC.push_back(llvmResourceDir.c_str());
4296  clingArgsC.push_back(0); // signal end of array
4297  const char ** &extraArgs = *gDriverConfig->fTROOT__GetExtraInterpreterArgs();
4298  extraArgs = &clingArgsC[1]; // skip binary name
4299  interpPtr = gDriverConfig->fTCling__GetInterpreter();
4300  if (!isGenreflex && !gOptGeneratePCH) {
4301  std::unique_ptr<TRootClingCallbacks> callBacks (new TRootClingCallbacks(interpPtr, filesIncludedByLinkdef));
4302  interpPtr->setCallbacks(std::move(callBacks));
4303  }
4304  } else {
4305 #ifdef R__FAST_MATH
4306  // Same setting as in TCling.cxx.
4307  clingArgsC.push_back("-ffast-math");
4308 #endif
4309 
4310  owningInterpPtr.reset(new cling::Interpreter(clingArgsC.size(), &clingArgsC[0],
4311  llvmResourceDir.c_str()));
4312  interpPtr = owningInterpPtr.get();
4313  // Force generation of _Builtin_intrinsics by rootcling_stage1.
4314  // The rest of the modules are implicitly generated by cling when including
4315  // RuntimeUniverse.h (via <new>).
4316  // FIXME: This should really go in the build system as for the rest of the
4317  // implicitly created modules.
4318  if (gOptCxxModule)
4319  interpPtr->loadModule("_Builtin_intrinsics", /*Complain*/ true);
4320  }
4321  cling::Interpreter &interp = *interpPtr;
4322  clang::CompilerInstance *CI = interp.getCI();
4323  // FIXME: Remove this once we switch cling to use the driver. This would handle -fmodules-embed-all-files for us.
4324  CI->getFrontendOpts().ModulesEmbedAllFiles = true;
4325  CI->getSourceManager().setAllFilesAreTransient(true);
4326 
4327  clang::Preprocessor &PP = CI->getPreprocessor();
4328  clang::HeaderSearch &headerSearch = PP.getHeaderSearchInfo();
4329  clang::ModuleMap &moduleMap = headerSearch.getModuleMap();
4330  auto &diags = interp.getDiagnostics();
4331 
4332  // Manually enable the module build remarks. We don't enable them via the
4333  // normal clang command line arg because otherwise we would get remarks for
4334  // building STL/libc when starting the interpreter in rootcling_stage1.
4335  // We can't prevent these diags in any other way because we can only attach
4336  // our own diag client now after the interpreter has already started.
4337  diags.setSeverity(clang::diag::remark_module_build, clang::diag::Severity::Remark, clang::SourceLocation());
4338 
4339  // Attach our own diag client that listens to the module_build remarks from
4340  // clang to check that we don't build dictionary C++ modules implicitly.
4341  auto recordingClient = new CheckModuleBuildClient(diags.getClient(), diags.ownsClient(), moduleMap);
4342  diags.setClient(recordingClient, true);
4343 
4345  ROOT::TMetaUtils::Info(0, "\n");
4346  ROOT::TMetaUtils::Info(0, "==== INTERPRETER CONFIGURATION ====\n");
4347  ROOT::TMetaUtils::Info(0, "== Include paths\n");
4348  interp.DumpIncludePath();
4349  printf("\n\n");
4350  fflush(stdout);
4351 
4352  ROOT::TMetaUtils::Info(0, "== Included files\n");
4353  interp.printIncludedFiles(llvm::outs());
4354  llvm::outs() << "\n\n";
4355  llvm::outs().flush();
4356 
4357  ROOT::TMetaUtils::Info(0, "== Language Options\n");
4358  const clang::LangOptions& LangOpts
4359  = interp.getCI()->getASTContext().getLangOpts();
4360 #define LANGOPT(Name, Bits, Default, Description) \
4361  ROOT::TMetaUtils::Info(0, "%s = %d // %s\n", #Name, (int)LangOpts.Name, Description);
4362 #define ENUM_LANGOPT(Name, Type, Bits, Default, Description)
4363 #include "clang/Basic/LangOptions.def"
4364  ROOT::TMetaUtils::Info(0, "==== END interpreter configuration ====\n\n");
4365  }
4366 
4367  interp.getOptions().ErrorOut = true;
4368  interp.enableRawInput(true);
4369 
4370  if (gOptCxxModule) {
4371  for (llvm::StringRef DepMod : gOptModuleDependencies) {
4372  if (DepMod.endswith("_rdict.pcm")) {
4373  ROOT::TMetaUtils::Warning(0, "'%s' value is deprecated. Please use [<fullpat>]%s.pcm\n",
4374  DepMod.data(),
4375  GetModuleNameFromRdictName(DepMod).str().data());
4376  }
4377  DepMod = GetModuleNameFromRdictName(DepMod);
4378  if (!interp.loadModule(DepMod, /*complain*/false)) {
4379  ROOT::TMetaUtils::Error(0, "Module '%s' failed to load.\n",
4380  DepMod.data());
4381  }
4382  }
4383  }
4384 
4385  if (interp.declare("namespace std {} using namespace std;") != cling::Interpreter::kSuccess) {
4386  ROOT::TMetaUtils::Error(0, "Error loading the default header files.\n");
4387  return 1;
4388  }
4389  if (!isGenreflex) { // rootcling
4390  // ROOTCINT uses to define a few header implicitly, we need to do it explicitly.
4391  if (interp.declare("#include <assert.h>\n") != cling::Interpreter::kSuccess
4392  || interp.declare("#include \"Rtypes.h\"\n"
4393  "#include \"TObject.h\"") != cling::Interpreter::kSuccess
4394  ) {
4395  // There was an error.
4396  ROOT::TMetaUtils::Error(0, "Error loading the default header files.\n");
4397  return 1;
4398  }
4399  }
4400 
4401  // For the list of 'opaque' typedef to also include string, we have to include it now.
4402  interp.declare("#include <string>");
4403  // For initializing TNormalizedCtxt.
4404  interp.declare("#include <RtypesCore.h>");
4405 
4406  // We are now ready (enough is loaded) to init the list of opaque typedefs.
4407  ROOT::TMetaUtils::TNormalizedCtxt normCtxt(interp.getLookupHelper());
4408  ROOT::TMetaUtils::TClingLookupHelper helper(interp, normCtxt, 0, 0, nullptr);
4409  TClassEdit::Init(&helper);
4410 
4411  // flags used only for the pragma parser:
4412  clingArgs.push_back("-D__CINT__");
4413  clingArgs.push_back("-D__MAKECINT__");
4414 
4415  AddPlatformDefines(clingArgs);
4416 
4417  std::string currentDirectory = ROOT::FoundationUtils::GetCurrentDir();
4418 
4419  std::string interpPragmaSource;
4420  std::string includeForSource;
4421  std::string interpreterDeclarations;
4422  std::string linkdef;
4423 
4424  for (size_t i = 0, e = gOptDictionaryHeaderFiles.size(); i < e; ++i) {
4425  const std::string& optHeaderFileName = gOptDictionaryHeaderFiles[i];
4426  bool isSelectionFile = IsSelectionFile(optHeaderFileName.c_str());
4427 
4428  if (isSelectionFile) {
4429  if (i == e - 1) {
4430  linkdef = optHeaderFileName;
4431  } else { // if the linkdef was not last, issue an error.
4432  ROOT::TMetaUtils::Error(0, "%s: %s must be last file on command line\n",
4433  executableFileName, optHeaderFileName.c_str());
4434  return 1;
4435  }
4436  }
4437 
4438  // coverity[tainted_data] The OS should already limit the argument size, so we are safe here
4439  std::string fullheader(optHeaderFileName);
4440  // Strip any trailing + which is only used by GeneratedLinkdef.h which currently
4441  // use directly argv.
4442  if (fullheader[fullheader.length() - 1] == '+') {
4443  fullheader.erase(fullheader.length() - 1);
4444  }
4445  std::string header(
4446  isSelectionFile ? fullheader : ROOT::FoundationUtils::MakePathRelative(fullheader, currentDirectory, gBuildingROOT));
4447 
4448  interpPragmaSource += std::string("#include \"") + header + "\"\n";
4449  if (!isSelectionFile) {
4450  // In order to not have to add the equivalent to -I${PWD} to the
4451  // command line, include the complete file name, even if it is a
4452  // full pathname, when we write it down in the dictionary.
4453  // Note: have -I${PWD} means in that (at least in the case of
4454  // ACLiC) we inadvertently pick local file that have the same
4455  // name as system header (e.g. new or list) and -iquote has not
4456  // equivalent on some platforms.
4457  includeForSource += std::string("#include \"") + fullheader + "\"\n";
4458  pcmArgs.push_back(header);
4459  } else if (!IsSelectionXml(optHeaderFileName.c_str())) {
4460  interpreterDeclarations += std::string("#include \"") + header + "\"\n";
4461  }
4462  }
4463 
4464  if (gOptUmbrellaInput) {
4465  bool hasSelectionFile = !linkdef.empty();
4466  unsigned expectedHeaderFilesSize = 1 + hasSelectionFile;
4467  if (gOptDictionaryHeaderFiles.size() > expectedHeaderFilesSize)
4468  ROOT::TMetaUtils::Error(0, "Option %s used but more than one header file specified.\n",
4469  gOptUmbrellaInput.ArgStr.data());
4470  }
4471 
4472  // We have a multiDict request. This implies generating a pcm which is of the form
4473  // dictName_libname_rdict.pcm
4474  if (gOptMultiDict) {
4475 
4476  std::string newName = llvm::sys::path::parent_path(gOptSharedLibFileName).str();
4477  if (!newName.empty())
4478  newName += gPathSeparator;
4479  newName += llvm::sys::path::stem(gOptSharedLibFileName);
4480  newName += "_";
4481  newName += llvm::sys::path::stem(gOptDictionaryFileName);
4483  gOptSharedLibFileName = newName;
4484  }
4485 
4486  // Until the module are actually enabled in ROOT, we need to register
4487  // the 'current' directory to make it relocatable (i.e. have a way
4488  // to find the headers).
4490  string incCurDir = "-I";
4491  incCurDir += currentDirectory;
4492  pcmArgs.push_back(incCurDir);
4493  }
4494 
4495  // Add the diagnostic pragmas distilled from the -Wno-xyz
4496  {
4497  std::stringstream res;
4498  const char* delim="\n";
4499  std::copy(diagnosticPragmas.begin(),
4500  diagnosticPragmas.end(),
4501  std::ostream_iterator<std::string>(res, delim));
4502  interp.declare(res.str());
4503  }
4504 
4505  class IgnoringPragmaHandler: public clang::PragmaNamespace {
4506  public:
4507  IgnoringPragmaHandler(const char* pragma):
4508  clang::PragmaNamespace(pragma) {}
4509  void HandlePragma(clang::Preprocessor &PP,
4510  clang::PragmaIntroducerKind Introducer,
4511  clang::Token &tok) {
4512  PP.DiscardUntilEndOfDirective();
4513  }
4514  };
4515 
4516  // Ignore these #pragmas to suppress "unknown pragma" warnings.
4517  // See LinkdefReader.cxx.
4518  PP.AddPragmaHandler(new IgnoringPragmaHandler("link"));
4519  PP.AddPragmaHandler(new IgnoringPragmaHandler("extra_include"));
4520  PP.AddPragmaHandler(new IgnoringPragmaHandler("read"));
4521  PP.AddPragmaHandler(new IgnoringPragmaHandler("create"));
4522 
4523  if (!interpreterDeclarations.empty() &&
4524  interp.declare(interpreterDeclarations) != cling::Interpreter::kSuccess) {
4525  ROOT::TMetaUtils::Error(0, "%s: Linkdef compilation failure\n", executableFileName);
4526  return 1;
4527  }
4528 
4529 
4530  TModuleGenerator modGen(interp.getCI(),
4534 
4535  if (!gDriverConfig->fBuildingROOTStage1 && !filesIncludedByLinkdef.empty()) {
4536  pcmArgs.push_back(linkdef);
4537  }
4538 
4539  modGen.ParseArgs(pcmArgs);
4540 
4542  // Forward the -I, -D, -U
4543  for (const std::string & inclPath : modGen.GetIncludePaths()) {
4544  interp.AddIncludePath(inclPath);
4545  }
4546  std::stringstream definesUndefinesStr;
4547  modGen.WritePPDefines(definesUndefinesStr);
4548  modGen.WritePPUndefines(definesUndefinesStr);
4549  if (!definesUndefinesStr.str().empty())
4550  interp.declare(definesUndefinesStr.str());
4551  }
4552 
4553  if (!InjectModuleUtilHeader(executableFileName, modGen, interp, true)
4554  || !InjectModuleUtilHeader(executableFileName, modGen, interp, false)) {
4555  return 1;
4556  }
4557 
4558  if (linkdef.empty()) {
4559  // Generate autolinkdef
4560  GenerateLinkdef(gOptDictionaryHeaderFiles, interpPragmaSource);
4561  }
4562 
4563  // Check if code goes to stdout or rootcling file
4564  std::ofstream fileout;
4565  string main_dictname(gOptDictionaryFileName.getValue());
4566  std::ostream *splitDictStream = nullptr;
4567  std::unique_ptr<std::ostream> splitDeleter(nullptr);
4568  // Store the temp files
4569  tempFileNamesCatalog tmpCatalog;
4570  if (!gOptIgnoreExistingDict) {
4571  if (!gOptDictionaryFileName.empty()) {
4572  tmpCatalog.addFileName(gOptDictionaryFileName.getValue());
4573  fileout.open(gOptDictionaryFileName.c_str());
4574  if (!fileout) {
4575  ROOT::TMetaUtils::Error(0, "rootcling: failed to open %s in main\n",
4576  gOptDictionaryFileName.c_str());
4577  return 1;
4578  }
4579  }
4580  }
4581 
4582  std::ostream &dictStream = (!gOptIgnoreExistingDict && !gOptDictionaryFileName.empty()) ? fileout : std::cout;
4583 
4584  if (!gOptIgnoreExistingDict) {
4585  // Now generate a second stream for the split dictionary if it is necessary
4586  if (gOptSplit) {
4587  splitDictStream = CreateStreamPtrForSplitDict(gOptDictionaryFileName.getValue(), tmpCatalog);
4588  splitDeleter.reset(splitDictStream);
4589  } else {
4590  splitDictStream = &dictStream;
4591  }
4592 
4593  size_t dh = main_dictname.rfind('.');
4594  if (dh != std::string::npos) {
4595  main_dictname.erase(dh);
4596  }
4597  // Need to replace all the characters not allowed in a symbol ...
4598  std::string main_dictname_copy(main_dictname);
4599  TMetaUtils::GetCppName(main_dictname, main_dictname_copy.c_str());
4600 
4601  CreateDictHeader(dictStream, main_dictname);
4602  if (gOptSplit)
4603  CreateDictHeader(*splitDictStream, main_dictname);
4604 
4605  if (!gOptNoGlobalUsingStd) {
4606  AddNamespaceSTDdeclaration(dictStream);
4607  if (gOptSplit) {
4608  AddNamespaceSTDdeclaration(*splitDictStream);
4609  }
4610  }
4611  }
4612 
4613  //---------------------------------------------------------------------------
4614  // Parse the linkdef or selection.xml file.
4615  /////////////////////////////////////////////////////////////////////////////
4616 
4617  string linkdefFilename;
4618  if (linkdef.empty()) {
4619  linkdefFilename = "in memory";
4620  } else {
4621  bool found = Which(interp, linkdef.c_str(), linkdefFilename);
4622  if (!found) {
4623  ROOT::TMetaUtils::Error(0, "%s: cannot open linkdef file %s\n", executableFileName, linkdef.c_str());
4624  return 1;
4625  }
4626  }
4627 
4628  // Exclude string not to re-generate the dictionary
4629  std::vector<std::pair<std::string, std::string>> namesForExclusion;
4630  if (!gBuildingROOT) {
4631  namesForExclusion.push_back(std::make_pair(ROOT::TMetaUtils::propNames::name, "std::string"));
4632  namesForExclusion.push_back(std::make_pair(ROOT::TMetaUtils::propNames::pattern, "ROOT::Meta::Selection*"));
4633  }
4634 
4635  SelectionRules selectionRules(interp, normCtxt, namesForExclusion);
4636 
4637  std::string extraIncludes;
4638 
4639  ROOT::TMetaUtils::RConstructorTypes constructorTypes;
4640 
4641  // Select using DictSelection
4642  const unsigned int selRulesInitialSize = selectionRules.Size();
4643  if (dictSelection && !gOptGeneratePCH)
4644  ROOT::Internal::DictSelectionReader dictSelReader(interp, selectionRules, CI->getASTContext(), normCtxt);
4645 
4646  bool dictSelRulesPresent = selectionRules.Size() > selRulesInitialSize;
4647 
4648  bool isSelXML = IsSelectionXml(linkdefFilename.c_str());
4649 
4650  int rootclingRetCode(0);
4651 
4652  if (linkdef.empty()) {
4653  // There is no linkdef file, we added the 'default' #pragma to
4654  // interpPragmaSource.
4655 
4656  LinkdefReader ldefr(interp, constructorTypes);
4657  clingArgs.push_back("-Ietc/cling/cint"); // For multiset and multimap
4658 
4659  if (!ldefr.Parse(selectionRules, interpPragmaSource, clingArgs,
4660  llvmResourceDir.c_str())) {
4661  ROOT::TMetaUtils::Error(0, "Parsing #pragma failed %s\n", linkdefFilename.c_str());
4662  rootclingRetCode += 1;
4663  } else {
4664  ROOT::TMetaUtils::Info(0, "#pragma successfully parsed.\n");
4665  }
4666 
4667  if (!ldefr.LoadIncludes(extraIncludes)) {
4668  ROOT::TMetaUtils::Error(0, "Error loading the #pragma extra_include.\n");
4669  return 1;
4670  }
4671 
4672  } else if (isSelXML) {
4673 
4675 
4676  std::ifstream file(linkdefFilename.c_str());
4677  if (file.is_open()) {
4678  ROOT::TMetaUtils::Info(0, "Selection XML file\n");
4679 
4680  XMLReader xmlr(interp);
4681  if (!xmlr.Parse(linkdefFilename.c_str(), selectionRules)) {
4682  ROOT::TMetaUtils::Error(0, "Parsing XML file %s\n", linkdefFilename.c_str());
4683  return 1; // Return here to propagate the failure up to the build system
4684  } else {
4685  ROOT::TMetaUtils::Info(0, "XML file successfully parsed\n");
4686  }
4687  file.close();
4688  } else {
4689  ROOT::TMetaUtils::Error(0, "XML file %s couldn't be opened!\n", linkdefFilename.c_str());
4690  }
4691 
4692  } else if (ROOT::TMetaUtils::IsLinkdefFile(linkdefFilename.c_str())) {
4693 
4694  std::ifstream file(linkdefFilename.c_str());
4695  if (file.is_open()) {
4696  ROOT::TMetaUtils::Info(0, "Using linkdef file: %s\n", linkdefFilename.c_str());
4697  file.close();
4698  } else {
4699  ROOT::TMetaUtils::Error(0, "Linkdef file %s couldn't be opened!\n", linkdefFilename.c_str());
4700  }
4701 
4703 
4704  LinkdefReader ldefr(interp, constructorTypes);
4705  clingArgs.push_back("-Ietc/cling/cint"); // For multiset and multimap
4706 
4707  if (!ldefr.Parse(selectionRules, interpPragmaSource, clingArgs,
4708  llvmResourceDir.c_str())) {
4709  ROOT::TMetaUtils::Error(0, "Parsing Linkdef file %s\n", linkdefFilename.c_str());
4710  rootclingRetCode += 1;
4711  } else {
4712  ROOT::TMetaUtils::Info(0, "Linkdef file successfully parsed.\n");
4713  }
4714 
4715  if (! ldefr.LoadIncludes(extraIncludes)) {
4716  ROOT::TMetaUtils::Error(0, "Error loading the #pragma extra_include.\n");
4717  return 1;
4718  }
4719 
4720  } else {
4721 
4722  ROOT::TMetaUtils::Error(0, "Unrecognized selection file: %s\n", linkdefFilename.c_str());
4723 
4724  }
4725 
4726  // Speed up the operations with rules
4727  selectionRules.FillCache();
4728  selectionRules.Optimize();
4729 
4730  if (isGenreflex){
4731  if (0 != selectionRules.CheckDuplicates()){
4732  return 1;
4733  }
4734  }
4735 
4736  // If we want to validate the selection only, we just quit.
4738  return 0;
4739 
4740  //---------------------------------------------------------------------------
4741  // Write schema evolution related headers and declarations
4742  /////////////////////////////////////////////////////////////////////////////
4743 
4744  if ((!ROOT::gReadRules.empty() || !ROOT::gReadRawRules.empty()) && !gOptIgnoreExistingDict) {
4745  dictStream << "#include \"TBuffer.h\"\n"
4746  << "#include \"TVirtualObject.h\"\n"
4747  << "#include <vector>\n"
4748  << "#include \"TSchemaHelper.h\"\n\n";
4749 
4750  std::list<std::string> includes;
4751  GetRuleIncludes(includes);
4752  for (auto & incFile : includes) {
4753  dictStream << "#include <" << incFile << ">" << std::endl;
4754  }
4755  dictStream << std::endl;
4756  }
4757 
4758  selectionRules.SearchNames(interp);
4759 
4760  int scannerVerbLevel = 0;
4761  {
4762  using namespace ROOT::TMetaUtils;
4763  scannerVerbLevel = GetErrorIgnoreLevel() == kInfo; // 1 if true, 0 if false
4764  if (isGenreflex){
4765  scannerVerbLevel = GetErrorIgnoreLevel() < kWarning;
4766  }
4767  }
4768 
4769  // Select the type of scan
4770  auto scanType = RScanner::EScanType::kNormal;
4771  if (gOptGeneratePCH)
4772  scanType = RScanner::EScanType::kOnePCM;
4773  if (dictSelection)
4775 
4776  RScanner scan(selectionRules,
4777  scanType,
4778  interp,
4779  normCtxt,
4780  scannerVerbLevel);
4781 
4782  // If needed initialize the autoloading hook
4783  if (!gOptLibListPrefix.empty()) {
4786  }
4787 
4788  scan.Scan(CI->getASTContext());
4789 
4790  bool has_input_error = false;
4791 
4792  if (genreflex::verbose)
4793  selectionRules.PrintSelectionRules();
4794 
4796  !gOptGeneratePCH &&
4797  !dictSelRulesPresent &&
4798  !selectionRules.AreAllSelectionRulesUsed()) {
4799  ROOT::TMetaUtils::Warning(0, "Not all selection rules are used!\n");
4800  }
4801 
4802  if (!gOptGeneratePCH){
4803  rootclingRetCode += CheckForUnsupportedClasses(scan.fSelectedClasses);
4804  if (rootclingRetCode) return rootclingRetCode;
4805  }
4806 
4807  // SELECTION LOOP
4808  // Check for error in the class layout before doing anything else.
4809  for (auto const & annRcd : scan.fSelectedClasses) {
4810  if (ROOT::TMetaUtils::ClassInfo__HasMethod(annRcd, "Streamer", interp)) {
4811  if (annRcd.RequestNoInputOperator()) {
4812  int version = ROOT::TMetaUtils::GetClassVersion(annRcd, interp);
4813  if (version != 0) {
4814  // Only Check for input operator is the object is I/O has
4815  // been requested.
4816  has_input_error |= CheckInputOperator(annRcd, interp);
4817  }
4818  }
4819  }
4820  has_input_error |= !CheckClassDef(*annRcd, interp);
4821  }
4822 
4823  if (has_input_error) {
4824  // Be a little bit makefile friendly and remove the dictionary in case of error.
4825  // We could add an option -k to keep the file even in case of error.
4826  exit(1);
4827  }
4828 
4829  //---------------------------------------------------------------------------
4830  // Write all the necessary #include
4831  /////////////////////////////////////////////////////////////////////////////
4833  for (auto &&includedFromLinkdef : filesIncludedByLinkdef) {
4834  includeForSource += "#include \"" + includedFromLinkdef + "\"\n";
4835  }
4836  }
4837 
4838  if (!gOptGeneratePCH) {
4839  if (!gOptIgnoreExistingDict) {
4840  GenerateNecessaryIncludes(dictStream, includeForSource, extraIncludes);
4841  if (gOptSplit) {
4842  GenerateNecessaryIncludes(*splitDictStream, includeForSource, extraIncludes);
4843  }
4844  }
4846  gDriverConfig->fInitializeStreamerInfoROOTFile(modGen.GetModuleFileName().c_str());
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(0, "%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(0, "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 {
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) {
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]) {
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 build 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" , "" ,
5834  ""
5835  },
5836 
5837  {
5838  PREPROCUNDEFINE,
5839  STRING ,
5840  "U" , "" ,
5842  ""
5843  },
5844 
5845  {
5846  WARNING,
5847  STRING ,
5848  "W" , "" ,
5850  ""
5851  },
5852 
5853  {
5854  NOMEMBERTYPEDEFS, // Option which is not meant for the user: deprecated
5855  STRING ,
5856  "" , "no_membertypedefs" ,
5858  ""
5859  },
5860 
5861  {
5862  NOTEMPLATETYPEDEFS, // Option which is not meant for the user: deprecated
5863  STRING ,
5864  "" , "no_templatetypedefs" ,
5866  ""
5867  },
5868 
5869  {0, 0, 0, 0, 0, 0}
5870  };
5871 
5872  std::vector<std::string> headersNames;
5873  const int originalArgc = argc;
5874  // The only args are the headers here
5875  const int extractedArgs = extractArgs(argc, argv, headersNames);
5876 
5877  const int offset = 1; // skip argv[0]
5878  argc -= offset + extractedArgs;
5879  argv += offset;
5880 
5881  // Parse the options
5882  ROOT::option::Stats stats(genreflexUsageDescriptor, argc, argv);
5883  std::vector<ROOT::option::Option> options(stats.options_max);// non POD var size arrays are not C++!
5884  std::vector<ROOT::option::Option> buffer(stats.buffer_max);
5885  // The 4 is the minimum size of the abbreviation length.
5886  // For example, --selection_file can be abbreviated with --sele at least.
5887 
5888  ROOT::option::Parser parse(genreflexUsageDescriptor, argc, argv, &options[0], &buffer[0], 5);
5889 
5890  if (parse.error()) {
5891  ROOT::TMetaUtils::Error(0, "Argument parsing error!\n");
5892  return 1;
5893  }
5894 
5895  // Print help if needed
5896  if (options[HELP] || originalArgc == 1) {
5897  ROOT::option::printUsage(std::cout, genreflexUsageDescriptor);
5898  return 0;
5899  }
5900  // See if no header was provided
5901  int numberOfHeaders = checkHeadersNames(headersNames);
5902  if (0 == numberOfHeaders) {
5903  ROOT::TMetaUtils::Error(0, "No valid header was provided!\n");
5904  return 1;
5905  }
5906 
5908 
5909  if (options[DEEP])
5910  ROOT::TMetaUtils::Warning(0, "--deep has no effect. Please remove the deprecated flag!\n");
5911  // The verbosity: debug wins over quiet
5912  //std::string verbosityOption("-v4"); // To be uncommented for the testing phase. It should be -v
5913  std::string verbosityOption("-v2");
5914  if (options[SILENT]) verbosityOption = "-v0";
5915  if (options[VERBOSE] || getenv ("VERBOSE")) verbosityOption = "-v3";
5916  if (options[DEBUG]) verbosityOption = "-v4";
5917 
5918  genreflex::verbose = verbosityOption == "-v4";
5919 
5920  // The selection file
5921  std::string selectionFileName;
5922  if (options[SELECTIONFILENAME]) {
5923  selectionFileName = options[SELECTIONFILENAME].arg;
5924  if (!ROOT::TMetaUtils::EndsWith(selectionFileName, ".xml")) {
5926  "Invalid selection file extension: filename is %s and extension .xml is expected!\n",
5927  selectionFileName.c_str());
5928  return 1;
5929  }
5930  }
5931 
5932 // // Warn if a selection file is not present and exit
5933 // if (NULL==options[SELECTIONFILENAME].arg){
5934 // ROOT::TMetaUtils::Warning(0,"The usage of genreflex without a selection file is not yet supported.\n");
5935 // return 1;
5936 // }
5937 
5938 
5939  // Set the parameters for the rootmap file. If the libname is not set,
5940  // it will be set according to the header in invokeRootCling.
5941  // FIXME: treatment of directories
5942  std::string rootmapFileName(options[ROOTMAP].arg ? options[ROOTMAP].arg : "");
5943  std::string rootmapLibName(options[ROOTMAPLIB].arg ? options[ROOTMAPLIB].arg : "");
5944 
5945  // The target lib name
5946  std::string targetLibName;
5947  if (options[TARGETLIB]) {
5948  targetLibName = options[TARGETLIB].arg;
5949  if (!IsGoodLibraryName(targetLibName)) {
5951  "Invalid target library extension: filename is %s and extension %s is expected!\n",
5952  targetLibName.c_str(),
5953  gLibraryExtension.c_str());
5954  }
5955  // Target lib has precedence over rootmap lib
5956  if (options[ROOTMAP]) {
5957  rootmapLibName =