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