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