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