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  bool deleteOutputFile = compilerInstance->getDiagnostics().hasErrorOccurred();
2007  compilerInstance->clearOutputFiles(deleteOutputFile);
2008 
2009  return true;
2010 }
2011 
2012 ////////////////////////////////////////////////////////////////////////////////
2013 /// Generates a PCH from the given ModuleGenerator and CompilerInstance.
2014 /// Returns true iff the PCH was successfully generated.
2015 static bool GenerateAllDict(TModuleGenerator &modGen, clang::CompilerInstance *compilerInstance,
2016  const std::string &currentDirectory)
2017 {
2018  assert(modGen.IsPCH() && "modGen must be in PCH mode");
2019 
2020  std::string iSysRoot("/DUMMY_SYSROOT/include/");
2021  if (gBuildingROOT) iSysRoot = (currentDirectory + "/");
2022  return WriteAST(modGen.GetModuleFileName(), compilerInstance, iSysRoot);
2023 }
2024 
2025 ////////////////////////////////////////////////////////////////////////////////
2026 /// Includes all given headers in the interpreter. Returns true when we could
2027 /// include the headers and otherwise false on an error when including.
2028 static bool IncludeHeaders(const std::vector<std::string> &headers, cling::Interpreter &interpreter)
2029 {
2030  // If no headers are given, this is a no-op.
2031  if (headers.empty())
2032  return true;
2033 
2034  // Turn every header name into an include and parse it in the interpreter.
2035  std::stringstream includes;
2036  for (const std::string &header : headers) {
2037  includes << "#include \"" << header << "\"\n";
2038  }
2039  std::string includeListStr = includes.str();
2040  auto result = interpreter.declare(includeListStr);
2041  return result == cling::Interpreter::CompilationResult::kSuccess;
2042 }
2043 
2044 
2045 ////////////////////////////////////////////////////////////////////////////////
2046 
2047 void AddPlatformDefines(std::vector<std::string> &clingArgs)
2048 {
2049  char platformDefines[64] = {0};
2050 #ifdef __INTEL_COMPILER
2051  snprintf(platformDefines, 64, "-DG__INTEL_COMPILER=%ld", (long)__INTEL_COMPILER);
2052  clingArgs.push_back(platformDefines);
2053 #endif
2054 #ifdef __xlC__
2055  snprintf(platformDefines, 64, "-DG__xlC=%ld", (long)__xlC__);
2056  clingArgs.push_back(platformDefines);
2057 #endif
2058 #ifdef __GNUC__
2059  snprintf(platformDefines, 64, "-DG__GNUC=%ld", (long)__GNUC__);
2060  snprintf(platformDefines, 64, "-DG__GNUC_VER=%ld", (long)__GNUC__ * 1000 + __GNUC_MINOR__);
2061  clingArgs.push_back(platformDefines);
2062 #endif
2063 #ifdef __GNUC_MINOR__
2064  snprintf(platformDefines, 64, "-DG__GNUC_MINOR=%ld", (long)__GNUC_MINOR__);
2065  clingArgs.push_back(platformDefines);
2066 #endif
2067 #ifdef __HP_aCC
2068  snprintf(platformDefines, 64, "-DG__HP_aCC=%ld", (long)__HP_aCC);
2069  clingArgs.push_back(platformDefines);
2070 #endif
2071 #ifdef __sun
2072  snprintf(platformDefines, 64, "-DG__sun=%ld", (long)__sun);
2073  clingArgs.push_back(platformDefines);
2074 #endif
2075 #ifdef __SUNPRO_CC
2076  snprintf(platformDefines, 64, "-DG__SUNPRO_CC=%ld", (long)__SUNPRO_CC);
2077  clingArgs.push_back(platformDefines);
2078 #endif
2079 #ifdef _STLPORT_VERSION
2080  // stlport version, used on e.g. SUN
2081  snprintf(platformDefines, 64, "-DG__STLPORT_VERSION=%ld", (long)_STLPORT_VERSION);
2082  clingArgs.push_back(platformDefines);
2083 #endif
2084 #ifdef __ia64__
2085  snprintf(platformDefines, 64, "-DG__ia64=%ld", (long)__ia64__);
2086  clingArgs.push_back(platformDefines);
2087 #endif
2088 #ifdef __x86_64__
2089  snprintf(platformDefines, 64, "-DG__x86_64=%ld", (long)__x86_64__);
2090  clingArgs.push_back(platformDefines);
2091 #endif
2092 #ifdef __i386__
2093  snprintf(platformDefines, 64, "-DG__i386=%ld", (long)__i386__);
2094  clingArgs.push_back(platformDefines);
2095 #endif
2096 #ifdef __arm__
2097  snprintf(platformDefines, 64, "-DG__arm=%ld", (long)__arm__);
2098  clingArgs.push_back(platformDefines);
2099 #endif
2100 #ifdef _WIN32
2101  snprintf(platformDefines, 64, "-DG__WIN32=%ld", (long)_WIN32);
2102  clingArgs.push_back(platformDefines);
2103 #else
2104 # ifdef WIN32
2105  snprintf(platformDefines, 64, "-DG__WIN32=%ld", (long)WIN32);
2106  clingArgs.push_back(platformDefines);
2107 # endif
2108 #endif
2109 #ifdef _MSC_VER
2110  snprintf(platformDefines, 64, "-DG__MSC_VER=%ld", (long)_MSC_VER);
2111  clingArgs.push_back(platformDefines);
2112  snprintf(platformDefines, 64, "-DG__VISUAL=%ld", (long)_MSC_VER);
2113  clingArgs.push_back(platformDefines);
2114 #endif
2115 }
2116 
2117 ////////////////////////////////////////////////////////////////////////////////
2118 /// Extract the filename from a fullpath
2119 
2120 std::string ExtractFileName(const std::string &path)
2121 {
2122  return llvm::sys::path::filename(path);
2123 }
2124 
2125 ////////////////////////////////////////////////////////////////////////////////
2126 /// Extract the path from a fullpath finding the last \ or /
2127 /// according to the content in gPathSeparator
2128 
2129 void ExtractFilePath(const std::string &path, std::string &dirname)
2130 {
2131  const size_t pos = path.find_last_of(gPathSeparator);
2132  if (std::string::npos != pos) {
2133  dirname.assign(path.begin(), path.begin() + pos + 1);
2134  } else {
2135  dirname.assign("");
2136  }
2137 }
2138 
2139 ////////////////////////////////////////////////////////////////////////////////
2140 /// Check if file has a path
2141 
2142 bool HasPath(const std::string &name)
2143 {
2144  std::string dictLocation;
2145  ExtractFilePath(name, dictLocation);
2146  return !dictLocation.empty();
2147 }
2148 
2149 ////////////////////////////////////////////////////////////////////////////////
2150 
2151 void AdjustRootMapNames(std::string &rootmapFileName,
2152  std::string &rootmapLibName)
2153 {
2154  // If the rootmap file name does not exist, create one following the libname
2155  // I.E. put into the directory of the lib the rootmap and within the rootmap the normalised path to the lib
2156  if (rootmapFileName.empty()) {
2157  size_t libExtensionPos = rootmapLibName.find_last_of(gLibraryExtension) - gLibraryExtension.size() + 1;
2158  rootmapFileName = rootmapLibName.substr(0, libExtensionPos) + ".rootmap";
2159  size_t libCleanNamePos = rootmapLibName.find_last_of(gPathSeparator) + 1;
2160  rootmapLibName = rootmapLibName.substr(libCleanNamePos, std::string::npos);
2161  ROOT::TMetaUtils::Info(0, "Rootmap file name %s built from rootmap lib name %s",
2162  rootmapLibName.c_str(),
2163  rootmapFileName.c_str());
2164  }
2165 }
2166 
2167 ////////////////////////////////////////////////////////////////////////////////
2168 /// Extract the proper autoload key for nested classes
2169 /// The routine does not erase the name, just updates it
2170 
2171 void GetMostExternalEnclosingClassName(const clang::DeclContext &theContext,
2172  std::string &ctxtName,
2173  const cling::Interpreter &interpreter,
2174  bool treatParent = true)
2175 {
2176  const clang::DeclContext *outerCtxt = treatParent ? theContext.getParent() : &theContext;
2177  // If the context has no outer context, we are finished
2178  if (!outerCtxt) return;
2179  // If the context is a class, we update the name
2180  if (const clang::RecordDecl *thisRcdDecl = llvm::dyn_cast<clang::RecordDecl>(outerCtxt)) {
2181  ROOT::TMetaUtils::GetNormalizedName(ctxtName, thisRcdDecl, interpreter);
2182  }
2183  // We recurse
2184  GetMostExternalEnclosingClassName(*outerCtxt, ctxtName, interpreter);
2185 }
2186 
2187 ////////////////////////////////////////////////////////////////////////////////
2188 
2189 void GetMostExternalEnclosingClassNameFromDecl(const clang::Decl &theDecl,
2190  std::string &ctxtName,
2191  const cling::Interpreter &interpreter)
2192 {
2193  const clang::DeclContext *theContext = theDecl.getDeclContext();
2194  GetMostExternalEnclosingClassName(*theContext, ctxtName, interpreter, false);
2195 }
2196 
2197 ////////////////////////////////////////////////////////////////////////////////
2198 template<class COLL>
2199 int ExtractAutoloadKeys(std::list<std::string> &names,
2200  const COLL &decls,
2201  const cling::Interpreter &interp)
2202 {
2203  if (!decls.empty()) {
2204  std::string autoLoadKey;
2205  for (auto & d : decls) {
2206  autoLoadKey = "";
2207  GetMostExternalEnclosingClassNameFromDecl(*d, autoLoadKey, interp);
2208  // If there is an outer class, it is already considered
2209  if (autoLoadKey.empty()) {
2210  names.push_back(d->getQualifiedNameAsString());
2211  }
2212  }
2213  }
2214  return 0;
2215 }
2216 
2217 ////////////////////////////////////////////////////////////////////////////////
2218 /// Generate a rootmap file in the new format, like
2219 /// { decls }
2220 /// namespace A { namespace B { template <typename T> class myTemplate; } }
2221 /// [libGpad.so libGraf.so libHist.so libMathCore.so]
2222 /// class TAttCanvas
2223 /// class TButton
2224 /// (header1.h header2.h .. headerN.h)
2225 /// class TMyClass
2226 
2227 int CreateNewRootMapFile(const std::string &rootmapFileName,
2228  const std::string &rootmapLibName,
2229  const std::list<std::string> &classesDefsList,
2230  const std::list<std::string> &classesNames,
2231  const std::list<std::string> &nsNames,
2232  const std::list<std::string> &tdNames,
2233  const std::list<std::string> &enNames,
2234  const std::list<std::string> &varNames,
2235  const HeadersDeclsMap_t &headersClassesMap,
2236  const std::unordered_set<std::string> headersToIgnore)
2237 {
2238  // Create the rootmap file from the selected classes and namespaces
2239  std::ofstream rootmapFile(rootmapFileName.c_str());
2240  if (!rootmapFile) {
2241  ROOT::TMetaUtils::Error(0, "Opening new rootmap file %s\n", rootmapFileName.c_str());
2242  return 1;
2243  }
2244 
2245  // Keep track of the classes keys
2246  // This is done to avoid duplications of keys with typedefs
2247  std::unordered_set<std::string> classesKeys;
2248 
2249 
2250  // Add the "section"
2251  if (!classesNames.empty() || !nsNames.empty() || !tdNames.empty() ||
2252  !enNames.empty() || !varNames.empty()) {
2253 
2254  // Add the template definitions
2255  if (!classesDefsList.empty()) {
2256  rootmapFile << "{ decls }\n";
2257  for (auto & classDef : classesDefsList) {
2258  rootmapFile << classDef << std::endl;
2259  }
2260  rootmapFile << "\n";
2261  }
2262  rootmapFile << "[ " << rootmapLibName << " ]\n";
2263 
2264  // Loop on selected classes and insert them in the rootmap
2265  if (!classesNames.empty()) {
2266  rootmapFile << "# List of selected classes\n";
2267  for (auto & className : classesNames) {
2268  rootmapFile << "class " << className << std::endl;
2269  classesKeys.insert(className);
2270  }
2271  // And headers
2272  std::unordered_set<std::string> treatedHeaders;
2273  for (auto & className : classesNames) {
2274  // Don't treat templates
2275  if (className.find("<") != std::string::npos) continue;
2276  if (headersClassesMap.count(className)) {
2277  auto &headers = headersClassesMap.at(className);
2278  if (!headers.empty()){
2279  auto &header = headers.front();
2280  if (treatedHeaders.insert(header).second &&
2281  headersToIgnore.find(header) == headersToIgnore.end() &&
2282  ROOT::TMetaUtils::IsHeaderName(header)){
2283  rootmapFile << "header " << header << std::endl;
2284  }
2285  }
2286  }
2287  }
2288  }
2289 
2290  // Same for namespaces
2291  if (!nsNames.empty()) {
2292  rootmapFile << "# List of selected namespaces\n";
2293  for (auto & nsName : nsNames) {
2294  rootmapFile << "namespace " << nsName << std::endl;
2295  }
2296  }
2297 
2298  // And typedefs. These are used just to trigger the autoload mechanism
2299  if (!tdNames.empty()) {
2300  rootmapFile << "# List of selected typedefs and outer classes\n";
2301  for (const auto & autoloadKey : tdNames)
2302  if (classesKeys.insert(autoloadKey).second)
2303  rootmapFile << "typedef " << autoloadKey << std::endl;
2304  }
2305 
2306  // And Enums. There is no incomplete type for an enum but we can nevertheless
2307  // have the key for the cases where the root typesystem is interrogated.
2308  if (!enNames.empty()){
2309  rootmapFile << "# List of selected enums and outer classes\n";
2310  for (const auto & autoloadKey : enNames)
2311  if (classesKeys.insert(autoloadKey).second)
2312  rootmapFile << "enum " << autoloadKey << std::endl;
2313  }
2314 
2315  // And variables.
2316  if (!varNames.empty()){
2317  rootmapFile << "# List of selected vars\n";
2318  for (const auto & autoloadKey : varNames)
2319  if (classesKeys.insert(autoloadKey).second)
2320  rootmapFile << "var " << autoloadKey << std::endl;
2321  }
2322 
2323  }
2324 
2325  return 0;
2326 
2327 }
2328 
2329 ////////////////////////////////////////////////////////////////////////////////
2330 /// Performance is not critical here.
2331 
2332 std::pair<std::string,std::string> GetExternalNamespaceAndContainedEntities(const std::string line)
2333 {
2334  auto nsPattern = '{'; auto nsPatternLength = 1;
2335  auto foundNsPos = line.find_last_of(nsPattern);
2336  if (foundNsPos == std::string::npos) return {"",""};
2337  foundNsPos+=nsPatternLength;
2338  auto extNs = line.substr(0,foundNsPos);
2339 
2340  auto nsEndPattern = '}';
2341  auto foundEndNsPos = line.find(nsEndPattern);
2342  auto contained = line.substr(foundNsPos, foundEndNsPos-foundNsPos);
2343 
2344  return {extNs, contained};
2345 
2346 
2347 }
2348 
2349 ////////////////////////////////////////////////////////////////////////////////
2350 /// If two identical namespaces are there, just declare one only
2351 /// Example:
2352 /// namespace A { namespace B { fwd1; }}
2353 /// namespace A { namespace B { fwd2; }}
2354 /// get a namespace A { namespace B { fwd1; fwd2; }} line
2355 
2356 std::list<std::string> CollapseIdenticalNamespaces(const std::list<std::string>& fwdDeclarationsList)
2357 {
2358  // Temp data structure holding the namespaces and the entities therewith
2359  // contained
2360  std::map<std::string, std::string> nsEntitiesMap;
2361  std::list<std::string> optFwdDeclList;
2362  for (auto const & fwdDecl : fwdDeclarationsList){
2363  // Check if the decl(s) are contained in a ns and which one
2364  auto extNsAndEntities = GetExternalNamespaceAndContainedEntities(fwdDecl);
2365  if (extNsAndEntities.first.empty()) {
2366  // no namespace found. Just put this on top
2367  optFwdDeclList.push_front(fwdDecl);
2368  };
2369  auto currentVal = nsEntitiesMap[extNsAndEntities.first];
2370  nsEntitiesMap[extNsAndEntities.first] = currentVal +=extNsAndEntities.second;
2371  }
2372 
2373  // Now fill the new, optimised list
2374  std::string optFwdDecl;
2375  for (auto const & extNsAndEntities : nsEntitiesMap) {
2376  optFwdDecl = extNsAndEntities.first;
2377  optFwdDecl += extNsAndEntities.second;
2378  for (int i = 0; i < std::count(optFwdDecl.begin(), optFwdDecl.end(), '{'); ++i ){
2379  optFwdDecl += " }";
2380  }
2381  optFwdDeclList.push_front(optFwdDecl);
2382  }
2383 
2384  return optFwdDeclList;
2385 
2386 }
2387 
2388 ////////////////////////////////////////////////////////////////////////////////
2389 /// Separate multiline strings
2390 
2391 bool ProcessAndAppendIfNotThere(const std::string &el,
2392  std::list<std::string> &el_list,
2393  std::unordered_set<std::string> &el_set)
2394 {
2395  std::stringstream elStream(el);
2396  std::string tmp;
2397  bool added = false;
2398  while (getline(elStream, tmp, '\n')) {
2399  // Add if not there
2400  if (el_set.insert(tmp).second && !tmp.empty()) {
2401  el_list.push_back(tmp);
2402  added = true;
2403  }
2404  }
2405 
2406  return added;
2407 }
2408 
2409 ////////////////////////////////////////////////////////////////////////////////
2410 
2412  std::list<std::string> &classesList,
2413  std::list<std::string> &classesListForRootmap,
2414  std::list<std::string> &fwdDeclarationsList,
2415  const cling::Interpreter &interpreter)
2416 {
2417  // Loop on selected classes. If they don't have the attribute "rootmap"
2418  // set to "false", store them in the list of classes for the rootmap
2419  // Returns 0 in case of success and 1 in case of issues.
2420 
2421  // An unordered_set to keep track of the existing classes.
2422  // We want to avoid duplicates there as they may hint to a serious corruption
2423  std::unordered_set<std::string> classesSet;
2424  std::unordered_set<std::string> outerMostClassesSet;
2425 
2426  std::string attrName, attrValue;
2427  bool isClassSelected;
2428  std::unordered_set<std::string> availableFwdDecls;
2429  std::string fwdDeclaration;
2430  for (auto const & selVar : scan.fSelectedVariables) {
2431  fwdDeclaration = "";
2432  int retCode = ROOT::TMetaUtils::AST2SourceTools::EncloseInNamespaces(*selVar, fwdDeclaration);
2433  if (retCode == 0) ProcessAndAppendIfNotThere(fwdDeclaration, fwdDeclarationsList, availableFwdDecls);
2434  }
2435 
2436  for (auto const & selEnum : scan.fSelectedEnums) {
2437  fwdDeclaration = "";
2438  int retCode = ROOT::TMetaUtils::AST2SourceTools::EncloseInNamespaces(*selEnum, fwdDeclaration);
2439  if (retCode == 0) ProcessAndAppendIfNotThere(fwdDeclaration, fwdDeclarationsList, availableFwdDecls);
2440  }
2441 
2442  // Loop on selected classes and put them in a list
2443  for (auto const & selClass : scan.fSelectedClasses) {
2444  isClassSelected = true;
2445  const clang::RecordDecl *rDecl = selClass.GetRecordDecl();
2446  std::string normalizedName;
2447  normalizedName = selClass.GetNormalizedName();
2448  if (!normalizedName.empty() &&
2449  !classesSet.insert(normalizedName).second &&
2450  outerMostClassesSet.count(normalizedName) == 0) {
2451  std::cerr << "FATAL: A class with normalized name " << normalizedName
2452  << " was already selected. This means that two different instances of"
2453  << " clang::RecordDecl had the same name, which is not possible."
2454  << " This can be a hint of a serious problem in the class selection."
2455  << " In addition, the generated dictionary would not even compile.\n";
2456  return 1;
2457  }
2458  classesList.push_back(normalizedName);
2459  // Allow to autoload with the name of the class as it was specified in the
2460  // selection xml or linkdef
2461  const char *reqName(selClass.GetRequestedName());
2462 
2463  // Get always the containing namespace, put it in the list if not there
2464  fwdDeclaration = "";
2465  int retCode = ROOT::TMetaUtils::AST2SourceTools::EncloseInNamespaces(*rDecl, fwdDeclaration);
2466  if (retCode == 0) ProcessAndAppendIfNotThere(fwdDeclaration, fwdDeclarationsList, availableFwdDecls);
2467 
2468  // Get template definition and put it in if not there
2469  if (llvm::isa<clang::ClassTemplateSpecializationDecl>(rDecl)) {
2470  fwdDeclaration = "";
2471  retCode = ROOT::TMetaUtils::AST2SourceTools::FwdDeclFromRcdDecl(*rDecl, interpreter, fwdDeclaration);
2472  if (retCode == 0) ProcessAndAppendIfNotThere(fwdDeclaration, fwdDeclarationsList, availableFwdDecls);
2473  }
2474 
2475 
2476  // Loop on attributes, if rootmap=false, don't put it in the list!
2477  for (auto ait = rDecl->attr_begin(); ait != rDecl->attr_end(); ++ait) {
2478  if (0 == ROOT::TMetaUtils::extractPropertyNameVal(*ait, attrName, attrValue) &&
2479  attrName == "rootmap" &&
2480  attrValue == "false") {
2481  attrName = attrValue = "";
2482  isClassSelected = false;
2483  break;
2484  }
2485  }
2486  if (isClassSelected) {
2487  // Now, check if this is an internal class. If yes, we check the name of the outermost one
2488  // This is because of ROOT-6517. On the other hand, we exclude from this treatment
2489  // classes which are template instances which are nested in classes. For example:
2490  // class A{
2491  // class B{};
2492  // };
2493  // selection: <class name="A::B" />
2494  // Will result in a rootmap entry like "class A"
2495  // On the other hand, taking
2496  // class A{
2497  // public:
2498  // template <class T> class B{};
2499  // };
2500  // selection: <class name="A::B<int>" />
2501  // Would result in an entry like "class A::B<int>"
2502  std::string outerMostClassName;
2503  GetMostExternalEnclosingClassName(*rDecl, outerMostClassName, interpreter);
2504  if (!outerMostClassName.empty() &&
2505  !llvm::isa<clang::ClassTemplateSpecializationDecl>(rDecl) &&
2506  classesSet.insert(outerMostClassName).second &&
2507  outerMostClassesSet.insert(outerMostClassName).second) {
2508  classesListForRootmap.push_back(outerMostClassName);
2509  } else {
2510  classesListForRootmap.push_back(normalizedName);
2511  if (reqName != nullptr && 0 != strcmp(reqName, "") && reqName != normalizedName) {
2512  classesListForRootmap.push_back(reqName);
2513  }
2514 
2515  // Also register typeinfo::name(), unless we have pseudo-strong typedefs:
2516  if (normalizedName.find("Double32_t") == std::string::npos
2517  && normalizedName.find("Float16_t") == std::string::npos) {
2518  std::unique_ptr<clang::MangleContext> mangleCtx(rDecl->getASTContext().createMangleContext());
2519  std::string mangledName;
2520  {
2521  llvm::raw_string_ostream sstr(mangledName);
2522  if (const clang::TypeDecl* TD = llvm::dyn_cast<clang::TypeDecl>(rDecl)) {
2523  mangleCtx->mangleCXXRTTI(clang::QualType(TD->getTypeForDecl(), 0), sstr);
2524  }
2525  }
2526  if (!mangledName.empty()) {
2527  int errDemangle = 0;
2528 #ifdef WIN32
2529  if (mangledName[0] == '\01')
2530  mangledName.erase(0, 1);
2531  char *demangledTIName = TClassEdit::DemangleName(mangledName.c_str(), errDemangle);
2532  if (!errDemangle && demangledTIName) {
2533  static const char typeinfoNameFor[] = " `RTTI Type Descriptor'";
2534  if (strstr(demangledTIName, typeinfoNameFor)) {
2535  std::string demangledName = demangledTIName;
2536  demangledName.erase(demangledName.end() - strlen(typeinfoNameFor), demangledName.end());
2537  if (demangledName.compare(0, 6, "class ") == 0)
2538  demangledName.erase(0, 6);
2539  else if (demangledName.compare(0, 7, "struct ") == 0)
2540  demangledName.erase(0, 7);
2541 #else
2542  char* demangledTIName = TClassEdit::DemangleName(mangledName.c_str(), errDemangle);
2543  if (!errDemangle && demangledTIName) {
2544  static const char typeinfoNameFor[] = "typeinfo for ";
2545  if (!strncmp(demangledTIName, typeinfoNameFor, strlen(typeinfoNameFor))) {
2546  std::string demangledName = demangledTIName + strlen(typeinfoNameFor);
2547 #endif
2548  // See the operations in TCling::AutoLoad(type_info)
2550  splitname.ShortType(demangledName, TClassEdit::kDropStlDefault | TClassEdit::kDropStd);
2551 
2552  if (demangledName != normalizedName && (!reqName || demangledName != reqName)) {
2553  classesListForRootmap.push_back(demangledName);
2554  } // if demangledName != other name
2555  } else {
2556 #ifdef WIN32
2557  ROOT::TMetaUtils::Error("ExtractClassesListAndDeclLines",
2558  "Demangled typeinfo name '%s' does not contain `RTTI Type Descriptor'\n",
2559  demangledTIName);
2560 #else
2561  ROOT::TMetaUtils::Error("ExtractClassesListAndDeclLines",
2562  "Demangled typeinfo name '%s' does not start with 'typeinfo for'\n",
2563  demangledTIName);
2564 #endif
2565  } // if demangled type_info starts with "typeinfo for "
2566  } // if demangling worked
2567  free(demangledTIName);
2568  } // if mangling worked
2569  } // if no pseudo-strong typedef involved
2570  }
2571  }
2572  }
2573  classesListForRootmap.sort();
2574 
2575  // Disable for the moment
2576  // fwdDeclarationsList = CollapseIdenticalNamespaces(fwdDeclarationsList);
2577 
2578  return 0;
2579 }
2580 
2581 ////////////////////////////////////////////////////////////////////////////////
2582 /// Loop on selected classes and put them in a list
2583 
2584 void ExtractSelectedNamespaces(RScanner &scan, std::list<std::string> &nsList)
2585 {
2586  for (RScanner::NamespaceColl_t::const_iterator selNsIter = scan.fSelectedNamespaces.begin();
2587  selNsIter != scan.fSelectedNamespaces.end(); ++selNsIter) {
2588  nsList.push_back(ROOT::TMetaUtils::GetQualifiedName(* selNsIter->GetNamespaceDecl()));
2589  }
2590 }
2591 
2592 ////////////////////////////////////////////////////////////////////////////////
2593 /// We need annotations even in the PCH: // !, // || etc.
2594 
2595 void AnnotateAllDeclsForPCH(cling::Interpreter &interp,
2596  RScanner &scan)
2597 {
2598  auto const & declSelRulesMap = scan.GetDeclsSelRulesMap();
2599  for (auto const & selClass : scan.fSelectedClasses) {
2600  // Very important: here we decide if we want to attach attributes to the decl.
2601  if (clang::CXXRecordDecl *CXXRD =
2602  llvm::dyn_cast<clang::CXXRecordDecl>(const_cast<clang::RecordDecl *>(selClass.GetRecordDecl()))) {
2603  AnnotateDecl(*CXXRD, declSelRulesMap, interp, false);
2604  }
2605  }
2606 }
2607 
2608 ////////////////////////////////////////////////////////////////////////////////
2609 
2610 int CheckClassesForInterpreterOnlyDicts(cling::Interpreter &interp,
2611  RScanner &scan)
2612 {
2613  for (auto const & selClass : scan.fSelectedClasses) {
2614  if (!selClass.GetRecordDecl()->isCompleteDefinition() || selClass.RequestOnlyTClass()) {
2615  continue;
2616  }
2617  const clang::CXXRecordDecl *cxxdecl = llvm::dyn_cast<clang::CXXRecordDecl>(selClass.GetRecordDecl());
2618  if (cxxdecl && ROOT::TMetaUtils::ClassInfo__HasMethod(selClass, "Class_Name", interp)) {
2619  ROOT::TMetaUtils::Error("CheckClassesForInterpreterOnlyDicts",
2620  "Interactivity only dictionaries are not supported for classes with ClassDef\n");
2621  return 1;
2622  }
2623  }
2624  return 0;
2625 }
2626 
2627 ////////////////////////////////////////////////////////////////////////////////
2628 /// Make up for skipping RegisterModule, now that dictionary parsing
2629 /// is done and these headers cannot be selected anymore.
2630 
2631 int FinalizeStreamerInfoWriting(cling::Interpreter &interp, bool writeEmptyRootPCM=false)
2632 {
2634  return 0;
2635 
2636  if (interp.parseForModule("#include \"TStreamerInfo.h\"\n"
2637  "#include \"TFile.h\"\n"
2638  "#include \"TObjArray.h\"\n"
2639  "#include \"TVirtualArray.h\"\n"
2640  "#include \"TStreamerElement.h\"\n"
2641  "#include \"TProtoClass.h\"\n"
2642  "#include \"TBaseClass.h\"\n"
2643  "#include \"TListOfDataMembers.h\"\n"
2644  "#include \"TListOfEnums.h\"\n"
2645  "#include \"TListOfEnumsWithLock.h\"\n"
2646  "#include \"TDataMember.h\"\n"
2647  "#include \"TEnum.h\"\n"
2648  "#include \"TEnumConstant.h\"\n"
2649  "#include \"TDictAttributeMap.h\"\n"
2650  "#include \"TMessageHandler.h\"\n"
2651  "#include \"TArray.h\"\n"
2652  "#include \"TRefArray.h\"\n"
2653  "#include \"root_std_complex.h\"\n")
2654  != cling::Interpreter::kSuccess)
2655  return 1;
2656  if (!gDriverConfig->fCloseStreamerInfoROOTFile(writeEmptyRootPCM)) {
2657  return 1;
2658  }
2659  return 0;
2660 }
2661 
2662 ////////////////////////////////////////////////////////////////////////////////
2663 
2664 int GenerateFullDict(std::ostream &dictStream,
2665  cling::Interpreter &interp,
2666  RScanner &scan,
2667  const ROOT::TMetaUtils::RConstructorTypes &ctorTypes,
2668  bool isSplit,
2669  bool isGenreflex,
2670  bool writeEmptyRootPCM)
2671 {
2672  ROOT::TMetaUtils::TNormalizedCtxt normCtxt(interp.getLookupHelper());
2673 
2674  bool needsCollectionProxy = false;
2675 
2676  //
2677  // We will loop over all the classes several times.
2678  // In order we will call
2679  //
2680  // WriteClassInit (code to create the TGenericClassInfo)
2681  // check for constructor and operator input
2682  // WriteClassFunctions (declared in ClassDef)
2683  // WriteClassCode (Streamer,ShowMembers,Auxiliary functions)
2684  //
2685 
2686 
2687  //
2688  // Loop over all classes and create Streamer() & Showmembers() methods
2689  //
2690 
2691  // SELECTION LOOP
2692  for (auto const & ns : scan.fSelectedNamespaces) {
2693  WriteNamespaceInit(ns, interp, dictStream);
2694  auto nsName = ns.GetNamespaceDecl()->getQualifiedNameAsString();
2695  if (nsName.find("(anonymous)") == std::string::npos)
2696  EmitStreamerInfo(nsName.c_str());
2697  }
2698 
2699  for (auto const & selClass : scan.fSelectedClasses) {
2700  if (!selClass.GetRecordDecl()->isCompleteDefinition()) {
2701  ROOT::TMetaUtils::Error(0, "A dictionary has been requested for %s but there is no declaration!\n", ROOT::TMetaUtils::GetQualifiedName(selClass).c_str());
2702  continue;
2703  }
2704  if (selClass.RequestOnlyTClass()) {
2705  // fprintf(stderr,"rootcling: Skipping class %s\n",R__GetQualifiedName(* selClass.GetRecordDecl()).c_str());
2706  // For now delay those for later.
2707  continue;
2708  }
2709 
2710  // Very important: here we decide if we want to attach attributes to the decl.
2711 
2712  if (clang::CXXRecordDecl *CXXRD =
2713  llvm::dyn_cast<clang::CXXRecordDecl>(const_cast<clang::RecordDecl *>(selClass.GetRecordDecl()))) {
2714  AnnotateDecl(*CXXRD, scan.GetDeclsSelRulesMap() , interp, isGenreflex);
2715  }
2716 
2717  const clang::CXXRecordDecl *CRD = llvm::dyn_cast<clang::CXXRecordDecl>(selClass.GetRecordDecl());
2718 
2719  if (CRD) {
2720  ROOT::TMetaUtils::Info(0, "Generating code for class %s\n", selClass.GetNormalizedName());
2721  if (TMetaUtils::IsStdClass(*CRD) && 0 != TClassEdit::STLKind(CRD->getName().str() /* unqualified name without template argument */)) {
2722  // Register the collections
2723  // coverity[fun_call_w_exception] - that's just fine.
2724  Internal::RStl::Instance().GenerateTClassFor(selClass.GetNormalizedName(), CRD, interp, normCtxt);
2725  } else {
2726  ROOT::TMetaUtils::WriteClassInit(dictStream, selClass, CRD, interp, normCtxt, ctorTypes, needsCollectionProxy);
2727  EmitStreamerInfo(selClass.GetNormalizedName());
2728  }
2729  }
2730  }
2731 
2732  //
2733  // Write all TBuffer &operator>>(...), Class_Name(), Dictionary(), etc.
2734  // first to allow template specialisation to occur before template
2735  // instantiation (STK)
2736  //
2737  // SELECTION LOOP
2738  for (auto const & selClass : scan.fSelectedClasses) {
2739 
2740  if (!selClass.GetRecordDecl()->isCompleteDefinition() || selClass.RequestOnlyTClass()) {
2741  // For now delay those for later.
2742  continue;
2743  }
2744  const clang::CXXRecordDecl *cxxdecl = llvm::dyn_cast<clang::CXXRecordDecl>(selClass.GetRecordDecl());
2745  if (cxxdecl && ROOT::TMetaUtils::ClassInfo__HasMethod(selClass, "Class_Name", interp)) {
2746  WriteClassFunctions(cxxdecl, dictStream, isSplit);
2747  }
2748  }
2749 
2750  // LINKDEF SELECTION LOOP
2751  // Loop to get the shadow class for the class marked 'RequestOnlyTClass' (but not the
2752  // STL class which is done via Internal::RStl::Instance().WriteClassInit(0);
2753  // and the ClassInit
2754 
2755  for (auto const & selClass : scan.fSelectedClasses) {
2756  if (!selClass.GetRecordDecl()->isCompleteDefinition() || !selClass.RequestOnlyTClass()) {
2757  continue;
2758  }
2759 
2760  const clang::CXXRecordDecl *CRD = llvm::dyn_cast<clang::CXXRecordDecl>(selClass.GetRecordDecl());
2761 
2762  if (!ROOT::TMetaUtils::IsSTLContainer(selClass)) {
2763  ROOT::TMetaUtils::WriteClassInit(dictStream, selClass, CRD, interp, normCtxt, ctorTypes, needsCollectionProxy);
2764  EmitStreamerInfo(selClass.GetNormalizedName());
2765  }
2766  }
2767  // Loop to write all the ClassCode
2768  for (auto const & selClass : scan.fSelectedClasses) {
2769  ROOT::TMetaUtils::WriteClassCode(&CallWriteStreamer,
2770  selClass,
2771  interp,
2772  normCtxt,
2773  dictStream,
2774  ctorTypes,
2775  isGenreflex);
2776  }
2777 
2778  // Loop on the registered collections internally
2779  // coverity[fun_call_w_exception] - that's just fine.
2780  ROOT::Internal::RStl::Instance().WriteClassInit(dictStream, interp, normCtxt, ctorTypes, needsCollectionProxy, EmitStreamerInfo);
2781 
2784  EmitEnums(scan.fSelectedEnums);
2785  // Make up for skipping RegisterModule, now that dictionary parsing
2786  // is done and these headers cannot be selected anymore.
2787  int finRetCode = FinalizeStreamerInfoWriting(interp, writeEmptyRootPCM);
2788  if (finRetCode != 0) return finRetCode;
2789  }
2790 
2791  return 0;
2792 }
2793 
2794 ////////////////////////////////////////////////////////////////////////////////
2795 
2796 void CreateDictHeader(std::ostream &dictStream, const std::string &main_dictname)
2797 {
2798  dictStream << "// Do NOT change. Changes will be lost next time file is generated\n\n"
2799  << "#define R__DICTIONARY_FILENAME " << main_dictname << std::endl
2800 
2801  // We do not want deprecation warnings to fire in dictionaries
2802  << "#define R__NO_DEPRECATION" << std::endl
2803 
2804  // Now that CINT is not longer there to write the header file,
2805  // write one and include in there a few things for backward
2806  // compatibility.
2807  << "\n/*******************************************************************/\n"
2808  << "#include <stddef.h>\n"
2809  << "#include <stdio.h>\n"
2810  << "#include <stdlib.h>\n"
2811  << "#include <string.h>\n"
2812  << "#include <assert.h>\n"
2813  << "#define G__DICTIONARY\n"
2814  << "#include \"RConfig.h\"\n"
2815  << "#include \"TClass.h\"\n"
2816  << "#include \"TDictAttributeMap.h\"\n"
2817  << "#include \"TInterpreter.h\"\n"
2818  << "#include \"TROOT.h\"\n"
2819  << "#include \"TBuffer.h\"\n"
2820  << "#include \"TMemberInspector.h\"\n"
2821  << "#include \"TInterpreter.h\"\n"
2822  << "#include \"TVirtualMutex.h\"\n"
2823  << "#include \"TError.h\"\n\n"
2824  << "#ifndef G__ROOT\n"
2825  << "#define G__ROOT\n"
2826  << "#endif\n\n"
2827  << "#include \"RtypesImp.h\"\n"
2828  << "#include \"TIsAProxy.h\"\n"
2829  << "#include \"TFileMergeInfo.h\"\n"
2830  << "#include <algorithm>\n"
2831  << "#include \"TCollectionProxyInfo.h\"\n"
2832  << "/*******************************************************************/\n\n"
2833  << "#include \"TDataMember.h\"\n\n"; // To set their transiency
2834 #ifndef R__SOLARIS
2835  dictStream << "// The generated code does not explicitly qualifies STL entities\n"
2836  << "namespace std {} using namespace std;\n\n";
2837 #endif
2838 }
2839 
2840 ////////////////////////////////////////////////////////////////////////////////
2841 
2842 void GenerateNecessaryIncludes(std::ostream &dictStream,
2843  const std::string &includeForSource,
2844  const std::string &extraIncludes)
2845 {
2846  dictStream << "// Header files passed as explicit arguments\n"
2847  << includeForSource << std::endl
2848  << "// Header files passed via #pragma extra_include\n"
2849  << extraIncludes << std::endl;
2850 }
2851 
2852 //______________________________________________________________________________
2853 
2854 // cross-compiling for iOS and iOS simulator (assumes host is Intel Mac OS X)
2855 #if defined(R__IOSSIM) || defined(R__IOS)
2856 #ifdef __x86_64__
2857 #undef __x86_64__
2858 #endif
2859 #ifdef __i386__
2860 #undef __i386__
2861 #endif
2862 #ifdef R__IOSSIM
2863 #define __i386__ 1
2864 #endif
2865 #ifdef R__IOS
2866 #define __arm__ 1
2867 #endif
2868 #endif
2869 
2870 ////////////////////////////////////////////////////////////////////////////////
2871 /// Little helper class to bookkeep the files names which we want to make
2872 /// temporary.
2873 
2874 class tempFileNamesCatalog {
2875 public:
2876  //______________________________________________
2877  tempFileNamesCatalog(): m_size(0), m_emptyString("") {};
2878 
2879  std::string getTmpFileName(const std::string &filename) {
2880  return filename + "_tmp_" + std::to_string(getpid());
2881  }
2882  /////////////////////////////////////////////////////////////////////////////
2883  /// Adds the name and the associated temp name to the catalog.
2884  /// Changes the name into the temp name
2885 
2886  void addFileName(std::string &nameStr) {
2887  if (nameStr.empty()) return;
2888 
2889  std::string tmpNameStr(getTmpFileName(nameStr));
2890 
2891  // For brevity
2892  const char *name(nameStr.c_str());
2893  const char *tmpName(tmpNameStr.c_str());
2894 
2895  m_names.push_back(nameStr);
2896  m_tempNames.push_back(tmpNameStr);
2897  ROOT::TMetaUtils::Info(0, "File %s added to the tmp catalog.\n", name);
2898 
2899  // This is to allow update of existing files
2900  if (0 == std::rename(name , tmpName)) {
2901  ROOT::TMetaUtils::Info(0, "File %s existing. Preserved as %s.\n", name, tmpName);
2902  }
2903 
2904  // To change the name to its tmp version
2905  nameStr = tmpNameStr;
2906 
2907  m_size++;
2908 
2909  }
2910 
2911  /////////////////////////////////////////////////////////////////////////////
2912 
2913  int clean() {
2914  int retval = 0;
2915  // rename the temp files into the normal ones
2916  for (unsigned int i = 0; i < m_size; ++i) {
2917  const char *tmpName = m_tempNames[i].c_str();
2918  // Check if the file exists
2919  std::ifstream ifile(tmpName);
2920  if (!ifile)
2921  ROOT::TMetaUtils::Error(0, "Cannot find %s!\n", tmpName);
2922 
2923  if (0 != std::remove(tmpName)) {
2924  ROOT::TMetaUtils::Error(0, "Removing %s!\n", tmpName);
2925  retval++;
2926  }
2927  }
2928  return retval;
2929  }
2930 
2931  /////////////////////////////////////////////////////////////////////////////
2932 
2933  int commit() {
2934  int retval = 0;
2935  // rename the temp files into the normal ones
2936  for (unsigned int i = 0; i < m_size; ++i) {
2937  const char *tmpName = m_tempNames[i].c_str();
2938  const char *name = m_names[i].c_str();
2939  // Check if the file exists
2940  std::ifstream ifile(tmpName);
2941  if (!ifile)
2942  ROOT::TMetaUtils::Error(0, "Cannot find %s!\n", tmpName);
2943 #ifdef WIN32
2944  // Sometimes files cannot be renamed on Windows if they don't have
2945  // been released by the system. So just copy them and try to delete
2946  // the old one afterwards.
2947  if (ifile.is_open())
2948  ifile.close();
2949  if (0 != std::rename(tmpName , name)) {
2950  if (llvm::sys::fs::copy_file(tmpName , name)) {
2951  llvm::sys::fs::remove(tmpName);
2952  }
2953  }
2954 #else
2955  if (0 != std::rename(tmpName , name)) {
2956  ROOT::TMetaUtils::Error(0, "Renaming %s into %s!\n", tmpName, name);
2957  retval++;
2958  }
2959 #endif
2960  }
2961  return retval;
2962  }
2963 
2964  /////////////////////////////////////////////////////////////////////////////
2965 
2966  const std::string &getFileName(const std::string &tmpFileName) {
2967  size_t i = std::distance(m_tempNames.begin(),
2968  find(m_tempNames.begin(), m_tempNames.end(), tmpFileName));
2969  if (i == m_tempNames.size()) return m_emptyString;
2970  return m_names[i];
2971  }
2972 
2973  /////////////////////////////////////////////////////////////////////////////
2974 
2975  void dump() {
2976  std::cout << "Restoring files in temporary file catalog:\n";
2977  for (unsigned int i = 0; i < m_size; ++i) {
2978  std::cout << m_tempNames[i] << " --> " << m_names[i] << std::endl;
2979  }
2980  }
2981 
2982 private:
2983  unsigned int m_size;
2984  const std::string m_emptyString;
2985  std::vector<std::string> m_names;
2986  std::vector<std::string> m_tempNames;
2987 };
2988 
2989 ////////////////////////////////////////////////////////////////////////////////
2990 /// Transform name of dictionary
2991 
2992 std::ostream *CreateStreamPtrForSplitDict(const std::string &dictpathname,
2993  tempFileNamesCatalog &tmpCatalog)
2994 {
2995  std::string splitDictName(tmpCatalog.getFileName(dictpathname));
2996  const size_t dotPos = splitDictName.find_last_of(".");
2997  splitDictName.insert(dotPos, "_classdef");
2998  tmpCatalog.addFileName(splitDictName);
2999  return new std::ofstream(splitDictName.c_str());
3000 }
3001 
3002 ////////////////////////////////////////////////////////////////////////////////
3003 /// Transform -W statements in diagnostic pragmas for cling reacting on "-Wno-"
3004 /// For example
3005 /// -Wno-deprecated-declarations --> #pragma clang diagnostic ignored "-Wdeprecated-declarations"
3006 
3007 static void CheckForMinusW(std::string arg,
3008  std::list<std::string> &diagnosticPragmas)
3009 {
3010  static const std::string pattern("-Wno-");
3011 
3012  if (arg.find(pattern) != 0)
3013  return;
3014  if (arg == "-Wno-noexcept-type") {
3015  // GCC7 warning not supported by clang 3.9
3016  return;
3017  }
3018 
3019  ROOT::TMetaUtils::ReplaceAll(arg, pattern, "#pragma clang diagnostic ignored \"-W");
3020  arg += "\"";
3021  diagnosticPragmas.push_back(arg);
3022 }
3023 
3024 ////////////////////////////////////////////////////////////////////////////////
3025 
3026 std::string GetFwdDeclnArgsToKeepString(const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt,
3027  cling::Interpreter &interp)
3028 {
3029  using namespace ROOT::TMetaUtils::AST2SourceTools;
3030  std::string fwdDecl;
3031  std::string initStr("{");
3032  auto &fwdDeclnArgsToSkipColl = normCtxt.GetTemplNargsToKeepMap();
3033  for (auto & strigNargsToKeepPair : fwdDeclnArgsToSkipColl) {
3034  auto &clTemplDecl = *strigNargsToKeepPair.first;
3035  FwdDeclFromTmplDecl(clTemplDecl , interp, fwdDecl);
3036  initStr += "{\"" +
3037  fwdDecl + "\", "
3038  + std::to_string(strigNargsToKeepPair.second)
3039  + "},";
3040  }
3041  if (!fwdDeclnArgsToSkipColl.empty())
3042  initStr.pop_back();
3043  initStr += "}";
3044  return initStr;
3045 }
3046 
3047 ////////////////////////////////////////////////////////////////////////////////
3048 /// Get the pointee type if possible
3049 
3050 clang::QualType GetPointeeTypeIfPossible(const clang::QualType &qt)
3051 {
3052  if (qt.isNull()) return qt;
3053  clang::QualType thisQt(qt);
3054  while (thisQt->isPointerType() ||
3055  thisQt->isReferenceType()) {
3056  thisQt = thisQt->getPointeeType();
3057  }
3058  return thisQt;
3059 
3060 }
3061 
3062 ////////////////////////////////////////////////////////////////////////////////
3063 /// Extract the list of headers necessary for the Decl
3064 
3065 std::list<std::string> RecordDecl2Headers(const clang::CXXRecordDecl &rcd,
3066  const cling::Interpreter &interp,
3067  std::set<const clang::CXXRecordDecl *> &visitedDecls)
3068 {
3069  std::list<std::string> headers;
3070 
3071  // We push a new transaction because we could deserialize decls here
3072  cling::Interpreter::PushTransactionRAII RAII(&interp);
3073 
3074  // Avoid infinite recursion
3075  if (!visitedDecls.insert(rcd.getCanonicalDecl()).second)
3076  return headers;
3077 
3078  // If this is a template
3079  if (const clang::ClassTemplateSpecializationDecl *tsd = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(&rcd)) {
3080 
3081  // Loop on the template args
3082  for (auto & tArg : tsd->getTemplateArgs().asArray()) {
3083  if (clang::TemplateArgument::ArgKind::Type != tArg.getKind()) continue;
3084  auto tArgQualType = GetPointeeTypeIfPossible(tArg.getAsType());
3085  if (tArgQualType.isNull()) continue;
3086  if (const clang::CXXRecordDecl *tArgCxxRcd = tArgQualType->getAsCXXRecordDecl()) {
3087  headers.splice(headers.end(), RecordDecl2Headers(*tArgCxxRcd, interp, visitedDecls));
3088  }
3089  }
3090 
3091  if (!ROOT::TMetaUtils::IsStdClass(rcd) && rcd.hasDefinition()) {
3092 
3093  // Loop on base classes - with a newer llvm, range based possible
3094  for (auto baseIt = tsd->bases_begin(); baseIt != tsd->bases_end(); baseIt++) {
3095  auto baseQualType = GetPointeeTypeIfPossible(baseIt->getType());
3096  if (baseQualType.isNull()) continue;
3097  if (const clang::CXXRecordDecl *baseRcdPtr = baseQualType->getAsCXXRecordDecl()) {
3098  headers.splice(headers.end(), RecordDecl2Headers(*baseRcdPtr, interp, visitedDecls));
3099  }
3100  }
3101 
3102  // Loop on the data members - with a newer llvm, range based possible
3103  for (auto declIt = tsd->decls_begin(); declIt != tsd->decls_end(); ++declIt) {
3104  if (const clang::FieldDecl *fieldDecl = llvm::dyn_cast<clang::FieldDecl>(*declIt)) {
3105  auto fieldQualType = GetPointeeTypeIfPossible(fieldDecl->getType());
3106  if (fieldQualType.isNull()) continue ;
3107  if (const clang::CXXRecordDecl *fieldCxxRcd = fieldQualType->getAsCXXRecordDecl()) {
3108  if (fieldCxxRcd->hasDefinition())
3109  headers.splice(headers.end(), RecordDecl2Headers(*fieldCxxRcd, interp, visitedDecls));
3110  }
3111  }
3112  }
3113 
3114  // Loop on methods
3115  for (auto methodIt = tsd->method_begin(); methodIt != tsd->method_end(); ++methodIt) {
3116  // Check arguments
3117  for (auto & fPar : methodIt->parameters()) {
3118  auto fParQualType = GetPointeeTypeIfPossible(fPar->getOriginalType());
3119  if (fParQualType.isNull()) continue;
3120  if (const clang::CXXRecordDecl *fParCxxRcd = fParQualType->getAsCXXRecordDecl()) {
3121  if (fParCxxRcd->hasDefinition())
3122  headers.splice(headers.end(), RecordDecl2Headers(*fParCxxRcd, interp, visitedDecls));
3123  }
3124  }
3125  // Check return value
3126  auto retQualType = GetPointeeTypeIfPossible(methodIt->getReturnType());
3127  if (retQualType.isNull()) continue;
3128  if (const clang::CXXRecordDecl *retCxxRcd = retQualType->getAsCXXRecordDecl()) {
3129  if (retCxxRcd->hasDefinition())
3130  headers.splice(headers.end(), RecordDecl2Headers(*retCxxRcd, interp, visitedDecls));
3131  }
3132  }
3133  }
3134 
3135  } // End template instance
3136 
3137  std::string header = ROOT::TMetaUtils::GetFileName(rcd, interp);
3138  headers.emplace_back(header);
3139  headers.reverse();
3140  return headers;
3141 
3142 }
3143 
3144 ////////////////////////////////////////////////////////////////////////////////
3145 /// Check if the class good for being an autoparse key.
3146 /// We exclude from this set stl containers of pods/strings
3147 /// TODO: we may use also __gnu_cxx::
3148 bool IsGoodForAutoParseMap(const clang::RecordDecl& rcd){
3149 
3150  // If it's not an std class, we just pick it up.
3151  if (auto dclCtxt= rcd.getDeclContext()){
3152  if (! dclCtxt->isStdNamespace()){
3153  return true;
3154  }
3155  } else {
3156  return true;
3157  }
3158 
3159  // Now, we have a stl class. We now check if it's a template. If not, we
3160  // do not take it: bitset, string and so on.
3161  auto clAsTmplSpecDecl = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(&rcd);
3162  if (!clAsTmplSpecDecl) return false;
3163 
3164  // Now we have a template in the stl. Let's see what the arguments are.
3165  // If they are not a POD or something which is good for autoparsing, we keep
3166  // them.
3167  auto& astCtxt = rcd.getASTContext();
3168  auto& templInstArgs = clAsTmplSpecDecl->getTemplateInstantiationArgs();
3169  for (auto&& arg : templInstArgs.asArray()){
3170 
3171  auto argKind = arg.getKind();
3172  if (argKind != clang::TemplateArgument::Type){
3173  if (argKind == clang::TemplateArgument::Integral) continue;
3174  else return true;
3175  }
3176 
3177  auto argQualType = arg.getAsType();
3178  auto isPOD = argQualType.isPODType(astCtxt);
3179  // This is a POD, we can inspect the next arg
3180  if (isPOD) continue;
3181 
3182  auto argType = argQualType.getTypePtr();
3183  if (auto recType = llvm::dyn_cast<clang::RecordType>(argType)){
3184  auto isArgGoodForAutoParseMap = IsGoodForAutoParseMap(*recType->getDecl());
3185  // The arg is a class but good for the map
3186  if (isArgGoodForAutoParseMap) continue;
3187  } else {
3188  // The class is not a POD nor a class we can skip
3189  return true;
3190  }
3191  }
3192 
3193  return false;
3194 }
3195 
3196 ////////////////////////////////////////////////////////////////////////////////
3197 
3199  const RScanner::TypedefColl_t tDefDecls,
3200  const RScanner::FunctionColl_t funcDecls,
3201  const RScanner::VariableColl_t varDecls,
3202  const RScanner::EnumColl_t enumDecls,
3203  HeadersDeclsMap_t &headersClassesMap,
3204  HeadersDeclsMap_t &headersDeclsMap,
3205  const cling::Interpreter &interp)
3206 {
3207  std::set<const clang::CXXRecordDecl *> visitedDecls;
3208  std::unordered_set<std::string> buffer;
3209  std::string autoParseKey;
3210 
3211  // Add some manip of headers
3212  for (auto & annotatedRcd : annotatedRcds) {
3213  if (const clang::CXXRecordDecl *cxxRcd =
3214  llvm::dyn_cast_or_null<clang::CXXRecordDecl>(annotatedRcd.GetRecordDecl())) {
3215  autoParseKey = "";
3216  visitedDecls.clear();
3217  std::list<std::string> headers(RecordDecl2Headers(*cxxRcd, interp, visitedDecls));
3218  // remove duplicates, also if not subsequent
3219  buffer.clear();
3220  headers.remove_if([&buffer](const std::string & s) {
3221  return !buffer.insert(s).second;
3222  });
3223  GetMostExternalEnclosingClassName(*cxxRcd, autoParseKey, interp);
3224  if (autoParseKey.empty()) autoParseKey = annotatedRcd.GetNormalizedName();
3225  if (IsGoodForAutoParseMap(*cxxRcd)){
3226  headersDeclsMap[autoParseKey] = headers;
3227  headersDeclsMap[annotatedRcd.GetRequestedName()] = headers;
3228  } else {
3229  ROOT::TMetaUtils::Info(0, "Class %s is not included in the set of autoparse keys.\n", autoParseKey.c_str());
3230  }
3231 
3232  // Propagate to the classes map only if this is not a template.
3233  // The header is then used as autoload key and we want to avoid duplicates.
3234  if (!llvm::isa<clang::ClassTemplateSpecializationDecl>(cxxRcd)){
3235  headersClassesMap[autoParseKey] = headersDeclsMap[autoParseKey];
3236  headersClassesMap[annotatedRcd.GetRequestedName()] = headersDeclsMap[annotatedRcd.GetRequestedName()];
3237  }
3238  }
3239  }
3240 
3241  // The same for the typedefs:
3242  for (auto & tDef : tDefDecls) {
3243  if (clang::CXXRecordDecl *cxxRcd = tDef->getUnderlyingType()->getAsCXXRecordDecl()) {
3244  autoParseKey = "";
3245  visitedDecls.clear();
3246  std::list<std::string> headers(RecordDecl2Headers(*cxxRcd, interp, visitedDecls));
3247  headers.push_back(ROOT::TMetaUtils::GetFileName(*tDef, interp));
3248  // remove duplicates, also if not subsequent
3249  buffer.clear();
3250  headers.remove_if([&buffer](const std::string & s) {
3251  return !buffer.insert(s).second;
3252  });
3253  GetMostExternalEnclosingClassNameFromDecl(*tDef, autoParseKey, interp);
3254  if (autoParseKey.empty()) autoParseKey = tDef->getQualifiedNameAsString();
3255  headersDeclsMap[autoParseKey] = headers;
3256  }
3257  }
3258 
3259  // The same for the functions:
3260  for (auto & func : funcDecls) {
3261  std::list<std::string> headers = {ROOT::TMetaUtils::GetFileName(*func, interp)};
3262  headersDeclsMap[ROOT::TMetaUtils::GetQualifiedName(*func)] = headers;
3263  }
3264 
3265  // The same for the variables:
3266  for (auto & var : varDecls) {
3267  std::list<std::string> headers = {ROOT::TMetaUtils::GetFileName(*var, interp)};
3268  headersDeclsMap[ROOT::TMetaUtils::GetQualifiedName(*var)] = headers;
3269  }
3270 
3271  // The same for the enums:
3272  for (auto & en : enumDecls) {
3273  std::list<std::string> headers = {ROOT::TMetaUtils::GetFileName(*en, interp)};
3274  headersDeclsMap[ROOT::TMetaUtils::GetQualifiedName(*en)] = headers;
3275  }
3276 }
3277 
3278 ////////////////////////////////////////////////////////////////////////////////
3279 /// Generate the fwd declarations of the selected entities
3280 
3281 static std::string GenerateFwdDeclString(const RScanner &scan,
3282  const cling::Interpreter &interp)
3283 {
3284  std::string newFwdDeclString;
3285 
3286  using namespace ROOT::TMetaUtils::AST2SourceTools;
3287 
3288  std::string fwdDeclString;
3289  std::string buffer;
3290  std::unordered_set<std::string> fwdDecls;
3291 
3292  // Classes
3293 /*
3294  for (auto const & annRcd : scan.fSelectedClasses) {
3295  const auto rcdDeclPtr = annRcd.GetRecordDecl();
3296 
3297  int retCode = FwdDeclFromRcdDecl(*rcdDeclPtr, interp, buffer);
3298  if (-1 == retCode) {
3299  ROOT::TMetaUtils::Error("GenerateFwdDeclString",
3300  "Error generating fwd decl for class %s\n",
3301  annRcd.GetNormalizedName());
3302  return emptyString;
3303  }
3304  if (retCode == 0 && fwdDecls.insert(buffer).second)
3305  fwdDeclString += "\"" + buffer + "\"\n";
3306  }
3307 */
3308  // Build the input for a transaction containing all of the selected declarations
3309  // Cling will produce the fwd declaration payload.
3310 
3311  std::vector<const clang::Decl *> selectedDecls(scan.fSelectedClasses.size());
3312 
3313  // Pick only RecordDecls
3314  std::transform (scan.fSelectedClasses.begin(),
3315  scan.fSelectedClasses.end(),
3316  selectedDecls.begin(),
3317  [](const ROOT::TMetaUtils::AnnotatedRecordDecl& rcd){return rcd.GetRecordDecl();});
3318 
3319  for (auto* TD: scan.fSelectedTypedefs)
3320  selectedDecls.push_back(TD);
3321 
3322 // for (auto* VAR: scan.fSelectedVariables)
3323 // selectedDecls.push_back(VAR);
3324 
3325  // The "R\"DICTFWDDCLS(\n" ")DICTFWDDCLS\"" pieces have been moved to
3326  // TModuleGenerator to be able to make the diagnostics more telling in presence
3327  // of an issue ROOT-6752.
3328  fwdDeclString += Decls2FwdDecls(selectedDecls,IsLinkdefFile,interp);
3329 
3330  // Functions
3331 // for (auto const& fcnDeclPtr : scan.fSelectedFunctions){
3332 // int retCode = FwdDeclFromFcnDecl(*fcnDeclPtr, interp, buffer);
3333 // newFwdDeclString += Decl2FwdDecl(*fcnDeclPtr,interp);
3334 // if (-1 == retCode){
3335 // ROOT::TMetaUtils::Error("GenerateFwdDeclString",
3336 // "Error generating fwd decl for function %s\n",
3337 // fcnDeclPtr->getNameAsString().c_str());
3338 // return emptyString;
3339 // }
3340 // if (retCode == 0 && fwdDecls.insert(buffer).second)
3341 // fwdDeclString+="\""+buffer+"\"\n";
3342 // }
3343 
3344  if (fwdDeclString.empty()) fwdDeclString = "";
3345  return fwdDeclString;
3346 }
3347 
3348 ////////////////////////////////////////////////////////////////////////////////
3349 /// Generate a string for the dictionary from the headers-classes map.
3350 
3351 const std::string GenerateStringFromHeadersForClasses(const HeadersDeclsMap_t &headersClassesMap,
3352  const std::string &detectedUmbrella,
3353  bool payLoadOnly = false)
3354 {
3355  std::string headerName;
3356 
3357  if (genreflex::verbose)
3358  std::cout << "Class-headers Mapping:\n";
3359  std::string headersClassesMapString = "";
3360  for (auto const & classHeaders : headersClassesMap) {
3361  if (genreflex::verbose)
3362  std::cout << " o " << classHeaders.first << " --> ";
3363  headersClassesMapString += "\"";
3364  headersClassesMapString += classHeaders.first + "\"";
3365  for (auto const & header : classHeaders.second) {
3366  headerName = (detectedUmbrella == header || payLoadOnly) ? "payloadCode" : "\"" + header + "\"";
3367  headersClassesMapString += ", " + headerName;
3368  if (genreflex::verbose)
3369  std::cout << ", " << headerName;
3370  if (payLoadOnly)
3371  break;
3372  }
3373  if (genreflex::verbose)
3374  std::cout << std::endl;
3375  headersClassesMapString += ", \"@\",\n";
3376  }
3377  headersClassesMapString += "nullptr";
3378  return headersClassesMapString;
3379 }
3380 
3381 ////////////////////////////////////////////////////////////////////////////////
3382 
3383 bool IsImplementationName(const std::string &filename)
3384 {
3385  return !ROOT::TMetaUtils::IsHeaderName(filename);
3386 }
3387 
3388 ////////////////////////////////////////////////////////////////////////////////
3389 /// Check if the argument is a sane cling argument. Performing the following checks:
3390 /// 1) It does not start with "--" and is not the --param option.
3391 
3392 bool IsCorrectClingArgument(const std::string& argument)
3393 {
3394  if (ROOT::TMetaUtils::BeginsWith(argument,"--") && !ROOT::TMetaUtils::BeginsWith(argument,"--param")) return false;
3395  return true;
3396 }
3397 
3398 ////////////////////////////////////////////////////////////////////////////////
3399 bool NeedsSelection(const char* name)
3400 {
3401  static const std::vector<std::string> namePrfxes {
3402  "array<",
3403  "unique_ptr<"};
3404  auto pos = find_if(namePrfxes.begin(),
3405  namePrfxes.end(),
3406  [&](const std::string& str){return ROOT::TMetaUtils::BeginsWith(name,str);});
3407  return namePrfxes.end() == pos;
3408 }
3409 
3410 ////////////////////////////////////////////////////////////////////////////////
3411 
3412 bool IsSupportedClassName(const char* name)
3413 {
3414  static const std::vector<std::string> uclNamePrfxes {
3415  "chrono:",
3416  "ratio<",
3417  "shared_ptr<"};
3418  static const std::set<std::string> unsupportedClassesNormNames{
3419  "regex",
3420  "thread"};
3421  if ( unsupportedClassesNormNames.count(name) == 1) return false;
3422  auto pos = find_if(uclNamePrfxes.begin(),
3423  uclNamePrfxes.end(),
3424  [&](const std::string& str){return ROOT::TMetaUtils::BeginsWith(name,str);});
3425  return uclNamePrfxes.end() == pos;
3426 }
3427 
3428 ////////////////////////////////////////////////////////////////////////////////
3429 /// Check if the list of selected classes contains any class which is not
3430 /// supported. Return the number of unsupported classes in the selection.
3431 
3433 {
3434  int nerrors = 0;
3435  for (auto&& aRcd : annotatedRcds){
3436  auto clName = aRcd.GetNormalizedName();
3437  if (!IsSupportedClassName(clName)){
3438  std::cerr << "Error: Class " << clName << " has been selected but "
3439  << "currently the support for its I/O is not yet available. Note that "
3440  << clName << ", even if not selected, will be available for "
3441  << "interpreted code.\n";
3442  nerrors++;
3443  }
3444  if (!NeedsSelection(clName)){
3445  std::cerr << "Error: It is not necessary to explicitly select class "
3446  << clName << ". I/O is supported for it transparently.\n";
3447  nerrors++;
3448  }
3449  }
3450  return nerrors;
3451 }
3452 
3453 ////////////////////////////////////////////////////////////////////////////////
3454 
3455 class TRootClingCallbacks : public cling::InterpreterCallbacks {
3456 private:
3457  std::list<std::string>& fFilesIncludedByLinkdef;
3458  bool isLocked = false;
3459 public:
3460  TRootClingCallbacks(cling::Interpreter* interp, std::list<std::string>& filesIncludedByLinkdef):
3461  InterpreterCallbacks(interp),
3462  fFilesIncludedByLinkdef(filesIncludedByLinkdef){};
3463 
3464  ~TRootClingCallbacks(){};
3465 
3466  virtual void InclusionDirective(clang::SourceLocation /*HashLoc*/, const clang::Token & /*IncludeTok*/,
3467  llvm::StringRef FileName, bool IsAngled, clang::CharSourceRange /*FilenameRange*/,
3468  const clang::FileEntry * /*File*/, llvm::StringRef /*SearchPath*/,
3469  llvm::StringRef /*RelativePath*/, const clang::Module * /*Imported*/)
3470  {
3471  if (isLocked) return;
3472  if (IsAngled) return;
3473  auto& PP = m_Interpreter->getCI()->getPreprocessor();
3474  auto curLexer = PP.getCurrentFileLexer();
3475  if (!curLexer) return;
3476  auto fileEntry = curLexer->getFileEntry();
3477  if (!fileEntry) return;
3478  auto thisFileName = fileEntry->getName();
3479  auto fileNameAsString = FileName.str();
3480  auto isThisLinkdef = ROOT::TMetaUtils::IsLinkdefFile(thisFileName.data());
3481  if (isThisLinkdef) {
3482  auto isTheIncludedLinkdef = ROOT::TMetaUtils::IsLinkdefFile(fileNameAsString.c_str());
3483  if (isTheIncludedLinkdef) {
3484  fFilesIncludedByLinkdef.clear();
3485  isLocked = true;
3486  } else {
3487  fFilesIncludedByLinkdef.emplace_back(fileNameAsString.c_str());
3488  }
3489  }
3490  }
3491 
3492  // rootcling pre-includes things such as Rtypes.h. This means that ACLiC can
3493  // call rootcling asking it to create a module for a file with no #includes
3494  // but relying on things from Rtypes.h such as the ClassDef macro.
3495  //
3496  // When rootcling starts building a module, it becomes resilient to the
3497  // outside environment and pre-included files have no effect. This hook
3498  // informs rootcling when a new submodule is being built so that it can
3499  // make Core.Rtypes.h visible.
3500  virtual void EnteredSubmodule(clang::Module* M,
3501  clang::SourceLocation ImportLoc,
3502  bool ForPragma) {
3503  assert(M);
3504  using namespace clang;
3505  if (llvm::StringRef(M->Name).endswith("ACLiC_dict")) {
3506  Preprocessor& PP = m_Interpreter->getCI()->getPreprocessor();
3507  HeaderSearch& HS = PP.getHeaderSearchInfo();
3508  // FIXME: Reduce to Core.Rtypes.h.
3509  Module* CoreModule = HS.lookupModule("Core", /*AllowSearch*/false);
3510  assert(M && "Must have module Core");
3511  PP.makeModuleVisible(CoreModule, ImportLoc);
3512  }
3513  }
3514 };
3515 
3516 ////////////////////////////////////////////////////////////////////////////////
3517 /// Custom diag client for clang that verifies that each implicitly build module
3518 /// is a system module. If not, it will let the current rootcling invocation
3519 /// fail with an error. All other diags beside module build remarks will be
3520 /// forwarded to the passed child diag client.
3521 ///
3522 /// The reason why we need this is that if we built implicitly a C++ module
3523 /// that belongs to a ROOT dictionary, then we will miss information generated
3524 /// by rootcling in this file (e.g. the source code comments to annotation
3525 /// attributes transformation will be missing in the module file).
3526 class CheckModuleBuildClient : public clang::DiagnosticConsumer {
3527  clang::DiagnosticConsumer *fChild;
3528  bool fOwnsChild;
3529  clang::ModuleMap &fMap;
3530 
3531 public:
3532  CheckModuleBuildClient(clang::DiagnosticConsumer *Child, bool OwnsChild, clang::ModuleMap &Map)
3533  : fChild(Child), fOwnsChild(OwnsChild), fMap(Map)
3534  {
3535  }
3536 
3537  ~CheckModuleBuildClient()
3538  {
3539  if (fOwnsChild)
3540  delete fChild;
3541  }
3542 
3543  virtual void HandleDiagnostic(clang::DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &Info) override
3544  {
3545  using namespace clang::diag;
3546 
3547  // This method catches the module_build remark from clang and checks if
3548  // the implicitly built module is a system module or not. We only support
3549  // building system modules implicitly.
3550 
3551  std::string moduleName;
3552  const clang::Module *module = nullptr;
3553 
3554  // Extract the module from the diag argument with index 0.
3555  const auto &ID = Info.getID();
3556  if (ID == remark_module_build || ID == remark_module_build_done) {
3557  moduleName = Info.getArgStdStr(0);
3558  module = fMap.findModule(moduleName);
3559  // We should never be able to build a module without having it in the
3560  // modulemap. Still, let's print a warning that we at least tell the
3561  // user that this could lead to problems.
3562  if (!module) {
3564  "Couldn't find module %s in the available modulemaps. This"
3565  "prevents us from correctly diagnosing wrongly built modules.\n",
3566  moduleName.c_str());
3567  }
3568  }
3569 
3570  // Skip the diag only if we build a ROOT system module or a system module. We still print the diag
3571  // when building a non-system module as we will print an error below and the
3572  // user should see the detailed default clang diagnostic.
3573  bool isROOTSystemModuleDiag = module && llvm::StringRef(moduleName).startswith("ROOT_");
3574  bool isSystemModuleDiag = module && module->IsSystem;
3575  if (!isROOTSystemModuleDiag && !isSystemModuleDiag)
3576  fChild->HandleDiagnostic(DiagLevel, Info);
3577 
3578  if (ID == remark_module_build && !isROOTSystemModuleDiag && !isSystemModuleDiag) {
3580  "Had to build non-system module %s implicitly. You first need to\n"
3581  "generate the dictionary for %s or mark the C++ module as a system\n"
3582  "module if you provided your own system modulemap file:\n"
3583  "%s [system] { ... }\n",
3584  moduleName.c_str(), moduleName.c_str(), moduleName.c_str());
3585  }
3586  }
3587 
3588  // All methods below just forward to the child and the default method.
3589  virtual void clear() override
3590  {
3591  fChild->clear();
3592  DiagnosticConsumer::clear();
3593  }
3594 
3595  virtual void BeginSourceFile(const clang::LangOptions &LangOpts, const clang::Preprocessor *PP) override
3596  {
3597  fChild->BeginSourceFile(LangOpts, PP);
3598  DiagnosticConsumer::BeginSourceFile(LangOpts, PP);
3599  }
3600 
3601  virtual void EndSourceFile() override
3602  {
3603  fChild->EndSourceFile();
3604  DiagnosticConsumer::EndSourceFile();
3605  }
3606 
3607  virtual void finish() override
3608  {
3609  fChild->finish();
3610  DiagnosticConsumer::finish();
3611  }
3612 
3613  virtual bool IncludeInDiagnosticCounts() const override { return fChild->IncludeInDiagnosticCounts(); }
3614 };
3615 
3617 #if defined(_WIN32) && defined(_MSC_VER)
3618  // Suppress error dialogs to avoid hangs on build nodes.
3619  // One can use an environment variable (Cling_GuiOnAssert) to enable
3620  // the error dialogs.
3621  const char *EnablePopups = getenv("Cling_GuiOnAssert");
3622  if (EnablePopups == nullptr || EnablePopups[0] == '0') {
3623  ::_set_error_mode(_OUT_TO_STDERR);
3624  _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
3625  _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
3626  _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
3627  _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
3628  _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
3629  _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
3630  }
3631 #endif
3632 }
3633 
3634 static llvm::cl::OptionCategory gRootclingOptions("rootcling common options");
3635 static llvm::cl::opt<bool> gOptForce("f", llvm::cl::desc("Overwrite <file>s."),
3636  llvm::cl::cat(gRootclingOptions));
3637 static llvm::cl::opt<bool> gOptRootBuild("rootbuild", llvm::cl::desc("If we are building ROOT."),
3638  llvm::cl::Hidden,
3639  llvm::cl::cat(gRootclingOptions));
3641  v = ROOT::TMetaUtils::kError,
3642  v0 = ROOT::TMetaUtils::kFatal,
3643  v1 = v,
3644  v2 = ROOT::TMetaUtils::kWarning,
3645  v3 = ROOT::TMetaUtils::kNote,
3646  v4 = ROOT::TMetaUtils::kInfo
3647 };
3648 static llvm::cl::opt<VerboseLevel>
3649 gOptVerboseLevel(llvm::cl::desc("Choose verbosity level:"),
3650  llvm::cl::values(clEnumVal(v, "Show errors (default)."),
3651  clEnumVal(v0, "Show only fatal errors."),
3652  clEnumVal(v1, "Show errors (the same as -v)."),
3653  clEnumVal(v2, "Show warnings."),
3654  clEnumVal(v3, "Show notes."),
3655  clEnumVal(v4, "Show information.")),
3656  llvm::cl::init(v),
3657  llvm::cl::cat(gRootclingOptions));
3658 
3659 static llvm::cl::opt<bool>
3660 gOptCint("cint", llvm::cl::desc("Deprecated, legacy flag which is ignored."),
3661  llvm::cl::Hidden,
3662  llvm::cl::cat(gRootclingOptions));
3663 static llvm::cl::opt<bool>
3664 gOptReflex("reflex", llvm::cl::desc("Deprecated, legacy flag which is ignored."),
3665  llvm::cl::Hidden,
3666  llvm::cl::cat(gRootclingOptions));
3667 static llvm::cl::opt<bool>
3668 gOptGccXml("gccxml", llvm::cl::desc("Deprecated, legacy flag which is ignored."),
3669  llvm::cl::Hidden,
3670  llvm::cl::cat(gRootclingOptions));
3671 static llvm::cl::opt<std::string>
3672 gOptLibListPrefix("lib-list-prefix",
3673  llvm::cl::desc("An ACLiC feature which exports the list of dependent libraries."),
3674  llvm::cl::Hidden,
3675  llvm::cl::cat(gRootclingOptions));
3676 static llvm::cl::opt<bool>
3677 gOptGeneratePCH("generate-pch",
3678  llvm::cl::desc("Generates a pch file from a predefined set of headers. See makepch.py."),
3679  llvm::cl::Hidden,
3680  llvm::cl::cat(gRootclingOptions));
3681  // FIXME: We should remove the IgnoreExistingDict option as it is not used.
3682 static llvm::cl::opt<bool>
3684  llvm::cl::desc("Similar to -f but it ignores the dictionary generation. \
3685 When -r is present rootcling becomes a tool to generate rootmaps (and capability files)."),
3686  llvm::cl::Hidden,
3687  llvm::cl::cat(gRootclingOptions));
3688 static llvm::cl::opt<std::string>
3689 gOptDictionaryFileName(llvm::cl::Positional, llvm::cl::Required,
3690  llvm::cl::desc("<output dictionary file>"),
3691  llvm::cl::cat(gRootclingOptions));
3692 static llvm::cl::opt<bool>
3693 gOptC("c", llvm::cl::desc("Deprecated, legacy flag which is ignored."),
3694  llvm::cl::cat(gRootclingOptions));
3695 static llvm::cl::opt<bool>
3696 gOptP("p", llvm::cl::desc("Deprecated, legacy flag which is ignored."),
3697  llvm::cl::cat(gRootclingOptions));
3698 static llvm::cl::list<std::string>
3699 gOptRootmapLibNames("rml", llvm::cl::ZeroOrMore,
3700  llvm::cl::desc("Generate rootmap file."),
3701  llvm::cl::cat(gRootclingOptions));
3702 static llvm::cl::opt<std::string>
3703 gOptRootMapFileName("rmf",
3704  llvm::cl::desc("Generate a rootmap file with the specified name."),
3705  llvm::cl::cat(gRootclingOptions));
3706 static llvm::cl::opt<bool>
3707 gOptCxxModule("cxxmodule",
3708  llvm::cl::desc("Generate a C++ module."),
3709  llvm::cl::cat(gRootclingOptions));
3710 static llvm::cl::list<std::string>
3711 gOptModuleMapFiles("moduleMapFile",
3712  llvm::cl::desc("Specify a C++ modulemap file."),
3713  llvm::cl::cat(gRootclingOptions));
3714 // FIXME: Figure out how to combine the code of -umbrellaHeader and inlineInputHeader
3715 static llvm::cl::opt<bool>
3716 gOptUmbrellaInput("umbrellaHeader",
3717  llvm::cl::desc("A single header including all headers instead of specifying them on the command line."),
3718  llvm::cl::cat(gRootclingOptions));
3719 static llvm::cl::opt<bool>
3720 gOptMultiDict("multiDict",
3721  llvm::cl::desc("If this library has multiple separate LinkDef files."),
3722  llvm::cl::cat(gRootclingOptions));
3723 static llvm::cl::opt<bool>
3724 gOptInterpreterOnly("interpreteronly",
3725  llvm::cl::desc("Generate minimal dictionary for interactivity (without IO information)."),
3726  llvm::cl::cat(gRootclingOptions));
3727 static llvm::cl::opt<bool>
3728 gOptSplit("split",
3729  llvm::cl::desc("Split the dictionary into two parts: one containing the IO (ClassDef)\
3730 information and another the interactivity support."),
3731  llvm::cl::cat(gRootclingOptions));
3732 static llvm::cl::opt<bool>
3733 gOptNoDictSelection("noDictSelection",
3734  llvm::cl::Hidden,
3735  llvm::cl::desc("Do not run the selection rules. Useful when in -onepcm mode."),
3736  llvm::cl::cat(gRootclingOptions));
3737 static llvm::cl::opt<std::string>
3739  llvm::cl::desc("The path to the library of the built dictionary."),
3740  llvm::cl::cat(gRootclingOptions));
3741 static llvm::cl::list<std::string>
3743  llvm::cl::desc("The list of dependent modules of the dictionary."),
3744  llvm::cl::cat(gRootclingOptions));
3745 static llvm::cl::list<std::string>
3746 gOptExcludePaths("excludePath", llvm::cl::ZeroOrMore,
3747  llvm::cl::desc("Do not store the <path> in the dictionary."),
3748  llvm::cl::cat(gRootclingOptions));
3749 // FIXME: This does not seem to work. We have one use of -inlineInputHeader in
3750 // ROOT and it does not produce the expected result.
3751 static llvm::cl::opt<bool>
3752 gOptInlineInput("inlineInputHeader",
3753  llvm::cl::desc("Does not generate #include <header> but expands the header content."),
3754  llvm::cl::cat(gRootclingOptions));
3755 // FIXME: This is totally the wrong concept. We should not expose an interface
3756 // to be able to tell which component is in the pch and which needs extra
3757 // scaffolding for interactive use. Moreover, some of the ROOT components are
3758 // partially in the pch and this option makes it impossible to express that.
3759 // We should be able to get the list of headers in the pch early and scan
3760 // through them.
3761 static llvm::cl::opt<bool>
3762 gOptWriteEmptyRootPCM("writeEmptyRootPCM",
3763  llvm::cl::Hidden,
3764  llvm::cl::desc("Does not include the header files as it assumes they exist in the pch."),
3765  llvm::cl::cat(gRootclingOptions));
3766 static llvm::cl::opt<bool>
3767 gOptCheckSelectionSyntax("selSyntaxOnly",
3768  llvm::cl::desc("Check the selection syntax only."),
3769  llvm::cl::cat(gRootclingOptions));
3770 static llvm::cl::opt<bool>
3771 gOptFailOnWarnings("failOnWarnings",
3772  llvm::cl::desc("Fail if there are warnings."),
3773  llvm::cl::cat(gRootclingOptions));
3774 static llvm::cl::opt<bool>
3775 gOptNoIncludePaths("noIncludePaths",
3776  llvm::cl::desc("Do not store include paths but rely on the env variable ROOT_INCLUDE_PATH."),
3777  llvm::cl::cat(gRootclingOptions));
3778 static llvm::cl::opt<std::string>
3779 gOptISysRoot("isysroot", llvm::cl::Prefix, llvm::cl::Hidden,
3780  llvm::cl::desc("Specify an isysroot."),
3781  llvm::cl::cat(gRootclingOptions),
3782  llvm::cl::init("-"));
3783 static llvm::cl::list<std::string>
3784 gOptIncludePaths("I", llvm::cl::Prefix, llvm::cl::ZeroOrMore,
3785  llvm::cl::desc("Specify an include path."),
3786  llvm::cl::cat(gRootclingOptions));
3787 static llvm::cl::list<std::string>
3788 gOptPPDefines("D", llvm::cl::Prefix, llvm::cl::ZeroOrMore,
3789  llvm::cl::desc("Specify defined macros."),
3790  llvm::cl::cat(gRootclingOptions));
3791 static llvm::cl::list<std::string>
3792 gOptPPUndefines("U", llvm::cl::Prefix, llvm::cl::ZeroOrMore,
3793  llvm::cl::desc("Specify undefined macros."),
3794  llvm::cl::cat(gRootclingOptions));
3795 static llvm::cl::list<std::string>
3796 gOptWDiags("W", llvm::cl::Prefix, llvm::cl::ZeroOrMore,
3797  llvm::cl::desc("Specify compiler diagnostics options."),
3798  llvm::cl::cat(gRootclingOptions));
3799 static llvm::cl::list<std::string>
3800 gOptDictionaryHeaderFiles(llvm::cl::Positional, llvm::cl::OneOrMore,
3801  llvm::cl::desc("<list of dictionary header files> <LinkDef file>"),
3802  llvm::cl::cat(gRootclingOptions));
3803 static llvm::cl::list<std::string>
3804 gOptSink(llvm::cl::ZeroOrMore, llvm::cl::Sink,
3805  llvm::cl::desc("Consumes all unrecognized options."),
3806  llvm::cl::cat(gRootclingOptions));
3807 
3808 ////////////////////////////////////////////////////////////////////////////////
3809 /// Returns true iff a given module (and its submodules) contains all headers
3810 /// needed by the given ModuleGenerator.
3811 /// The names of all header files that are needed by the ModuleGenerator but are
3812 /// not in the given module will be inserted into the MissingHeader variable.
3813 /// Returns true iff the PCH was successfully generated.
3814 static bool ModuleContainsHeaders(TModuleGenerator &modGen, clang::Module *module,
3815  std::vector<std::string> &missingHeaders)
3816 {
3817  // Now we collect all header files from the previously collected modules.
3818  std::vector<clang::Module::Header> moduleHeaders;
3819  ROOT::TMetaUtils::foreachHeaderInModule(*module,
3820  [&moduleHeaders](const clang::Module::Header &h) { moduleHeaders.push_back(h); });
3821 
3822  bool foundAllHeaders = true;
3823 
3824  // Go through the list of headers that are required by the ModuleGenerator
3825  // and check for each header if it's in one of the modules we loaded.
3826  // If not, make sure we fail at the end and mark the header as missing.
3827  for (const std::string &header : modGen.GetHeaders()) {
3828  bool headerFound = false;
3829  for (const clang::Module::Header &moduleHeader : moduleHeaders) {
3830  if (header == moduleHeader.NameAsWritten) {
3831  headerFound = true;
3832  break;
3833  }
3834  }
3835  if (!headerFound) {
3836  missingHeaders.push_back(header);
3837  foundAllHeaders = false;
3838  }
3839  }
3840  return foundAllHeaders;
3841 }
3842 
3843 ////////////////////////////////////////////////////////////////////////////////
3844 /// Check moduleName validity from modulemap. Check if this module is defined or not.
3845 static bool CheckModuleValid(TModuleGenerator &modGen, const std::string &resourceDir, cling::Interpreter &interpreter,
3846  StringRef LinkdefPath, const std::string &moduleName)
3847 {
3848 #ifdef __APPLE__
3849 
3850  if (moduleName == "Krb5Auth" || moduleName == "GCocoa" || moduleName == "GQuartz")
3851  return true;
3852 #endif
3853 
3854  clang::CompilerInstance *CI = interpreter.getCI();
3855  clang::HeaderSearch &headerSearch = CI->getPreprocessor().getHeaderSearchInfo();
3856  headerSearch.loadTopLevelSystemModules();
3857 
3858  // Actually lookup the module on the computed module name.
3859  clang::Module *module = headerSearch.lookupModule(StringRef(moduleName));
3860 
3861  // Inform the user and abort if we can't find a module with a given name.
3862  if (!module) {
3863  ROOT::TMetaUtils::Error("CheckModuleValid", "Couldn't find module with name '%s' in modulemap!\n",
3864  moduleName.c_str());
3865  return false;
3866  }
3867 
3868  // Check if the loaded module covers all headers that were specified
3869  // by the user on the command line. This is an integrity check to
3870  // ensure that our used module map is
3871  std::vector<std::string> missingHeaders;
3872  if (!ModuleContainsHeaders(modGen, module, missingHeaders)) {
3873  // FIXME: Upgrade this to an error once modules are stable.
3874  std::stringstream msgStream;
3875  msgStream << "warning: Couldn't find in "
3876  << module->PresumedModuleMapFile
3877  << " the following specified headers in "
3878  << "the module " << module->Name << ":\n";
3879  for (auto &H : missingHeaders) {
3880  msgStream << " " << H << "\n";
3881  }
3882  std::string warningMessage = msgStream.str();
3883 
3884  bool maybeUmbrella = modGen.GetHeaders().size() == 1;
3885  // We may have an umbrella and forgot to add the flag. Downgrade the
3886  // warning into an information message.
3887  // FIXME: We should open the umbrella, extract the set of header files
3888  // and check if they exist in the modulemap.
3889  // FIXME: We should also check if the header files are specified in the
3890  // modulemap file as they appeared in the rootcling invocation, i.e.
3891  // if we passed rootcling ... -I/some/path somedir/some/header, the
3892  // modulemap should contain module M { header "somedir/some/header" }
3893  // This way we will make sure the module is properly activated.
3894  if (!gOptUmbrellaInput && maybeUmbrella) {
3895  ROOT::TMetaUtils::Info("CheckModuleValid, %s. You can silence this message by adding %s to the invocation.",
3896  warningMessage.c_str(),
3897  gOptUmbrellaInput.ArgStr.data());
3898  return true;
3899  }
3900 
3901  ROOT::TMetaUtils::Warning("CheckModuleValid", warningMessage.c_str());
3902  // We include the missing headers to fix the module for the user.
3903  if (!IncludeHeaders(missingHeaders, interpreter)) {
3904  ROOT::TMetaUtils::Error("CheckModuleValid", "Couldn't include missing module headers for module '%s'!\n",
3905  module->Name.c_str());
3906  }
3907  }
3908 
3909  return true;
3910 }
3911 
3912 
3913 ////////////////////////////////////////////////////////////////////////////////
3914 
3915 int RootClingMain(int argc,
3916  char **argv,
3917  bool isGenreflex = false)
3918 {
3919  // Define Options aliasses
3920  auto &opts = llvm::cl::getRegisteredOptions();
3921  auto &optHelp = *opts["help"];
3922  llvm::cl::alias optHelpAlias1("h",
3923  llvm::cl::desc("Alias for -help"),
3924  llvm::cl::aliasopt(optHelp));
3925  llvm::cl::alias optHelpAlias2("?",
3926  llvm::cl::desc("Alias for -help"),
3927  llvm::cl::aliasopt(optHelp));
3928 
3929  // Copied from cling driver.
3930  // FIXME: Uncomment once we fix ROOT's teardown order.
3931  //llvm::llvm_shutdown_obj shutdownTrigger;
3932 
3933  const char *executableFileName = argv[0];
3934 
3935  llvm::sys::PrintStackTraceOnErrorSignal(executableFileName);
3936  llvm::PrettyStackTraceProgram X(argc, argv);
3938 
3939 #if defined(R__WIN32) && !defined(R__WINGCC)
3940  // FIXME: This is terrible hack allocating and changing the argument set.
3941  // We should remove it and use standard llvm facilities to convert the paths.
3942  // cygwin's make is presenting us some cygwin paths even though
3943  // we are windows native. Convert them as good as we can.
3944  for (int iic = 1 /* ignore binary file name in argv[0] */; iic < argc; ++iic) {
3945  std::string iiarg(argv[iic]);
3946  if (FromCygToNativePath(iiarg)) {
3947  size_t len = iiarg.length();
3948  // yes, we leak.
3949  char *argviic = new char[len + 1];
3950  strlcpy(argviic, iiarg.c_str(), len + 1);
3951  argv[iic] = argviic;
3952  }
3953  }
3954 #endif
3955 
3956  // Hide options from llvm which we got from static initialization of libCling.
3957  llvm::cl::HideUnrelatedOptions(/*keep*/gRootclingOptions);
3958 
3959  llvm::cl::ParseCommandLineOptions(argc, argv, "rootcling");
3960 
3961  std::string dictname;
3962  std::string dictpathname;
3963 
3965  if (gOptRootBuild) {
3966  // running rootcling as part of the ROOT build for ROOT libraries.
3967  gBuildingROOT = true;
3968  }
3969  }
3970 
3971  if (!gOptModuleMapFiles.empty() && !gOptCxxModule) {
3972  ROOT::TMetaUtils::Error("", "Option %s can be used only when option %s is specified.\n",
3973  gOptModuleMapFiles.ArgStr.str().c_str(),
3974  gOptCxxModule.ArgStr.str().c_str());
3975  // FIXME: Show the output of -help.
3976  return 1;
3977  }
3978 
3979  // Set the default verbosity
3980  ROOT::TMetaUtils::GetErrorIgnoreLevel() = gOptVerboseLevel;
3981  if (gOptVerboseLevel == v4)
3982  genreflex::verbose = true;
3983 
3984  if (gOptReflex)
3985  isGenreflex = true;
3986 
3987 #if ROOT_VERSION_CODE < ROOT_VERSION(6,21,00)
3988  if (gOptCint)
3989  fprintf(stderr, "warning: Please remove the deprecated flag -cint.\n");
3990  if (gOptGccXml)
3991  fprintf(stderr, "warning: Please remove the deprecated flag -gccxml.\n");
3992  if (gOptC)
3993  fprintf(stderr, "warning: Please remove the deprecated flag -c.\n");
3994  if (gOptP)
3995  fprintf(stderr, "warning: Please remove the deprecated flag -p.\n");
3996 
3997  for (auto I = gOptDictionaryHeaderFiles.begin(), E = gOptDictionaryHeaderFiles.end(); I != E; ++I) {
3998  if ((*I)[0] == '+') {
3999  // Mostly for +P, +V, +STUB which are legacy CINT flags.
4000  fprintf(stderr, "warning: Please remove the deprecated flag %s\n", I->c_str());
4001  // Remove it from the list because it will mess up our header input.
4003  }
4004  }
4005 
4006  for (const std::string& Opt : gOptSink)
4007  fprintf(stderr, "warning: Please remove the deprecated flag %s\n", Opt.c_str());
4008 #else
4009 # error "Remove this deprecated code"
4010 #endif
4011 
4012  if (!gOptLibListPrefix.empty()) {
4013  string filein = gOptLibListPrefix + ".in";
4014  FILE *fp;
4015  if ((fp = fopen(filein.c_str(), "r")) == 0) {
4016  ROOT::TMetaUtils::Error(0, "%s: The input list file %s does not exist\n", executableFileName, filein.c_str());
4017  return 1;
4018  }
4019  fclose(fp);
4020  }
4021 
4023  FILE *fp;
4024  if (!gOptIgnoreExistingDict && (fp = fopen(gOptDictionaryFileName.c_str(), "r")) != 0) {
4025  fclose(fp);
4026  if (!gOptForce) {
4027  ROOT::TMetaUtils::Error(0, "%s: output file %s already exists\n", executableFileName, gOptDictionaryFileName.c_str());
4028  return 1;
4029  }
4030  }
4031 
4032  // remove possible pathname to get the dictionary name
4033  if (gOptDictionaryFileName.size() > (PATH_MAX - 1)) {
4034  ROOT::TMetaUtils::Error(0, "rootcling: dictionary name too long (more than %d characters): %s\n",
4035  (PATH_MAX - 1), gOptDictionaryFileName.c_str());
4036  return 1;
4037  }
4038 
4039  dictpathname = gOptDictionaryFileName;
4040  dictname = llvm::sys::path::filename(gOptDictionaryFileName);
4041  }
4042 
4043  if (gOptForce && dictname.empty()) {
4044  ROOT::TMetaUtils::Error(0, "Inconsistent set of arguments detected: overwrite of dictionary file forced but no filename specified.\n");
4045  fprintf(stderr, "%s\n", shortHelp);
4046  return 1;
4047  }
4048 
4049  std::vector<std::string> clingArgs;
4050  clingArgs.push_back(executableFileName);
4051  clingArgs.push_back("-iquote.");
4052 
4053  bool dictSelection = !gOptNoDictSelection;
4054 
4055  // Collect the diagnostic pragmas linked to the usage of -W
4056  // Workaround for ROOT-5656
4057  std::list<std::string> diagnosticPragmas = {"#pragma clang diagnostic ignored \"-Wdeprecated-declarations\""};
4058 
4059  if (gOptFailOnWarnings) {
4060  using namespace ROOT::TMetaUtils;
4061  // If warnings are disabled with the current verbosity settings, lower
4062  // it so that the user sees the warning that caused the failure.
4063  if (GetErrorIgnoreLevel() > kWarning)
4064  GetErrorIgnoreLevel() = kWarning;
4065  GetWarningsAreErrors() = true;
4066  }
4067 
4068  if (gOptISysRoot != "-") {
4069  if (gOptISysRoot.empty()) {
4070  ROOT::TMetaUtils::Error("", "isysroot specified without a value.\n");
4071  return 1;
4072  }
4073  clingArgs.push_back(gOptISysRoot.ArgStr);
4074  clingArgs.push_back(gOptISysRoot.ValueStr);
4075  }
4076 
4077  // Check if we have a multi dict request but no target library
4078  if (gOptMultiDict && gOptSharedLibFileName.empty()) {
4079  ROOT::TMetaUtils::Error("", "Multidict requested but no target library. Please specify one with the -s argument.\n");
4080  return 1;
4081  }
4082 
4083  for (const std::string &PPDefine : gOptPPDefines)
4084  clingArgs.push_back(std::string("-D") + PPDefine);
4085 
4086  for (const std::string &PPUndefine : gOptPPUndefines)
4087  clingArgs.push_back(std::string("-U") + PPUndefine);
4088 
4089  for (const std::string &IncludePath : gOptIncludePaths)
4090  clingArgs.push_back(std::string("-I") + llvm::sys::path::convert_to_slash(IncludePath));
4091 
4092  for (const std::string &WDiag : gOptWDiags) {
4093  const std::string FullWDiag = std::string("-W") + WDiag;
4094  // Suppress warning when compiling the dictionary, eg. gcc G__xxx.cxx
4095  CheckForMinusW(FullWDiag, diagnosticPragmas);
4096  // Suppress warning when compiling the input headers by cling.
4097  clingArgs.push_back(FullWDiag);
4098  }
4099 
4100  std::string includeDir = llvm::sys::path::convert_to_slash(gDriverConfig->fTROOT__GetIncludeDir());
4101  clingArgs.push_back(std::string("-I") + includeDir);
4102 
4103  std::vector<std::string> pcmArgs;
4104  for (size_t parg = 0, n = clingArgs.size(); parg < n; ++parg) {
4105  auto thisArg = clingArgs[parg];
4106  auto isInclude = ROOT::TMetaUtils::BeginsWith(thisArg,"-I");
4107  if (thisArg == "-c" ||
4108  (gOptNoIncludePaths && isInclude)) continue;
4109  // We now check if the include directories are not excluded
4110  if (isInclude) {
4111  unsigned int offset = 2; // -I is two characters. Now account for spaces
4112  char c = thisArg[offset];
4113  while (c == ' ') c = thisArg[++offset];
4114  auto excludePathsEnd = gOptExcludePaths.end();
4115  auto excludePathPos = std::find_if(gOptExcludePaths.begin(),
4116  excludePathsEnd,
4117  [&](const std::string& path){
4118  return ROOT::TMetaUtils::BeginsWith(&thisArg[offset], path);});
4119  if (excludePathsEnd != excludePathPos) continue;
4120  }
4121  pcmArgs.push_back(thisArg);
4122  }
4123 
4124  // cling-only arguments
4125  clingArgs.push_back(std::string("-I") + llvm::sys::path::convert_to_slash(gDriverConfig->fTROOT__GetEtcDir()));
4126  // We do not want __ROOTCLING__ in the pch!
4127  if (!gOptGeneratePCH) {
4128  clingArgs.push_back("-D__ROOTCLING__");
4129  }
4130 #ifdef R__MACOSX
4131  clingArgs.push_back("-DSYSTEM_TYPE_macosx");
4132 #elif defined(R__WIN32)
4133  clingArgs.push_back("-DSYSTEM_TYPE_winnt");
4134 
4135  // Prevent the following #error: The C++ Standard Library forbids macroizing keywords.
4136  clingArgs.push_back("-D_XKEYCHECK_H");
4137  // Tell windows.h not to #define min and max, it clashes with numerical_limits.
4138  clingArgs.push_back("-DNOMINMAX");
4139 #else // assume UNIX
4140  clingArgs.push_back("-DSYSTEM_TYPE_unix");
4141 #endif
4142 
4143  clingArgs.push_back("-fsyntax-only");
4144 #ifndef R__WIN32
4145  clingArgs.push_back("-fPIC");
4146 #endif
4147  clingArgs.push_back("-Xclang");
4148  clingArgs.push_back("-fmodules-embed-all-files");
4149  clingArgs.push_back("-Xclang");
4150  clingArgs.push_back("-main-file-name");
4151  clingArgs.push_back("-Xclang");
4152  clingArgs.push_back((dictname + ".h").c_str());
4153 
4154  ROOT::TMetaUtils::SetPathsForRelocatability(clingArgs);
4155 
4156  // FIXME: This line is from TModuleGenerator, but we can't reuse this code
4157  // at this point because TModuleGenerator needs a CompilerInstance (and we
4158  // currently create the arguments for creating said CompilerInstance).
4159  bool isPCH = (dictpathname == "allDict.cxx");
4160  std::string outputFile;
4161  // Data is in 'outputFile', therefore in the same scope.
4162  StringRef moduleName;
4163  std::string vfsArg;
4164  // Adding -fmodules to the args will break lexing with __CINT__ defined,
4165  // and we actually do lex with __CINT__ and reuse this variable later,
4166  // we have to copy it now.
4167  auto clingArgsInterpreter = clingArgs;
4168 
4169  if (gOptSharedLibFileName.empty()) {
4170  gOptSharedLibFileName = dictpathname;
4171  }
4172 
4173  if (!isPCH && gOptCxxModule) {
4174  // We just pass -fmodules, the CIFactory will do the rest and configure
4175  // clang correctly once it sees this flag.
4176  clingArgsInterpreter.push_back("-fmodules");
4177  clingArgsInterpreter.push_back("-fno-implicit-module-maps");
4178 
4179  for (const std::string &modulemap : gOptModuleMapFiles)
4180  clingArgsInterpreter.push_back("-fmodule-map-file=" + modulemap);
4181 
4182  clingArgsInterpreter.push_back("-fmodule-map-file=" +
4184  "/module.modulemap");
4185  std::string ModuleMapCWD = ROOT::FoundationUtils::GetCurrentDir() + "/module.modulemap";
4186  if (llvm::sys::fs::exists(ModuleMapCWD))
4187  clingArgsInterpreter.push_back("-fmodule-map-file=" + ModuleMapCWD);
4188 
4189  // Specify the module name that we can lookup the module in the modulemap.
4190  outputFile = llvm::sys::path::stem(gOptSharedLibFileName).str();
4191  // Try to get the module name in the modulemap based on the filepath.
4192  moduleName = llvm::sys::path::filename(outputFile);
4193  moduleName.consume_front("lib");
4194  moduleName.consume_back("_rdict.pcm");
4195 
4196  clingArgsInterpreter.push_back("-fmodule-name");
4197  clingArgsInterpreter.push_back(moduleName.str());
4198 
4199  std::string moduleCachePath = llvm::sys::path::parent_path(gOptSharedLibFileName).str();
4200  // FIXME: This is a horrible workaround to fix the incremental builds.
4201  // The enumerated modules are built by clang impicitly based on #include of
4202  // a header which is contained within that module. The build system has
4203  // no way to track dependencies on them and trigger a rebuild.
4204  // A possible solution can be to disable completely the implicit build of
4205  // modules and each module to be built by rootcling. We need to teach
4206  // rootcling how to build modules with no IO support.
4207  if (moduleName == "Core") {
4209  remove((moduleCachePath + llvm::sys::path::get_separator() + "_Builtin_stddef_max_align_t.pcm").str().c_str());
4210  remove((moduleCachePath + llvm::sys::path::get_separator() + "Cling_Runtime.pcm").str().c_str());
4211  remove((moduleCachePath + llvm::sys::path::get_separator() + "Cling_Runtime_Extra.pcm").str().c_str());
4212  remove((moduleCachePath + llvm::sys::path::get_separator() + "libc.pcm").str().c_str());
4213  remove((moduleCachePath + llvm::sys::path::get_separator() + "std.pcm").str().c_str());
4214  remove((moduleCachePath + llvm::sys::path::get_separator() + "cuda.pcm").str().c_str());
4215  remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Config.pcm").str().c_str());
4216  remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Rtypes.pcm").str().c_str());
4217  remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Foundation_C.pcm").str().c_str());
4218  remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Foundation_Stage1_NoRTTI.pcm").str().c_str());
4219  }
4220 
4221  // Set the C++ modules output directory to the directory where we generate
4222  // the shared library.
4223  clingArgsInterpreter.push_back("-fmodules-cache-path=" + moduleCachePath);
4224  }
4225 
4226  if (gOptVerboseLevel == v4)
4227  clingArgsInterpreter.push_back("-v");
4228 
4229  // Convert arguments to a C array and check if they are sane
4230  std::vector<const char *> clingArgsC;
4231  for (auto const &clingArg : clingArgsInterpreter) {
4232  if (!IsCorrectClingArgument(clingArg)){
4233  std::cerr << "Argument \""<< clingArg << "\" is not a supported cling argument. "
4234  << "This could be mistyped rootcling argument. Please check the commandline.\n";
4235  return 1;
4236  }
4237  clingArgsC.push_back(clingArg.c_str());
4238  }
4239 
4240 
4241  std::unique_ptr<cling::Interpreter> owningInterpPtr;
4242  cling::Interpreter* interpPtr = nullptr;
4243 
4244  std::list<std::string> filesIncludedByLinkdef;
4245  std::string llvmResourceDir = std::string(gDriverConfig->fTROOT__GetEtcDir()) + "/cling";
4247  // Pass the interpreter arguments to TCling's interpreter:
4248  clingArgsC.push_back("-resource-dir");
4249  clingArgsC.push_back(llvmResourceDir.c_str());
4250  clingArgsC.push_back(0); // signal end of array
4251  const char ** &extraArgs = *gDriverConfig->fTROOT__GetExtraInterpreterArgs();
4252  extraArgs = &clingArgsC[1]; // skip binary name
4253  interpPtr = gDriverConfig->fTCling__GetInterpreter();
4254  if (!isGenreflex && !gOptGeneratePCH) {
4255  std::unique_ptr<TRootClingCallbacks> callBacks (new TRootClingCallbacks(interpPtr, filesIncludedByLinkdef));
4256  interpPtr->setCallbacks(std::move(callBacks));
4257  }
4258  } else {
4259 #ifdef R__FAST_MATH
4260  // Same setting as in TCling.cxx.
4261  clingArgsC.push_back("-ffast-math");
4262 #endif
4263 
4264  owningInterpPtr.reset(new cling::Interpreter(clingArgsC.size(), &clingArgsC[0],
4265  llvmResourceDir.c_str()));
4266  interpPtr = owningInterpPtr.get();
4267  }
4268  cling::Interpreter &interp = *interpPtr;
4269  clang::CompilerInstance *CI = interp.getCI();
4270  // FIXME: Remove this once we switch cling to use the driver. This would handle -fmodules-embed-all-files for us.
4271  CI->getFrontendOpts().ModulesEmbedAllFiles = true;
4272  CI->getSourceManager().setAllFilesAreTransient(true);
4273 
4274  clang::Preprocessor &PP = CI->getPreprocessor();
4275  clang::HeaderSearch &headerSearch = PP.getHeaderSearchInfo();
4276  clang::ModuleMap &moduleMap = headerSearch.getModuleMap();
4277  auto &diags = interp.getDiagnostics();
4278 
4279  // Manually enable the module build remarks. We don't enable them via the
4280  // normal clang command line arg because otherwise we would get remarks for
4281  // building STL/libc when starting the interpreter in rootcling_stage1.
4282  // We can't prevent these diags in any other way because we can only attach
4283  // our own diag client now after the interpreter has already started.
4284  diags.setSeverity(clang::diag::remark_module_build, clang::diag::Severity::Remark, clang::SourceLocation());
4285 
4286  // Attach our own diag client that listens to the module_build remarks from
4287  // clang to check that we don't build dictionary C++ modules implicitly.
4288  auto recordingClient = new CheckModuleBuildClient(diags.getClient(), diags.ownsClient(), moduleMap);
4289  diags.setClient(recordingClient, true);
4290 
4291  if (ROOT::TMetaUtils::GetErrorIgnoreLevel() == ROOT::TMetaUtils::kInfo) {
4292  ROOT::TMetaUtils::Info(0, "\n");
4293  ROOT::TMetaUtils::Info(0, "==== INTERPRETER CONFIGURATION ====\n");
4294  ROOT::TMetaUtils::Info(0, "== Include paths\n");
4295  interp.DumpIncludePath();
4296  printf("\n\n");
4297  fflush(stdout);
4298 
4299  ROOT::TMetaUtils::Info(0, "== Included files\n");
4300  interp.printIncludedFiles(llvm::outs());
4301  llvm::outs() << "\n\n";
4302  llvm::outs().flush();
4303 
4304  ROOT::TMetaUtils::Info(0, "== Language Options\n");
4305  const clang::LangOptions& LangOpts
4306  = interp.getCI()->getASTContext().getLangOpts();
4307 #define LANGOPT(Name, Bits, Default, Description) \
4308  ROOT::TMetaUtils::Info(0, "%s = %d // %s\n", #Name, (int)LangOpts.Name, Description);
4309 #define ENUM_LANGOPT(Name, Type, Bits, Default, Description)
4310 #include "clang/Basic/LangOptions.def"
4311  ROOT::TMetaUtils::Info(0, "==== END interpreter configuration ====\n\n");
4312  }
4313 
4314  interp.getOptions().ErrorOut = true;
4315  interp.enableRawInput(true);
4316  if (isGenreflex) {
4317  if (interp.declare("namespace std {} using namespace std;") != cling::Interpreter::kSuccess) {
4318  // There was an error.
4319  ROOT::TMetaUtils::Error(0, "Error loading the default header files.\n");
4320  return 1;
4321  }
4322  } else {
4323  // rootcling
4324  if (interp.declare("namespace std {} using namespace std;") != cling::Interpreter::kSuccess
4325  // CINT uses to define a few header implicitly, we need to do it explicitly.
4326  || interp.declare("#include <assert.h>\n"
4327  "#include <stdlib.h>\n"
4328  "#include <stddef.h>\n"
4329  "#include <string.h>\n"
4330  ) != cling::Interpreter::kSuccess
4331  || interp.declare("#include \"Rtypes.h\"\n"
4332  "#include \"TClingRuntime.h\"\n"
4333  "#include \"TObject.h\""
4334  ) != cling::Interpreter::kSuccess
4335  ) {
4336  // There was an error.
4337  ROOT::TMetaUtils::Error(0, "Error loading the default header files.\n");
4338  return 1;
4339  }
4340  }
4341 
4342  // For the list of 'opaque' typedef to also include string, we have to include it now.
4343  interp.declare("#include <string>");
4344 
4345  // We are now ready (enough is loaded) to init the list of opaque typedefs.
4346  ROOT::TMetaUtils::TNormalizedCtxt normCtxt(interp.getLookupHelper());
4347  ROOT::TMetaUtils::TClingLookupHelper helper(interp, normCtxt, 0, 0, nullptr);
4348  TClassEdit::Init(&helper);
4349 
4350  // flags used only for the pragma parser:
4351  clingArgs.push_back("-D__CINT__");
4352  clingArgs.push_back("-D__MAKECINT__");
4353 
4354  AddPlatformDefines(clingArgs);
4355 
4356  std::string currentDirectory = ROOT::FoundationUtils::GetCurrentDir();
4357 
4358  std::string interpPragmaSource;
4359  std::string includeForSource;
4360  std::string interpreterDeclarations;
4361  std::string linkdef;
4362 
4363  for (size_t i = 0, e = gOptDictionaryHeaderFiles.size(); i < e; ++i) {
4364  const std::string& optHeaderFileName = gOptDictionaryHeaderFiles[i];
4365  bool isSelectionFile = IsSelectionFile(optHeaderFileName.c_str());
4366 
4367  if (isSelectionFile) {
4368  if (i == e - 1) {
4369  linkdef = optHeaderFileName;
4370  } else { // if the linkdef was not last, issue an error.
4371  ROOT::TMetaUtils::Error(0, "%s: %s must be last file on command line\n",
4372  executableFileName, optHeaderFileName.c_str());
4373  return 1;
4374  }
4375  }
4376 
4377  // coverity[tainted_data] The OS should already limit the argument size, so we are safe here
4378  std::string fullheader(optHeaderFileName);
4379  // Strip any trailing + which is only used by GeneratedLinkdef.h which currently
4380  // use directly argv.
4381  if (fullheader[fullheader.length() - 1] == '+') {
4382  fullheader.erase(fullheader.length() - 1);
4383  }
4384  std::string header(
4385  isSelectionFile ? fullheader : ROOT::FoundationUtils::MakePathRelative(fullheader, currentDirectory, gBuildingROOT));
4386 
4387  interpPragmaSource += std::string("#include \"") + header + "\"\n";
4388  if (!isSelectionFile) {
4389  // In order to not have to add the equivalent to -I${PWD} to the
4390  // command line, include the complete file name, even if it is a
4391  // full pathname, when we write it down in the dictionary.
4392  // Note: have -I${PWD} means in that (at least in the case of
4393  // ACLiC) we inadvertently pick local file that have the same
4394  // name as system header (e.g. new or list) and -iquote has not
4395  // equivalent on some platforms.
4396  includeForSource += std::string("#include \"") + fullheader + "\"\n";
4397  pcmArgs.push_back(header);
4398  } else if (!IsSelectionXml(optHeaderFileName.c_str())) {
4399  interpreterDeclarations += std::string("#include \"") + header + "\"\n";
4400  }
4401  }
4402 
4403  if (gOptUmbrellaInput) {
4404  bool hasSelectionFile = !linkdef.empty();
4405  unsigned expectedHeaderFilesSize = 1 + hasSelectionFile;
4406  if (gOptDictionaryHeaderFiles.size() > expectedHeaderFilesSize)
4407  ROOT::TMetaUtils::Error(0, "Option %s used but more than one header file specified.\n",
4408  gOptUmbrellaInput.ArgStr.data());
4409  }
4410 
4411 
4413  for (const auto & baseModule : gOptModuleDependencies)
4414  gDriverConfig->fAddAncestorPCMROOTFile(baseModule.c_str());
4415  }
4416 
4417  // We have a multiDict request. This implies generating a pcm which is of the form
4418  // dictName_libname_rdict.pcm
4419  if (gOptMultiDict) {
4420 
4421  std::string newName = llvm::sys::path::parent_path(gOptSharedLibFileName).str();
4422  if (!newName.empty())
4423  newName += gPathSeparator;
4424  newName += llvm::sys::path::stem(gOptSharedLibFileName);
4425  newName += "_";
4426  newName += llvm::sys::path::stem(dictpathname);
4428  gOptSharedLibFileName = newName;
4429  }
4430 
4431  // Until the module are actually enabled in ROOT, we need to register
4432  // the 'current' directory to make it relocatable (i.e. have a way
4433  // to find the headers).
4435  string incCurDir = "-I";
4436  incCurDir += currentDirectory;
4437  pcmArgs.push_back(incCurDir);
4438  }
4439 
4440  // Add the diagnostic pragmas distilled from the -Wno-xyz
4441  {
4442  std::stringstream res;
4443  const char* delim="\n";
4444  std::copy(diagnosticPragmas.begin(),
4445  diagnosticPragmas.end(),
4446  std::ostream_iterator<std::string>(res, delim));
4447  interp.declare(res.str());
4448  }
4449 
4450  class IgnoringPragmaHandler: public clang::PragmaNamespace {
4451  public:
4452  IgnoringPragmaHandler(const char* pragma):
4453  clang::PragmaNamespace(pragma) {}
4454  void HandlePragma(clang::Preprocessor &PP,
4455  clang::PragmaIntroducerKind Introducer,
4456  clang::Token &tok) {
4457  PP.DiscardUntilEndOfDirective();
4458  }
4459  };
4460 
4461  // Ignore these #pragmas to suppress "unknown pragma" warnings.
4462  // See LinkdefReader.cxx.
4463  PP.AddPragmaHandler(new IgnoringPragmaHandler("link"));
4464  PP.AddPragmaHandler(new IgnoringPragmaHandler("extra_include"));
4465  PP.AddPragmaHandler(new IgnoringPragmaHandler("read"));
4466  PP.AddPragmaHandler(new IgnoringPragmaHandler("create"));
4467 
4468  if (!interpreterDeclarations.empty() &&
4469  interp.declare(interpreterDeclarations) != cling::Interpreter::kSuccess) {
4470  ROOT::TMetaUtils::Error(0, "%s: Linkdef compilation failure\n", executableFileName);
4471  return 1;
4472  }
4473 
4474 
4475  TModuleGenerator modGen(interp.getCI(),
4479 
4480  if (!gDriverConfig->fBuildingROOTStage1 && !filesIncludedByLinkdef.empty()) {
4481  pcmArgs.push_back(linkdef);
4482  }
4483 
4484  modGen.ParseArgs(pcmArgs);
4485 
4487  // Forward the -I, -D, -U
4488  for (const std::string & inclPath : modGen.GetIncludePaths()) {
4489  interp.AddIncludePath(inclPath);
4490  }
4491  std::stringstream definesUndefinesStr;
4492  modGen.WritePPDefines(definesUndefinesStr);
4493  modGen.WritePPUndefines(definesUndefinesStr);
4494  if (!definesUndefinesStr.str().empty())
4495  interp.declare(definesUndefinesStr.str());
4496  }
4497 
4498  if (!InjectModuleUtilHeader(executableFileName, modGen, interp, true)
4499  || !InjectModuleUtilHeader(executableFileName, modGen, interp, false)) {
4500  return 1;
4501  }
4502 
4503  if (linkdef.empty()) {
4504  // Generate autolinkdef
4505  GenerateLinkdef(gOptDictionaryHeaderFiles, interpPragmaSource);
4506  }
4507 
4508  // Check if code goes to stdout or rootcling file
4509  std::ofstream fileout;
4510  string main_dictname(dictpathname);
4511  std::ostream *dictStreamPtr = NULL;
4512  // Store the temp files
4513  tempFileNamesCatalog tmpCatalog;
4514  if (!gOptIgnoreExistingDict) {
4515  if (!dictpathname.empty()) {
4516  tmpCatalog.addFileName(dictpathname);
4517  fileout.open(dictpathname.c_str());
4518  dictStreamPtr = &fileout;
4519  if (!(*dictStreamPtr)) {
4520  ROOT::TMetaUtils::Error(0, "rootcling: failed to open %s in main\n",
4521  dictpathname.c_str());
4522  return 1;
4523  }
4524  } else {
4525  dictStreamPtr = &std::cout;
4526  }
4527  } else {
4528  fileout.open("/dev/null");
4529  dictStreamPtr = &fileout;
4530  }
4531 
4532  // Now generate a second stream for the split dictionary if it is necessary
4533  std::ostream *splitDictStreamPtr = gOptSplit ? CreateStreamPtrForSplitDict(dictpathname, tmpCatalog) : dictStreamPtr;
4534  std::ostream &dictStream = *dictStreamPtr;
4535  std::ostream &splitDictStream = *splitDictStreamPtr;
4536 
4537  size_t dh = main_dictname.rfind('.');
4538  if (dh != std::string::npos) {
4539  main_dictname.erase(dh);
4540  }
4541  // Need to replace all the characters not allowed in a symbol ...
4542  std::string main_dictname_copy(main_dictname);
4543  TMetaUtils::GetCppName(main_dictname, main_dictname_copy.c_str());
4544 
4545  CreateDictHeader(dictStream, main_dictname);
4546  if (gOptSplit)
4547  CreateDictHeader(splitDictStream, main_dictname);
4548 
4549  //---------------------------------------------------------------------------
4550  // Parse the linkdef or selection.xml file.
4551  /////////////////////////////////////////////////////////////////////////////
4552 
4553  string linkdefFilename;
4554  if (linkdef.empty()) {
4555  linkdefFilename = "in memory";
4556  } else {
4557  bool found = Which(interp, linkdef.c_str(), linkdefFilename);
4558  if (!found) {
4559  ROOT::TMetaUtils::Error(0, "%s: cannot open linkdef file %s\n", executableFileName, linkdef.c_str());
4560  return 1;
4561  }
4562  }
4563 
4564  // Exclude string not to re-generate the dictionary
4565  std::vector<std::pair<std::string, std::string>> namesForExclusion;
4566  if (!gBuildingROOT) {
4567  namesForExclusion.push_back(std::make_pair(ROOT::TMetaUtils::propNames::name, "std::string"));
4568  namesForExclusion.push_back(std::make_pair(ROOT::TMetaUtils::propNames::pattern, "ROOT::Meta::Selection*"));
4569  }
4570 
4571  SelectionRules selectionRules(interp, normCtxt, namesForExclusion);
4572 
4573  std::string extraIncludes;
4574 
4575  ROOT::TMetaUtils::RConstructorTypes constructorTypes;
4576 
4577  // Select using DictSelection
4578  const unsigned int selRulesInitialSize = selectionRules.Size();
4579  if (dictSelection && !gOptGeneratePCH)
4580  ROOT::Internal::DictSelectionReader dictSelReader(interp, selectionRules, CI->getASTContext(), normCtxt);
4581 
4582  bool dictSelRulesPresent = selectionRules.Size() > selRulesInitialSize;
4583 
4584  bool isSelXML = IsSelectionXml(linkdefFilename.c_str());
4585 
4586  int rootclingRetCode(0);
4587 
4588  if (linkdef.empty()) {
4589  // There is no linkdef file, we added the 'default' #pragma to
4590  // interpPragmaSource.
4591 
4592  LinkdefReader ldefr(interp, constructorTypes);
4593  clingArgs.push_back("-Ietc/cling/cint"); // For multiset and multimap
4594 
4595  if (!ldefr.Parse(selectionRules, interpPragmaSource, clingArgs,
4596  llvmResourceDir.c_str())) {
4597  ROOT::TMetaUtils::Error(0, "Parsing #pragma failed %s\n", linkdefFilename.c_str());
4598  rootclingRetCode += 1;
4599  } else {
4600  ROOT::TMetaUtils::Info(0, "#pragma successfully parsed.\n");
4601  }
4602 
4603  if (!ldefr.LoadIncludes(extraIncludes)) {
4604  ROOT::TMetaUtils::Error(0, "Error loading the #pragma extra_include.\n");
4605  return 1;
4606  }
4607 
4608  } else if (isSelXML) {
4609 
4611 
4612  std::ifstream file(linkdefFilename.c_str());
4613  if (file.is_open()) {
4614  ROOT::TMetaUtils::Info(0, "Selection XML file\n");
4615 
4616  XMLReader xmlr(interp);
4617  if (!xmlr.Parse(linkdefFilename.c_str(), selectionRules)) {
4618  ROOT::TMetaUtils::Error(0, "Parsing XML file %s\n", linkdefFilename.c_str());
4619  return 1; // Return here to propagate the failure up to the build system
4620  } else {
4621  ROOT::TMetaUtils::Info(0, "XML file successfully parsed\n");
4622  }
4623  file.close();
4624  } else {
4625  ROOT::TMetaUtils::Error(0, "XML file %s couldn't be opened!\n", linkdefFilename.c_str());
4626  }
4627 
4628  } else if (ROOT::TMetaUtils::IsLinkdefFile(linkdefFilename.c_str())) {
4629 
4630  std::ifstream file(linkdefFilename.c_str());
4631  if (file.is_open()) {
4632  ROOT::TMetaUtils::Info(0, "Using linkdef file: %s\n", linkdefFilename.c_str());
4633  file.close();
4634  } else {
4635  ROOT::TMetaUtils::Error(0, "Linkdef file %s couldn't be opened!\n", linkdefFilename.c_str());
4636  }
4637 
4639 
4640  LinkdefReader ldefr(interp, constructorTypes);
4641  clingArgs.push_back("-Ietc/cling/cint"); // For multiset and multimap
4642 
4643  if (!ldefr.Parse(selectionRules, interpPragmaSource, clingArgs,
4644  llvmResourceDir.c_str())) {
4645  ROOT::TMetaUtils::Error(0, "Parsing Linkdef file %s\n", linkdefFilename.c_str());
4646  rootclingRetCode += 1;
4647  } else {
4648  ROOT::TMetaUtils::Info(0, "Linkdef file successfully parsed.\n");
4649  }
4650 
4651  if (! ldefr.LoadIncludes(extraIncludes)) {
4652  ROOT::TMetaUtils::Error(0, "Error loading the #pragma extra_include.\n");
4653  return 1;
4654  }
4655 
4656  } else {
4657 
4658  ROOT::TMetaUtils::Error(0, "Unrecognized selection file: %s\n", linkdefFilename.c_str());
4659 
4660  }
4661 
4662  // Speed up the operations with rules
4663  selectionRules.FillCache();
4664  selectionRules.Optimize();
4665 
4666  if (isGenreflex){
4667  if (0 != selectionRules.CheckDuplicates()){
4668  return 1;
4669  }
4670  }
4671 
4672  // If we want to validate the selection only, we just quit.
4674  return 0;
4675 
4676  //---------------------------------------------------------------------------
4677  // Write schema evolution related headers and declarations
4678  /////////////////////////////////////////////////////////////////////////////
4679 
4680  if (!ROOT::gReadRules.empty() || !ROOT::gReadRawRules.empty()) {
4681  dictStream << "#include \"TBuffer.h\"\n"
4682  << "#include \"TVirtualObject.h\"\n"
4683  << "#include <vector>\n"
4684  << "#include \"TSchemaHelper.h\"\n\n";
4685 
4686  std::list<std::string> includes;
4687  GetRuleIncludes(includes);
4688  for (auto & incFile : includes) {
4689  dictStream << "#include <" << incFile << ">" << std::endl;
4690  }
4691  dictStream << std::endl;
4692  }
4693 
4694  selectionRules.SearchNames(interp);
4695 
4696  int scannerVerbLevel = 0;
4697  {
4698  using namespace ROOT::TMetaUtils;
4699  scannerVerbLevel = GetErrorIgnoreLevel() == kInfo; // 1 if true, 0 if false
4700  if (isGenreflex){
4701  scannerVerbLevel = GetErrorIgnoreLevel() < kWarning;
4702  }
4703  }
4704 
4705  // Select the type of scan
4706  auto scanType = RScanner::EScanType::kNormal;
4707  if (gOptGeneratePCH)
4708  scanType = RScanner::EScanType::kOnePCM;
4709  if (dictSelection)
4711 
4712  RScanner scan(selectionRules,
4713  scanType,
4714  interp,
4715  normCtxt,
4716  scannerVerbLevel);
4717 
4718  // If needed initialize the autoloading hook
4719  if (!gOptLibListPrefix.empty()) {
4722  }
4723 
4724  scan.Scan(CI->getASTContext());
4725 
4726  bool has_input_error = false;
4727 
4728  if (genreflex::verbose)
4729  selectionRules.PrintSelectionRules();
4730 
4731  if (ROOT::TMetaUtils::GetErrorIgnoreLevel() != ROOT::TMetaUtils::kFatal &&
4732  !gOptGeneratePCH &&
4733  !dictSelRulesPresent &&
4734  !selectionRules.AreAllSelectionRulesUsed()) {
4735  ROOT::TMetaUtils::Warning(0, "Not all selection rules are used!\n");
4736  }
4737 
4738  if (!gOptGeneratePCH){
4739  rootclingRetCode += CheckForUnsupportedClasses(scan.fSelectedClasses);
4740  if (rootclingRetCode) return rootclingRetCode;
4741  }
4742 
4743  // SELECTION LOOP
4744  // Check for error in the class layout before doing anything else.
4745  for (auto const & annRcd : scan.fSelectedClasses) {
4746  if (ROOT::TMetaUtils::ClassInfo__HasMethod(annRcd, "Streamer", interp)) {
4747  if (annRcd.RequestNoInputOperator()) {
4748  int version = ROOT::TMetaUtils::GetClassVersion(annRcd, interp);
4749  if (version != 0) {
4750  // Only Check for input operator is the object is I/O has
4751  // been requested.
4752  has_input_error |= CheckInputOperator(annRcd, interp);
4753  }
4754  }
4755  }
4756  has_input_error |= !CheckClassDef(*annRcd, interp);
4757  }
4758 
4759  if (has_input_error) {
4760  // Be a little bit makefile friendly and remove the dictionary in case of error.
4761  // We could add an option -k to keep the file even in case of error.
4762  exit(1);
4763  }
4764 
4765  //---------------------------------------------------------------------------
4766  // Write all the necessary #include
4767  /////////////////////////////////////////////////////////////////////////////
4769  for (auto &&includedFromLinkdef : filesIncludedByLinkdef) {
4770  includeForSource += "#include \"" + includedFromLinkdef + "\"\n";
4771  }
4772  }
4773 
4774  if (!gOptGeneratePCH) {
4775  GenerateNecessaryIncludes(dictStream, includeForSource, extraIncludes);
4776  if (gOptSplit) {
4777  GenerateNecessaryIncludes(splitDictStream, includeForSource, extraIncludes);
4778  }
4780  gDriverConfig->fInitializeStreamerInfoROOTFile(modGen.GetModuleFileName().c_str());
4781  }
4782 
4783  // The order of addition to the list of constructor type
4784  // is significant. The list is sorted by with the highest
4785  // priority first.
4786  if (!gOptInterpreterOnly) {
4787  constructorTypes.push_back(ROOT::TMetaUtils::RConstructorType("TRootIOCtor", interp));
4788  constructorTypes.push_back(ROOT::TMetaUtils::RConstructorType("__void__", interp)); // ROOT-7723
4789  constructorTypes.push_back(ROOT::TMetaUtils::RConstructorType("", interp));
4790  }
4791  }
4792 
4793  if (gOptGeneratePCH) {
4794  AnnotateAllDeclsForPCH(interp, scan);
4795  } else if (gOptInterpreterOnly) {
4796  rootclingRetCode += CheckClassesForInterpreterOnlyDicts(interp, scan);
4797  // generate an empty pcm nevertheless for consistency
4798  // Negate as true is 1 and true is returned in case of success.
4800  rootclingRetCode += FinalizeStreamerInfoWriting(interp);
4801  }
4802  } else {
4803  rootclingRetCode += GenerateFullDict(splitDictStream,
4804  interp,
4805  scan,
4806  constructorTypes,
4807  gOptSplit,
4808  isGenreflex,
4810  }
4811 
4812  if (rootclingRetCode != 0) {
4813  return rootclingRetCode;
4814  }
4815 
4816  if (gOptSplit && splitDictStreamPtr) delete splitDictStreamPtr;
4817 
4818  // Now we have done all our looping and thus all the possible
4819  // annotation, let's write the pcms.
4820  HeadersDeclsMap_t headersClassesMap;
4821  HeadersDeclsMap_t headersDeclsMap;
4822  if (!gOptIgnoreExistingDict) {
4823  const std::string fwdDeclnArgsToKeepString(GetFwdDeclnArgsToKeepString(normCtxt, interp));
4824 
4826  scan.fSelectedTypedefs,
4827  scan.fSelectedFunctions,
4828  scan.fSelectedVariables,
4829  scan.fSelectedEnums,
4830  headersClassesMap,
4831  headersDeclsMap,
4832  interp);
4833 
4834  std::string detectedUmbrella;
4835  for (auto & arg : pcmArgs) {
4836  if (gOptInlineInput && !ROOT::TMetaUtils::IsLinkdefFile(arg.c_str()) && ROOT::TMetaUtils::IsHeaderName(arg)) {
4837  detectedUmbrella = arg;
4838  break;
4839  }
4840  }
4841 
4842  if (gOptWriteEmptyRootPCM){
4843  headersDeclsMap.clear();
4844  }
4845 
4846 
4847  std::string headersClassesMapString = "\"\"";
4848  std::string fwdDeclsString = "\"\"";
4849  if (!gOptCxxModule) {
4850  headersClassesMapString = GenerateStringFromHeadersForClasses(headersDeclsMap,
4851  detectedUmbrella,
4852  true);
4854  if (!gOptWriteEmptyRootPCM)
4855  fwdDeclsString = GenerateFwdDeclString(scan, interp);
4856  }
4857  }
4858  modGen.WriteRegistrationSource(dictStream, fwdDeclnArgsToKeepString, headersClassesMapString, fwdDeclsString,
4859  extraIncludes, gOptCxxModule);
4860  // If we just want to inline the input header, we don't need
4861  // to generate any files.
4862  if (!gOptInlineInput) {
4863  // Write the module/PCH depending on what mode we are on
4864  if (modGen.IsPCH()) {
4865  if (!GenerateAllDict(modGen, CI, currentDirectory)) return 1;
4866  } else if (gOptCxxModule) {
4867  if (!CheckModuleValid(modGen, llvmResourceDir, interp, linkdefFilename, moduleName.str()))
4868  return 1;
4869  }
4870  }
4871  }
4872 
4873 
4874  if (!gOptLibListPrefix.empty()) {
4875  string liblist_filename = gOptLibListPrefix + ".out";
4876 
4877  ofstream outputfile(liblist_filename.c_str(), ios::out);
4878  if (!outputfile) {
4879  ROOT::TMetaUtils::Error(0, "%s: Unable to open output lib file %s\n",
4880  executableFileName, liblist_filename.c_str());
4881  } else {
4882  const size_t endStr = gLibsNeeded.find_last_not_of(" \t");
4883  outputfile << gLibsNeeded.substr(0, endStr + 1) << endl;
4884  // Add explicit delimiter
4885  outputfile << "# Now the list of classes\n";
4886  // SELECTION LOOP
4887  for (auto const & annRcd : scan.fSelectedClasses) {
4888  // Shouldn't it be GetLong64_Name( cl_input.GetNormalizedName() )
4889  // or maybe we should be normalizing to turn directly all long long into Long64_t
4890  outputfile << annRcd.GetNormalizedName() << endl;
4891  }
4892  }
4893  }
4894 
4895  // Check for errors in module generation
4896  rootclingRetCode += modGen.GetErrorCount();
4897  if (0 != rootclingRetCode) return rootclingRetCode;
4898 
4899  // Create the rootmap file
4900  std::string rootmapLibName = std::accumulate(gOptRootmapLibNames.begin(),
4901  gOptRootmapLibNames.end(),
4902  std::string(),
4903  [](const std::string & a, const std::string & b) -> std::string {
4904  if (a.empty()) return b;
4905  else return a + " " + b;
4906  });
4907 
4908  bool rootMapNeeded = !gOptRootMapFileName.empty() || !rootmapLibName.empty();
4909 
4910  std::list<std::string> classesNames;
4911  std::list<std::string> classesNamesForRootmap;
4912  std::list<std::string> classesDefsList;
4913 
4914  rootclingRetCode = ExtractClassesListAndDeclLines(scan,
4915  classesNames,
4916  classesNamesForRootmap,
4917  classesDefsList,
4918  interp);
4919 
4920  std::list<std::string> enumNames;
4921  rootclingRetCode += ExtractAutoloadKeys(enumNames,
4922  scan.fSelectedEnums,
4923  interp);
4924 
4925  std::list<std::string> varNames;
4926  rootclingRetCode += ExtractAutoloadKeys(varNames,
4927  scan.fSelectedVariables,
4928  interp);
4929 
4930  if (0 != rootclingRetCode) return rootclingRetCode;
4931 
4932  // Create the rootmapfile if needed
4933  if (rootMapNeeded) {
4934 
4935  std::list<std::string> nsNames;
4936 
4937  ExtractSelectedNamespaces(scan, nsNames);
4938 
4940  rootmapLibName);
4941 
4942  ROOT::TMetaUtils::Info(0, "Rootmap file name %s and lib name(s) \"%s\"\n",
4943  gOptRootMapFileName.c_str(),
4944  rootmapLibName.c_str());
4945 
4946  tmpCatalog.addFileName(gOptRootMapFileName);
4947  std::unordered_set<std::string> headersToIgnore;
4948  if (gOptInlineInput)
4949  for (const std::string& optHeaderFileName : gOptDictionaryHeaderFiles)
4950  headersToIgnore.insert(optHeaderFileName.c_str());
4951 
4952  std::list<std::string> typedefsRootmapLines;
4953  rootclingRetCode += ExtractAutoloadKeys(typedefsRootmapLines,
4954  scan.fSelectedTypedefs,
4955  interp);
4956 
4957  rootclingRetCode = CreateNewRootMapFile(gOptRootMapFileName,
4958  rootmapLibName,
4959  classesDefsList,
4960  classesNamesForRootmap,
4961  nsNames,
4962  typedefsRootmapLines,
4963  enumNames,
4964  varNames,
4965  headersClassesMap,
4966  headersToIgnore);
4967 
4968  if (0 != rootclingRetCode) return 1;
4969  }
4970 
4971  if (genreflex::verbose)
4972  tmpCatalog.dump();
4973 
4974  // Manually call end of translation unit because we never call the
4975  // appropriate deconstructors in the interpreter. This writes out the C++
4976  // module file that we currently generate.
4977  {
4978  cling::Interpreter::PushTransactionRAII RAII(&interp);
4979  CI->getSema().getASTConsumer().HandleTranslationUnit(CI->getSema().getASTContext());
4980  CI->clearOutputFiles(CI->getDiagnostics().hasErrorOccurred());
4981  }
4982 
4983  // Add the warnings
4984  rootclingRetCode += ROOT::TMetaUtils::GetNumberOfErrors();
4985 
4986  // make sure the file is closed before committing
4987  fileout.close();
4988 
4989  // Before returning, rename the files if no errors occurred
4990  // otherwise clean them to avoid remnants (see ROOT-10015)
4991  if(rootclingRetCode == 0) {
4992  rootclingRetCode += tmpCatalog.commit();
4993  } else {
4994  tmpCatalog.clean();
4995  }
4996 
4997  return rootclingRetCode;
4998 
4999 }
5000 
5001 namespace genreflex {
5002 
5003 ////////////////////////////////////////////////////////////////////////////////
5004 /// Loop on arguments: stop at the first which starts with -
5005 
5006  unsigned int checkHeadersNames(std::vector<std::string> &headersNames)
5007  {
5008  unsigned int numberOfHeaders = 0;
5009  for (std::vector<std::string>::iterator it = headersNames.begin();
5010  it != headersNames.end(); ++it) {
5011  const std::string headername(*it);
5012  if (ROOT::TMetaUtils::IsHeaderName(headername)) {
5013  numberOfHeaders++;
5014  } else {
5016  "*** genreflex: %s is not a valid header name (.h and .hpp extensions expected)!\n",
5017  headername.c_str());
5018  }
5019  }
5020  return numberOfHeaders;
5021  }
5022 
5023 ////////////////////////////////////////////////////////////////////////////////
5024 /// Extract the arguments from the command line
5025 
5026  unsigned int extractArgs(int argc, char **argv, std::vector<std::string> &args)
5027  {
5028  // loop on argv, spot strings which are not preceded by something
5029  unsigned int argvCounter = 0;
5030  for (int i = 1; i < argc; ++i) {
5031  if (!ROOT::TMetaUtils::BeginsWith(argv[i - 1], "-") && // so, if preceding element starts with -, this is a value for an option
5032  !ROOT::TMetaUtils::BeginsWith(argv[i], "-")) { // and the element itself is not an option
5033  args.push_back(argv[i]);
5034  argvCounter++;
5035  } else if (argvCounter) {
5036  argv[i - argvCounter] = argv[i];
5037  }
5038  }
5039 
5040  // Some debug
5041  if (genreflex::verbose) {
5042  int i = 0;
5043  std::cout << "Args: \n";
5044  for (std::vector<std::string>::iterator it = args.begin();
5045  it < args.end(); ++it) {
5046  std::cout << i << ") " << *it << std::endl;
5047  ++i;
5048  }
5049 
5050  }
5051 
5052  return argvCounter;
5053  }
5054 
5055 ////////////////////////////////////////////////////////////////////////////////
5056 
5057  void changeExtension(std::string &filename, const std::string &newExtension)
5058  {
5059  size_t result = filename.find_last_of('.');
5060  if (std::string::npos != result) {
5061  filename.erase(result);
5062  filename.append(newExtension);
5063  }
5064 
5065  }
5066 
5067 ////////////////////////////////////////////////////////////////////////////////
5068 /// The caller is responsible for deleting the string!
5069 
5070  char *string2charptr(const std::string &str)
5071  {
5072  const unsigned int size(str.size());
5073  char *a = new char[size + 1];
5074  a[size] = 0;
5075  memcpy(a, str.c_str(), size);
5076  return a;
5077  }
5078 
5079 ////////////////////////////////////////////////////////////////////////////////
5080 /// Replace the extension with "_rflx.cpp"
5081 
5082  void header2outputName(std::string &fileName)
5083  {
5084  changeExtension(fileName, "_rflx.cpp");
5085  }
5086 
5087 ////////////////////////////////////////////////////////////////////////////////
5088 /// Get a proper name for the output file
5089 
5090  void headers2outputsNames(const std::vector<std::string> &headersNames,
5091  std::vector<std::string> &ofilesnames)
5092  {
5093  ofilesnames.reserve(headersNames.size());
5094 
5095  for (std::vector<std::string>::const_iterator it = headersNames.begin();
5096  it != headersNames.end(); ++it) {
5097  std::string ofilename(*it);
5098  header2outputName(ofilename);
5099  ofilesnames.push_back(ofilename);
5100  }
5101  }
5102 
5103 ////////////////////////////////////////////////////////////////////////////////
5104 
5105  void AddToArgVector(std::vector<char *> &argvVector,
5106  const std::vector<std::string> &argsToBeAdded,
5107  const std::string &optName = "")
5108  {
5109  for (std::vector<std::string>::const_iterator it = argsToBeAdded.begin();
5110  it != argsToBeAdded.end(); ++it) {
5111  argvVector.push_back(string2charptr(optName + *it));
5112  }
5113  }
5114 
5115 ////////////////////////////////////////////////////////////////////////////////
5116 
5117  void AddToArgVectorSplit(std::vector<char *> &argvVector,
5118  const std::vector<std::string> &argsToBeAdded,
5119  const std::string &optName = "")
5120  {
5121  for (std::vector<std::string>::const_iterator it = argsToBeAdded.begin();
5122  it != argsToBeAdded.end(); ++it) {
5123  if (optName.length()) {
5124  argvVector.push_back(string2charptr(optName));
5125  }
5126  argvVector.push_back(string2charptr(*it));
5127  }
5128  }
5129 
5130 ////////////////////////////////////////////////////////////////////////////////
5131 
5132  int invokeRootCling(const std::string &verbosity,
5133  const std::string &selectionFileName,
5134  const std::string &targetLibName,
5135  bool multiDict,
5136  const std::vector<std::string> &pcmsNames,
5137  const std::vector<std::string> &includes,
5138  const std::vector<std::string> &preprocDefines,
5139  const std::vector<std::string> &preprocUndefines,
5140  const std::vector<std::string> &warnings,
5141  const std::string &rootmapFileName,
5142  const std::string &rootmapLibName,
5143  bool interpreteronly,
5144  bool doSplit,
5145  bool isCxxmodule,
5146  bool writeEmptyRootPCM,
5147  bool selSyntaxOnly,
5148  bool noIncludePaths,
5149  const std::vector<std::string> &headersNames,
5150  bool failOnWarnings,
5151  const std::string &ofilename)
5152  {
5153  // Prepare and invoke the commandline to invoke rootcling
5154 
5155  std::vector<char *> argvVector;
5156 
5157  argvVector.push_back(string2charptr("rootcling"));
5158  argvVector.push_back(string2charptr(verbosity));
5159  argvVector.push_back(string2charptr("-f"));
5160  argvVector.push_back(string2charptr(ofilename));
5161 
5162  if (isCxxmodule)
5163  argvVector.push_back(string2charptr("-cxxmodule"));
5164 
5165  // Extract the path to the dictionary
5166  std::string dictLocation;
5167  ExtractFilePath(ofilename, dictLocation);
5168 
5169  // Rootmaps
5170 
5171  // Prepare the correct rootmap libname if not already set.
5172  std::string newRootmapLibName(rootmapLibName);
5173  if (!rootmapFileName.empty() && newRootmapLibName.empty()) {
5174  if (headersNames.size() != 1) {
5176  "*** genreflex: No rootmap lib and several header specified!\n");
5177  }
5178  std::string cleanHeaderName = ExtractFileName(headersNames[0]);
5179  newRootmapLibName = "lib";
5180  newRootmapLibName += cleanHeaderName;
5181  changeExtension(newRootmapLibName, gLibraryExtension);
5182  }
5183 
5184  // Prepend to the rootmap the designed directory of the dictionary
5185  // if no path is specified for the rootmap itself
5186  std::string newRootmapFileName(rootmapFileName);
5187  if (!newRootmapFileName.empty() && !HasPath(newRootmapFileName)) {
5188  newRootmapFileName = dictLocation + newRootmapFileName;
5189  }
5190 
5191 
5192  // RootMap filename
5193  if (!newRootmapFileName.empty()) {
5194  argvVector.push_back(string2charptr("-rmf"));
5195  argvVector.push_back(string2charptr(newRootmapFileName));
5196  }
5197 
5198  // RootMap Lib filename
5199  if (!newRootmapLibName.empty()) {
5200  argvVector.push_back(string2charptr("-rml"));
5201  argvVector.push_back(string2charptr(newRootmapLibName));
5202  }
5203 
5204  // Interpreter only dictionaries
5205  if (interpreteronly)
5206  argvVector.push_back(string2charptr("-interpreteronly"));
5207 
5208  // Split dictionaries
5209  if (doSplit)
5210  argvVector.push_back(string2charptr("-split"));
5211 
5212  // Targetlib
5213  if (!targetLibName.empty()) {
5214  argvVector.push_back(string2charptr("-s"));
5215  argvVector.push_back(string2charptr(targetLibName));
5216  }
5217 
5218  // Multidict support
5219  if (multiDict)
5220  argvVector.push_back(string2charptr("-multiDict"));
5221 
5222 
5223  AddToArgVectorSplit(argvVector, pcmsNames, "-m");
5224 
5225  // Inline the input header
5226  argvVector.push_back(string2charptr("-inlineInputHeader"));
5227 
5228  // Write empty root pcms
5229  if (writeEmptyRootPCM)
5230  argvVector.push_back(string2charptr("-writeEmptyRootPCM"));
5231 
5232  // Just test the syntax of the selection file
5233  if (selSyntaxOnly)
5234  argvVector.push_back(string2charptr("-selSyntaxOnly"));
5235 
5236  // No include paths
5237  if (noIncludePaths)
5238  argvVector.push_back(string2charptr("-noIncludePaths"));
5239 
5240  // Fail on warnings
5241  if (failOnWarnings)
5242  argvVector.push_back(string2charptr("-failOnWarnings"));
5243 
5244  // Clingargs
5245  AddToArgVector(argvVector, includes, "-I");
5246  AddToArgVector(argvVector, preprocDefines, "-D");
5247  AddToArgVector(argvVector, preprocUndefines, "-U");
5248  AddToArgVector(argvVector, warnings, "-W");
5249 
5250  AddToArgVector(argvVector, headersNames);
5251 
5252  if (!selectionFileName.empty()) {
5253  argvVector.push_back(string2charptr(selectionFileName));
5254  }
5255 
5256  const int argc = argvVector.size();
5257 
5258  // Output commandline for rootcling
5259  if (genreflex::verbose) {
5260  std::cout << "Rootcling commandline:\n";
5261  for (int i = 0; i < argc; i++)
5262  std::cout << i << ") " << argvVector[i] << std::endl;
5263  }
5264 
5265  char **argv = & (argvVector[0]);
5266  int rootclingReturnCode = RootClingMain(argc,
5267  argv,
5268  /*isGenReflex=*/true);
5269 
5270  for (int i = 0; i < argc; i++)
5271  delete [] argvVector[i];
5272 
5273  return rootclingReturnCode;
5274 
5275  }
5276 
5277 ////////////////////////////////////////////////////////////////////////////////
5278 /// Get the right ofilenames and invoke several times rootcling
5279 /// One invokation per header
5280 
5281  int invokeManyRootCling(const std::string &verbosity,
5282  const std::string &selectionFileName,
5283  const std::string &targetLibName,
5284  bool multiDict,
5285  const std::vector<std::string> &pcmsNames,
5286  const std::vector<std::string> &includes,
5287  const std::vector<std::string> &preprocDefines,
5288  const std::vector<std::string> &preprocUndefines,
5289  const std::vector<std::string> &warnings,
5290  const std::string &rootmapFileName,
5291  const std::string &rootmapLibName,
5292  bool interpreteronly,
5293  bool doSplit,
5294  bool isCxxmodule,
5295  bool writeEmptyRootPCM,
5296  bool selSyntaxOnly,
5297  bool noIncludePaths,
5298  const std::vector<std::string> &headersNames,
5299  bool failOnWarnings,
5300  const std::string &outputDirName_const = "")
5301  {
5302  std::string outputDirName(outputDirName_const);
5303 
5304  std::vector<std::string> ofilesNames;
5305  headers2outputsNames(headersNames, ofilesNames);
5306 
5307  if (!outputDirName.empty() && !ROOT::TMetaUtils::EndsWith(outputDirName, gPathSeparator)) {
5308  outputDirName += gPathSeparator;
5309  }
5310 
5311  std::vector<std::string> namesSingleton(1);
5312  for (unsigned int i = 0; i < headersNames.size(); ++i) {
5313  namesSingleton[0] = headersNames[i];
5314  std::string ofilenameFullPath(ofilesNames[i]);
5315  if (llvm::sys::path::parent_path(ofilenameFullPath) == "")
5316  ofilenameFullPath = outputDirName + ofilenameFullPath;
5317  int returnCode = invokeRootCling(verbosity,
5318  selectionFileName,
5319  targetLibName,
5320  multiDict,
5321  pcmsNames,
5322  includes,
5323  preprocDefines,
5324  preprocUndefines,
5325  warnings,
5326  rootmapFileName,
5327  rootmapLibName,
5328  interpreteronly,
5329  doSplit,
5330  isCxxmodule,
5331  writeEmptyRootPCM,
5332  selSyntaxOnly,
5333  noIncludePaths,
5334  namesSingleton,
5335  failOnWarnings,
5336  ofilenameFullPath);
5337  if (returnCode != 0)
5338  return returnCode;
5339  }
5340 
5341  return 0;
5342  }
5343 
5344 
5345 } // end genreflex namespace
5346 
5347 ////////////////////////////////////////////////////////////////////////////////
5348 /// Extract from options multiple values with the same option
5349 
5350 int extractMultipleOptions(std::vector<ROOT::option::Option> &options,
5351  int oIndex,
5352  std::vector<std::string> &values)
5353 {
5354  int nValues = 0;
5355  if (options[oIndex]) {
5356  const int nVals = options[oIndex].count();
5357  values.reserve(nVals);
5358  int optionIndex = 0;
5359  for (ROOT::option::Option *opt = options[oIndex]; opt; opt = opt->next()) {
5360  if (genreflex::verbose) std::cout << "Extracting multiple args: "
5361  << optionIndex << "/" << nVals << " "
5362  << opt->arg << std::endl;
5363  optionIndex++;
5364  values.push_back(opt->arg);
5365  nValues++;
5366  }
5367  }
5368  return nValues;
5369 }
5370 
5371 ////////////////////////////////////////////////////////////////////////////////
5372 
5373 void RiseWarningIfPresent(std::vector<ROOT::option::Option> &options,
5374  int optionIndex,
5375  const char *descriptor)
5376 {
5377  if (options[optionIndex]) {
5379  "*** genereflex: %s is not supported anymore.\n",
5380  descriptor);
5381  }
5382 }
5383 
5384 ////////////////////////////////////////////////////////////////////////////////
5385 
5386 bool IsGoodLibraryName(const std::string &name)
5387 {
5388 
5389 
5390  auto isGood = ROOT::TMetaUtils::EndsWith(name, gLibraryExtension);
5391 #ifdef __APPLE__
5392  isGood |= ROOT::TMetaUtils::EndsWith(name, ".dylib");
5393 #endif
5394  return isGood;
5395 }
5396 
5397 ////////////////////////////////////////////////////////////////////////////////
5398 /// Translate the arguments of genreflex into rootcling ones and forward them
5399 /// to the RootCling function.
5400 /// These are two typical genreflex and rootcling commandlines
5401 /// 1) genreflex header1.h [header2.h ...] [options] [preprocessor options]
5402 /// 2) rootcling [-v] [-v0-4] [-f] [out.cxx] [-s sharedlib.so] [-m pcmfilename]
5403 /// header1.h[{+,-}][!] ..headerN.h[{+,-}][!] [{LinkDef.h,selectionRules.xml}]
5404 /// The rules with which the arguments are translated are (1st column genreflex):
5405 /// --debug -v4
5406 /// --quiet -v0
5407 /// -o ofile positional arg after -f
5408 /// -s selection file Last argument of the call
5409 /// --fail_on_warning Wrap ROOT::TMetaUtils::Warning and throw if selected
5410 ///
5411 /// New arguments:
5412 /// -l --library targetLib name (new) -s targetLib name
5413 /// -m pcmname (can be many -m) (new) -m pcmname (can be many -m)
5414 /// --rootmap -rmf (new)
5415 /// --rootmap-lib -rml (new)
5416 ///
5417 /// genreflex options which rise warnings (feedback is desirable)
5418 /// --no_membertypedefs (it should be irrelevant)
5419 /// --no_templatetypedefs (it should be irrelevant)
5420 ///
5421 /// genreflex options which are ignored (know for sure they are not needed)
5422 /// --pool, --dataonly
5423 /// --interpreteronly
5424 /// --gccxml{path,opt,post}
5425 ///
5426 ///
5427 /// Exceptions
5428 /// The --deep option of genreflex is passed as function parameter to rootcling
5429 /// since it's not needed at the moment there.
5430 
5431 int GenReflexMain(int argc, char **argv)
5432 {
5433  using namespace genreflex;
5434 
5435  // Setup the options parser
5436  enum optionIndex { UNKNOWN,
5437  OFILENAME,
5438  TARGETLIB,
5439  MULTIDICT,
5440  SELECTIONFILENAME,
5441  ROOTMAP,
5442  ROOTMAPLIB,
5443  PCMFILENAME,
5444  DEEP,
5445  DEBUG,
5446  VERBOSE,
5447  QUIET,
5448  SILENT,
5449  CXXMODULE,
5450  WRITEEMPTYROOTPCM,
5451  HELP,
5452  FAILONWARNINGS,
5453  SELSYNTAXONLY,
5454  INTERPRETERONLY,
5455  SPLIT,
5456  NOMEMBERTYPEDEFS,
5457  NOTEMPLATETYPEDEFS,
5458  NOINCLUDEPATHS,
5459  // Don't show up in the help
5460  PREPROCDEFINE,
5461  PREPROCUNDEFINE,
5462  INCLUDE,
5463  WARNING
5464  };
5465 
5466  enum optionTypes { NOTYPE, STRING } ;
5467 
5468  // Some long help strings
5469  const char *genreflexUsage =
5470  "Generates dictionary sources and related ROOT pcm starting from an header.\n"
5471  "Usage: genreflex headerfile.h [opts] [preproc. opts]\n\n"
5472  "Options:\n";
5473 
5474  const char *selectionFilenameUsage =
5475  "-s, --selection_file\tSelection filename\n"
5476  " Class selection file to specify for which classes the dictionary\n"
5477  " will be generated. The final set can be crafted with exclusion and\n"
5478  " exclusion rules.\n"
5479  " Properties can be specified. Some have special meaning:\n"
5480  " - name [string] name of the entity to select with an exact matching\n"
5481  " - pattern [string] name with wildcards (*) to select entities\n"
5482  " - file_name/file_pattern [string]: as name/pattern but referring to\n"
5483  " file where the C++ entities reside and not to C++ entities themselves.\n"
5484  " - transient/persistent [string: true/false] The fields to which they are\n"
5485  " applied will not be persistified if requested.\n"
5486  " - comment [string]: what you could write in code after an inline comment\n"
5487  " without \"//\". For example comment=\"!\" or \"||\".\n"
5488  " - noStreamer [true/false]: turns off streamer generation if set to 'true.'\n"
5489  " Default value is 'false'\n"
5490  " - noInputOperator [true/false]: turns off input operator generation if set\n"
5491  " to 'true'. Default value is 'false'\n"
5492  " Example XML:\n"
5493  " <lcgdict>\n"
5494  " [<selection>]\n"
5495  " <class [name=\"classname\"] [pattern=\"wildname\"]\n"
5496  " [file_name=\"filename\"] [file_pattern=\"wildname\"]\n"
5497  " [id=\"xxxx\"] [noStreamer=\"true/false\"]\n"
5498  " [noInputOperator=\"true/false\"] />\n"
5499  " <class name=\"classname\" >\n"
5500  " <field name=\"m_transient\" transient=\"true\"/>\n"
5501  " <field name=\"m_anothertransient\" persistent=\"false\"/>\n"
5502  " <field name=\"m_anothertransient\" comment=\"||\"/>\n"
5503  " <properties prop1=\"value1\" [prop2=\"value2\"]/>\n"
5504  " </class>\n"
5505  " <function [name=\"funcname\"] [pattern=\"wildname\"] />\n"
5506  " <enum [name=\"enumname\"] [pattern=\"wildname\"] />\n"
5507  " <variable [name=\"varname\"] [pattern=\"wildname\"] />\n"
5508  " [</selection>]\n"
5509  " <exclusion>\n"
5510  " <class [name=\"classname\"] [pattern=\"wildname\"] />\n"
5511  " <method name=\"unwanted\" />\n"
5512  " </class>\n"
5513  " ...\n"
5514  " </lcgdict>\n"
5515  "\n"
5516  " If no selection file is specified, the class with the filename without\n"
5517  " extension will be selected, i.e. myClass.h as argument without any\n"
5518  " selection xml comes with an implicit selection rule for class \"myClass\".\n";
5519 
5520  const char *outputFilenameUsage =
5521  "-o, --output\tOutput filename\n"
5522  " Output file name. If an existing directory is specified instead of a file,\n"
5523  " then a filename will be build using the name of the input file and will\n"
5524  " be placed in the given directory. <headerfile>_rflx.cpp.\n"
5525  " NOTA BENE: the dictionaries that will be used within the same project must\n"
5526  " have unique names.\n";
5527 
5528 
5529  const char *targetLib =
5530  "-l, --library\tTarget library\n"
5531  " The flag -l must be followed by the name of the library that will\n"
5532  " contain the object file corresponding to the dictionary produced by\n"
5533  " this invocation of genreflex.\n"
5534  " The name takes priority over the one specified for the rootmapfile.\n"
5535  " The name influences the name of the created pcm:\n"
5536  " 1) If it is not specified, the pcm is called libINPUTHEADER_rdict.pcm\n"
5537  " 2) If it is specified, the pcm is called libTARGETLIBRARY_rdict.pcm\n"
5538  " Any \"liblib\" occurence is transformed in the expected \"lib\".\n"
5539  " 3) If this is specified in conjunction with --multiDict, the output is\n"
5540  " libTARGETLIBRARY_DICTIONARY_rdict.pcm\n";
5541 
5542  const char *rootmapUsage =
5543  "--rootmap\tGenerate the rootmap file to be used by ROOT.\n"
5544  " This file lists the autoload keys. For example classes for which the\n"
5545  " reflection information is provided.\n"
5546  " The format of the rootmap is the following:\n"
5547  " - Forward declarations section\n"
5548  " - Libraries sections\n"
5549  " Rootmaps can be concatenated together, for example with the cat util.\n"
5550  " In order for ROOT to pick up the information in the rootmaps, they\n"
5551  " have to be located in the library path and have the .rootmap extension.\n"
5552  " An example rootmap file could be:\n"
5553  " { decls }\n"
5554  " template <class T> class A;\n"
5555  " [ libMyLib.so ]\n"
5556  " class A<double>\n"
5557  " class B\n"
5558  " typedef C\n"
5559  " header H.h\n";
5560 
5561  const char *rootmapLibUsage =
5562  "--rootmap-lib\tLibrary name for the rootmap file.\n";
5563 
5564  // The Descriptor
5565  const ROOT::option::Descriptor genreflexUsageDescriptor[] = {
5566  {
5567  UNKNOWN,
5568  NOTYPE,
5569  "", "",
5571  genreflexUsage
5572  },
5573 
5574  {
5575  OFILENAME,
5576  STRING ,
5577  "o" , "output" ,
5579  outputFilenameUsage
5580  },
5581 
5582  {
5583  TARGETLIB,
5584  STRING ,
5585  "l" , "library" ,
5587  targetLib
5588  },
5589 
5590  {
5591  MULTIDICT,
5592  NOTYPE ,
5593  "" , "multiDict" ,
5595  "--multiDict\tSupport for many dictionaries in one library\n"
5596  " Form correct pcm names if multiple dictionaries will be in the same\n"
5597  " library (needs target library switch. See its documentation).\n"
5598  },
5599 
5600  {
5601  SELECTIONFILENAME,
5602  STRING ,
5603  "s" , "selection_file" ,
5605  selectionFilenameUsage
5606  },
5607 
5608  {
5609  ROOTMAP,
5610  STRING ,
5611  "" , "rootmap" ,
5613  rootmapUsage
5614  },
5615 
5616  {
5617  ROOTMAPLIB,
5618  STRING ,
5619  "" , "rootmap-lib" ,
5621  rootmapLibUsage
5622  },
5623 
5624  {
5625  INTERPRETERONLY,
5626  NOTYPE,
5627  "" , "interpreteronly",
5629  "--interpreteronly\tDo not generate I/O related information.\n"
5630  " Generate minimal dictionary required for interactivity.\n"
5631  },
5632 
5633  {
5634  SPLIT,
5635  NOTYPE,
5636  "" , "split",
5638  "--split\tSplit the dictionary\n"
5639  " Split in two the dictionary, isolating the part with\n"
5640  " ClassDef related functions in a separate file.\n"
5641  },
5642 
5643  {
5644  PCMFILENAME,
5645  STRING ,
5646  "m" , "" ,
5648  "-m \tPcm file loaded before any header (option can be repeated).\n"
5649  },
5650 
5651  {
5652 #if ROOT_VERSION_CODE >= ROOT_VERSION(6,20,00)
5653 # error "Remove this deprecated code"
5654 #endif
5655  DEEP, // Not active. Will be removed for 6.2
5656  NOTYPE ,
5657  "" , "deep",
5659  ""
5660  },
5661  //"--deep\tGenerate dictionaries for all dependent classes (ignored).\n"
5662 
5663  {
5664  VERBOSE,
5665  NOTYPE ,
5666  "-v" , "verbose",
5668  "-v, --verbose\tPrint some debug information.\n"
5669  },
5670 
5671  {
5672  DEBUG,
5673  NOTYPE ,
5674  "" , "debug",
5676  "--debug\tPrint all debug information.\n"
5677  },
5678 
5679  {
5680  QUIET,
5681  NOTYPE ,
5682  "" , "quiet",
5684  "--quiet\tPrint only warnings and errors (default).\n"
5685  },
5686 
5687  {
5688  SILENT,
5689  NOTYPE ,
5690  "" , "silent",
5692  "--silent\tPrint no information at all.\n"
5693  },
5694 
5695  {
5696  WRITEEMPTYROOTPCM,
5697  NOTYPE ,
5698  "" , "writeEmptyPCM",
5700  "--writeEmptyPCM\tWrite an empty ROOT pcm.\n"
5701  },
5702 
5703  {
5704  CXXMODULE,
5705  NOTYPE ,
5706  "" , "cxxmodule",
5708  "--cxxmodule\tGenerates a PCM for C++ Modules.\n"
5709  },
5710 
5711 
5712  {
5713  HELP,
5714  NOTYPE,
5715  "h" , "help",
5717  "--help\tPrint usage and exit.\n"
5718  },
5719 
5720  {
5721  FAILONWARNINGS,
5722  NOTYPE,
5723  "", "fail_on_warnings",
5725  "--fail_on_warnings\tFail on warnings and errors.\n"
5726  },
5727 
5728  {
5729  SELSYNTAXONLY,
5730  NOTYPE,
5731  "", "selSyntaxOnly",
5733  "--selSyntaxOnly\tValidate selection file w/o generating the dictionary.\n"
5734  },
5735 
5736  {
5737  NOINCLUDEPATHS,
5738  NOTYPE ,
5739  "" , "noIncludePaths",
5741  "--noIncludePaths\tDo not store the headers' directories in the dictionary. Instead, rely on the environment variable $ROOT_INCLUDE_PATH at runtime.\n"
5742  },
5743 
5744  // Left intentionally empty not to be shown in the help, like in the first genreflex
5745  {
5746  INCLUDE,
5747  STRING ,
5748  "I" , "" ,
5750  ""
5751  },
5752 
5753  {
5754  PREPROCDEFINE,
5755  STRING ,
5756  "D" , "" ,
5758  ""
5759  },
5760 
5761  {
5762  PREPROCUNDEFINE,
5763  STRING ,
5764  "U" , "" ,
5766  ""
5767  },
5768 
5769  {
5770  WARNING,
5771  STRING ,
5772  "W" , "" ,
5774  ""
5775  },
5776 
5777  {
5778  NOMEMBERTYPEDEFS, // Option which is not meant for the user: deprecated
5779  STRING ,
5780  "" , "no_membertypedefs" ,
5782  ""
5783  },
5784 
5785  {
5786  NOTEMPLATETYPEDEFS, // Option which is not meant for the user: deprecated
5787  STRING ,
5788  "" , "no_templatetypedefs" ,
5790  ""
5791  },
5792 
5793  {0, 0, 0, 0, 0, 0}
5794  };
5795 
5796  std::vector<std::string> headersNames;
5797  const int originalArgc = argc;
5798  // The only args are the headers here
5799  const int extractedArgs = extractArgs(argc, argv, headersNames);
5800 
5801  const int offset = 1; // skip argv[0]
5802  argc -= offset + extractedArgs;
5803  argv += offset;
5804 
5805  // Parse the options
5806  ROOT::option::Stats stats(genreflexUsageDescriptor, argc, argv);
5807  std::vector<ROOT::option::Option> options(stats.options_max);// non POD var size arrays are not C++!
5808  std::vector<ROOT::option::Option> buffer(stats.buffer_max);
5809  // The 4 is the minimum size of the abbreviation length.
5810  // For example, --selection_file can be abbreviated with --sele at least.
5811 
5812  ROOT::option::Parser parse(genreflexUsageDescriptor, argc, argv, &options[0], &buffer[0], 5);
5813 
5814  if (parse.error()) {
5815  ROOT::TMetaUtils::Error(0, "Argument parsing error!\n");
5816  return 1;
5817  }
5818 
5819  // Print help if needed
5820  if (options[HELP] || originalArgc == 1) {
5821  ROOT::option::printUsage(std::cout, genreflexUsageDescriptor);
5822  return 0;
5823  }
5824  // See if no header was provided
5825  int numberOfHeaders = checkHeadersNames(headersNames);
5826  if (0 == numberOfHeaders) {
5827  ROOT::TMetaUtils::Error(0, "No valid header was provided!\n");
5828  return 1;
5829  }
5830 
5831  ROOT::TMetaUtils::GetErrorIgnoreLevel() = ROOT::TMetaUtils::kNote;
5832 
5833  if (options[DEEP])
5834  ROOT::TMetaUtils::Warning(0, "--deep has no effect. Please remove the deprecated flag!\n");
5835  // The verbosity: debug wins over quiet
5836  //std::string verbosityOption("-v4"); // To be uncommented for the testing phase. It should be -v
5837  std::string verbosityOption("-v2");
5838  if (options[SILENT]) verbosityOption = "-v0";
5839  if (options[VERBOSE] || getenv ("VERBOSE")) verbosityOption = "-v3";
5840  if (options[DEBUG]) verbosityOption = "-v4";
5841 
5842  genreflex::verbose = verbosityOption == "-v4";
5843 
5844  // The selection file
5845  std::string selectionFileName;
5846  if (options[SELECTIONFILENAME]) {
5847  selectionFileName = options[SELECTIONFILENAME].arg;
5848  if (!ROOT::TMetaUtils::EndsWith(selectionFileName, ".xml")) {
5850  "Invalid selection file extension: filename is %s and extension .xml is expected!\n",
5851  selectionFileName.c_str());
5852  return 1;
5853  }
5854  }
5855 
5856 // // Warn if a selection file is not present and exit
5857 // if (NULL==options[SELECTIONFILENAME].arg){
5858 // ROOT::TMetaUtils::Warning(0,"The usage of genreflex without a selection file is not yet supported.\n");
5859 // return 1;
5860 // }
5861 
5862 
5863  // Set the parameters for the rootmap file. If the libname is not set,
5864  // it will be set according to the header in invokeRootCling.
5865  // FIXME: treatment of directories
5866  std::string rootmapFileName(options[ROOTMAP].arg ? options[ROOTMAP].arg : "");
5867  std::string rootmapLibName(options[ROOTMAPLIB].arg ? options[ROOTMAPLIB].arg : "");
5868 
5869  // The target lib name
5870  std::string targetLibName;
5871  if (options[TARGETLIB]) {
5872  targetLibName = options[TARGETLIB].arg;
5873  if (!IsGoodLibraryName(targetLibName)) {
5875  "Invalid target library extension: filename is %s and extension %s is expected!\n",
5876  targetLibName.c_str(),
5877  gLibraryExtension.c_str());
5878  }
5879  // Target lib has precedence over rootmap lib
5880  if (options[ROOTMAP]) {
5881  rootmapLibName = ExtractFileName(options[TARGETLIB].arg);
5882  }
5883  }
5884 
5885  bool isCxxmodule = options[CXXMODULE];
5886 
5887  bool multidict = false;
5888  if (options[MULTIDICT]) multidict = true;
5889 
5890  if (multidict && targetLibName.empty()) {
5892  "Multilib support is requested but no target lib is specified. A sane pcm name cannot be formed.\n");
5893  return 1;
5894  }
5895 
5896  bool interpreteronly = false;
5897  if (options[INTERPRETERONLY])
5898  interpreteronly = true;
5899 
5900  bool doSplit = false;
5901  if (options[SPLIT])
5902  doSplit = true;
5903 
5904  bool writeEmptyRootPCM = false;
5905  if (options[WRITEEMPTYROOTPCM])
5906  writeEmptyRootPCM = true;
5907 
5908  bool selSyntaxOnly = false;
5909  if (options[SELSYNTAXONLY]) {
5910  selSyntaxOnly = true;
5911  }
5912 
5913  bool noIncludePaths = false;
5914  if (options[NOINCLUDEPATHS]) {
5915  noIncludePaths = true;
5916  }
5917 
5918  bool failOnWarnings = false;
5919  if (options[FAILONWARNINGS]) {
5920  failOnWarnings = true;
5921  }
5922 
5923  // Add the .so extension to the rootmap lib if not there
5924  if (!rootmapLibName.empty() && !IsGoodLibraryName(rootmapLibName)) {
5925  rootmapLibName += gLibraryExtension;
5926  }
5927 
5928  // The list of pcms to be preloaded
5929  std::vector<std::string> pcmsNames;
5930  extractMultipleOptions(options, PCMFILENAME, pcmsNames);
5931 
5932  // Preprocessor defines
5933  std::vector<std::string> preprocDefines;
5934  extractMultipleOptions(options, PREPROCDEFINE, preprocDefines);
5935 
5936  // Preprocessor undefines
5937  std::vector<std::string> preprocUndefines;
5938  extractMultipleOptions(options, PREPROCUNDEFINE, preprocUndefines);
5939 
5940  // Includes
5941  std::vector<std::string> includes;
5942  extractMultipleOptions(options, INCLUDE, includes);
5943 
5944  // Warnings
5945  std::vector<std::string> warnings;
5946  extractMultipleOptions(options, WARNING, warnings);
5947 
5948  // The outputfilename(s)
5949  // There are two cases:
5950  // 1) The outputfilename is specified
5951  // --> The information of all headers will be in one single dictionary
5952  // (1 call to rootcling)
5953  // 2) The outputfilename is not specified
5954  // --> There will be a dictionary per header
5955  // (N calls to rootcling)
5956  int returnValue = 0;
5957  std::string ofileName(options[OFILENAME] ? options[OFILENAME].arg : "");
5958 
5959  // If not empty and not a directory (therefore it's a file)
5960  // call rootcling directly. The number of headers files is irrelevant.
5961  if (!ofileName.empty() && !llvm::sys::fs::is_directory(ofileName)) {
5962  returnValue = invokeRootCling(verbosityOption,
5963  selectionFileName,
5964  targetLibName,
5965  multidict,
5966  pcmsNames,
5967  includes,
5968  preprocDefines,
5969  preprocUndefines,
5970  warnings,
5971  rootmapFileName,
5972  rootmapLibName,
5973  interpreteronly,
5974  doSplit,
5975  isCxxmodule,
5976  writeEmptyRootPCM,
5977  selSyntaxOnly,
5978  noIncludePaths,
5979  headersNames,
5980  failOnWarnings,
5981  ofileName);
5982  } else {
5983  // Here ofilename is either "" or a directory: this is irrelevant.
5984  returnValue = invokeManyRootCling(verbosityOption,
5985  selectionFileName,
5986  targetLibName,
5987  multidict,
5988  pcmsNames,
5989  includes,
5990  preprocDefines,
5991  preprocUndefines,
5992  warnings,
5993  rootmapFileName,
5994  rootmapLibName,
5995  interpreteronly,
5996  doSplit,
5997  isCxxmodule,
5998  writeEmptyRootPCM,
5999  selSyntaxOnly,
6000  noIncludePaths,
6001  headersNames,
6002  failOnWarnings,
6003  ofileName);
6004  }
6005 
6006  return returnValue;
6007 }
6008 
6009 
6010 ////////////////////////////////////////////////////////////////////////////////
6011 
6012 extern "C"
6013 int ROOT_rootcling_Driver(int argc, char **argv, const ROOT::Internal::RootCling::DriverConfig& config)
6014 {
6015 
6016  assert(!gDriverConfig && "Driver configuration already set!");
6017  gDriverConfig = &config;
6018 
6019  gBuildingROOT = config.fBuildingROOTStage1; // gets refined later
6020 
6021  std::string exeName = ExtractFileName(GetExePath());
6022 
6023  // Select according to the name of the executable the procedure to follow:
6024  // 1) RootCling
6025  // 2) GenReflex
6026  // The default is rootcling
6027 
6028  int retVal = 0;
6029 
6030  if (std::string::npos != exeName.find("genreflex"))
6031  retVal = GenReflexMain(argc, argv);
6032  else // rootcling or default
6033  retVal = RootClingMain(argc, argv);
6034 
6035  gDriverConfig = nullptr;
6036 
6037  if (ROOT::TMetaUtils::GetNumberOfErrors()){
6038  ROOT::TMetaUtils::Info(0,"Problems have been detected during the generation of the dictionary.\n");
6039  return 1;
6040  }
6041  return retVal;
6042 }
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
std::map< const clang::Decl *, const BaseSelectionRule * > DeclsSelRulesMap_t
Definition: Scanner.h:74
static bool IncludeHeaders(const std::vector< std::string > &headers, cling::Interpreter &interpreter)
Includes all given headers in the interpreter.
int GenerateFullDict(std::ostream &dictStream, cling::Interpreter &interp, RScanner &scan, const ROOT::TMetaUtils::RConstructorTypes &ctorTypes, bool isSplit, bool isGenreflex, bool writeEmptyRootPCM)
static llvm::cl::list< std::string > gOptIncludePaths("I", llvm::cl::Prefix, llvm::cl::ZeroOrMore, llvm::cl::desc("Specify an include path."), llvm::cl::cat(gRootclingOptions))
static bool InjectModuleUtilHeader(const char *argv0, TModuleGenerator &modGen, cling::Interpreter &interp, bool umbrella)
Write the extra header injected into the module: umbrella header if (umbrella) else content header...
NamespaceColl_t fSelectedNamespaces
Definition: Scanner.h:125
ESTLType
Definition: ESTLType.h:28
const std::string & GetIncludeDir()
\ returns the include directory in the installation.
static llvm::cl::list< std::string > gOptWDiags("W", llvm::cl::Prefix, llvm::cl::ZeroOrMore, llvm::cl::desc("Specify compiler diagnostics options."), llvm::cl::cat(gRootclingOptions))
static llvm::cl::opt< bool > gOptMultiDict("multiDict", llvm::cl::desc("If this library has multiple separate LinkDef files."), llvm::cl::cat(gRootclingOptions))
void WriteArrayDimensions(const clang::QualType &type, std::ostream &dictStream)
Write "[0]" for all but the 1st dimension.
auto * m
Definition: textangle.C:8
VSD Structures.
Definition: StringConv.hxx:21
void WriteContentHeader(std::ostream &out) const
Write a header file describing the content of this module through a series of variables inside the na...</