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