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