Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
rootcling_impl.cxx
Go to the documentation of this file.
1// Authors: Axel Naumann, Philippe Canal, Danilo Piparo
2
3/*************************************************************************
4 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
5 * All rights reserved. *
6 * *
7 * For the licensing terms see $ROOTSYS/LICENSE. *
8 * For the list of contributors see $ROOTSYS/README/CREDITS. *
9 *************************************************************************/
10
11#include "rootcling_impl.h"
12#include "rootclingCommandLineOptionsHelp.h"
13
14#include "RConfigure.h"
15#include <ROOT/RConfig.hxx>
17#include "snprintf.h"
18
19#include <iostream>
20#include <iomanip>
21#include <memory>
22#include <vector>
23#include <algorithm>
24#include <cstdio>
25
26#include <errno.h>
27#include <string>
28#include <list>
29#include <sstream>
30#include <map>
31#include <fstream>
32#include <sys/stat.h>
33#include <unordered_map>
34#include <unordered_set>
35#include <numeric>
36
37
38#ifdef _WIN32
39#ifdef system
40#undef system
41#endif
42#undef UNICODE
43#include <windows.h>
44#include <Tlhelp32.h> // for MAX_MODULE_NAME32
45#include <process.h>
46#define PATH_MAX _MAX_PATH
47#ifdef interface
48// prevent error coming from clang/AST/Attrs.inc
49#undef interface
50#endif
51#endif
52
53#ifdef __APPLE__
54#include <mach-o/dyld.h>
55#endif
56
57#ifdef R__FBSD
58#include <sys/param.h>
59#include <sys/user.h>
60#include <sys/types.h>
61#include <libutil.h>
62#include <libprocstat.h>
63#endif // R__FBSD
64
65#if !defined(R__WIN32)
66#include <limits.h>
67#include <unistd.h>
68#endif
69
70
71#include "cling/Interpreter/Interpreter.h"
72#include "cling/Interpreter/InterpreterCallbacks.h"
73#include "cling/Interpreter/LookupHelper.h"
74#include "cling/Interpreter/Value.h"
75#include "clang/AST/CXXInheritance.h"
76#include "clang/Basic/Diagnostic.h"
77#include "clang/Frontend/CompilerInstance.h"
78#include "clang/Frontend/FrontendActions.h"
79#include "clang/Frontend/FrontendDiagnostic.h"
80#include "clang/Lex/HeaderSearch.h"
81#include "clang/Lex/Preprocessor.h"
82#include "clang/Lex/ModuleMap.h"
83#include "clang/Lex/Pragma.h"
84#include "clang/Sema/Sema.h"
85#include "clang/Serialization/ASTWriter.h"
86#include "cling/Utils/AST.h"
87
88#include "llvm/ADT/StringRef.h"
89
90#include "llvm/Support/CommandLine.h"
91#include "llvm/Support/Path.h"
92#include "llvm/Support/PrettyStackTrace.h"
93#include "llvm/Support/Signals.h"
94
95#include "RtypesCore.h"
96#include "TModuleGenerator.h"
97#include "TClassEdit.h"
98#include "TClingUtils.h"
99#include "RStl.h"
100#include "XMLReader.h"
101#include "LinkdefReader.h"
102#include "DictSelectionReader.h"
103#include "SelectionRules.h"
104#include "Scanner.h"
105#include "strlcpy.h"
106
107#include "OptionParser.h"
108
109#ifdef WIN32
110const std::string gLibraryExtension(".dll");
111#else
112const std::string gLibraryExtension(".so"); // no dylib for the moment
113#endif
115
116#ifdef __APPLE__
117#include <mach-o/dyld.h>
118#endif
119
120#if defined(R__WIN32)
121#include "cygpath.h"
122#define strcasecmp _stricmp
123#define strncasecmp _strnicmp
124#else
125#include <unistd.h>
126#endif
127
128bool gBuildingROOT = false;
130
131#define rootclingStringify(s) rootclingStringifyx(s)
132#define rootclingStringifyx(s) #s
133
134// Maybe too ugly? let's see how it performs.
135using HeadersDeclsMap_t = std::map<std::string, std::list<std::string>>;
136
137using namespace ROOT;
138
139using std::string, std::map, std::ifstream, std::ofstream, std::endl, std::ios, std::vector;
140
141namespace genreflex {
142 bool verbose = false;
143}
144
145////////////////////////////////////////////////////////////////////////////////
146
147static llvm::cl::OptionCategory gRootclingOptions("rootcling common options");
148
149 // FIXME: We should remove after removal of r flag.
150static llvm::cl::opt<bool>
152 llvm::cl::desc("Deprecated. Similar to -f but it ignores the dictionary generation. \
153When -r is present rootcling becomes a tool to generate rootmaps (and capability files)."),
154 llvm::cl::Hidden,
155 llvm::cl::cat(gRootclingOptions));
156
157////////////////////////////////////////////////////////////////////////////////
158
159void SetRootSys();
160
162 // rootcling's libCore needs "our" ROOTSYS:
163 SetRootSys();
164};
165
166////////////////////////////////////////////////////////////////////////////////
167
168void EmitStreamerInfo(const char *normName)
169{
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 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 void clear() override
3649 {
3650 fChild->clear();
3651 DiagnosticConsumer::clear();
3652 }
3653
3654 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 void EndSourceFile() override
3661 {
3662 fChild->EndSourceFile();
3663 DiagnosticConsumer::EndSourceFile();
3664 }
3665
3666 void finish() override
3667 {
3668 fChild->finish();
3669 DiagnosticConsumer::finish();
3670 }
3671
3672 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*/ nullptr, CurDir,
3911 clang::ArrayRef<std::pair<clang::OptionalFileEntryRef, clang::DirectoryEntryRef>>(),
3912 /*SearchPath*/ nullptr,
3913 /*RelativePath*/ nullptr,
3914 /*RequestingModule*/ nullptr, &SuggestedModule,
3915 /*IsMapped*/ nullptr,
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 const char *etcDir = gDriverConfig->fTROOT__GetEtcDir();
4077 std::string llvmResourceDir = etcDir ? std::string(etcDir) + "/cling" : "";
4078
4080 std::vector<const char *> clingArgsC;
4081 clingArgsC.push_back(executableFileName);
4082 // Help cling finds its runtime (RuntimeUniverse.h and such).
4083 if (etcDir) {
4084 clingArgsC.push_back("-I");
4085 clingArgsC.push_back(etcDir);
4086 }
4087
4088 //clingArgsC.push_back("-resource-dir");
4089 //clingArgsC.push_back(llvmResourceDir.c_str());
4090
4091 for (const std::string& Opt : gOptBareClingSink)
4092 clingArgsC.push_back(Opt.c_str());
4093
4094 auto interp = std::make_unique<cling::Interpreter>(clingArgsC.size(),
4095 &clingArgsC[0],
4096 llvmResourceDir.c_str());
4097 // FIXME: Diagnose when we have misspelled a flag. Currently we show no
4098 // diagnostic and report exit as success.
4099 return interp->getDiagnostics().hasFatalErrorOccurred();
4100 }
4101
4102 std::string dictname;
4103
4104 if (!gDriverConfig->fBuildingROOTStage1) {
4105 if (gOptRootBuild) {
4106 // running rootcling as part of the ROOT build for ROOT libraries.
4107 gBuildingROOT = true;
4108 }
4109 }
4110
4111 if (!gOptModuleMapFiles.empty() && !gOptCxxModule) {
4112 ROOT::TMetaUtils::Error("", "Option %s can be used only when option %s is specified.\n",
4113 gOptModuleMapFiles.ArgStr.str().c_str(),
4114 gOptCxxModule.ArgStr.str().c_str());
4115 std::cout << "\n";
4116 llvm::cl::PrintHelpMessage();
4117 return 1;
4118 }
4119
4120 // Set the default verbosity
4122 if (gOptVerboseLevel == v4)
4123 genreflex::verbose = true;
4124
4125 if (gOptReflex)
4126 isGenreflex = true;
4127
4128 if (!gOptLibListPrefix.empty()) {
4129 string filein = gOptLibListPrefix + ".in";
4130 FILE *fp;
4131 if ((fp = fopen(filein.c_str(), "r")) == nullptr) {
4132 ROOT::TMetaUtils::Error(nullptr, "%s: The input list file %s does not exist\n", executableFileName, filein.c_str());
4133 return 1;
4134 }
4135 fclose(fp);
4136 }
4137
4139 FILE *fp;
4140 if (!gOptIgnoreExistingDict && (fp = fopen(gOptDictionaryFileName.c_str(), "r")) != nullptr) {
4141 fclose(fp);
4142 if (!gOptForce) {
4143 ROOT::TMetaUtils::Error(nullptr, "%s: output file %s already exists\n", executableFileName, gOptDictionaryFileName.c_str());
4144 return 1;
4145 }
4146 }
4147
4148 // remove possible pathname to get the dictionary name
4149 if (gOptDictionaryFileName.size() > (PATH_MAX - 1)) {
4150 ROOT::TMetaUtils::Error(nullptr, "rootcling: dictionary name too long (more than %d characters): %s\n",
4151 (PATH_MAX - 1), gOptDictionaryFileName.c_str());
4152 return 1;
4153 }
4154
4155 dictname = llvm::sys::path::filename(gOptDictionaryFileName).str();
4156 }
4157
4158 if (gOptForce && dictname.empty()) {
4159 ROOT::TMetaUtils::Error(nullptr, "Inconsistent set of arguments detected: overwrite of dictionary file forced but no filename specified.\n");
4160 llvm::cl::PrintHelpMessage();
4161 return 1;
4162 }
4163
4164 std::vector<std::string> clingArgs;
4165 clingArgs.push_back(executableFileName);
4166 clingArgs.push_back("-iquote.");
4167
4169
4170 // Collect the diagnostic pragmas linked to the usage of -W
4171 // Workaround for ROOT-5656
4172 std::list<std::string> diagnosticPragmas = {"#pragma clang diagnostic ignored \"-Wdeprecated-declarations\""};
4173
4174 if (gOptFailOnWarnings) {
4175 using namespace ROOT::TMetaUtils;
4176 // If warnings are disabled with the current verbosity settings, lower
4177 // it so that the user sees the warning that caused the failure.
4178 if (GetErrorIgnoreLevel() > kWarning)
4179 GetErrorIgnoreLevel() = kWarning;
4180 GetWarningsAreErrors() = true;
4181 }
4182
4183 if (gOptISysRoot != "-") {
4184 if (gOptISysRoot.empty()) {
4185 ROOT::TMetaUtils::Error("", "isysroot specified without a value.\n");
4186 return 1;
4187 }
4188 clingArgs.push_back(gOptISysRoot.ArgStr.str());
4189 clingArgs.push_back(gOptISysRoot.ValueStr.str());
4190 }
4191
4192 // Check if we have a multi dict request but no target library
4193 if (gOptMultiDict && gOptSharedLibFileName.empty()) {
4194 ROOT::TMetaUtils::Error("", "Multidict requested but no target library. Please specify one with the -s argument.\n");
4195 return 1;
4196 }
4197
4198 for (const std::string &PPDefine : gOptPPDefines)
4199 clingArgs.push_back(std::string("-D") + PPDefine);
4200
4201 for (const std::string &PPUndefine : gOptPPUndefines)
4202 clingArgs.push_back(std::string("-U") + PPUndefine);
4203
4204 for (const std::string &IncludePath : gOptIncludePaths)
4205 clingArgs.push_back(std::string("-I") + llvm::sys::path::convert_to_slash(IncludePath));
4206
4207 for (const std::string &IncludePath : gOptSysIncludePaths) {
4208 // Prevent mentioning compiler default include directories as -isystem
4209 // (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70129)
4212 clingArgs.push_back("-isystem");
4213 clingArgs.push_back(llvm::sys::path::convert_to_slash(IncludePath));
4214 }
4215 }
4216
4217 for (const std::string &WDiag : gOptWDiags) {
4218 const std::string FullWDiag = std::string("-W") + WDiag;
4219 // Suppress warning when compiling the dictionary, eg. gcc G__xxx.cxx
4221 // Suppress warning when compiling the input headers by cling.
4222 clingArgs.push_back(FullWDiag);
4223 }
4224
4225 const char *includeDir = gDriverConfig->fTROOT__GetIncludeDir();
4226 if (includeDir) {
4227 clingArgs.push_back(std::string("-I") + llvm::sys::path::convert_to_slash(includeDir));
4228 }
4229
4230 std::vector<std::string> pcmArgs;
4231 for (size_t parg = 0, n = clingArgs.size(); parg < n; ++parg) {
4232 auto thisArg = clingArgs[parg];
4234 if (thisArg == "-c" ||
4235 (gOptNoIncludePaths && isInclude)) continue;
4236 // We now check if the include directories are not excluded
4237 if (isInclude) {
4238 unsigned int offset = 2; // -I is two characters. Now account for spaces
4239 char c = thisArg[offset];
4240 while (c == ' ') c = thisArg[++offset];
4242 auto excludePathPos = std::find_if(gOptExcludePaths.begin(),
4244 [&](const std::string& path){
4245 return ROOT::TMetaUtils::BeginsWith(&thisArg[offset], path);});
4246 if (excludePathsEnd != excludePathPos) continue;
4247 }
4248 pcmArgs.push_back(thisArg);
4249 }
4250
4251 // cling-only arguments
4252 if (etcDir)
4253 clingArgs.push_back(std::string("-I") + llvm::sys::path::convert_to_slash(etcDir));
4254
4255 // We do not want __ROOTCLING__ in the pch!
4256 if (!gOptGeneratePCH) {
4257 clingArgs.push_back("-D__ROOTCLING__");
4258 }
4259#ifdef R__MACOSX
4260 clingArgs.push_back("-DSYSTEM_TYPE_macosx");
4261#elif defined(R__WIN32)
4262 clingArgs.push_back("-DSYSTEM_TYPE_winnt");
4263
4264 // Prevent the following #error: The C++ Standard Library forbids macroizing keywords.
4265 clingArgs.push_back("-D_XKEYCHECK_H");
4266 // Tell windows.h not to #define min and max, it clashes with numerical_limits.
4267 clingArgs.push_back("-DNOMINMAX");
4268#else // assume UNIX
4269 clingArgs.push_back("-DSYSTEM_TYPE_unix");
4270#endif
4271
4272 clingArgs.push_back("-fsyntax-only");
4273#ifndef R__WIN32
4274 clingArgs.push_back("-fPIC");
4275#endif
4276 clingArgs.push_back("-Xclang");
4277 clingArgs.push_back("-fmodules-embed-all-files");
4278 clingArgs.push_back("-Xclang");
4279 clingArgs.push_back("-main-file-name");
4280 clingArgs.push_back("-Xclang");
4281 clingArgs.push_back((dictname + ".h").c_str());
4282
4284
4285 // FIXME: This line is from TModuleGenerator, but we can't reuse this code
4286 // at this point because TModuleGenerator needs a CompilerInstance (and we
4287 // currently create the arguments for creating said CompilerInstance).
4288 bool isPCH = (gOptDictionaryFileName.getValue() == "allDict.cxx");
4289 std::string outputFile;
4290 // Data is in 'outputFile', therefore in the same scope.
4291 llvm::StringRef moduleName;
4292 std::string vfsArg;
4293 // Adding -fmodules to the args will break lexing with __CINT__ defined,
4294 // and we actually do lex with __CINT__ and reuse this variable later,
4295 // we have to copy it now.
4297
4298 if (gOptSharedLibFileName.empty()) {
4300 }
4301
4302 if (!isPCH && gOptCxxModule) {
4303 // We just pass -fmodules, the CIFactory will do the rest and configure
4304 // clang correctly once it sees this flag.
4305 clingArgsInterpreter.push_back("-fmodules");
4306 clingArgsInterpreter.push_back("-fno-implicit-module-maps");
4307
4308 for (const std::string &modulemap : gOptModuleMapFiles)
4309 clingArgsInterpreter.push_back("-fmodule-map-file=" + modulemap);
4310
4311 if (includeDir) {
4312 clingArgsInterpreter.push_back("-fmodule-map-file=" + std::string(includeDir) + "/ROOT.modulemap");
4313 }
4314 std::string ModuleMapCWD = ROOT::FoundationUtils::GetCurrentDir() + "/module.modulemap";
4315 if (llvm::sys::fs::exists(ModuleMapCWD))
4316 clingArgsInterpreter.push_back("-fmodule-map-file=" + ModuleMapCWD);
4317
4318 // Specify the module name that we can lookup the module in the modulemap.
4319 outputFile = llvm::sys::path::stem(gOptSharedLibFileName).str();
4320 // Try to get the module name in the modulemap based on the filepath.
4322
4323#ifdef _MSC_VER
4324 clingArgsInterpreter.push_back("-Xclang");
4325 clingArgsInterpreter.push_back("-fmodule-feature");
4326 clingArgsInterpreter.push_back("-Xclang");
4327 clingArgsInterpreter.push_back("msvc" + std::string(rootclingStringify(_MSC_VER)));
4328#endif
4329 clingArgsInterpreter.push_back("-fmodule-name=" + moduleName.str());
4330
4331 std::string moduleCachePath = llvm::sys::path::parent_path(gOptSharedLibFileName).str();
4332 // FIXME: This is a horrible workaround to fix the incremental builds.
4333 // The enumerated modules are built by clang impicitly based on #include of
4334 // a header which is contained within that module. The build system has
4335 // no way to track dependencies on them and trigger a rebuild.
4336 // A possible solution can be to disable completely the implicit build of
4337 // modules and each module to be built by rootcling. We need to teach
4338 // rootcling how to build modules with no IO support.
4339 if (moduleName == "Core") {
4340 assert(gDriverConfig->fBuildingROOTStage1);
4341 remove((moduleCachePath + llvm::sys::path::get_separator() + "_Builtin_intrinsics.pcm").str().c_str());
4342 remove((moduleCachePath + llvm::sys::path::get_separator() + "_Builtin_stddef_max_align_t.pcm").str().c_str());
4343 remove((moduleCachePath + llvm::sys::path::get_separator() + "Cling_Runtime.pcm").str().c_str());
4344 remove((moduleCachePath + llvm::sys::path::get_separator() + "Cling_Runtime_Extra.pcm").str().c_str());
4345#ifdef R__WIN32
4346 remove((moduleCachePath + llvm::sys::path::get_separator() + "vcruntime.pcm").str().c_str());
4347 remove((moduleCachePath + llvm::sys::path::get_separator() + "services.pcm").str().c_str());
4348#endif
4349
4350#ifdef R__MACOSX
4351 remove((moduleCachePath + llvm::sys::path::get_separator() + "Darwin.pcm").str().c_str());
4352#else
4353 remove((moduleCachePath + llvm::sys::path::get_separator() + "libc.pcm").str().c_str());
4354#endif
4355 remove((moduleCachePath + llvm::sys::path::get_separator() + "std.pcm").str().c_str());
4356 remove((moduleCachePath + llvm::sys::path::get_separator() + "boost.pcm").str().c_str());
4357 remove((moduleCachePath + llvm::sys::path::get_separator() + "tinyxml2.pcm").str().c_str());
4358 remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Config.pcm").str().c_str());
4359 remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Rtypes.pcm").str().c_str());
4360 remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Foundation_C.pcm").str().c_str());
4361 remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Foundation_Stage1_NoRTTI.pcm").str().c_str());
4362 } else if (moduleName == "MathCore") {
4363 remove((moduleCachePath + llvm::sys::path::get_separator() + "Vc.pcm").str().c_str());
4364 }
4365
4366 // Set the C++ modules output directory to the directory where we generate
4367 // the shared library.
4368 clingArgsInterpreter.push_back("-fmodules-cache-path=" + moduleCachePath);
4369 }
4370
4371 if (gOptVerboseLevel == v4)
4372 clingArgsInterpreter.push_back("-v");
4373
4374 // Convert arguments to a C array and check if they are sane
4375 std::vector<const char *> clingArgsC;
4376 for (auto const &clingArg : clingArgsInterpreter) {
4378 std::cerr << "Argument \""<< clingArg << "\" is not a supported cling argument. "
4379 << "This could be mistyped rootcling argument. Please check the commandline.\n";
4380 return 1;
4381 }
4382 clingArgsC.push_back(clingArg.c_str());
4383 }
4384
4385
4386 std::unique_ptr<cling::Interpreter> owningInterpPtr;
4387 cling::Interpreter* interpPtr = nullptr;
4388
4389 std::list<std::string> filesIncludedByLinkdef;
4390 if (gDriverConfig->fBuildingROOTStage1) {
4391#ifdef R__FAST_MATH
4392 // Same setting as in TCling.cxx.
4393 clingArgsC.push_back("-ffast-math");
4394#endif
4395
4396 owningInterpPtr.reset(new cling::Interpreter(clingArgsC.size(), &clingArgsC[0],
4397 llvmResourceDir.c_str()));
4398 interpPtr = owningInterpPtr.get();
4399 } else {
4400 // Pass the interpreter arguments to TCling's interpreter:
4401 clingArgsC.push_back("-resource-dir");
4402 clingArgsC.push_back(llvmResourceDir.c_str());
4403 clingArgsC.push_back(nullptr); // signal end of array
4404 const char ** &extraArgs = *gDriverConfig->fTROOT__GetExtraInterpreterArgs();
4405 extraArgs = &clingArgsC[1]; // skip binary name
4406 interpPtr = gDriverConfig->fTCling__GetInterpreter();
4407 if (!interpPtr->getCI()) // Compiler instance could not be created. See https://its.cern.ch/jira/browse/ROOT-10239
4408 return 1;
4409 if (!isGenreflex && !gOptGeneratePCH) {
4410 std::unique_ptr<TRootClingCallbacks> callBacks (new TRootClingCallbacks(interpPtr, filesIncludedByLinkdef));
4411 interpPtr->setCallbacks(std::move(callBacks));
4412 }
4413 }
4414 cling::Interpreter &interp = *interpPtr;
4415 clang::CompilerInstance *CI = interp.getCI();
4416 // FIXME: Remove this once we switch cling to use the driver. This would handle -fmodules-embed-all-files for us.
4417 CI->getFrontendOpts().ModulesEmbedAllFiles = true;
4418 CI->getSourceManager().setAllFilesAreTransient(true);
4419
4420 clang::Preprocessor &PP = CI->getPreprocessor();
4421 clang::HeaderSearch &headerSearch = PP.getHeaderSearchInfo();
4422 clang::ModuleMap &moduleMap = headerSearch.getModuleMap();
4423 auto &diags = interp.getDiagnostics();
4424
4425 // Manually enable the module build remarks. We don't enable them via the
4426 // normal clang command line arg because otherwise we would get remarks for
4427 // building STL/libc when starting the interpreter in rootcling_stage1.
4428 // We can't prevent these diags in any other way because we can only attach
4429 // our own diag client now after the interpreter has already started.
4430 diags.setSeverity(clang::diag::remark_module_build, clang::diag::Severity::Remark, clang::SourceLocation());
4431
4432 // Attach our own diag client that listens to the module_build remarks from
4433 // clang to check that we don't build dictionary C++ modules implicitly.
4434 auto recordingClient = new CheckModuleBuildClient(diags.getClient(), diags.ownsClient(), moduleMap);
4435 diags.setClient(recordingClient, true);
4436
4438 ROOT::TMetaUtils::Info(nullptr, "\n");
4439 ROOT::TMetaUtils::Info(nullptr, "==== INTERPRETER CONFIGURATION ====\n");
4440 ROOT::TMetaUtils::Info(nullptr, "== Include paths\n");
4441 interp.DumpIncludePath();
4442 printf("\n\n");
4443 fflush(stdout);
4444
4445 ROOT::TMetaUtils::Info(nullptr, "== Included files\n");
4446 interp.printIncludedFiles(llvm::outs());
4447 llvm::outs() << "\n\n";
4448 llvm::outs().flush();
4449
4450 ROOT::TMetaUtils::Info(nullptr, "== Language Options\n");
4451 const clang::LangOptions& LangOpts
4452 = interp.getCI()->getASTContext().getLangOpts();
4453#define LANGOPT(Name, Bits, Default, Description) \
4454 ROOT::TMetaUtils::Info(nullptr, "%s = %d // %s\n", #Name, (int)LangOpts.Name, Description);
4455#define ENUM_LANGOPT(Name, Type, Bits, Default, Description)
4456#include "clang/Basic/LangOptions.def"
4457 ROOT::TMetaUtils::Info(nullptr, "==== END interpreter configuration ====\n\n");
4458 }
4459
4460 interp.getOptions().ErrorOut = true;
4461 interp.enableRawInput(true);
4462
4463 if (gOptCxxModule) {
4464 for (llvm::StringRef DepMod : gOptModuleDependencies) {
4465 if (DepMod.ends_with("_rdict.pcm")) {
4466 ROOT::TMetaUtils::Warning(nullptr, "'%s' value is deprecated. Please use [<fullpath>]%s.pcm\n",
4467 DepMod.data(),
4469 }
4471 // We might deserialize.
4472 cling::Interpreter::PushTransactionRAII RAII(&interp);
4473 if (!interp.loadModule(DepMod.str(), /*complain*/false)) {
4474 ROOT::TMetaUtils::Error(nullptr, "Module '%s' failed to load.\n",
4475 DepMod.data());
4476 }
4477 }
4478 }
4479
4480 if (!isGenreflex) { // rootcling
4481 // ROOTCINT uses to define a few header implicitly, we need to do it explicitly.
4482 if (interp.declare("#include <assert.h>\n"
4483 "#include \"Rtypes.h\"\n"
4484 "#include \"TObject.h\"") != cling::Interpreter::kSuccess
4485 ) {
4486 // There was an error.
4487 ROOT::TMetaUtils::Error(nullptr, "Error loading the default rootcling header files.\n");
4488 return 1;
4489 }
4490 }
4491
4492 if (interp.declare("#include <string>\n" // For the list of 'opaque' typedef to also include string.
4493 "#include <RtypesCore.h>\n" // For initializing TNormalizedCtxt.
4494 "namespace std {} using namespace std;") != cling::Interpreter::kSuccess) {
4495 ROOT::TMetaUtils::Error(nullptr, "Error loading the default header files.\n");
4496 return 1;
4497 }
4498
4499 // We are now ready (enough is loaded) to init the list of opaque typedefs.
4501 ROOT::TMetaUtils::TClingLookupHelper helper(interp, normCtxt, nullptr, nullptr, nullptr);
4503
4504 // flags used only for the pragma parser:
4505 clingArgs.push_back("-D__CINT__");
4506 clingArgs.push_back("-D__MAKECINT__");
4507
4509
4511
4512 std::string interpPragmaSource;
4513 std::string includeForSource;
4514 std::string interpreterDeclarations;
4515 std::string linkdef;
4516
4517 for (size_t i = 0, e = gOptDictionaryHeaderFiles.size(); i < e; ++i) {
4518 const std::string& optHeaderFileName = gOptDictionaryHeaderFiles[i];
4520
4521 if (isSelectionFile) {
4522 if (i == e - 1) {
4524 } else { // if the linkdef was not last, issue an error.
4525 ROOT::TMetaUtils::Error(nullptr, "%s: %s must be last file on command line\n",
4527 return 1;
4528 }
4529 }
4530
4531 // coverity[tainted_data] The OS should already limit the argument size, so we are safe here
4532 std::string fullheader(optHeaderFileName);
4533 // Strip any trailing + which is only used by GeneratedLinkdef.h which currently
4534 // use directly argv.
4535 if (fullheader[fullheader.length() - 1] == '+') {
4536 fullheader.erase(fullheader.length() - 1);
4537 }
4538 std::string header(
4540
4541 interpPragmaSource += std::string("#include \"") + header + "\"\n";
4542 if (!isSelectionFile) {
4543 // In order to not have to add the equivalent to -I${PWD} to the
4544 // command line, include the complete file name, even if it is a
4545 // full pathname, when we write it down in the dictionary.
4546 // Note: have -I${PWD} means in that (at least in the case of
4547 // ACLiC) we inadvertently pick local file that have the same
4548 // name as system header (e.g. new or list) and -iquote has not
4549 // equivalent on some platforms.
4550 includeForSource += std::string("#include \"") + fullheader + "\"\n";
4551 pcmArgs.push_back(header);
4552 } else if (!IsSelectionXml(optHeaderFileName.c_str())) {
4553 interpreterDeclarations += std::string("#include \"") + header + "\"\n";
4554 }
4555 }
4556
4557 if (gOptUmbrellaInput) {
4558 bool hasSelectionFile = !linkdef.empty();
4561 ROOT::TMetaUtils::Error(nullptr, "Option %s used but more than one header file specified.\n",
4562 gOptUmbrellaInput.ArgStr.data());
4563 }
4564
4565 // We have a multiDict request. This implies generating a pcm which is of the form
4566 // dictName_libname_rdict.pcm
4567 if (gOptMultiDict) {
4568
4569 std::string newName = llvm::sys::path::parent_path(gOptSharedLibFileName).str();
4570 if (!newName.empty())
4572 newName += llvm::sys::path::stem(gOptSharedLibFileName);
4573 newName += "_";
4574 newName += llvm::sys::path::stem(gOptDictionaryFileName);
4575 newName += llvm::sys::path::extension(gOptSharedLibFileName);
4577 }
4578
4579 // Until the module are actually enabled in ROOT, we need to register
4580 // the 'current' directory to make it relocatable (i.e. have a way
4581 // to find the headers).
4583 string incCurDir = "-I";
4585 pcmArgs.push_back(incCurDir);
4586 }
4587
4588 // Add the diagnostic pragmas distilled from the -Wno-xyz
4589 {
4590 std::stringstream res;
4591 const char* delim="\n";
4592 std::copy(diagnosticPragmas.begin(),
4594 std::ostream_iterator<std::string>(res, delim));
4595 if (interp.declare(res.str()) != cling::Interpreter::kSuccess) {
4596 ROOT::TMetaUtils::Error(nullptr, "Failed to parse -Wno-xyz flags as pragmas:\n%s", res.str().c_str());
4597 return 1;
4598 }
4599 }
4600
4601 class IgnoringPragmaHandler: public clang::PragmaNamespace {
4602 public:
4603 IgnoringPragmaHandler(const char* pragma):
4604 clang::PragmaNamespace(pragma) {}
4605 void HandlePragma(clang::Preprocessor &PP,
4606 clang::PragmaIntroducer Introducer,
4607 clang::Token &tok) override {
4608 PP.DiscardUntilEndOfDirective();
4609 }
4610 };
4611
4612 // Ignore these #pragmas to suppress "unknown pragma" warnings.
4613 // See LinkdefReader.cxx.
4614 PP.AddPragmaHandler(new IgnoringPragmaHandler("link"));
4615 PP.AddPragmaHandler(new IgnoringPragmaHandler("extra_include"));
4616 PP.AddPragmaHandler(new IgnoringPragmaHandler("read"));
4617 PP.AddPragmaHandler(new IgnoringPragmaHandler("create"));
4618
4619 if (!interpreterDeclarations.empty() &&
4620 interp.declare(interpreterDeclarations) != cling::Interpreter::kSuccess) {
4621 ROOT::TMetaUtils::Error(nullptr, "%s: Linkdef compilation failure\n", executableFileName);
4622 return 1;
4623 }
4624
4625
4630
4631 if (!gDriverConfig->fBuildingROOTStage1 && !filesIncludedByLinkdef.empty()) {
4632 pcmArgs.push_back(linkdef);
4633 }
4634
4635 modGen.ParseArgs(pcmArgs);
4636
4637 if (!gDriverConfig->fBuildingROOTStage1) {
4638 // Forward the -I, -D, -U
4639 for (const std::string & inclPath : modGen.GetIncludePaths()) {
4640 interp.AddIncludePath(inclPath);
4641 }
4642 std::stringstream definesUndefinesStr;
4643 modGen.WritePPDefines(definesUndefinesStr);
4644 modGen.WritePPUndefines(definesUndefinesStr);
4645 if (!definesUndefinesStr.str().empty()) {
4646 if (interp.declare(definesUndefinesStr.str()) != cling::Interpreter::kSuccess) {
4647 ROOT::TMetaUtils::Error(nullptr, "Failed to parse -D, -U flags as preprocessor directives:\n%s", definesUndefinesStr.str().c_str());
4648 return 1;
4649 }
4650 }
4651 }
4652
4655 return 1;
4656 }
4657
4658 if (linkdef.empty()) {
4659 // Generate autolinkdef
4661 }
4662
4663 // Check if code goes to stdout or rootcling file
4664 std::ofstream fileout;
4665 string main_dictname(gOptDictionaryFileName.getValue());
4666 std::ostream *splitDictStream = nullptr;
4667 std::unique_ptr<std::ostream> splitDeleter(nullptr);
4668 // Store the temp files
4671 if (!gOptDictionaryFileName.empty()) {
4672 tmpCatalog.addFileName(gOptDictionaryFileName.getValue());
4673 fileout.open(gOptDictionaryFileName.c_str());
4674 if (!fileout) {
4675 ROOT::TMetaUtils::Error(nullptr, "rootcling: failed to open %s in main\n",
4676 gOptDictionaryFileName.c_str());
4677 return 1;
4678 }
4679 }
4680 }
4681
4682 std::ostream &dictStream = (!gOptIgnoreExistingDict && !gOptDictionaryFileName.empty()) ? fileout : std::cout;
4683 bool isACLiC = gOptDictionaryFileName.getValue().find("_ACLiC_dict") != std::string::npos;
4684
4686 // Now generate a second stream for the split dictionary if it is necessary
4687 if (gOptSplit) {
4690 } else {
4692 }
4693
4694 size_t dh = main_dictname.rfind('.');
4695 if (dh != std::string::npos) {
4696 main_dictname.erase(dh);
4697 }
4698 // Need to replace all the characters not allowed in a symbol ...
4699 std::string main_dictname_copy(main_dictname);
4701
4703 if (gOptSplit)
4705
4706 if (!gOptNoGlobalUsingStd) {
4707 // ACLiC'ed macros might rely on `using namespace std` in front of user headers
4708 if (isACLiC) {
4710 if (gOptSplit) {
4712 }
4713 }
4714 }
4715 }
4716
4717 //---------------------------------------------------------------------------
4718 // Parse the linkdef or selection.xml file.
4719 /////////////////////////////////////////////////////////////////////////////
4720
4721 string linkdefFilename;
4722 if (linkdef.empty()) {
4723 linkdefFilename = "in memory";
4724 } else {
4725 bool found = Which(interp, linkdef.c_str(), linkdefFilename);
4726 if (!found) {
4727 ROOT::TMetaUtils::Error(nullptr, "%s: cannot open linkdef file %s\n", executableFileName, linkdef.c_str());
4728 return 1;
4729 }
4730 }
4731
4732 // Exclude string not to re-generate the dictionary
4733 std::vector<std::pair<std::string, std::string>> namesForExclusion;
4734 if (!gBuildingROOT) {
4735 namesForExclusion.push_back(std::make_pair(ROOT::TMetaUtils::propNames::name, "std::string"));
4736 namesForExclusion.push_back(std::make_pair(ROOT::TMetaUtils::propNames::pattern, "ROOT::Meta::Selection*"));
4737 }
4738
4740
4741 std::string extraIncludes;
4742
4744
4745 // Select using DictSelection
4746 const unsigned int selRulesInitialSize = selectionRules.Size();
4749
4751
4752 bool isSelXML = IsSelectionXml(linkdefFilename.c_str());
4753
4754 int rootclingRetCode(0);
4755
4758 std::ifstream file(linkdefFilename.c_str());
4759 if (file.is_open()) {
4760 ROOT::TMetaUtils::Info(nullptr, "Using linkdef file: %s\n", linkdefFilename.c_str());
4761 file.close();
4762 } else {
4763 ROOT::TMetaUtils::Error(nullptr, "Linkdef file %s couldn't be opened!\n", linkdefFilename.c_str());
4764 }
4765
4766 selectionRules.SetSelectionFileType(SelectionRules::kLinkdefFile);
4767 }
4768 // If there is no linkdef file, we added the 'default' #pragma to
4769 // interpPragmaSource and we still need to process it.
4770
4772 clingArgs.push_back("-Ietc/cling/cint"); // For multiset and multimap
4773
4775 llvmResourceDir.c_str())) {
4776 ROOT::TMetaUtils::Error(nullptr, "Parsing #pragma failed %s\n", linkdefFilename.c_str());
4777 rootclingRetCode += 1;
4778 } else {
4779 ROOT::TMetaUtils::Info(nullptr, "#pragma successfully parsed.\n");
4780 }
4781
4782 if (!ldefr.LoadIncludes(extraIncludes)) {
4783 ROOT::TMetaUtils::Error(nullptr, "Error loading the #pragma extra_include.\n");
4784 return 1;
4785 }
4786
4787 } else if (isSelXML) {
4788
4790
4791 std::ifstream file(linkdefFilename.c_str());
4792 if (file.is_open()) {
4793 ROOT::TMetaUtils::Info(nullptr, "Selection XML file\n");
4794
4796 if (!xmlr.Parse(linkdefFilename.c_str(), selectionRules)) {
4797 ROOT::TMetaUtils::Error(nullptr, "Parsing XML file %s\n", linkdefFilename.c_str());
4798 return 1; // Return here to propagate the failure up to the build system
4799 } else {
4800 ROOT::TMetaUtils::Info(nullptr, "XML file successfully parsed\n");
4801 }
4802 file.close();
4803 } else {
4804 ROOT::TMetaUtils::Error(nullptr, "XML file %s couldn't be opened!\n", linkdefFilename.c_str());
4805 }
4806
4807 } else {
4808
4809 ROOT::TMetaUtils::Error(nullptr, "Unrecognized selection file: %s\n", linkdefFilename.c_str());
4810
4811 }
4812
4813 // Speed up the operations with rules
4814 selectionRules.FillCache();
4815 selectionRules.Optimize();
4816
4817 if (isGenreflex){
4818 if (0 != selectionRules.CheckDuplicates()){
4819 return 1;
4820 }
4821 }
4822
4823 // If we want to validate the selection only, we just quit.
4825 return 0;
4826
4827 //---------------------------------------------------------------------------
4828 // Write schema evolution related headers and declarations
4829 /////////////////////////////////////////////////////////////////////////////
4830
4831 if ((!ROOT::gReadRules.empty() || !ROOT::gReadRawRules.empty()) && !gOptIgnoreExistingDict) {
4832 dictStream << "#include \"TBuffer.h\"\n"
4833 << "#include \"TVirtualObject.h\"\n"
4834 << "#include <vector>\n"
4835 << "#include \"TSchemaHelper.h\"\n\n";
4836
4837 std::list<std::string> includes;
4839 for (auto & incFile : includes) {
4840 dictStream << "#include <" << incFile << ">" << std::endl;
4841 }
4842 dictStream << std::endl;
4843 }
4844
4845 selectionRules.SearchNames(interp);
4846
4847 int scannerVerbLevel = 0;
4848 {
4849 using namespace ROOT::TMetaUtils;
4850 scannerVerbLevel = GetErrorIgnoreLevel() == kInfo; // 1 if true, 0 if false
4851 if (isGenreflex){
4852 scannerVerbLevel = GetErrorIgnoreLevel() < kWarning;
4853 }
4854 }
4855
4856 // Select the type of scan
4858 if (gOptGeneratePCH)
4860 if (dictSelection)
4862
4864 scanType,
4865 interp,
4866 normCtxt,
4868
4869 // If needed initialize the autoloading hook
4870 if (!gOptLibListPrefix.empty()) {
4873 }
4874
4875 scan.Scan(CI->getASTContext());
4876
4877 bool has_input_error = false;
4878
4880 selectionRules.PrintSelectionRules();
4881
4883 !gOptGeneratePCH &&
4885 !selectionRules.AreAllSelectionRulesUsed()) {
4886 ROOT::TMetaUtils::Warning(nullptr, "Not all selection rules are used!\n");
4887 }
4888
4889 if (!gOptGeneratePCH){
4892 }
4893
4894 // SELECTION LOOP
4895 // Check for error in the class layout before doing anything else.
4896 for (auto const & annRcd : scan.fSelectedClasses) {
4898 if (annRcd.RequestNoInputOperator()) {
4900 if (version != 0) {
4901 // Only Check for input operator is the object is I/O has
4902 // been requested.
4904 }
4905 }
4906 }
4908 }
4909
4910 if (has_input_error) {
4911 // Be a little bit makefile friendly and remove the dictionary in case of error.
4912 // We could add an option -k to keep the file even in case of error.
4913 exit(1);
4914 }
4915
4916 //---------------------------------------------------------------------------
4917 // Write all the necessary #include
4918 /////////////////////////////////////////////////////////////////////////////
4919 if (!gDriverConfig->fBuildingROOTStage1) {
4921 includeForSource += "#include \"" + includedFromLinkdef + "\"\n";
4922 }
4923 }
4924
4925 if (!gOptGeneratePCH) {
4928 if (gOptSplit) {
4930 }
4931 }
4932 if (!gOptNoGlobalUsingStd) {
4933 // ACLiC'ed macros might have relied on `using namespace std` in front of user headers
4934 if (!isACLiC) {
4936 if (gOptSplit) {
4938 }
4939 }
4940 }
4941 if (gDriverConfig->fInitializeStreamerInfoROOTFile) {
4942 gDriverConfig->fInitializeStreamerInfoROOTFile(modGen.GetModuleFileName().c_str());
4943 }
4944
4945 // The order of addition to the list of constructor type
4946 // is significant. The list is sorted by with the highest
4947 // priority first.
4948 if (!gOptInterpreterOnly) {
4949 constructorTypes.emplace_back("TRootIOCtor", interp);
4950 constructorTypes.emplace_back("__void__", interp); // ROOT-7723
4951 constructorTypes.emplace_back("", interp);
4952 }
4953 }
4956
4957 if (gOptSplit && splitDictStream) {
4959 }
4960 }
4961
4962 if (gOptGeneratePCH) {
4964 } else if (gOptInterpreterOnly) {
4966 // generate an empty pcm nevertheless for consistency
4967 // Negate as true is 1 and true is returned in case of success.
4968 if (!gDriverConfig->fBuildingROOTStage1) {
4970 }
4971 } else {
4974 }
4975
4976 if (rootclingRetCode != 0) {
4977 return rootclingRetCode;
4978 }
4979
4980 // Now we have done all our looping and thus all the possible
4981 // annotation, let's write the pcms.
4986
4988 scan.fSelectedTypedefs,
4989 scan.fSelectedFunctions,
4990 scan.fSelectedVariables,
4991 scan.fSelectedEnums,
4994 interp);
4995
4996 std::string detectedUmbrella;
4997 for (auto & arg : pcmArgs) {
4999 detectedUmbrella = arg;
5000 break;
5001 }
5002 }
5003
5005 headersDeclsMap.clear();
5006 }
5007
5008
5009 std::string headersClassesMapString = "\"\"";
5010 std::string fwdDeclsString = "\"\"";
5011 if (!gOptCxxModule) {
5014 true);
5015 if (!gDriverConfig->fBuildingROOTStage1) {
5018 }
5019 }
5022 // If we just want to inline the input header, we don't need
5023 // to generate any files.
5024 if (!gOptInlineInput) {
5025 // Write the module/PCH depending on what mode we are on
5026 if (modGen.IsPCH()) {
5027 if (!GenerateAllDict(modGen, CI, currentDirectory)) return 1;
5028 } else if (gOptCxxModule) {
5030 return 1;
5031 }
5032 }
5033 }
5034
5035
5036 if (!gOptLibListPrefix.empty()) {
5037 string liblist_filename = gOptLibListPrefix + ".out";
5038
5039 ofstream outputfile(liblist_filename.c_str(), ios::out);
5040 if (!outputfile) {
5041 ROOT::TMetaUtils::Error(nullptr, "%s: Unable to open output lib file %s\n",
5043 } else {
5044 const size_t endStr = gLibsNeeded.find_last_not_of(" \t");
5045 outputfile << gLibsNeeded.substr(0, endStr + 1) << endl;
5046 // Add explicit delimiter
5047 outputfile << "# Now the list of classes\n";
5048 // SELECTION LOOP
5049 for (auto const & annRcd : scan.fSelectedClasses) {
5050 // Shouldn't it be GetLong64_Name( cl_input.GetNormalizedName() )
5051 // or maybe we should be normalizing to turn directly all long long into Long64_t
5052 outputfile << annRcd.GetNormalizedName() << endl;
5053 }
5054 }
5055 }
5056
5057 // Check for errors in module generation
5058 rootclingRetCode += modGen.GetErrorCount();
5059 if (0 != rootclingRetCode) return rootclingRetCode;
5060
5061 // Create the rootmap file
5062 std::string rootmapLibName = std::accumulate(gOptRootmapLibNames.begin(),
5064 std::string(),
5065 [](const std::string & a, const std::string & b) -> std::string {
5066 if (a.empty()) return b;
5067 else return a + " " + b;
5068 });
5069
5070 bool rootMapNeeded = !gOptRootMapFileName.empty() || !rootmapLibName.empty();
5071
5072 std::list<std::string> classesNames;
5073 std::list<std::string> classesNamesForRootmap;
5074 std::list<std::string> classesDefsList;
5075
5080 interp);
5081
5082 std::list<std::string> enumNames;
5084 scan.fSelectedEnums,
5085 interp);
5086
5087 std::list<std::string> varNames;
5089 scan.fSelectedVariables,
5090 interp);
5091
5092 if (0 != rootclingRetCode) return rootclingRetCode;
5093
5094 // Create the rootmapfile if needed
5095 if (rootMapNeeded) {
5096
5097 std::list<std::string> nsNames;
5098
5100
5103
5104 ROOT::TMetaUtils::Info(nullptr, "Rootmap file name %s and lib name(s) \"%s\"\n",
5105 gOptRootMapFileName.c_str(),
5106 rootmapLibName.c_str());
5107
5108 tmpCatalog.addFileName(gOptRootMapFileName);
5109 std::unordered_set<std::string> headersToIgnore;
5110 if (gOptInlineInput)
5111 for (const std::string& optHeaderFileName : gOptDictionaryHeaderFiles)
5112 headersToIgnore.insert(optHeaderFileName.c_str());
5113
5114 std::list<std::string> typedefsRootmapLines;
5116 scan.fSelectedTypedefs,
5117 interp);
5118
5123 nsNames,
5125 enumNames,
5126 varNames,
5129
5130 if (0 != rootclingRetCode) return 1;
5131 }
5132
5134 tmpCatalog.dump();
5135
5136 // Manually call end of translation unit because we never call the
5137 // appropriate deconstructors in the interpreter. This writes out the C++
5138 // module file that we currently generate.
5139 {
5140 cling::Interpreter::PushTransactionRAII RAII(&interp);
5141 CI->getSema().getASTConsumer().HandleTranslationUnit(CI->getSema().getASTContext());
5142 }
5143
5144 // Add the warnings
5146
5147 // make sure the file is closed before committing
5148 fileout.close();
5149
5150 // Before returning, rename the files if no errors occurred
5151 // otherwise clean them to avoid remnants (see ROOT-10015)
5152 if(rootclingRetCode == 0) {
5153 rootclingRetCode += tmpCatalog.commit();
5154 } else {
5155 tmpCatalog.clean();
5156 }
5157
5158 return rootclingRetCode;
5159
5160}
5161
5162namespace genreflex {
5163
5164////////////////////////////////////////////////////////////////////////////////
5165/// Loop on arguments: stop at the first which starts with -
5166
5167 unsigned int checkHeadersNames(std::vector<std::string> &headersNames)
5168 {
5169 unsigned int numberOfHeaders = 0;
5170 for (std::vector<std::string>::iterator it = headersNames.begin();
5171 it != headersNames.end(); ++it) {
5172 const std::string headername(*it);
5175 } else {
5177 "*** genreflex: %s is not a valid header name (.h and .hpp extensions expected)!\n",
5178 headername.c_str());
5179 }
5180 }
5181 return numberOfHeaders;
5182 }
5183
5184////////////////////////////////////////////////////////////////////////////////
5185/// Extract the arguments from the command line
5186
5187 unsigned int extractArgs(int argc, char **argv, std::vector<std::string> &args)
5188 {
5189 // loop on argv, spot strings which are not preceded by something
5190 unsigned int argvCounter = 0;
5191 for (int i = 1; i < argc; ++i) {
5192 if (!ROOT::TMetaUtils::BeginsWith(argv[i - 1], "-") && // so, if preceding element starts with -, this is a value for an option
5193 !ROOT::TMetaUtils::BeginsWith(argv[i], "-")) { // and the element itself is not an option
5194 args.push_back(argv[i]);
5195 argvCounter++;
5196 } else if (argvCounter) {
5197 argv[i - argvCounter] = argv[i];
5198 }
5199 }
5200
5201 // Some debug
5202 if (genreflex::verbose) {
5203 int i = 0;
5204 std::cout << "Args: \n";
5205 for (std::vector<std::string>::iterator it = args.begin();
5206 it < args.end(); ++it) {
5207 std::cout << i << ") " << *it << std::endl;
5208 ++i;
5209 }
5210
5211 }
5212
5213 return argvCounter;
5214 }
5215
5216////////////////////////////////////////////////////////////////////////////////
5217
5218 void changeExtension(std::string &filename, const std::string &newExtension)
5219 {
5220 size_t result = filename.find_last_of('.');
5221 if (std::string::npos != result) {
5222 filename.erase(result);
5223 filename.append(newExtension);
5224 }
5225
5226 }
5227
5228////////////////////////////////////////////////////////////////////////////////
5229/// The caller is responsible for deleting the string!
5230
5231 char *string2charptr(const std::string &str)
5232 {
5233 const unsigned int size(str.size());
5234 char *a = new char[size + 1];
5235 a[size] = 0;
5236 memcpy(a, str.c_str(), size);
5237 return a;
5238 }
5239
5240////////////////////////////////////////////////////////////////////////////////
5241/// Replace the extension with "_rflx.cpp"
5242
5243 void header2outputName(std::string &fileName)
5244 {
5245 changeExtension(fileName, "_rflx.cpp");
5246 }
5247
5248////////////////////////////////////////////////////////////////////////////////
5249/// Get a proper name for the output file
5250
5251 void headers2outputsNames(const std::vector<std::string> &headersNames,
5252 std::vector<std::string> &ofilesnames)
5253 {
5254 ofilesnames.reserve(headersNames.size());
5255
5256 for (std::vector<std::string>::const_iterator it = headersNames.begin();
5257 it != headersNames.end(); ++it) {
5258 std::string ofilename(*it);
5260 ofilesnames.push_back(ofilename);
5261 }
5262 }
5263
5264////////////////////////////////////////////////////////////////////////////////
5265
5266 void AddToArgVector(std::vector<char *> &argvVector,
5267 const std::vector<std::string> &argsToBeAdded,
5268 const std::string &optName = "")
5269 {
5270 for (std::vector<std::string>::const_iterator it = argsToBeAdded.begin();
5271 it != argsToBeAdded.end(); ++it) {
5272 argvVector.push_back(string2charptr(optName + *it));
5273 }
5274 }
5275
5276////////////////////////////////////////////////////////////////////////////////
5277
5278 void AddToArgVectorSplit(std::vector<char *> &argvVector,
5279 const std::vector<std::string> &argsToBeAdded,
5280 const std::string &optName = "")
5281 {
5282 for (std::vector<std::string>::const_iterator it = argsToBeAdded.begin();
5283 it != argsToBeAdded.end(); ++it) {
5284 if (optName.length()) {
5285 argvVector.push_back(string2charptr(optName));
5286 }
5287 argvVector.push_back(string2charptr(*it));
5288 }
5289 }
5290
5291////////////////////////////////////////////////////////////////////////////////
5292
5293 int invokeRootCling(const std::string &verbosity,
5294 const std::string &selectionFileName,
5295 const std::string &targetLibName,
5296 bool multiDict,
5297 const std::vector<std::string> &pcmsNames,
5298 const std::vector<std::string> &includes,
5299 const std::vector<std::string> &preprocDefines,
5300 const std::vector<std::string> &preprocUndefines,
5301 const std::vector<std::string> &warnings,
5302 const std::string &rootmapFileName,
5303 const std::string &rootmapLibName,
5304 bool interpreteronly,
5305 bool doSplit,
5306 bool isCxxmodule,
5307 bool writeEmptyRootPCM,
5308 bool selSyntaxOnly,
5309 bool noIncludePaths,
5310 bool noGlobalUsingStd,
5311 const std::vector<std::string> &headersNames,
5312 bool failOnWarnings,
5314 const std::string &ofilename)
5315 {
5316 // Prepare and invoke the commandline to invoke rootcling
5317
5318 std::vector<char *> argvVector;
5319
5320 argvVector.push_back(string2charptr("rootcling"));
5322 argvVector.push_back(string2charptr("-f"));
5324
5325 if (isCxxmodule)
5326 argvVector.push_back(string2charptr("-cxxmodule"));
5327
5328 // Extract the path to the dictionary
5329 std::string dictLocation;
5331
5332 // Rootmaps
5333
5334 // Prepare the correct rootmap libname if not already set.
5335 std::string newRootmapLibName(rootmapLibName);
5336 if (!rootmapFileName.empty() && newRootmapLibName.empty()) {
5337 if (headersNames.size() != 1) {
5339 "*** genreflex: No rootmap lib and several header specified!\n");
5340 }
5342 newRootmapLibName = "lib";
5345 }
5346
5347 // Prepend to the rootmap the designed directory of the dictionary
5348 // if no path is specified for the rootmap itself
5350 if (!newRootmapFileName.empty() && !HasPath(newRootmapFileName)) {
5352 }
5353
5354
5355 // RootMap filename
5356 if (!newRootmapFileName.empty()) {
5357 argvVector.push_back(string2charptr("-rmf"));
5359 }
5360
5361 // RootMap Lib filename
5362 if (!newRootmapLibName.empty()) {
5363 argvVector.push_back(string2charptr("-rml"));
5365 }
5366
5367 // Always use the -reflex option: we want rootcling to behave
5368 // like genreflex in this case
5369 argvVector.push_back(string2charptr("-reflex"));
5370
5371 // Interpreter only dictionaries
5372 if (interpreteronly)
5373 argvVector.push_back(string2charptr("-interpreteronly"));
5374
5375 // Split dictionaries
5376 if (doSplit)
5377 argvVector.push_back(string2charptr("-split"));
5378
5379 // Targetlib
5380 if (!targetLibName.empty()) {
5381 argvVector.push_back(string2charptr("-s"));
5383 }
5384
5385 // Multidict support
5386 if (multiDict)
5387 argvVector.push_back(string2charptr("-multiDict"));
5388
5389 // Don't declare "using namespace std"
5390 if (noGlobalUsingStd)
5391 argvVector.push_back(string2charptr("-noGlobalUsingStd"));
5392
5393
5395
5396 // Inline the input header
5397 argvVector.push_back(string2charptr("-inlineInputHeader"));
5398
5399 // Write empty root pcms
5401 argvVector.push_back(string2charptr("-writeEmptyRootPCM"));
5402
5403 // Just test the syntax of the selection file
5404 if (selSyntaxOnly)
5405 argvVector.push_back(string2charptr("-selSyntaxOnly"));
5406
5407 // No include paths
5408 if (noIncludePaths)
5409 argvVector.push_back(string2charptr("-noIncludePaths"));
5410
5411 // Fail on warnings
5412 if (failOnWarnings)
5413 argvVector.push_back(string2charptr("-failOnWarnings"));
5414
5415 // Clingargs
5420
5422
5423 if (!selectionFileName.empty()) {
5425 }
5426
5427 const int argc = argvVector.size();
5428
5429 // Output commandline for rootcling
5431 std::string cmd;
5432 for (int i = 0; i < argc; i++) {
5433 cmd += argvVector[i];
5434 cmd += " ";
5435 }
5436 cmd.pop_back();
5437 if (genreflex::verbose) std::cout << "Rootcling commandline: ";
5438 std::cout << cmd << std::endl;
5439 if (printRootclingInvocation) return 0; // we do not generate anything
5440 }
5441
5442 char **argv = & (argvVector[0]);
5444 argv,
5445 /*isGenReflex=*/true);
5446
5447 for (int i = 0; i < argc; i++)
5448 delete [] argvVector[i];
5449
5450 return rootclingReturnCode;
5451
5452 }
5453
5454////////////////////////////////////////////////////////////////////////////////
5455/// Get the right ofilenames and invoke several times rootcling
5456/// One invokation per header
5457
5458 int invokeManyRootCling(const std::string &verbosity,
5459 const std::string &selectionFileName,
5460 const std::string &targetLibName,
5461 bool multiDict,
5462 const std::vector<std::string> &pcmsNames,
5463 const std::vector<std::string> &includes,
5464 const std::vector<std::string> &preprocDefines,
5465 const std::vector<std::string> &preprocUndefines,
5466 const std::vector<std::string> &warnings,
5467 const std::string &rootmapFileName,
5468 const std::string &rootmapLibName,
5469 bool interpreteronly,
5470 bool doSplit,
5471 bool isCxxmodule,
5472 bool writeEmptyRootPCM,
5473 bool selSyntaxOnly,
5474 bool noIncludePaths,
5475 bool noGlobalUsingStd,
5476 const std::vector<std::string> &headersNames,
5477 bool failOnWarnings,
5479 const std::string &outputDirName_const = "")
5480 {
5482
5483 std::vector<std::string> ofilesNames;
5485
5488 }
5489
5490 std::vector<std::string> namesSingleton(1);
5491 for (unsigned int i = 0; i < headersNames.size(); ++i) {
5493 std::string ofilenameFullPath(ofilesNames[i]);
5494 if (llvm::sys::path::parent_path(ofilenameFullPath) == "")
5499 multiDict,
5500 pcmsNames,
5501 includes,
5504 warnings,
5508 doSplit,
5518 if (returnCode != 0)
5519 return returnCode;
5520 }
5521
5522 return 0;
5523 }
5524
5525
5526} // end genreflex namespace
5527
5528////////////////////////////////////////////////////////////////////////////////
5529/// Extract from options multiple values with the same option
5530
5531int extractMultipleOptions(std::vector<ROOT::option::Option> &options,
5532 int oIndex,
5533 std::vector<std::string> &values)
5534{
5535 int nValues = 0;
5536 if (options[oIndex]) {
5537 const int nVals = options[oIndex].count();
5538 values.reserve(nVals);
5539 int optionIndex = 0;
5540 for (ROOT::option::Option *opt = options[oIndex]; opt; opt = opt->next()) {
5541 if (genreflex::verbose) std::cout << "Extracting multiple args: "
5542 << optionIndex << "/" << nVals << " "
5543 << opt->arg << std::endl;
5544 optionIndex++;
5545 values.push_back(opt->arg);
5546 nValues++;
5547 }
5548 }
5549 return nValues;
5550}
5551
5552////////////////////////////////////////////////////////////////////////////////
5553
5554void RiseWarningIfPresent(std::vector<ROOT::option::Option> &options,
5555 int optionIndex,
5556 const char *descriptor)
5557{
5558 if (options[optionIndex]) {
5560 "*** genereflex: %s is not supported anymore.\n",
5561 descriptor);
5562 }
5563}
5564
5565////////////////////////////////////////////////////////////////////////////////
5566
5567bool IsGoodLibraryName(const std::string &name)
5568{
5569
5570
5572#ifdef __APPLE__
5574#endif
5575 return isGood;
5576}
5577
5578////////////////////////////////////////////////////////////////////////////////
5579/// Translate the arguments of genreflex into rootcling ones and forward them
5580/// to the RootCling function.
5581/// These are two typical genreflex and rootcling commandlines
5582/// 1) genreflex header1.h [header2.h ...] [options] [preprocessor options]
5583/// 2) rootcling [-v] [-v0-4] [-f] [out.cxx] [-s sharedlib.so] [-m pcmfilename]
5584/// header1.h[{+,-}][!] ..headerN.h[{+,-}][!] [{LinkDef.h,selectionRules.xml}]
5585/// The rules with which the arguments are translated are (1st column genreflex):
5586/// --debug -v4
5587/// --quiet -v0
5588/// -o ofile positional arg after -f
5589/// -s selection file Last argument of the call
5590/// --fail_on_warning Wrap ROOT::TMetaUtils::Warning and throw if selected
5591///
5592/// New arguments:
5593/// -l --library targetLib name (new) -s targetLib name
5594/// -m pcmname (can be many -m) (new) -m pcmname (can be many -m)
5595/// --rootmap -rmf (new)
5596/// --rootmap-lib -rml (new)
5597///
5598/// genreflex options which rise warnings (feedback is desirable)
5599/// --no_membertypedefs (it should be irrelevant)
5600/// --no_templatetypedefs (it should be irrelevant)
5601///
5602/// genreflex options which are ignored (know for sure they are not needed)
5603/// --pool, --dataonly
5604/// --interpreteronly
5605/// --gccxml{path,opt,post}
5606///
5607///
5608/// Exceptions
5609/// The --deep option of genreflex is passed as function parameter to rootcling
5610/// since it's not needed at the moment there.
5611
5612int GenReflexMain(int argc, char **argv)
5613{
5614 using namespace genreflex;
5615
5616 // Setup the options parser
5617 enum optionIndex { UNKNOWN,
5619 OFILENAME,
5620 TARGETLIB,
5621 MULTIDICT,
5624 ROOTMAP,
5625 ROOTMAPLIB,
5627 DEEP,
5628 DEBUG,
5629 VERBOSE,
5630 QUIET,
5631 SILENT,
5632 CXXMODULE,
5634 HELP,
5638 SPLIT,
5642 // Don't show up in the help
5645 INCLUDE,
5646 WARNING
5647 };
5648
5649 enum optionTypes { NOTYPE, STRING } ;
5650
5651 // Some long help strings
5652 const char *genreflexUsage =
5653 "********************************************************************************\n"
5654 "* The genreflex utility does not allow to generate C++ modules containing *\n"
5655 "* reflection information required at runtime. Please use rootcling instead *\n"
5656 "* To print the rootcling invocation that corresponds to the current genreflex *\n"
5657 "* invocation please use the --print-rootcling-invocation flag. *\n"
5658 "********************************************************************************\n"
5659 "\n"
5660 "Generates dictionary sources and related ROOT pcm starting from an header.\n"
5661 "Usage: genreflex headerfile.h [opts] [preproc. opts]\n\n"
5662 "Options:\n";
5663
5664 const char *printRootclingInvocationUsage =
5665 "--print-rootcling-invocation\n"
5666 " Print to screen the rootcling invocation corresponding to the current \n"
5667 " genreflex invocation.\n";
5668
5669 const char *selectionFilenameUsage =
5670 "-s, --selection_file\tSelection filename\n"
5671 " Class selection file to specify for which classes the dictionary\n"
5672 " will be generated. The final set can be crafted with exclusion and\n"
5673 " exclusion rules.\n"
5674 " Properties can be specified. Some have special meaning:\n"
5675 " - name [string] name of the entity to select with an exact matching\n"
5676 " - pattern [string] name with wildcards (*) to select entities\n"
5677 " - file_name/file_pattern [string]: as name/pattern but referring to\n"
5678 " file where the C++ entities reside and not to C++ entities themselves.\n"
5679 " - transient/persistent [string: true/false] The fields to which they are\n"
5680 " applied will not be persistified if requested.\n"
5681 " - comment [string]: what you could write in code after an inline comment\n"
5682 " without \"//\". For example comment=\"!\" or \"||\".\n"
5683 " - noStreamer [true/false]: turns off streamer generation if set to 'true.'\n"
5684 " Default value is 'false'\n"
5685 " - rntupleStreamerMode [true/false]: enforce streamed or native writing for RNTuple.\n"
5686 " If unset, RNTuple stores classes in split mode or fails if the class cannot be split.\n"
5687 " - noInputOperator [true/false]: turns off input operator generation if set\n"
5688 " to 'true'. Default value is 'false'\n"
5689 " Example XML:\n"
5690 " <lcgdict>\n"
5691 " [<selection>]\n"
5692 " <class [name=\"classname\"] [pattern=\"wildname\"]\n"
5693 " [file_name=\"filename\"] [file_pattern=\"wildname\"]\n"
5694 " [id=\"xxxx\"] [noStreamer=\"true/false\"]\n"
5695 " [noInputOperator=\"true/false\"]\n"
5696 " [rntupleStreamerMode=\"true/false\"] />\n"
5697 " <class name=\"classname\" >\n"
5698 " <field name=\"m_transient\" transient=\"true\"/>\n"
5699 " <field name=\"m_anothertransient\" persistent=\"false\"/>\n"
5700 " <field name=\"m_anothertransient\" comment=\"||\"/>\n"
5701 " <properties prop1=\"value1\" [prop2=\"value2\"]/>\n"
5702 " </class>\n"
5703 " <function [name=\"funcname\"] [pattern=\"wildname\"] />\n"
5704 " <enum [name=\"enumname\"] [pattern=\"wildname\"] />\n"
5705 " <variable [name=\"varname\"] [pattern=\"wildname\"] />\n"
5706 " [</selection>]\n"
5707 " <exclusion>\n"
5708 " <class [name=\"classname\"] [pattern=\"wildname\"] />\n"
5709 " <method name=\"unwanted\" />\n"
5710 " </class>\n"
5711 " ...\n"
5712 " </lcgdict>\n"
5713 "\n"
5714 " If no selection file is specified, the class with the filename without\n"
5715 " extension will be selected, i.e. myClass.h as argument without any\n"
5716 " selection xml comes with an implicit selection rule for class \"myClass\".\n";
5717
5718 const char *outputFilenameUsage =
5719 "-o, --output\tOutput filename\n"
5720 " Output file name. If an existing directory is specified instead of a file,\n"
5721 " then a filename will be built using the name of the input file and will\n"
5722 " be placed in the given directory. <headerfile>_rflx.cpp.\n"
5723 " NOTA BENE: the dictionaries that will be used within the same project must\n"
5724 " have unique names.\n";
5725
5726
5727 const char *targetLib =
5728 "-l, --library\tTarget library\n"
5729 " The flag -l must be followed by the name of the library that will\n"
5730 " contain the object file corresponding to the dictionary produced by\n"
5731 " this invocation of genreflex.\n"
5732 " The name takes priority over the one specified for the rootmapfile.\n"
5733 " The name influences the name of the created pcm:\n"
5734 " 1) If it is not specified, the pcm is called libINPUTHEADER_rdict.pcm\n"
5735 " 2) If it is specified, the pcm is called libTARGETLIBRARY_rdict.pcm\n"
5736 " Any \"liblib\" occurence is transformed in the expected \"lib\".\n"
5737 " 3) If this is specified in conjunction with --multiDict, the output is\n"
5738 " libTARGETLIBRARY_DICTIONARY_rdict.pcm\n";
5739
5740 const char *rootmapUsage =
5741 "--rootmap\tGenerate the rootmap file to be used by ROOT.\n"
5742 " This file lists the autoload keys. For example classes for which the\n"
5743 " reflection information is provided.\n"
5744 " The format of the rootmap is the following:\n"
5745 " - Forward declarations section\n"
5746 " - Libraries sections\n"
5747 " Rootmaps can be concatenated together, for example with the cat util.\n"
5748 " In order for ROOT to pick up the information in the rootmaps, they\n"
5749 " have to be located in the library path and have the .rootmap extension.\n"
5750 " An example rootmap file could be:\n"
5751 " { decls }\n"
5752 " template <class T> class A;\n"
5753 " [ libMyLib.so ]\n"
5754 " class A<double>\n"
5755 " class B\n"
5756 " typedef C\n"
5757 " header H.h\n";
5758
5759 const char *rootmapLibUsage =
5760 "--rootmap-lib\tLibrary name for the rootmap file.\n";
5761
5762 // The Descriptor
5764
5765 {
5766 UNKNOWN,
5767 NOTYPE,
5768 "", "",
5771 },
5772
5773 {
5775 NOTYPE,
5776 "", "print-rootcling-invocation",
5779 },
5780
5781 {
5782 OFILENAME,
5783 STRING ,
5784 "o" , "output" ,
5787 },
5788
5789 {
5790 TARGETLIB,
5791 STRING ,
5792 "l" , "library" ,
5794 targetLib
5795 },
5796
5797 {
5798 MULTIDICT,
5799 NOTYPE ,
5800 "" , "multiDict" ,
5802 "--multiDict\tSupport for many dictionaries in one library\n"
5803 " Form correct pcm names if multiple dictionaries will be in the same\n"
5804 " library (needs target library switch. See its documentation).\n"
5805 },
5806
5807
5808 {
5810 NOTYPE ,
5811 "" , "noGlobalUsingStd" ,
5813 "--noGlobalUsingStd\tDo not declare {using namespace std} in the dictionary global scope\n"
5814 " All header files must have sumbols from std:: namespace fully qualified\n"
5815 },
5816
5817 {
5819 STRING ,
5820 "s" , "selection_file" ,
5823 },
5824
5825 {
5826 ROOTMAP,
5827 STRING ,
5828 "" , "rootmap" ,
5831 },
5832
5833 {
5834 ROOTMAPLIB,
5835 STRING ,
5836 "" , "rootmap-lib" ,
5839 },
5840
5841 {
5843 NOTYPE,
5844 "" , "interpreteronly",
5846 "--interpreteronly\tDo not generate I/O related information.\n"
5847 " Generate minimal dictionary required for interactivity.\n"
5848 },
5849
5850 {
5851 SPLIT,
5852 NOTYPE,
5853 "" , "split",
5855 "--split\tSplit the dictionary\n"
5856 " Split in two the dictionary, isolating the part with\n"
5857 " ClassDef related functions in a separate file.\n"
5858 },
5859
5860 {
5862 STRING ,
5863 "m" , "" ,
5865 "-m \tPcm file loaded before any header (option can be repeated).\n"
5866 },
5867
5868 {
5869 VERBOSE,
5870 NOTYPE ,
5871 "-v" , "verbose",
5873 "-v, --verbose\tPrint some debug information.\n"
5874 },
5875
5876 {
5877 DEBUG,
5878 NOTYPE ,
5879 "" , "debug",
5881 "--debug\tPrint all debug information.\n"
5882 },
5883
5884 {
5885 QUIET,
5886 NOTYPE ,
5887 "" , "quiet",
5889 "--quiet\tPrint only warnings and errors (default).\n"
5890 },
5891
5892 {
5893 SILENT,
5894 NOTYPE ,
5895 "" , "silent",
5897 "--silent\tPrint no information at all.\n"
5898 },
5899
5900 {
5902 NOTYPE ,
5903 "" , "writeEmptyPCM",
5905 "--writeEmptyPCM\tWrite an empty ROOT pcm.\n"
5906 },
5907
5908 {
5909 CXXMODULE,
5910 NOTYPE ,
5911 "" , "cxxmodule",
5913 "--cxxmodule\tGenerates a PCM for C++ Modules.\n"
5914 },
5915
5916
5917 {
5918 HELP,
5919 NOTYPE,
5920 "h" , "help",
5922 "--help\tPrint usage and exit.\n"
5923 },
5924
5925 {
5927 NOTYPE,
5928 "", "fail_on_warnings",
5930 "--fail_on_warnings\tFail on warnings and errors.\n"
5931 },
5932
5933 {
5935 NOTYPE,
5936 "", "selSyntaxOnly",
5938 "--selSyntaxOnly\tValidate selection file w/o generating the dictionary.\n"
5939 },
5940
5941 {
5943 NOTYPE ,
5944 "" , "noIncludePaths",
5946 "--noIncludePaths\tDo not store the headers' directories in the dictionary. Instead, rely on the environment variable $ROOT_INCLUDE_PATH at runtime.\n"
5947 },
5948
5949 // Left intentionally empty not to be shown in the help, like in the first genreflex
5950 {
5951 INCLUDE,
5952 STRING ,
5953 "I" , "" ,
5955 ""
5956 },
5957
5958 {
5960 STRING ,
5961 "D" , "" ,
5963 ""
5964 },
5965
5966 {
5968 STRING ,
5969 "U" , "" ,
5971 ""
5972 },
5973
5974 {
5975 WARNING,
5976 STRING ,
5977 "W" , "" ,
5979 ""
5980 },
5981
5982 {
5983 NOMEMBERTYPEDEFS, // Option which is not meant for the user: deprecated
5984 STRING ,
5985 "" , "no_membertypedefs" ,
5987 ""
5988 },
5989
5990 {
5991 NOTEMPLATETYPEDEFS, // Option which is not meant for the user: deprecated
5992 STRING ,
5993 "" , "no_templatetypedefs" ,
5995 ""
5996 },
5997
5998 {0, 0, nullptr, nullptr, nullptr, nullptr}
5999 };
6000
6001 std::vector<std::string> headersNames;
6002 const int originalArgc = argc;
6003 // The only args are the headers here
6004 const int extractedArgs = extractArgs(argc, argv, headersNames);
6005
6006 const int offset = 1; // skip argv[0]
6008 argv += offset;
6009
6010 // Parse the options
6012 std::vector<ROOT::option::Option> options(stats.options_max);// non POD var size arrays are not C++!
6013 std::vector<ROOT::option::Option> buffer(stats.buffer_max);
6014 // The 4 is the minimum size of the abbreviation length.
6015 // For example, --selection_file can be abbreviated with --sele at least.
6016
6017 ROOT::option::Parser parse(genreflexUsageDescriptor, argc, argv, &options[0], &buffer[0], 5);
6018
6019 if (parse.error()) {
6020 ROOT::TMetaUtils::Error(nullptr, "Argument parsing error!\n");
6021 return 1;
6022 }
6023
6024 // Print help if needed
6025 if (options[HELP] || originalArgc == 1) {
6027 return 0;
6028 }
6029 // See if no header was provided
6030 int numberOfHeaders = checkHeadersNames(headersNames);
6031 if (0 == numberOfHeaders) {
6032 ROOT::TMetaUtils::Error(nullptr, "No valid header was provided!\n");
6033 return 1;
6034 }
6035
6037
6038 if (options[DEEP])
6039 ROOT::TMetaUtils::Warning(nullptr, "--deep has no effect. Please remove the deprecated flag!\n");
6040 // The verbosity: debug wins over quiet
6041 //std::string verbosityOption("-v4"); // To be uncommented for the testing phase. It should be -v
6042 std::string verbosityOption("-v2");
6043 if (options[SILENT]) verbosityOption = "-v0";
6044 if (options[VERBOSE] || getenv ("VERBOSE")) verbosityOption = "-v3";
6045 if (options[DEBUG]) verbosityOption = "-v4";
6046
6048
6049 // The selection file
6050 std::string selectionFileName;
6051 if (options[SELECTIONFILENAME]) {
6052 selectionFileName = options[SELECTIONFILENAME].arg;
6055 "Invalid selection file extension: filename is %s and extension .xml is expected!\n",
6056 selectionFileName.c_str());
6057 return 1;
6058 }
6059 }
6060
6061// // Warn if a selection file is not present and exit
6062// if (NULL==options[SELECTIONFILENAME].arg){
6063// ROOT::TMetaUtils::Warning(0,"The usage of genreflex without a selection file is not yet supported.\n");
6064// return 1;
6065// }
6066
6067
6068 // Set the parameters for the rootmap file. If the libname is not set,
6069 // it will be set according to the header in invokeRootCling.
6070 // FIXME: treatment of directories
6071 std::string rootmapFileName(options[ROOTMAP].arg ? options[ROOTMAP].arg : "");
6072 std::string rootmapLibName(options[ROOTMAPLIB].arg ? options[ROOTMAPLIB].arg : "");
6073
6074 // The target lib name
6075 std::string targetLibName;
6076 if (options[TARGETLIB]) {
6077 targetLibName = options[TARGETLIB].arg;
6080 "Invalid target library extension: filename is %s and extension %s is expected!\n",
6081 targetLibName.c_str(),
6082 gLibraryExtension.c_str());
6083 }
6084 // Target lib has precedence over rootmap lib
6085 if (options[ROOTMAP]) {
6087 }
6088 }
6089
6090 bool isCxxmodule = options[CXXMODULE];
6091
6092 bool multidict = false;
6093 if (options[MULTIDICT]) multidict = true;
6094
6095 bool noGlobalUsingStd = false;
6096 if (options[NOGLOBALUSINGSTD]) noGlobalUsingStd = true;
6097
6098 if (multidict && targetLibName.empty()) {
6100 "Multilib support is requested but no target lib is specified. A sane pcm name cannot be formed.\n");
6101 return 1;
6102 }
6103
6104 bool printRootclingInvocation = false;
6105 if (options[PRINTROOTCLINGINVOCATION])
6107
6108 bool interpreteronly = false;
6109 if (options[INTERPRETERONLY])
6110 interpreteronly = true;
6111
6112 bool doSplit = false;
6113 if (options[SPLIT])
6114 doSplit = true;
6115
6116 bool writeEmptyRootPCM = false;
6117 if (options[WRITEEMPTYROOTPCM])
6118 writeEmptyRootPCM = true;
6119
6120 bool selSyntaxOnly = false;
6121 if (options[SELSYNTAXONLY]) {
6122 selSyntaxOnly = true;
6123 }
6124
6125 bool noIncludePaths = false;
6126 if (options[NOINCLUDEPATHS]) {
6127 noIncludePaths = true;
6128 }
6129
6130 bool failOnWarnings = false;
6131 if (options[FAILONWARNINGS]) {
6132 failOnWarnings = true;
6133 }
6134
6135 // Add the .so extension to the rootmap lib if not there
6138 }
6139
6140 // The list of pcms to be preloaded
6141 std::vector<std::string> pcmsNames;
6143
6144 // Preprocessor defines
6145 std::vector<std::string> preprocDefines;
6147
6148 // Preprocessor undefines
6149 std::vector<std::string> preprocUndefines;
6151
6152 // Includes
6153 std::vector<std::string> includes;
6155
6156 // Warnings
6157 std::vector<std::string> warnings;
6158 extractMultipleOptions(options, WARNING, warnings);
6159
6160 // The outputfilename(s)
6161 // There are two cases:
6162 // 1) The outputfilename is specified
6163 // --> The information of all headers will be in one single dictionary
6164 // (1 call to rootcling)
6165 // 2) The outputfilename is not specified
6166 // --> There will be a dictionary per header
6167 // (N calls to rootcling)
6168 int returnValue = 0;
6169 std::string ofileName(options[OFILENAME] ? options[OFILENAME].arg : "");
6170
6171 // If not empty and not a directory (therefore it's a file)
6172 // call rootcling directly. The number of headers files is irrelevant.
6173 if (!ofileName.empty() && !llvm::sys::fs::is_directory(ofileName)) {
6174 returnValue = invokeRootCling(verbosityOption,
6177 multidict,
6178 pcmsNames,
6179 includes,
6182 warnings,
6186 doSplit,
6195 ofileName);
6196 } else {
6197 // Here ofilename is either "" or a directory: this is irrelevant.
6198 returnValue = invokeManyRootCling(verbosityOption,
6201 multidict,
6202 pcmsNames,
6203 includes,
6206 warnings,
6210 doSplit,
6219 ofileName);
6220 }
6221
6222 return returnValue;
6223}
6224
6225
6226////////////////////////////////////////////////////////////////////////////////
6227
6228extern "C"
6230{
6231
6232 assert(!gDriverConfig && "Driver configuration already set!");
6233 gDriverConfig = &config;
6234
6235 gBuildingROOT = config.fBuildingROOTStage1; // gets refined later
6236
6237 std::string exeName = ExtractFileName(GetExePath());
6238#ifdef __APPLE__
6239 // _dyld_get_image_name() on macOS11 and later sometimes returns "rootcling" for "genreflex".
6240 // Fix that (while still initializing the binary path, needed for ROOTSYS) by updating the
6241 // exeName to argv[0]:
6243#endif
6244
6245 // Select according to the name of the executable the procedure to follow:
6246 // 1) RootCling
6247 // 2) GenReflex
6248 // The default is rootcling
6249
6250 int retVal = 0;
6251
6252 if (std::string::npos != exeName.find("genreflex"))
6254 else // rootcling or default
6256
6257 gDriverConfig = nullptr;
6258
6260 ROOT::TMetaUtils::Info(nullptr,"Problems have been detected during the generation of the dictionary.\n");
6261 return 1;
6262 }
6263 return retVal;
6264}
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.
void HandleDiagnostic(clang::DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &Info) override
CheckModuleBuildClient(clang::DiagnosticConsumer *Child, bool OwnsChild, clang::ModuleMap &Map)
clang::DiagnosticConsumer * fChild
bool IncludeInDiagnosticCounts() const override
void EndSourceFile() override
void BeginSourceFile(const clang::LangOptions &LangOpts, const clang::Preprocessor *PP) override
clang::ModuleMap & fMap
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:1050
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:998
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:177
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:83
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