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