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