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