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