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#if defined(_WIN64) && defined(_DEBUG)
1994 snprintf(platformDefines, 64, "-D_ITERATOR_DEBUG_LEVEL=0");
1995 clingArgs.push_back(platformDefines);
1996#endif
1997#endif
1998}
1999
2000////////////////////////////////////////////////////////////////////////////////
2001/// Extract the filename from a fullpath
2002
2003std::string ExtractFileName(const std::string &path)
2004{
2005 return llvm::sys::path::filename(path).str();
2006}
2007
2008////////////////////////////////////////////////////////////////////////////////
2009/// Extract the path from a fullpath finding the last \ or /
2010/// according to the content in gPathSeparator
2011
2012void ExtractFilePath(const std::string &path, std::string &dirname)
2013{
2014 const size_t pos = path.find_last_of(gPathSeparator);
2015 if (std::string::npos != pos) {
2016 dirname.assign(path.begin(), path.begin() + pos + 1);
2017 } else {
2018 dirname.assign("");
2019 }
2020}
2021
2022////////////////////////////////////////////////////////////////////////////////
2023/// Check if file has a path
2024
2025bool HasPath(const std::string &name)
2026{
2027 std::string dictLocation;
2029 return !dictLocation.empty();
2030}
2031
2032////////////////////////////////////////////////////////////////////////////////
2033
2035 std::string &rootmapLibName)
2036{
2037 // If the rootmap file name does not exist, create one following the libname
2038 // I.E. put into the directory of the lib the rootmap and within the rootmap the normalised path to the lib
2039 if (rootmapFileName.empty()) {
2040 size_t libExtensionPos = rootmapLibName.find_last_of(gLibraryExtension) - gLibraryExtension.size() + 1;
2041 rootmapFileName = rootmapLibName.substr(0, libExtensionPos) + ".rootmap";
2042 size_t libCleanNamePos = rootmapLibName.find_last_of(gPathSeparator) + 1;
2043 rootmapLibName = rootmapLibName.substr(libCleanNamePos, std::string::npos);
2044 ROOT::TMetaUtils::Info(nullptr, "Rootmap file name %s built from rootmap lib name %s",
2045 rootmapLibName.c_str(),
2046 rootmapFileName.c_str());
2047 }
2048}
2049
2050////////////////////////////////////////////////////////////////////////////////
2051/// Extract the proper autoload key for nested classes
2052/// The routine does not erase the name, just updates it
2053
2054void GetMostExternalEnclosingClassName(const clang::DeclContext &theContext,
2055 std::string &ctxtName,
2056 const cling::Interpreter &interpreter,
2057 bool treatParent = true)
2058{
2059 const clang::DeclContext *outerCtxt = treatParent ? theContext.getParent() : &theContext;
2060 // If the context has no outer context, we are finished
2061 if (!outerCtxt) return;
2062 // If the context is a class, we update the name
2063 if (const clang::RecordDecl *thisRcdDecl = llvm::dyn_cast<clang::RecordDecl>(outerCtxt)) {
2065 }
2066 // We recurse
2068}
2069
2070////////////////////////////////////////////////////////////////////////////////
2071
2073 std::string &ctxtName,
2074 const cling::Interpreter &interpreter)
2075{
2076 const clang::DeclContext *theContext = theDecl.getDeclContext();
2078}
2079
2080////////////////////////////////////////////////////////////////////////////////
2081template<class COLL>
2082int ExtractAutoloadKeys(std::list<std::string> &names,
2083 const COLL &decls,
2084 const cling::Interpreter &interp)
2085{
2086 if (!decls.empty()) {
2087 std::string autoLoadKey;
2088 for (auto & d : decls) {
2089 autoLoadKey = "";
2091 // If there is an outer class, it is already considered
2092 if (autoLoadKey.empty()) {
2093 names.push_back(d->getQualifiedNameAsString());
2094 }
2095 }
2096 }
2097 return 0;
2098}
2099
2100////////////////////////////////////////////////////////////////////////////////
2101/// Generate a rootmap file in the new format, like
2102/// { decls }
2103/// `namespace A { namespace B { template <typename T> class myTemplate; } }`
2104/// [libGpad.so libGraf.so libHist.so libMathCore.so]
2105/// class TAttCanvas
2106/// class TButton
2107/// (header1.h header2.h .. headerN.h)
2108/// class TMyClass
2109
2111 const std::string &rootmapLibName,
2112 const std::list<std::string> &classesDefsList,
2113 const std::list<std::string> &classesNames,
2114 const std::list<std::string> &nsNames,
2115 const std::list<std::string> &tdNames,
2116 const std::list<std::string> &enNames,
2117 const std::list<std::string> &varNames,
2119 const std::unordered_set<std::string> headersToIgnore)
2120{
2121 // Create the rootmap file from the selected classes and namespaces
2122 std::ofstream rootmapFile(rootmapFileName.c_str());
2123 if (!rootmapFile) {
2124 ROOT::TMetaUtils::Error(nullptr, "Opening new rootmap file %s\n", rootmapFileName.c_str());
2125 return 1;
2126 }
2127
2128 // Keep track of the classes keys
2129 // This is done to avoid duplications of keys with typedefs
2130 std::unordered_set<std::string> classesKeys;
2131
2132
2133 // Add the "section"
2134 if (!classesNames.empty() || !nsNames.empty() || !tdNames.empty() ||
2135 !enNames.empty() || !varNames.empty()) {
2136
2137 // Add the template definitions
2138 if (!classesDefsList.empty()) {
2139 rootmapFile << "{ decls }\n";
2140 for (auto & classDef : classesDefsList) {
2141 rootmapFile << classDef << std::endl;
2142 }
2143 rootmapFile << "\n";
2144 }
2145 rootmapFile << "[ " << rootmapLibName << " ]\n";
2146
2147 // Loop on selected classes and insert them in the rootmap
2148 if (!classesNames.empty()) {
2149 rootmapFile << "# List of selected classes\n";
2150 for (auto & className : classesNames) {
2151 rootmapFile << "class " << className << std::endl;
2152 classesKeys.insert(className);
2153 }
2154 // And headers
2155 std::unordered_set<std::string> treatedHeaders;
2156 for (auto & className : classesNames) {
2157 // Don't treat templates
2158 if (className.find("<") != std::string::npos) continue;
2159 if (headersClassesMap.count(className)) {
2160 auto &headers = headersClassesMap.at(className);
2161 if (!headers.empty()){
2162 auto &header = headers.front();
2163 if (treatedHeaders.insert(header).second &&
2164 headersToIgnore.find(header) == headersToIgnore.end() &&
2166 rootmapFile << "header " << header << std::endl;
2167 }
2168 }
2169 }
2170 }
2171 }
2172
2173 // Same for namespaces
2174 if (!nsNames.empty()) {
2175 rootmapFile << "# List of selected namespaces\n";
2176 for (auto & nsName : nsNames) {
2177 rootmapFile << "namespace " << nsName << std::endl;
2178 }
2179 }
2180
2181 // And typedefs. These are used just to trigger the autoload mechanism
2182 if (!tdNames.empty()) {
2183 rootmapFile << "# List of selected typedefs and outer classes\n";
2184 for (const auto & autoloadKey : tdNames)
2185 if (classesKeys.insert(autoloadKey).second)
2186 rootmapFile << "typedef " << autoloadKey << std::endl;
2187 }
2188
2189 // And Enums. There is no incomplete type for an enum but we can nevertheless
2190 // have the key for the cases where the root typesystem is interrogated.
2191 if (!enNames.empty()){
2192 rootmapFile << "# List of selected enums and outer classes\n";
2193 for (const auto & autoloadKey : enNames)
2194 if (classesKeys.insert(autoloadKey).second)
2195 rootmapFile << "enum " << autoloadKey << std::endl;
2196 }
2197
2198 // And variables.
2199 if (!varNames.empty()){
2200 rootmapFile << "# List of selected vars\n";
2201 for (const auto & autoloadKey : varNames)
2202 if (classesKeys.insert(autoloadKey).second)
2203 rootmapFile << "var " << autoloadKey << std::endl;
2204 }
2205
2206 }
2207
2208 return 0;
2209
2210}
2211
2212////////////////////////////////////////////////////////////////////////////////
2213/// Performance is not critical here.
2214
2215std::pair<std::string,std::string> GetExternalNamespaceAndContainedEntities(const std::string line)
2216{
2217 auto nsPattern = '{'; auto nsPatternLength = 1;
2218 auto foundNsPos = line.find_last_of(nsPattern);
2219 if (foundNsPos == std::string::npos) return {"",""};
2221 auto extNs = line.substr(0,foundNsPos);
2222
2223 auto nsEndPattern = '}';
2224 auto foundEndNsPos = line.find(nsEndPattern);
2226
2227 return {extNs, contained};
2228
2229
2230}
2231
2232////////////////////////////////////////////////////////////////////////////////
2233/// If two identical namespaces are there, just declare one only
2234/// Example:
2235/// namespace A { namespace B { fwd1; }}
2236/// namespace A { namespace B { fwd2; }}
2237/// get a namespace A { namespace B { fwd1; fwd2; }} line
2238
2239std::list<std::string> CollapseIdenticalNamespaces(const std::list<std::string>& fwdDeclarationsList)
2240{
2241 // Temp data structure holding the namespaces and the entities therewith
2242 // contained
2243 std::map<std::string, std::string> nsEntitiesMap;
2244 std::list<std::string> optFwdDeclList;
2245 for (auto const & fwdDecl : fwdDeclarationsList){
2246 // Check if the decl(s) are contained in a ns and which one
2248 if (extNsAndEntities.first.empty()) {
2249 // no namespace found. Just put this on top
2250 optFwdDeclList.push_front(fwdDecl);
2251 };
2254 }
2255
2256 // Now fill the new, optimised list
2257 std::string optFwdDecl;
2258 for (auto const & extNsAndEntities : nsEntitiesMap) {
2260 optFwdDecl += extNsAndEntities.second;
2261 for (int i = 0; i < std::count(optFwdDecl.begin(), optFwdDecl.end(), '{'); ++i ){
2262 optFwdDecl += " }";
2263 }
2264 optFwdDeclList.push_front(optFwdDecl);
2265 }
2266
2267 return optFwdDeclList;
2268
2269}
2270
2271////////////////////////////////////////////////////////////////////////////////
2272/// Separate multiline strings
2273
2274bool ProcessAndAppendIfNotThere(const std::string &el,
2275 std::list<std::string> &el_list,
2276 std::unordered_set<std::string> &el_set)
2277{
2278 std::stringstream elStream(el);
2279 std::string tmp;
2280 bool added = false;
2281 while (getline(elStream, tmp, '\n')) {
2282 // Add if not there
2283 if (el_set.insert(tmp).second && !tmp.empty()) {
2284 el_list.push_back(tmp);
2285 added = true;
2286 }
2287 }
2288
2289 return added;
2290}
2291
2292////////////////////////////////////////////////////////////////////////////////
2293
2295 std::list<std::string> &classesList,
2296 std::list<std::string> &classesListForRootmap,
2297 std::list<std::string> &fwdDeclarationsList,
2298 const cling::Interpreter &interpreter)
2299{
2300 // Loop on selected classes. If they don't have the attribute "rootmap"
2301 // set to "false", store them in the list of classes for the rootmap
2302 // Returns 0 in case of success and 1 in case of issues.
2303
2304 // An unordered_set to keep track of the existing classes.
2305 // We want to avoid duplicates there as they may hint to a serious corruption
2306 std::unordered_set<std::string> classesSet;
2307 std::unordered_set<std::string> outerMostClassesSet;
2308
2309 std::string attrName, attrValue;
2310 bool isClassSelected;
2311 std::unordered_set<std::string> availableFwdDecls;
2312 std::string fwdDeclaration;
2313 for (auto const & selVar : scan.fSelectedVariables) {
2314 fwdDeclaration = "";
2317 }
2318
2319 for (auto const & selEnum : scan.fSelectedEnums) {
2320 fwdDeclaration = "";
2323 }
2324
2325 // Loop on selected classes and put them in a list
2326 for (auto const & selClass : scan.fSelectedClasses) {
2327 isClassSelected = true;
2328 const clang::RecordDecl *rDecl = selClass.GetRecordDecl();
2329 std::string normalizedName;
2330 normalizedName = selClass.GetNormalizedName();
2331 if (!normalizedName.empty() &&
2332 !classesSet.insert(normalizedName).second &&
2333 outerMostClassesSet.count(normalizedName) == 0) {
2334 std::cerr << "FATAL: A class with normalized name " << normalizedName
2335 << " was already selected. This means that two different instances of"
2336 << " clang::RecordDecl had the same name, which is not possible."
2337 << " This can be a hint of a serious problem in the class selection."
2338 << " In addition, the generated dictionary would not even compile.\n";
2339 return 1;
2340 }
2341 classesList.push_back(normalizedName);
2342 // Allow to autoload with the name of the class as it was specified in the
2343 // selection xml or linkdef
2344 const char *reqName(selClass.GetRequestedName());
2345
2346 // Get always the containing namespace, put it in the list if not there
2347 fwdDeclaration = "";
2350
2351 // Get template definition and put it in if not there
2352 if (llvm::isa<clang::ClassTemplateSpecializationDecl>(rDecl)) {
2353 fwdDeclaration = "";
2355 if (retCode == 0) {
2356 std::string fwdDeclarationTemplateSpec;
2359 }
2360 if (retCode == 0)
2362 }
2363
2364
2365 // Loop on attributes, if rootmap=false, don't put it in the list!
2366 for (auto ait = rDecl->attr_begin(); ait != rDecl->attr_end(); ++ait) {
2368 attrName == "rootmap" &&
2369 attrValue == "false") {
2370 attrName = attrValue = "";
2371 isClassSelected = false;
2372 break;
2373 }
2374 }
2375 if (isClassSelected) {
2376 // Now, check if this is an internal class. If yes, we check the name of the outermost one
2377 // This is because of ROOT-6517. On the other hand, we exclude from this treatment
2378 // classes which are template instances which are nested in classes. For example:
2379 // class A{
2380 // class B{};
2381 // };
2382 // selection: <class name="A::B" />
2383 // Will result in a rootmap entry like "class A"
2384 // On the other hand, taking
2385 // class A{
2386 // public:
2387 // template <class T> class B{};
2388 // };
2389 // selection: <class name="A::B<int>" />
2390 // Would result in an entry like "class A::B<int>"
2391 std::string outerMostClassName;
2393 if (!outerMostClassName.empty() &&
2394 !llvm::isa<clang::ClassTemplateSpecializationDecl>(rDecl) &&
2395 classesSet.insert(outerMostClassName).second &&
2396 outerMostClassesSet.insert(outerMostClassName).second) {
2398 } else {
2400 if (reqName && reqName[0] && reqName != normalizedName) {
2401 classesListForRootmap.push_back(reqName);
2402 }
2403
2404 // Also register typeinfo::name(), unless we have pseudo-strong typedefs.
2405 // GetDemangledTypeInfo() checks for Double32_t etc already and returns an empty string.
2406 std::string demangledName = selClass.GetDemangledTypeInfo();
2407 if (!demangledName.empty()) {
2408 // See the operations in TCling::AutoLoad(type_info)
2411
2413 // if demangledName != other name
2415 }
2416 }
2417 }
2418 }
2419 }
2420 classesListForRootmap.sort();
2421
2422 // Disable for the moment
2423 // fwdDeclarationsList = CollapseIdenticalNamespaces(fwdDeclarationsList);
2424
2425 return 0;
2426}
2427
2428////////////////////////////////////////////////////////////////////////////////
2429/// Loop on selected classes and put them in a list
2430
2431void ExtractSelectedNamespaces(RScanner &scan, std::list<std::string> &nsList)
2432{
2433 for (RScanner::NamespaceColl_t::const_iterator selNsIter = scan.fSelectedNamespaces.begin();
2434 selNsIter != scan.fSelectedNamespaces.end(); ++selNsIter) {
2435 nsList.push_back(ROOT::TMetaUtils::GetQualifiedName(* selNsIter->GetNamespaceDecl()));
2436 }
2437}
2438
2439////////////////////////////////////////////////////////////////////////////////
2440/// We need annotations even in the PCH: // !, // || etc.
2441
2442void AnnotateAllDeclsForPCH(cling::Interpreter &interp,
2443 RScanner &scan)
2444{
2445 auto const & declSelRulesMap = scan.GetDeclsSelRulesMap();
2446 for (auto const & selClass : scan.fSelectedClasses) {
2447 // Very important: here we decide if we want to attach attributes to the decl.
2448 if (clang::CXXRecordDecl *CXXRD =
2449 llvm::dyn_cast<clang::CXXRecordDecl>(const_cast<clang::RecordDecl *>(selClass.GetRecordDecl()))) {
2451 }
2452 }
2453}
2454
2455////////////////////////////////////////////////////////////////////////////////
2456
2458 RScanner &scan)
2459{
2460 for (auto const & selClass : scan.fSelectedClasses) {
2461 if (!selClass.GetRecordDecl()->isCompleteDefinition() || selClass.RequestOnlyTClass()) {
2462 continue;
2463 }
2464 const clang::CXXRecordDecl *cxxdecl = llvm::dyn_cast<clang::CXXRecordDecl>(selClass.GetRecordDecl());
2466 ROOT::TMetaUtils::Error("CheckClassesForInterpreterOnlyDicts",
2467 "Interactivity only dictionaries are not supported for classes with ClassDef\n");
2468 return 1;
2469 }
2470 }
2471 return 0;
2472}
2473
2474////////////////////////////////////////////////////////////////////////////////
2475/// Make up for skipping RegisterModule, now that dictionary parsing
2476/// is done and these headers cannot be selected anymore.
2477
2478int FinalizeStreamerInfoWriting(cling::Interpreter &interp, bool writeEmptyRootPCM=false)
2479{
2480 if (!gDriverConfig->fCloseStreamerInfoROOTFile)
2481 return 0;
2482
2483 if (interp.parseForModule("#include \"TStreamerInfo.h\"\n"
2484 "#include \"TFile.h\"\n"
2485 "#include \"TObjArray.h\"\n"
2486 "#include \"TVirtualArray.h\"\n"
2487 "#include \"TStreamerElement.h\"\n"
2488 "#include \"TProtoClass.h\"\n"
2489 "#include \"TBaseClass.h\"\n"
2490 "#include \"TListOfDataMembers.h\"\n"
2491 "#include \"TListOfEnums.h\"\n"
2492 "#include \"TListOfEnumsWithLock.h\"\n"
2493 "#include \"TDataMember.h\"\n"
2494 "#include \"TEnum.h\"\n"
2495 "#include \"TEnumConstant.h\"\n"
2496 "#include \"TDictAttributeMap.h\"\n"
2497 "#include \"TMessageHandler.h\"\n"
2498 "#include \"TArray.h\"\n"
2499 "#include \"TRefArray.h\"\n"
2500 "#include \"root_std_complex.h\"\n")
2501 != cling::Interpreter::kSuccess)
2502 return 1;
2503 if (!gDriverConfig->fCloseStreamerInfoROOTFile(writeEmptyRootPCM)) {
2504 return 1;
2505 }
2506 return 0;
2507}
2508
2509////////////////////////////////////////////////////////////////////////////////
2510
2511int GenerateFullDict(std::ostream &dictStream, std::string dictName, cling::Interpreter &interp, RScanner &scan,
2513 bool isSelXML, bool writeEmptyRootPCM)
2514{
2516
2517 bool needsCollectionProxy = false;
2518
2519 //
2520 // We will loop over all the classes several times.
2521 // In order we will call
2522 //
2523 // WriteClassInit (code to create the TGenericClassInfo)
2524 // check for constructor and operator input
2525 // WriteClassFunctions (declared in ClassDef)
2526 // WriteClassCode (Streamer,ShowMembers,Auxiliary functions)
2527 //
2528
2529
2530 //
2531 // Loop over all classes and create Streamer() & Showmembers() methods
2532 //
2533
2534 // SELECTION LOOP
2535 for (auto const & ns : scan.fSelectedNamespaces) {
2537 auto nsName = ns.GetNamespaceDecl()->getQualifiedNameAsString();
2538 if (nsName.find("(anonymous)") == std::string::npos)
2539 EmitStreamerInfo(nsName.c_str());
2540 }
2541
2542 for (auto const & selClass : scan.fSelectedClasses) {
2543 if (!selClass.GetRecordDecl()->isCompleteDefinition()) {
2544 ROOT::TMetaUtils::Error(nullptr, "A dictionary has been requested for %s but there is no declaration!\n", ROOT::TMetaUtils::GetQualifiedName(selClass).c_str());
2545 continue;
2546 }
2547 if (selClass.RequestOnlyTClass()) {
2548 // fprintf(stderr,"rootcling: Skipping class %s\n",R__GetQualifiedName(* selClass.GetRecordDecl()).c_str());
2549 // For now delay those for later.
2550 continue;
2551 }
2552
2553 // Very important: here we decide if we want to attach attributes to the decl.
2554
2555 if (clang::CXXRecordDecl *CXXRD =
2556 llvm::dyn_cast<clang::CXXRecordDecl>(const_cast<clang::RecordDecl *>(selClass.GetRecordDecl()))) {
2558 }
2559
2560 const clang::CXXRecordDecl *CRD = llvm::dyn_cast<clang::CXXRecordDecl>(selClass.GetRecordDecl());
2561
2562 if (CRD) {
2563 ROOT::TMetaUtils::Info(nullptr, "Generating code for class %s\n", selClass.GetNormalizedName());
2564 if (TMetaUtils::IsStdClass(*CRD) && 0 != TClassEdit::STLKind(CRD->getName().str() /* unqualified name without template argument */)) {
2565 // Register the collections
2566 // coverity[fun_call_w_exception] - that's just fine.
2567 Internal::RStl::Instance().GenerateTClassFor(selClass.GetNormalizedName(), CRD, interp, normCtxt);
2568 } else if (CRD->getName() == "RVec") {
2569 static const clang::DeclContext *vecOpsDC = nullptr;
2570 if (!vecOpsDC)
2571 vecOpsDC = llvm::dyn_cast<clang::DeclContext>(
2572 interp.getLookupHelper().findScope("ROOT::VecOps", cling::LookupHelper::NoDiagnostics));
2573 if (vecOpsDC && vecOpsDC->Equals(CRD->getDeclContext())) {
2574 // Register the collections
2575 // coverity[fun_call_w_exception] - that's just fine.
2576 Internal::RStl::Instance().GenerateTClassFor(selClass.GetNormalizedName(), CRD, interp, normCtxt);
2577 }
2578 } else {
2581 EmitStreamerInfo(selClass.GetNormalizedName());
2582 }
2583 }
2584 }
2585
2586 //
2587 // Write all TBuffer &operator>>(...), Class_Name(), Dictionary(), etc.
2588 // first to allow template specialisation to occur before template
2589 // instantiation (STK)
2590 //
2591 // SELECTION LOOP
2592 for (auto const & selClass : scan.fSelectedClasses) {
2593
2594 if (!selClass.GetRecordDecl()->isCompleteDefinition() || selClass.RequestOnlyTClass()) {
2595 // For now delay those for later.
2596 continue;
2597 }
2598 const clang::CXXRecordDecl *cxxdecl = llvm::dyn_cast<clang::CXXRecordDecl>(selClass.GetRecordDecl());
2601 }
2602 }
2603
2604 // LINKDEF SELECTION LOOP
2605 // Loop to get the shadow class for the class marked 'RequestOnlyTClass' (but not the
2606 // STL class which is done via Internal::RStl::Instance().WriteClassInit(0);
2607 // and the ClassInit
2608
2609 for (auto const & selClass : scan.fSelectedClasses) {
2610 if (!selClass.GetRecordDecl()->isCompleteDefinition() || !selClass.RequestOnlyTClass()) {
2611 continue;
2612 }
2613
2614 const clang::CXXRecordDecl *CRD = llvm::dyn_cast<clang::CXXRecordDecl>(selClass.GetRecordDecl());
2615
2619 EmitStreamerInfo(selClass.GetNormalizedName());
2620 }
2621 }
2622 // Loop to write all the ClassCode
2623 for (auto const &selClass : scan.fSelectedClasses) {
2624 // The "isGenreflex" parameter allows the distinction between
2625 // genreflex and rootcling only for the treatment of collections which
2626 // are data members. To preserve the behaviour of the original
2627 // genreflex and rootcling tools, if the selection is performed with
2628 // genreflex, data members with collection type do not trigger the
2629 // selection of the collection type
2631 isGenreflex);
2632 }
2633
2634 // Loop on the registered collections internally
2635 // coverity[fun_call_w_exception] - that's just fine.
2638
2639 std::vector<std::string> standaloneTargets;
2643
2644 if (!gDriverConfig->fBuildingROOTStage1) {
2647 // Make up for skipping RegisterModule, now that dictionary parsing
2648 // is done and these headers cannot be selected anymore.
2650 if (finRetCode != 0) return finRetCode;
2651 }
2652
2653 return 0;
2654}
2655
2656////////////////////////////////////////////////////////////////////////////////
2657
2658void CreateDictHeader(std::ostream &dictStream, const std::string &main_dictname)
2659{
2660 dictStream << "// Do NOT change. Changes will be lost next time file is generated\n\n"
2661 << "#define R__DICTIONARY_FILENAME " << main_dictname << std::endl
2662
2663 // We do not want deprecation warnings to fire in dictionaries
2664 << "#define R__NO_DEPRECATION" << std::endl
2665
2666 // Now that CINT is not longer there to write the header file,
2667 // write one and include in there a few things for backward
2668 // compatibility.
2669 << "\n/*******************************************************************/\n"
2670 << "#include <cstddef>\n"
2671 << "#include <cstdio>\n"
2672 << "#include <cstdlib>\n"
2673 << "#include <cstring>\n"
2674 << "#include <cassert>\n"
2675 << "#define G__DICTIONARY\n"
2676 << "#include \"ROOT/RConfig.hxx\"\n"
2677 << "#include \"TClass.h\"\n"
2678 << "#include \"TDictAttributeMap.h\"\n"
2679 << "#include \"TInterpreter.h\"\n"
2680 << "#include \"TROOT.h\"\n"
2681 << "#include \"TBuffer.h\"\n"
2682 << "#include \"TMemberInspector.h\"\n"
2683 << "#include \"TInterpreter.h\"\n"
2684 << "#include \"TVirtualMutex.h\"\n"
2685 << "#include \"TError.h\"\n\n"
2686 << "#ifndef G__ROOT\n"
2687 << "#define G__ROOT\n"
2688 << "#endif\n\n"
2689 << "#include \"RtypesImp.h\"\n"
2690 << "#include \"TIsAProxy.h\"\n"
2691 << "#include \"TFileMergeInfo.h\"\n"
2692 << "#include <algorithm>\n"
2693 << "#include \"TCollectionProxyInfo.h\"\n"
2694 << "/*******************************************************************/\n\n"
2695 << "#include \"TDataMember.h\"\n\n"; // To set their transiency
2696}
2697
2698////////////////////////////////////////////////////////////////////////////////
2699
2701{
2702 dictStream << "// The generated code does not explicitly qualify STL entities\n"
2703 << "namespace std {} using namespace std;\n\n";
2704}
2705
2706////////////////////////////////////////////////////////////////////////////////
2707
2709 const std::string &includeForSource,
2710 const std::string &extraIncludes)
2711{
2712 dictStream << "// Header files passed as explicit arguments\n"
2713 << includeForSource << std::endl
2714 << "// Header files passed via #pragma extra_include\n"
2715 << extraIncludes << std::endl;
2716}
2717
2718//______________________________________________________________________________
2719
2720// cross-compiling for iOS and iOS simulator (assumes host is Intel Mac OS X)
2721#if defined(R__IOSSIM) || defined(R__IOS)
2722#ifdef __x86_64__
2723#undef __x86_64__
2724#endif
2725#ifdef __i386__
2726#undef __i386__
2727#endif
2728#ifdef R__IOSSIM
2729#define __i386__ 1
2730#endif
2731#ifdef R__IOS
2732#define __arm__ 1
2733#endif
2734#endif
2735
2736////////////////////////////////////////////////////////////////////////////////
2737/// Little helper class to bookkeep the files names which we want to make
2738/// temporary.
2739
2741public:
2742 //______________________________________________
2744
2745 std::string getTmpFileName(const std::string &filename) {
2746 return filename + "_tmp_" + std::to_string(getpid());
2747 }
2748 /////////////////////////////////////////////////////////////////////////////
2749 /// Adds the name and the associated temp name to the catalog.
2750 /// Changes the name into the temp name
2751
2752 void addFileName(std::string &nameStr) {
2753 if (nameStr.empty()) return;
2754
2755 std::string tmpNameStr(getTmpFileName(nameStr));
2756
2757 // For brevity
2758 const char *name(nameStr.c_str());
2759 const char *tmpName(tmpNameStr.c_str());
2760
2761 m_names.push_back(nameStr);
2762 m_tempNames.push_back(tmpNameStr);
2763 ROOT::TMetaUtils::Info(nullptr, "File %s added to the tmp catalog.\n", name);
2764
2765 // This is to allow update of existing files
2766 if (0 == std::rename(name , tmpName)) {
2767 ROOT::TMetaUtils::Info(nullptr, "File %s existing. Preserved as %s.\n", name, tmpName);
2768 }
2769
2770 // To change the name to its tmp version
2772
2773 m_size++;
2774
2775 }
2776
2777 /////////////////////////////////////////////////////////////////////////////
2778
2779 int clean() {
2780 int retval = 0;
2781 // rename the temp files into the normal ones
2782 for (unsigned int i = 0; i < m_size; ++i) {
2783 const char *tmpName = m_tempNames[i].c_str();
2784 // Check if the file exists
2785 std::ifstream ifile(tmpName);
2786 if (!ifile)
2787 ROOT::TMetaUtils::Error(nullptr, "Cannot find %s!\n", tmpName);
2788 // Make sure the file is closed, mostly for Windows FS, also when
2789 // accessing it from a Linux VM via a shared folder
2790 if (ifile.is_open())
2791 ifile.close();
2792 if (0 != std::remove(tmpName)) {
2793 ROOT::TMetaUtils::Error(nullptr, "Removing %s!\n", tmpName);
2794 retval++;
2795 }
2796 }
2797 return retval;
2798 }
2799
2800 /////////////////////////////////////////////////////////////////////////////
2801
2802 int commit() {
2803 int retval = 0;
2804 // rename the temp files into the normal ones
2805 for (unsigned int i = 0; i < m_size; ++i) {
2806 const char *tmpName = m_tempNames[i].c_str();
2807 const char *name = m_names[i].c_str();
2808 // Check if the file exists
2809 std::ifstream ifile(tmpName);
2810 if (!ifile)
2811 ROOT::TMetaUtils::Error(nullptr, "Cannot find %s!\n", tmpName);
2812 // Make sure the file is closed, mostly for Windows FS, also when
2813 // accessing it from a Linux VM via a shared folder
2814 if (ifile.is_open())
2815 ifile.close();
2816#ifdef WIN32
2817 // Sometimes files cannot be renamed on Windows if they don't have
2818 // been released by the system. So just copy them and try to delete
2819 // the old one afterwards.
2820 if (0 != std::rename(tmpName , name)) {
2821 if (llvm::sys::fs::copy_file(tmpName , name)) {
2822 llvm::sys::fs::remove(tmpName);
2823 }
2824 }
2825#else
2826 if (0 != std::rename(tmpName , name)) {
2827 ROOT::TMetaUtils::Error(nullptr, "Renaming %s into %s!\n", tmpName, name);
2828 retval++;
2829 }
2830#endif
2831 }
2832 return retval;
2833 }
2834
2835 /////////////////////////////////////////////////////////////////////////////
2836
2837 const std::string &getFileName(const std::string &tmpFileName) {
2838 size_t i = std::distance(m_tempNames.begin(),
2839 find(m_tempNames.begin(), m_tempNames.end(), tmpFileName));
2840 if (i == m_tempNames.size()) return m_emptyString;
2841 return m_names[i];
2842 }
2843
2844 /////////////////////////////////////////////////////////////////////////////
2845
2846 void dump() {
2847 std::cout << "Restoring files in temporary file catalog:\n";
2848 for (unsigned int i = 0; i < m_size; ++i) {
2849 std::cout << m_tempNames[i] << " --> " << m_names[i] << std::endl;
2850 }
2851 }
2852
2853private:
2854 unsigned int m_size;
2855 const std::string m_emptyString;
2856 std::vector<std::string> m_names;
2857 std::vector<std::string> m_tempNames;
2858};
2859
2860////////////////////////////////////////////////////////////////////////////////
2861/// Transform name of dictionary
2862
2863std::ostream *CreateStreamPtrForSplitDict(const std::string &dictpathname,
2865{
2866 std::string splitDictName(tmpCatalog.getFileName(dictpathname));
2867 const size_t dotPos = splitDictName.find_last_of(".");
2868 splitDictName.insert(dotPos, "_classdef");
2869 tmpCatalog.addFileName(splitDictName);
2870 return new std::ofstream(splitDictName.c_str());
2871}
2872
2873////////////////////////////////////////////////////////////////////////////////
2874/// Transform -W statements in diagnostic pragmas for cling reacting on "-Wno-"
2875/// For example
2876/// -Wno-deprecated-declarations --> `#pragma clang diagnostic ignored "-Wdeprecated-declarations"`
2877
2878static void CheckForMinusW(std::string arg,
2879 std::list<std::string> &diagnosticPragmas)
2880{
2881 static const std::string pattern("-Wno-");
2882
2883 if (arg.find(pattern) != 0)
2884 return;
2885
2886 ROOT::TMetaUtils::ReplaceAll(arg, pattern, "#pragma clang diagnostic ignored \"-W");
2887 arg += "\"";
2888 diagnosticPragmas.push_back(arg);
2889}
2890
2891////////////////////////////////////////////////////////////////////////////////
2892
2894 cling::Interpreter &interp)
2895{
2896 using namespace ROOT::TMetaUtils::AST2SourceTools;
2897 std::string fwdDecl;
2898 std::string initStr("{");
2899 auto &fwdDeclnArgsToSkipColl = normCtxt.GetTemplNargsToKeepMap();
2901 auto &clTemplDecl = *strigNargsToKeepPair.first;
2902 FwdDeclFromTmplDecl(clTemplDecl , interp, fwdDecl);
2903 initStr += "{\"" +
2904 fwdDecl + "\", "
2905 + std::to_string(strigNargsToKeepPair.second)
2906 + "},";
2907 }
2908 if (!fwdDeclnArgsToSkipColl.empty())
2909 initStr.pop_back();
2910 initStr += "}";
2911 return initStr;
2912}
2913
2914////////////////////////////////////////////////////////////////////////////////
2915/// Get the pointee type if possible
2916
2917clang::QualType GetPointeeTypeIfPossible(const clang::QualType &qt)
2918{
2919 if (qt.isNull()) return qt;
2920 clang::QualType thisQt(qt);
2921 while (thisQt->isPointerType() ||
2922 thisQt->isReferenceType()) {
2923 thisQt = thisQt->getPointeeType();
2924 }
2925 return thisQt;
2926
2927}
2928
2929////////////////////////////////////////////////////////////////////////////////
2930/// Extract the list of headers necessary for the Decl
2931
2932std::list<std::string> RecordDecl2Headers(const clang::CXXRecordDecl &rcd,
2933 const cling::Interpreter &interp,
2934 std::set<const clang::CXXRecordDecl *> &visitedDecls)
2935{
2936 std::list<std::string> headers;
2937
2938 // We push a new transaction because we could deserialize decls here
2939 cling::Interpreter::PushTransactionRAII RAII(&interp);
2940
2941 // Avoid infinite recursion
2942 if (!visitedDecls.insert(rcd.getCanonicalDecl()).second)
2943 return headers;
2944
2945 // If this is a template
2946 if (const clang::ClassTemplateSpecializationDecl *tsd = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(&rcd)) {
2947
2948 // Loop on the template args
2949 for (auto & tArg : tsd->getTemplateArgs().asArray()) {
2950 if (clang::TemplateArgument::ArgKind::Type != tArg.getKind()) continue;
2951 auto tArgQualType = GetPointeeTypeIfPossible(tArg.getAsType());
2952 if (tArgQualType.isNull()) continue;
2953 if (const clang::CXXRecordDecl *tArgCxxRcd = tArgQualType->getAsCXXRecordDecl()) {
2955 }
2956 }
2957
2958 if (!ROOT::TMetaUtils::IsStdClass(rcd) && rcd.hasDefinition()) {
2959
2960 // Loop on base classes - with a newer llvm, range based possible
2961 for (auto baseIt = tsd->bases_begin(); baseIt != tsd->bases_end(); baseIt++) {
2962 auto baseQualType = GetPointeeTypeIfPossible(baseIt->getType());
2963 if (baseQualType.isNull()) continue;
2964 if (const clang::CXXRecordDecl *baseRcdPtr = baseQualType->getAsCXXRecordDecl()) {
2966 }
2967 }
2968
2969 // Loop on the data members - with a newer llvm, range based possible
2970 for (auto declIt = tsd->decls_begin(); declIt != tsd->decls_end(); ++declIt) {
2971 if (const clang::FieldDecl *fieldDecl = llvm::dyn_cast<clang::FieldDecl>(*declIt)) {
2973 if (fieldQualType.isNull()) continue ;
2974 if (const clang::CXXRecordDecl *fieldCxxRcd = fieldQualType->getAsCXXRecordDecl()) {
2975 if (fieldCxxRcd->hasDefinition())
2977 }
2978 }
2979 }
2980
2981 // Loop on methods
2982 for (auto methodIt = tsd->method_begin(); methodIt != tsd->method_end(); ++methodIt) {
2983 // Check arguments
2984 for (auto & fPar : methodIt->parameters()) {
2985 auto fParQualType = GetPointeeTypeIfPossible(fPar->getOriginalType());
2986 if (fParQualType.isNull()) continue;
2987 if (const clang::CXXRecordDecl *fParCxxRcd = fParQualType->getAsCXXRecordDecl()) {
2988 if (fParCxxRcd->hasDefinition())
2990 }
2991 }
2992 // Check return value
2993 auto retQualType = GetPointeeTypeIfPossible(methodIt->getReturnType());
2994 if (retQualType.isNull()) continue;
2995 if (const clang::CXXRecordDecl *retCxxRcd = retQualType->getAsCXXRecordDecl()) {
2996 if (retCxxRcd->hasDefinition())
2998 }
2999 }
3000 }
3001
3002 } // End template instance
3003
3004 std::string header = ROOT::TMetaUtils::GetFileName(rcd, interp);
3005 headers.emplace_back(header);
3006 headers.reverse();
3007 return headers;
3008
3009}
3010
3011////////////////////////////////////////////////////////////////////////////////
3012/// Check if the class good for being an autoparse key.
3013/// We exclude from this set stl containers of pods/strings
3014/// TODO: we may use also __gnu_cxx::
3015bool IsGoodForAutoParseMap(const clang::RecordDecl& rcd){
3016
3017 // If it's not an std class, we just pick it up.
3018 if (auto dclCtxt= rcd.getDeclContext()){
3019 if (! dclCtxt->isStdNamespace()){
3020 return true;
3021 }
3022 } else {
3023 return true;
3024 }
3025
3026 // Now, we have a stl class. We now check if it's a template. If not, we
3027 // do not take it: bitset, string and so on.
3028 auto clAsTmplSpecDecl = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(&rcd);
3029 if (!clAsTmplSpecDecl) return false;
3030
3031 // Now we have a template in the stl. Let's see what the arguments are.
3032 // If they are not a POD or something which is good for autoparsing, we keep
3033 // them.
3034 auto& astCtxt = rcd.getASTContext();
3035 auto& templInstArgs = clAsTmplSpecDecl->getTemplateInstantiationArgs();
3036 for (auto&& arg : templInstArgs.asArray()){
3037
3038 auto argKind = arg.getKind();
3039 if (argKind != clang::TemplateArgument::Type){
3040 if (argKind == clang::TemplateArgument::Integral) continue;
3041 else return true;
3042 }
3043
3044 auto argQualType = arg.getAsType();
3045 auto isPOD = argQualType.isPODType(astCtxt);
3046 // This is a POD, we can inspect the next arg
3047 if (isPOD) continue;
3048
3049 auto argType = argQualType.getTypePtr();
3050 if (auto recType = llvm::dyn_cast<clang::RecordType>(argType)){
3052 // The arg is a class but good for the map
3053 if (isArgGoodForAutoParseMap) continue;
3054 } else {
3055 // The class is not a POD nor a class we can skip
3056 return true;
3057 }
3058 }
3059
3060 return false;
3061}
3062
3063////////////////////////////////////////////////////////////////////////////////
3064
3072 const cling::Interpreter &interp)
3073{
3074 std::set<const clang::CXXRecordDecl *> visitedDecls;
3075 std::unordered_set<std::string> buffer;
3076 std::string autoParseKey;
3077
3078 // Add some manip of headers
3079 for (auto & annotatedRcd : annotatedRcds) {
3080 if (const clang::CXXRecordDecl *cxxRcd =
3081 llvm::dyn_cast_or_null<clang::CXXRecordDecl>(annotatedRcd.GetRecordDecl())) {
3082 autoParseKey = "";
3083 visitedDecls.clear();
3084 std::list<std::string> headers(RecordDecl2Headers(*cxxRcd, interp, visitedDecls));
3085 // remove duplicates, also if not subsequent
3086 buffer.clear();
3087 headers.remove_if([&buffer](const std::string & s) {
3088 return !buffer.insert(s).second;
3089 });
3091 if (autoParseKey.empty()) autoParseKey = annotatedRcd.GetNormalizedName();
3094 headersDeclsMap[annotatedRcd.GetRequestedName()] = headers;
3095 } else {
3096 ROOT::TMetaUtils::Info(nullptr, "Class %s is not included in the set of autoparse keys.\n", autoParseKey.c_str());
3097 }
3098
3099 // Propagate to the classes map only if this is not a template.
3100 // The header is then used as autoload key and we want to avoid duplicates.
3101 if (!llvm::isa<clang::ClassTemplateSpecializationDecl>(cxxRcd)){
3103 headersClassesMap[annotatedRcd.GetRequestedName()] = headersDeclsMap[annotatedRcd.GetRequestedName()];
3104 }
3105 }
3106 }
3107
3108 // The same for the typedefs:
3109 for (auto & tDef : tDefDecls) {
3110 if (clang::CXXRecordDecl *cxxRcd = tDef->getUnderlyingType()->getAsCXXRecordDecl()) {
3111 autoParseKey = "";
3112 visitedDecls.clear();
3113 std::list<std::string> headers(RecordDecl2Headers(*cxxRcd, interp, visitedDecls));
3115 // remove duplicates, also if not subsequent
3116 buffer.clear();
3117 headers.remove_if([&buffer](const std::string & s) {
3118 return !buffer.insert(s).second;
3119 });
3121 if (autoParseKey.empty()) autoParseKey = tDef->getQualifiedNameAsString();
3123 }
3124 }
3125
3126 // The same for the functions:
3127 for (auto & func : funcDecls) {
3128 std::list<std::string> headers = {ROOT::TMetaUtils::GetFileName(*func, interp)};
3130 }
3131
3132 // The same for the variables:
3133 for (auto & var : varDecls) {
3134 std::list<std::string> headers = {ROOT::TMetaUtils::GetFileName(*var, interp)};
3136 }
3137
3138 // The same for the enums:
3139 for (auto & en : enumDecls) {
3140 std::list<std::string> headers = {ROOT::TMetaUtils::GetFileName(*en, interp)};
3142 }
3143}
3144
3145////////////////////////////////////////////////////////////////////////////////
3146/// Generate the fwd declarations of the selected entities
3147
3148static std::string GenerateFwdDeclString(const RScanner &scan,
3149 const cling::Interpreter &interp)
3150{
3151 std::string newFwdDeclString;
3152
3153 using namespace ROOT::TMetaUtils::AST2SourceTools;
3154
3155 std::string fwdDeclString;
3156 std::string buffer;
3157 std::unordered_set<std::string> fwdDecls;
3158
3159 // Classes
3160/*
3161 for (auto const & annRcd : scan.fSelectedClasses) {
3162 const auto rcdDeclPtr = annRcd.GetRecordDecl();
3163
3164 int retCode = FwdDeclFromRcdDecl(*rcdDeclPtr, interp, buffer);
3165 if (-1 == retCode) {
3166 ROOT::TMetaUtils::Error("GenerateFwdDeclString",
3167 "Error generating fwd decl for class %s\n",
3168 annRcd.GetNormalizedName());
3169 return emptyString;
3170 }
3171 if (retCode == 0 && fwdDecls.insert(buffer).second)
3172 fwdDeclString += "\"" + buffer + "\"\n";
3173 }
3174*/
3175 // Build the input for a transaction containing all of the selected declarations
3176 // Cling will produce the fwd declaration payload.
3177
3178 std::vector<const clang::Decl *> selectedDecls(scan.fSelectedClasses.size());
3179
3180 // Pick only RecordDecls
3181 std::transform (scan.fSelectedClasses.begin(),
3182 scan.fSelectedClasses.end(),
3184 [](const ROOT::TMetaUtils::AnnotatedRecordDecl& rcd){return rcd.GetRecordDecl();});
3185
3186 for (auto* TD: scan.fSelectedTypedefs)
3187 selectedDecls.push_back(TD);
3188
3189// for (auto* VAR: scan.fSelectedVariables)
3190// selectedDecls.push_back(VAR);
3191
3192 std::string fwdDeclLogs;
3193
3194 // The "R\"DICTFWDDCLS(\n" ")DICTFWDDCLS\"" pieces have been moved to
3195 // TModuleGenerator to be able to make the diagnostics more telling in presence
3196 // of an issue ROOT-6752.
3198
3199 if (genreflex::verbose && !fwdDeclLogs.empty())
3200 std::cout << "Logs from forward decl printer: \n"
3201 << fwdDeclLogs;
3202
3203 // Functions
3204// for (auto const& fcnDeclPtr : scan.fSelectedFunctions){
3205// int retCode = FwdDeclFromFcnDecl(*fcnDeclPtr, interp, buffer);
3206// newFwdDeclString += Decl2FwdDecl(*fcnDeclPtr,interp);
3207// if (-1 == retCode){
3208// ROOT::TMetaUtils::Error("GenerateFwdDeclString",
3209// "Error generating fwd decl for function %s\n",
3210// fcnDeclPtr->getNameAsString().c_str());
3211// return emptyString;
3212// }
3213// if (retCode == 0 && fwdDecls.insert(buffer).second)
3214// fwdDeclString+="\""+buffer+"\"\n";
3215// }
3216
3217 if (fwdDeclString.empty()) fwdDeclString = "";
3218 return fwdDeclString;
3219}
3220
3221////////////////////////////////////////////////////////////////////////////////
3222/// Generate a string for the dictionary from the headers-classes map.
3223
3225 const std::string &detectedUmbrella,
3226 bool payLoadOnly = false)
3227{
3228 std::string headerName;
3229
3231 std::cout << "Class-headers Mapping:\n";
3232 std::string headersClassesMapString = "";
3233 for (auto const & classHeaders : headersClassesMap) {
3235 std::cout << " o " << classHeaders.first << " --> ";
3237 headersClassesMapString += classHeaders.first + "\"";
3238 for (auto const & header : classHeaders.second) {
3239 headerName = (detectedUmbrella == header || payLoadOnly) ? "payloadCode" : "\"" + header + "\"";
3242 std::cout << ", " << headerName;
3243 if (payLoadOnly)
3244 break;
3245 }
3247 std::cout << std::endl;
3248 headersClassesMapString += ", \"@\",\n";
3249 }
3250 headersClassesMapString += "nullptr";
3252}
3253
3254////////////////////////////////////////////////////////////////////////////////
3255
3256bool IsImplementationName(const std::string &filename)
3257{
3259}
3260
3261////////////////////////////////////////////////////////////////////////////////
3262/// Check if the argument is a sane cling argument. Performing the following checks:
3263/// 1) It does not start with "--" and is not the --param option.
3264
3265bool IsCorrectClingArgument(const std::string& argument)
3266{
3267 if (ROOT::TMetaUtils::BeginsWith(argument,"--") && !ROOT::TMetaUtils::BeginsWith(argument,"--param")) return false;
3268 return true;
3269}
3270
3271////////////////////////////////////////////////////////////////////////////////
3272bool NeedsSelection(const char* name)
3273{
3274 static const std::vector<std::string> namePrfxes {
3275 "array<",
3276 "unique_ptr<"};
3277 auto pos = find_if(namePrfxes.begin(),
3278 namePrfxes.end(),
3279 [&](const std::string& str){return ROOT::TMetaUtils::BeginsWith(name,str);});
3280 return namePrfxes.end() == pos;
3281}
3282
3283////////////////////////////////////////////////////////////////////////////////
3284
3286{
3287 static const std::vector<std::string> uclNamePrfxes {
3288 "chrono:",
3289 "ratio<",
3290 "shared_ptr<"};
3291 static const std::set<std::string> unsupportedClassesNormNames{
3292 "regex",
3293 "thread"};
3294 if ( unsupportedClassesNormNames.count(name) == 1) return false;
3295 auto pos = find_if(uclNamePrfxes.begin(),
3297 [&](const std::string& str){return ROOT::TMetaUtils::BeginsWith(name,str);});
3298 return uclNamePrfxes.end() == pos;
3299}
3300
3301////////////////////////////////////////////////////////////////////////////////
3302/// Check if the list of selected classes contains any class which is not
3303/// supported. Return the number of unsupported classes in the selection.
3304
3306{
3307 int nerrors = 0;
3308 for (auto&& aRcd : annotatedRcds){
3309 auto clName = aRcd.GetNormalizedName();
3311 std::cerr << "Error: Class " << clName << " has been selected but "
3312 << "currently the support for its I/O is not yet available. Note that "
3313 << clName << ", even if not selected, will be available for "
3314 << "interpreted code.\n";
3315 nerrors++;
3316 }
3317 if (!NeedsSelection(clName)){
3318 std::cerr << "Error: It is not necessary to explicitly select class "
3319 << clName << ". I/O is supported for it transparently.\n";
3320 nerrors++;
3321 }
3322 }
3323 return nerrors;
3324}
3325
3326////////////////////////////////////////////////////////////////////////////////
3327
3328class TRootClingCallbacks : public cling::InterpreterCallbacks {
3329private:
3330 std::list<std::string>& fFilesIncludedByLinkdef;
3331 bool isLocked = false;
3332public:
3333 TRootClingCallbacks(cling::Interpreter* interp, std::list<std::string>& filesIncludedByLinkdef):
3334 InterpreterCallbacks(interp),
3336
3338
3339 void InclusionDirective(clang::SourceLocation /*HashLoc*/, const clang::Token & /*IncludeTok*/,
3340 llvm::StringRef FileName, bool IsAngled, clang::CharSourceRange /*FilenameRange*/,
3341 clang::OptionalFileEntryRef /*File*/, llvm::StringRef /*SearchPath*/,
3342 llvm::StringRef /*RelativePath*/, const clang::Module * /*Imported*/, bool /*ModuleImported*/,
3343 clang::SrcMgr::CharacteristicKind /*FileType*/) override
3344 {
3345 if (isLocked) return;
3346 if (IsAngled) return;
3347 auto& PP = m_Interpreter->getCI()->getPreprocessor();
3348 auto curLexer = PP.getCurrentFileLexer();
3349 if (!curLexer) return;
3350 auto fileEntry = curLexer->getFileEntry();
3351 if (!fileEntry) return;
3352 auto thisFileName = fileEntry->getName();
3353 auto fileNameAsString = FileName.str();
3355 if (isThisLinkdef) {
3359 isLocked = true;
3360 } else {
3361 fFilesIncludedByLinkdef.emplace_back(fileNameAsString.c_str());
3362 }
3363 }
3364 }
3365
3366 // rootcling pre-includes things such as Rtypes.h. This means that ACLiC can
3367 // call rootcling asking it to create a module for a file with no #includes
3368 // but relying on things from Rtypes.h such as the ClassDef macro.
3369 //
3370 // When rootcling starts building a module, it becomes resilient to the
3371 // outside environment and pre-included files have no effect. This hook
3372 // informs rootcling when a new submodule is being built so that it can
3373 // make Core.Rtypes.h visible.
3374 void EnteredSubmodule(clang::Module* M,
3375 clang::SourceLocation ImportLoc,
3376 bool ForPragma) override {
3377 assert(M);
3378 using namespace clang;
3379 if (llvm::StringRef(M->Name).ends_with("ACLiC_dict")) {
3380 Preprocessor& PP = m_Interpreter->getCI()->getPreprocessor();
3381 HeaderSearch& HS = PP.getHeaderSearchInfo();
3382 // FIXME: Reduce to Core.Rtypes.h.
3383 Module* CoreModule = HS.lookupModule("Core", SourceLocation(),
3384 /*AllowSearch*/false);
3385 assert(M && "Must have module Core");
3386 PP.makeModuleVisible(CoreModule, ImportLoc);
3387 }
3388 }
3389};
3390
3391static llvm::cl::opt<bool> gOptSystemModuleByproducts("mSystemByproducts", llvm::cl::Hidden,
3392 llvm::cl::desc("Allow implicit build of system modules."),
3393 llvm::cl::cat(gRootclingOptions));
3394static llvm::cl::list<std::string>
3395gOptModuleByproducts("mByproduct", llvm::cl::ZeroOrMore,
3396 llvm::cl::Hidden,
3397 llvm::cl::desc("The list of the expected implicit modules build as part of building the current module."),
3398 llvm::cl::cat(gRootclingOptions));
3399// Really llvm::cl::Required, will be changed in RootClingMain below.
3400static llvm::cl::opt<std::string>
3401gOptDictionaryFileName(llvm::cl::Positional,
3402 llvm::cl::desc("<output dictionary file>"),
3403 llvm::cl::cat(gRootclingOptions));
3404
3405////////////////////////////////////////////////////////////////////////////////
3406/// Custom diag client for clang that verifies that each implicitly build module
3407/// is a system module. If not, it will let the current rootcling invocation
3408/// fail with an error. All other diags beside module build remarks will be
3409/// forwarded to the passed child diag client.
3410///
3411/// The reason why we need this is that if we built implicitly a C++ module
3412/// that belongs to a ROOT dictionary, then we will miss information generated
3413/// by rootcling in this file (e.g. the source code comments to annotation
3414/// attributes transformation will be missing in the module file).
3415class CheckModuleBuildClient : public clang::DiagnosticConsumer {
3416 clang::DiagnosticConsumer *fChild;
3418 clang::ModuleMap &fMap;
3419
3420public:
3421 CheckModuleBuildClient(clang::DiagnosticConsumer *Child, bool OwnsChild, clang::ModuleMap &Map)
3423 {
3424 }
3425
3427 {
3428 if (fOwnsChild)
3429 delete fChild;
3430 }
3431
3432 void HandleDiagnostic(clang::DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &Info) override
3433 {
3434 using namespace clang::diag;
3435
3436 // This method catches the module_build remark from clang and checks if
3437 // the implicitly built module is a system module or not. We only support
3438 // building system modules implicitly.
3439
3440 std::string moduleName;
3441 const clang::Module *module = nullptr;
3442
3443 // Extract the module from the diag argument with index 0.
3444 const auto &ID = Info.getID();
3445 if (ID == remark_module_build || ID == remark_module_build_done) {
3446 moduleName = Info.getArgStdStr(0);
3447 module = fMap.findModule(moduleName);
3448 // We should never be able to build a module without having it in the
3449 // modulemap. Still, let's print a warning that we at least tell the
3450 // user that this could lead to problems.
3451 if (!module) {
3453 "Couldn't find module %s in the available modulemaps. This"
3454 "prevents us from correctly diagnosing wrongly built modules.\n",
3455 moduleName.c_str());
3456 }
3457 }
3458
3459 // A dictionary module could build implicitly a set of implicit modules.
3460 // For example, the Core module builds libc.pcm and std.pcm implicitly.
3461 // Those modules do not require I/O information and it is okay to build
3462 // them as part of another module.
3463 // However, we can build a module which requires I/O implictly which is
3464 // an error because rootcling is not able to generate the corresponding
3465 // dictionary.
3466 // If we build a I/O requiring module implicitly we should display
3467 // an error unless -mSystemByproducts or -mByproduct were specified.
3468 bool isByproductModule = false;
3469 if (module) {
3470 // -mSystemByproducts allows implicit building of any system module.
3471 if (module->IsSystem && gOptSystemModuleByproducts) {
3472 isByproductModule = true;
3473 }
3474 // -mByproduct lists concrete module names that are allowed.
3477 isByproductModule = true;
3478 }
3479 }
3480 if (!isByproductModule)
3481 fChild->HandleDiagnostic(DiagLevel, Info);
3482
3483 if (ID == remark_module_build && !isByproductModule) {
3485 "Building module '%s' implicitly. If '%s' requires a \n"
3486 "dictionary please specify build dependency: '%s' depends on '%s'.\n"
3487 "Otherwise, specify '-mByproduct %s' to disable this diagnostic.\n",
3488 moduleName.c_str(), moduleName.c_str(), gOptDictionaryFileName.c_str(),
3489 moduleName.c_str(), moduleName.c_str());
3490 }
3491 }
3492
3493 // All methods below just forward to the child and the default method.
3494 void clear() override
3495 {
3496 fChild->clear();
3497 DiagnosticConsumer::clear();
3498 }
3499
3500 void BeginSourceFile(const clang::LangOptions &LangOpts, const clang::Preprocessor *PP) override
3501 {
3502 fChild->BeginSourceFile(LangOpts, PP);
3503 DiagnosticConsumer::BeginSourceFile(LangOpts, PP);
3504 }
3505
3506 void EndSourceFile() override
3507 {
3508 fChild->EndSourceFile();
3509 DiagnosticConsumer::EndSourceFile();
3510 }
3511
3512 void finish() override
3513 {
3514 fChild->finish();
3515 DiagnosticConsumer::finish();
3516 }
3517
3518 bool IncludeInDiagnosticCounts() const override { return fChild->IncludeInDiagnosticCounts(); }
3519};
3520
3522#if defined(_WIN32) && defined(_MSC_VER)
3523 // Suppress error dialogs to avoid hangs on build nodes.
3524 // One can use an environment variable (Cling_GuiOnAssert) to enable
3525 // the error dialogs.
3526 const char *EnablePopups = std::getenv("Cling_GuiOnAssert");
3527 if (EnablePopups == nullptr || EnablePopups[0] == '0') {
3535 }
3536#endif
3537}
3538
3539static llvm::cl::opt<bool> gOptForce("f", llvm::cl::desc("Overwrite <file>s."),
3540 llvm::cl::cat(gRootclingOptions));
3541static llvm::cl::opt<bool> gOptRootBuild("rootbuild", llvm::cl::desc("If we are building ROOT."),
3542 llvm::cl::Hidden,
3543 llvm::cl::cat(gRootclingOptions));
3552static llvm::cl::opt<VerboseLevel>
3553gOptVerboseLevel(llvm::cl::desc("Choose verbosity level:"),
3554 llvm::cl::values(clEnumVal(v, "Show errors."),
3555 clEnumVal(v0, "Show only fatal errors."),
3556 clEnumVal(v1, "Show errors (the same as -v)."),
3557 clEnumVal(v2, "Show warnings (default)."),
3558 clEnumVal(v3, "Show notes."),
3559 clEnumVal(v4, "Show information.")),
3560 llvm::cl::init(v2),
3561 llvm::cl::cat(gRootclingOptions));
3562
3563static llvm::cl::opt<bool>
3564gOptCint("cint", llvm::cl::desc("Deprecated, legacy flag which is ignored."),
3565 llvm::cl::Hidden,
3566 llvm::cl::cat(gRootclingOptions));
3567static llvm::cl::opt<bool>
3568gOptReflex("reflex", llvm::cl::desc("Behave internally like genreflex."),
3569 llvm::cl::cat(gRootclingOptions));
3570static llvm::cl::opt<bool>
3571gOptGccXml("gccxml", llvm::cl::desc("Deprecated, legacy flag which is ignored."),
3572 llvm::cl::Hidden,
3573 llvm::cl::cat(gRootclingOptions));
3574static llvm::cl::opt<std::string>
3575gOptLibListPrefix("lib-list-prefix",
3576 llvm::cl::desc("An ACLiC feature which exports the list of dependent libraries."),
3577 llvm::cl::Hidden,
3578 llvm::cl::cat(gRootclingOptions));
3579static llvm::cl::opt<bool>
3580gOptGeneratePCH("generate-pch",
3581 llvm::cl::desc("Generates a pch file from a predefined set of headers. See makepch.py."),
3582 llvm::cl::Hidden,
3583 llvm::cl::cat(gRootclingOptions));
3584static llvm::cl::opt<bool>
3585gOptC("c", llvm::cl::desc("Deprecated, legacy flag which is ignored."),
3586 llvm::cl::cat(gRootclingOptions));
3587static llvm::cl::opt<bool>
3588gOptP("p", llvm::cl::desc("Deprecated, legacy flag which is ignored."),
3589 llvm::cl::cat(gRootclingOptions));
3590static llvm::cl::list<std::string>
3591gOptRootmapLibNames("rml", llvm::cl::ZeroOrMore,
3592 llvm::cl::desc("Generate rootmap file."),
3593 llvm::cl::cat(gRootclingOptions));
3594static llvm::cl::opt<std::string>
3596 llvm::cl::desc("Generate a rootmap file with the specified name."),
3597 llvm::cl::cat(gRootclingOptions));
3598static llvm::cl::opt<bool>
3599gOptCxxModule("cxxmodule",
3600 llvm::cl::desc("Generate a C++ module."),
3601 llvm::cl::cat(gRootclingOptions));
3602static llvm::cl::list<std::string>
3603gOptModuleMapFiles("moduleMapFile",
3604 llvm::cl::desc("Specify a C++ modulemap file."),
3605 llvm::cl::cat(gRootclingOptions));
3606// FIXME: Figure out how to combine the code of -umbrellaHeader and inlineInputHeader
3607static llvm::cl::opt<bool>
3608gOptUmbrellaInput("umbrellaHeader",
3609 llvm::cl::desc("A single header including all headers instead of specifying them on the command line."),
3610 llvm::cl::cat(gRootclingOptions));
3611static llvm::cl::opt<bool>
3612gOptMultiDict("multiDict",
3613 llvm::cl::desc("If this library has multiple separate LinkDef files."),
3614 llvm::cl::cat(gRootclingOptions));
3615static llvm::cl::opt<bool>
3616gOptNoGlobalUsingStd("noGlobalUsingStd",
3617 llvm::cl::desc("Do not declare {using namespace std} in dictionary global scope."),
3618 llvm::cl::cat(gRootclingOptions));
3619static llvm::cl::opt<bool>
3620gOptInterpreterOnly("interpreteronly",
3621 llvm::cl::desc("Generate minimal dictionary for interactivity (without IO information)."),
3622 llvm::cl::cat(gRootclingOptions));
3623static llvm::cl::opt<bool>
3625 llvm::cl::desc("Split the dictionary into two parts: one containing the IO (ClassDef)\
3626information and another the interactivity support."),
3627 llvm::cl::cat(gRootclingOptions));
3628static llvm::cl::opt<bool>
3629gOptNoDictSelection("noDictSelection",
3630 llvm::cl::Hidden,
3631 llvm::cl::desc("Do not run the selection rules. Useful when in -onepcm mode."),
3632 llvm::cl::cat(gRootclingOptions));
3633static llvm::cl::opt<std::string>
3635 llvm::cl::desc("The path to the library of the built dictionary."),
3636 llvm::cl::cat(gRootclingOptions));
3637static llvm::cl::list<std::string>
3639 llvm::cl::desc("The list of dependent modules of the dictionary."),
3640 llvm::cl::cat(gRootclingOptions));
3641static llvm::cl::list<std::string>
3642gOptExcludePaths("excludePath", llvm::cl::ZeroOrMore,
3643 llvm::cl::desc("Do not store the <path> in the dictionary."),
3644 llvm::cl::cat(gRootclingOptions));
3645// FIXME: This does not seem to work. We have one use of -inlineInputHeader in
3646// ROOT and it does not produce the expected result.
3647static llvm::cl::opt<bool>
3648gOptInlineInput("inlineInputHeader",
3649 llvm::cl::desc("Does not generate #include <header> but expands the header content."),
3650 llvm::cl::cat(gRootclingOptions));
3651// FIXME: This is totally the wrong concept. We should not expose an interface
3652// to be able to tell which component is in the pch and which needs extra
3653// scaffolding for interactive use. Moreover, some of the ROOT components are
3654// partially in the pch and this option makes it impossible to express that.
3655// We should be able to get the list of headers in the pch early and scan
3656// through them.
3657static llvm::cl::opt<bool>
3658gOptWriteEmptyRootPCM("writeEmptyRootPCM",
3659 llvm::cl::Hidden,
3660 llvm::cl::desc("Does not include the header files as it assumes they exist in the pch."),
3661 llvm::cl::cat(gRootclingOptions));
3662static llvm::cl::opt<bool>
3664 llvm::cl::desc("Check the selection syntax only."),
3665 llvm::cl::cat(gRootclingOptions));
3666static llvm::cl::opt<bool>
3667gOptFailOnWarnings("failOnWarnings",
3668 llvm::cl::desc("Fail if there are warnings."),
3669 llvm::cl::cat(gRootclingOptions));
3670static llvm::cl::opt<bool>
3671gOptNoIncludePaths("noIncludePaths",
3672 llvm::cl::desc("Do not store include paths but rely on the env variable ROOT_INCLUDE_PATH."),
3673 llvm::cl::cat(gRootclingOptions));
3674static llvm::cl::opt<std::string>
3675gOptISysRoot("isysroot", llvm::cl::Prefix, llvm::cl::Hidden,
3676 llvm::cl::desc("Specify an isysroot."),
3677 llvm::cl::cat(gRootclingOptions),
3678 llvm::cl::init("-"));
3679static llvm::cl::list<std::string>
3680gOptIncludePaths("I", llvm::cl::Prefix, llvm::cl::ZeroOrMore,
3681 llvm::cl::desc("Specify an include path."),
3682 llvm::cl::cat(gRootclingOptions));
3683static llvm::cl::list<std::string>
3684gOptCompDefaultIncludePaths("compilerI", llvm::cl::Prefix, llvm::cl::ZeroOrMore,
3685 llvm::cl::desc("Specify a compiler default include path, to suppress unneeded `-isystem` arguments."),
3686 llvm::cl::cat(gRootclingOptions));
3687static llvm::cl::list<std::string>
3688gOptSysIncludePaths("isystem", llvm::cl::ZeroOrMore,
3689 llvm::cl::desc("Specify a system include path."),
3690 llvm::cl::cat(gRootclingOptions));
3691static llvm::cl::list<std::string>
3692gOptPPDefines("D", llvm::cl::Prefix, llvm::cl::ZeroOrMore,
3693 llvm::cl::desc("Specify defined macros."),
3694 llvm::cl::cat(gRootclingOptions));
3695static llvm::cl::list<std::string>
3696gOptPPUndefines("U", llvm::cl::Prefix, llvm::cl::ZeroOrMore,
3697 llvm::cl::desc("Specify undefined macros."),
3698 llvm::cl::cat(gRootclingOptions));
3699static llvm::cl::list<std::string>
3700gOptWDiags("W", llvm::cl::Prefix, llvm::cl::ZeroOrMore,
3701 llvm::cl::desc("Specify compiler diagnostics options."),
3702 llvm::cl::cat(gRootclingOptions));
3703static llvm::cl::opt<std::string>
3705 llvm::cl::desc("Write dependency output to the specified file."),
3706 llvm::cl::cat(gRootclingOptions));
3707// Really OneOrMore, will be changed in RootClingMain below.
3708static llvm::cl::list<std::string>
3709gOptDictionaryHeaderFiles(llvm::cl::Positional, llvm::cl::ZeroOrMore,
3710 llvm::cl::desc("<list of dictionary header files> <LinkDef file | selection xml file>"),
3711 llvm::cl::cat(gRootclingOptions));
3712static llvm::cl::list<std::string>
3713gOptSink(llvm::cl::ZeroOrMore, llvm::cl::Sink,
3714 llvm::cl::desc("Consumes all unrecognized options."),
3715 llvm::cl::cat(gRootclingOptions));
3716
3717static llvm::cl::SubCommand
3718gBareClingSubcommand("bare-cling", "Call directly cling and exit.");
3719
3720static llvm::cl::list<std::string>
3721gOptBareClingSink(llvm::cl::OneOrMore, llvm::cl::Sink,
3722 llvm::cl::desc("Consumes options and sends them to cling."),
3723 llvm::cl::cat(gRootclingOptions), llvm::cl::sub(gBareClingSubcommand));
3724
3725////////////////////////////////////////////////////////////////////////////////
3726/// Returns true iff a given module (and its submodules) contains all headers
3727/// needed by the given ModuleGenerator.
3728/// The names of all header files that are needed by the ModuleGenerator but are
3729/// not in the given module will be inserted into the MissingHeader variable.
3730/// Returns true iff the PCH was successfully generated.
3732 clang::Module *module, std::vector<std::array<std::string, 2>> &missingHeaders)
3733{
3734 // Now we collect all header files from the previously collected modules.
3735 std::vector<clang::Module::Header> moduleHeaders;
3737 [&moduleHeaders](const clang::Module::Header &h) { moduleHeaders.push_back(h); });
3738
3739 bool foundAllHeaders = true;
3740
3741 auto isHeaderInModule = [&moduleHeaders](const std::string &header) {
3742 for (const clang::Module::Header &moduleHeader : moduleHeaders)
3743 if (header == moduleHeader.NameAsWritten)
3744 return true;
3745 return false;
3746 };
3747
3748 // Go through the list of headers that are required by the ModuleGenerator
3749 // and check for each header if it's in one of the modules we loaded.
3750 // If not, make sure we fail at the end and mark the header as missing.
3751 for (const std::string &header : modGen.GetHeaders()) {
3752 if (isHeaderInModule(header))
3753 continue;
3754
3755 clang::ModuleMap::KnownHeader SuggestedModule;
3756 clang::ConstSearchDirIterator *CurDir = nullptr;
3757 if (auto FE = headerSearch.LookupFile(
3758 header, clang::SourceLocation(),
3759 /*isAngled*/ false,
3760 /*FromDir*/ nullptr, CurDir,
3761 clang::ArrayRef<std::pair<clang::OptionalFileEntryRef, clang::DirectoryEntryRef>>(),
3762 /*SearchPath*/ nullptr,
3763 /*RelativePath*/ nullptr,
3764 /*RequestingModule*/ nullptr, &SuggestedModule,
3765 /*IsMapped*/ nullptr,
3766 /*IsFrameworkFound*/ nullptr,
3767 /*SkipCache*/ false,
3768 /*BuildSystemModule*/ false,
3769 /*OpenFile*/ false,
3770 /*CacheFail*/ false)) {
3771 if (auto OtherModule = SuggestedModule.getModule()) {
3772 std::string OtherModuleName;
3773 auto TLM = OtherModule->getTopLevelModuleName();
3774 if (!TLM.empty())
3775 OtherModuleName = TLM.str();
3776 else
3778
3779 // Don't complain about headers that are actually in by-products:
3782 continue;
3783
3784 missingHeaders.push_back({header, OtherModuleName});
3785 }
3786 } else {
3787 missingHeaders.push_back({header, {}});
3788 }
3789 foundAllHeaders = false;
3790 }
3791 return foundAllHeaders;
3792}
3793
3794////////////////////////////////////////////////////////////////////////////////
3795/// Check moduleName validity from modulemap. Check if this module is defined or not.
3796static bool CheckModuleValid(TModuleGenerator &modGen, const std::string &resourceDir, cling::Interpreter &interpreter,
3797 llvm::StringRef LinkdefPath, const std::string &moduleName)
3798{
3799 clang::CompilerInstance *CI = interpreter.getCI();
3800 clang::HeaderSearch &headerSearch = CI->getPreprocessor().getHeaderSearchInfo();
3801 headerSearch.loadTopLevelSystemModules();
3802
3803 // Actually lookup the module on the computed module name.
3804 clang::Module *module = headerSearch.lookupModule(llvm::StringRef(moduleName));
3805
3806 // Inform the user and abort if we can't find a module with a given name.
3807 if (!module) {
3808 ROOT::TMetaUtils::Error("CheckModuleValid", "Couldn't find module with name '%s' in modulemap!\n",
3809 moduleName.c_str());
3810 return false;
3811 }
3812
3813 // Check if the loaded module covers all headers that were specified
3814 // by the user on the command line. This is an integrity check to
3815 // ensure that our used module map is not containing extraneous headers.
3816 std::vector<std::array<std::string, 2>> missingHdrMod;
3818 // FIXME: Upgrade this to an error once modules are stable.
3819 std::stringstream msgStream;
3820 msgStream << "after creating module \"" << module->Name << "\" ";
3821 if (!module->PresumedModuleMapFile.empty())
3822 msgStream << "using modulemap \"" << module->PresumedModuleMapFile << "\" ";
3823 msgStream << "the following headers are not part of that module:\n";
3824 for (auto &H : missingHdrMod) {
3825 msgStream << " " << H[0];
3826 if (!H[1].empty())
3827 msgStream << " (already part of module \"" << H[1] << "\")";
3828 msgStream << "\n";
3829 }
3830 std::string warningMessage = msgStream.str();
3831
3832 bool maybeUmbrella = modGen.GetHeaders().size() == 1;
3833 // We may have an umbrella and forgot to add the flag. Downgrade the
3834 // warning into an information message.
3835 // FIXME: We should open the umbrella, extract the set of header files
3836 // and check if they exist in the modulemap.
3837 // FIXME: We should also check if the header files are specified in the
3838 // modulemap file as they appeared in the rootcling invocation, i.e.
3839 // if we passed rootcling ... -I/some/path somedir/some/header, the
3840 // modulemap should contain module M { header "somedir/some/header" }
3841 // This way we will make sure the module is properly activated.
3843 ROOT::TMetaUtils::Info("CheckModuleValid, %s. You can silence this message by adding %s to the invocation.",
3844 warningMessage.c_str(),
3845 gOptUmbrellaInput.ArgStr.data());
3846 return true;
3847 }
3848
3849 ROOT::TMetaUtils::Warning("CheckModuleValid", warningMessage.c_str());
3850 // We include the missing headers to fix the module for the user.
3851 std::vector<std::string> missingHeaders;
3853 [](const std::array<std::string, 2>& HdrMod) { return HdrMod[0];});
3855 ROOT::TMetaUtils::Error("CheckModuleValid", "Couldn't include missing module headers for module '%s'!\n",
3856 module->Name.c_str());
3857 }
3858 }
3859
3860 return true;
3861}
3862
3863static llvm::StringRef GetModuleNameFromRdictName(llvm::StringRef rdictName)
3864{
3865 // Try to get the module name in the modulemap based on the filepath.
3866 llvm::StringRef moduleName = llvm::sys::path::filename(rdictName);
3867 moduleName.consume_front("lib");
3868 moduleName.consume_back(".pcm");
3869 moduleName.consume_back("_rdict");
3870 return moduleName;
3871}
3872
3873////////////////////////////////////////////////////////////////////////////////
3874
3876 char **argv,
3877 bool isGenreflex = false)
3878{
3879 // Set number of required arguments. We cannot do this globally since it
3880 // would interfere with LLVM's option parsing.
3881 gOptDictionaryFileName.setNumOccurrencesFlag(llvm::cl::Required);
3882 gOptDictionaryHeaderFiles.setNumOccurrencesFlag(llvm::cl::OneOrMore);
3883
3884 // Copied from cling driver.
3885 // FIXME: Uncomment once we fix ROOT's teardown order.
3886 //llvm::llvm_shutdown_obj shutdownTrigger;
3887
3888 const char *executableFileName = argv[0];
3889
3890 llvm::sys::PrintStackTraceOnErrorSignal(executableFileName);
3891 llvm::PrettyStackTraceProgram X(argc, argv);
3893
3894#if defined(R__WIN32) && !defined(R__WINGCC)
3895 // FIXME: This is terrible hack allocating and changing the argument set.
3896 // We should remove it and use standard llvm facilities to convert the paths.
3897 // cygwin's make is presenting us some cygwin paths even though
3898 // we are windows native. Convert them as good as we can.
3899 for (int iic = 1 /* ignore binary file name in argv[0] */; iic < argc; ++iic) {
3900 std::string iiarg(argv[iic]);
3902 size_t len = iiarg.length();
3903 // yes, we leak.
3904 char *argviic = new char[len + 1];
3905 strlcpy(argviic, iiarg.c_str(), len + 1);
3906 argv[iic] = argviic;
3907 }
3908 }
3909#endif
3910
3911 // Hide options from llvm which we got from static initialization of libCling.
3912 llvm::cl::HideUnrelatedOptions(/*keep*/gRootclingOptions);
3913
3914 // Define Options aliasses
3915 auto &opts = llvm::cl::getRegisteredOptions();
3916 llvm::cl::Option* optHelp = opts["help"];
3917 llvm::cl::alias optHelpAlias1("h",
3918 llvm::cl::desc("Alias for -help"),
3919 llvm::cl::aliasopt(*optHelp));
3920 llvm::cl::alias optHelpAlias2("?",
3921 llvm::cl::desc("Alias for -help"),
3922 llvm::cl::aliasopt(*optHelp));
3923
3924 llvm::cl::ParseCommandLineOptions(argc, argv, "rootcling");
3925
3926 const char *etcDir = gDriverConfig->fTROOT__GetEtcDir();
3927 std::string llvmResourceDir = etcDir ? std::string(etcDir) + "/cling" : "";
3928
3930 std::vector<const char *> clingArgsC;
3931 clingArgsC.push_back(executableFileName);
3932 // Help cling finds its runtime (RuntimeUniverse.h and such).
3933 if (etcDir) {
3934 clingArgsC.push_back("-I");
3935 clingArgsC.push_back(etcDir);
3936 }
3937
3938 //clingArgsC.push_back("-resource-dir");
3939 //clingArgsC.push_back(llvmResourceDir.c_str());
3940
3941 for (const std::string& Opt : gOptBareClingSink)
3942 clingArgsC.push_back(Opt.c_str());
3943
3944 auto interp = std::make_unique<cling::Interpreter>(clingArgsC.size(),
3945 &clingArgsC[0],
3946 llvmResourceDir.c_str());
3947 // FIXME: Diagnose when we have misspelled a flag. Currently we show no
3948 // diagnostic and report exit as success.
3949 return interp->getDiagnostics().hasFatalErrorOccurred();
3950 }
3951
3952 std::string dictname;
3953
3954 if (!gDriverConfig->fBuildingROOTStage1) {
3955 if (gOptRootBuild) {
3956 // running rootcling as part of the ROOT build for ROOT libraries.
3957 gBuildingROOT = true;
3958 }
3959 }
3960
3961 if (!gOptModuleMapFiles.empty() && !gOptCxxModule) {
3962 ROOT::TMetaUtils::Error("", "Option %s can be used only when option %s is specified.\n",
3963 gOptModuleMapFiles.ArgStr.str().c_str(),
3964 gOptCxxModule.ArgStr.str().c_str());
3965 std::cout << "\n";
3966 llvm::cl::PrintHelpMessage();
3967 return 1;
3968 }
3969
3970 // Set the default verbosity
3972 if (gOptVerboseLevel == v4)
3973 genreflex::verbose = true;
3974
3975 if (gOptReflex)
3976 isGenreflex = true;
3977
3978 if (!gOptLibListPrefix.empty()) {
3979 string filein = gOptLibListPrefix + ".in";
3980 FILE *fp;
3981 if ((fp = fopen(filein.c_str(), "r")) == nullptr) {
3982 ROOT::TMetaUtils::Error(nullptr, "%s: The input list file %s does not exist\n", executableFileName, filein.c_str());
3983 return 1;
3984 }
3985 fclose(fp);
3986 }
3987
3989 FILE *fp;
3990 if ((fp = fopen(gOptDictionaryFileName.c_str(), "r")) != nullptr) {
3991 fclose(fp);
3992 if (!gOptForce) {
3993 ROOT::TMetaUtils::Error(nullptr, "%s: output file %s already exists\n", executableFileName, gOptDictionaryFileName.c_str());
3994 return 1;
3995 }
3996 }
3997
3998 // remove possible pathname to get the dictionary name
3999 if (gOptDictionaryFileName.size() > (PATH_MAX - 1)) {
4000 ROOT::TMetaUtils::Error(nullptr, "rootcling: dictionary name too long (more than %d characters): %s\n",
4001 (PATH_MAX - 1), gOptDictionaryFileName.c_str());
4002 return 1;
4003 }
4004
4005 dictname = llvm::sys::path::filename(gOptDictionaryFileName).str();
4006 }
4007
4008 if (gOptForce && dictname.empty()) {
4009 ROOT::TMetaUtils::Error(nullptr, "Inconsistent set of arguments detected: overwrite of dictionary file forced but no filename specified.\n");
4010 llvm::cl::PrintHelpMessage();
4011 return 1;
4012 }
4013
4014 std::vector<std::string> clingArgs;
4015 clingArgs.push_back(executableFileName);
4016 clingArgs.push_back("-iquote.");
4017
4019
4020 // Collect the diagnostic pragmas linked to the usage of -W
4021 // Workaround for ROOT-5656
4022 std::list<std::string> diagnosticPragmas = {"#pragma clang diagnostic ignored \"-Wdeprecated-declarations\""};
4023
4024 if (gOptFailOnWarnings) {
4025 using namespace ROOT::TMetaUtils;
4026 // If warnings are disabled with the current verbosity settings, lower
4027 // it so that the user sees the warning that caused the failure.
4028 if (GetErrorIgnoreLevel() > kWarning)
4029 GetErrorIgnoreLevel() = kWarning;
4030 GetWarningsAreErrors() = true;
4031 }
4032
4033 if (gOptISysRoot != "-") {
4034 if (gOptISysRoot.empty()) {
4035 ROOT::TMetaUtils::Error("", "isysroot specified without a value.\n");
4036 return 1;
4037 }
4038 clingArgs.push_back(gOptISysRoot.ArgStr.str());
4039 clingArgs.push_back(gOptISysRoot.ValueStr.str());
4040 }
4041
4042 // Check if we have a multi dict request but no target library
4043 if (gOptMultiDict && gOptSharedLibFileName.empty()) {
4044 ROOT::TMetaUtils::Error("", "Multidict requested but no target library. Please specify one with the -s argument.\n");
4045 return 1;
4046 }
4047
4048 for (const std::string &PPDefine : gOptPPDefines)
4049 clingArgs.push_back(std::string("-D") + PPDefine);
4050
4051 for (const std::string &PPUndefine : gOptPPUndefines)
4052 clingArgs.push_back(std::string("-U") + PPUndefine);
4053
4054 for (const std::string &IncludePath : gOptIncludePaths)
4055 clingArgs.push_back(std::string("-I") + llvm::sys::path::convert_to_slash(IncludePath));
4056
4057 for (const std::string &IncludePath : gOptSysIncludePaths) {
4058 // Prevent mentioning compiler default include directories as -isystem
4059 // (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70129)
4062 clingArgs.push_back("-isystem");
4063 clingArgs.push_back(llvm::sys::path::convert_to_slash(IncludePath));
4064 }
4065 }
4066
4067 for (const std::string &WDiag : gOptWDiags) {
4068 const std::string FullWDiag = std::string("-W") + WDiag;
4069 // Suppress warning when compiling the dictionary, eg. gcc G__xxx.cxx
4071 // Suppress warning when compiling the input headers by cling.
4072 clingArgs.push_back(FullWDiag);
4073 }
4074
4075 const char *includeDir = gDriverConfig->fTROOT__GetIncludeDir();
4076 if (includeDir) {
4077 clingArgs.push_back(std::string("-I") + llvm::sys::path::convert_to_slash(includeDir));
4078 }
4079
4080 std::vector<std::string> pcmArgs;
4081 for (size_t parg = 0, n = clingArgs.size(); parg < n; ++parg) {
4082 auto thisArg = clingArgs[parg];
4084 if (thisArg == "-c" ||
4085 (gOptNoIncludePaths && isInclude)) continue;
4086 // We now check if the include directories are not excluded
4087 if (isInclude) {
4088 unsigned int offset = 2; // -I is two characters. Now account for spaces
4089 char c = thisArg[offset];
4090 while (c == ' ') c = thisArg[++offset];
4092 auto excludePathPos = std::find_if(gOptExcludePaths.begin(),
4094 [&](const std::string& path){
4095 return ROOT::TMetaUtils::BeginsWith(&thisArg[offset], path);});
4096 if (excludePathsEnd != excludePathPos) continue;
4097 }
4098 pcmArgs.push_back(thisArg);
4099 }
4100
4101 // cling-only arguments
4102 if (etcDir)
4103 clingArgs.push_back(std::string("-I") + llvm::sys::path::convert_to_slash(etcDir));
4104
4105 // We do not want __ROOTCLING__ in the pch!
4106 if (!gOptGeneratePCH) {
4107 clingArgs.push_back("-D__ROOTCLING__");
4108 }
4109#ifdef R__MACOSX
4110 clingArgs.push_back("-DSYSTEM_TYPE_macosx");
4111#elif defined(R__WIN32)
4112 clingArgs.push_back("-DSYSTEM_TYPE_winnt");
4113
4114 // Prevent the following #error: The C++ Standard Library forbids macroizing keywords.
4115 clingArgs.push_back("-D_XKEYCHECK_H");
4116 // Tell windows.h not to #define min and max, it clashes with numerical_limits.
4117 clingArgs.push_back("-DNOMINMAX");
4118#else // assume UNIX
4119 clingArgs.push_back("-DSYSTEM_TYPE_unix");
4120#endif
4121
4122 clingArgs.push_back("-fsyntax-only");
4123#ifndef R__WIN32
4124 clingArgs.push_back("-fPIC");
4125#endif
4126 clingArgs.push_back("-Xclang");
4127 clingArgs.push_back("-fmodules-embed-all-files");
4128 clingArgs.push_back("-Xclang");
4129 clingArgs.push_back("-main-file-name");
4130 clingArgs.push_back("-Xclang");
4131 clingArgs.push_back((dictname + ".h").c_str());
4132
4134
4135 // FIXME: This line is from TModuleGenerator, but we can't reuse this code
4136 // at this point because TModuleGenerator needs a CompilerInstance (and we
4137 // currently create the arguments for creating said CompilerInstance).
4138 bool isPCH = (gOptDictionaryFileName.getValue() == "allDict.cxx");
4139 std::string outputFile;
4140 // Data is in 'outputFile', therefore in the same scope.
4141 llvm::StringRef moduleName;
4142 std::string vfsArg;
4143 // Adding -fmodules to the args will break lexing with __CLING__ defined,
4144 // and we actually do lex with __CLING__ and reuse this variable later,
4145 // we have to copy it now.
4147
4148 if (gOptSharedLibFileName.empty()) {
4150 }
4151
4152 if (!isPCH && gOptCxxModule) {
4153 // We just pass -fmodules, the CIFactory will do the rest and configure
4154 // clang correctly once it sees this flag.
4155 clingArgsInterpreter.push_back("-fmodules");
4156 clingArgsInterpreter.push_back("-fno-implicit-module-maps");
4157
4158 for (const std::string &modulemap : gOptModuleMapFiles)
4159 clingArgsInterpreter.push_back("-fmodule-map-file=" + modulemap);
4160
4161 if (includeDir) {
4162 clingArgsInterpreter.push_back("-fmodule-map-file=" + std::string(includeDir) + "/ROOT.modulemap");
4163 }
4164 std::string ModuleMapCWD = ROOT::FoundationUtils::GetCurrentDir() + "/module.modulemap";
4165 if (llvm::sys::fs::exists(ModuleMapCWD))
4166 clingArgsInterpreter.push_back("-fmodule-map-file=" + ModuleMapCWD);
4167
4168 // Specify the module name that we can lookup the module in the modulemap.
4169 outputFile = llvm::sys::path::stem(gOptSharedLibFileName).str();
4170 // Try to get the module name in the modulemap based on the filepath.
4172
4173#ifdef _MSC_VER
4174 clingArgsInterpreter.push_back("-Xclang");
4175 clingArgsInterpreter.push_back("-fmodule-feature");
4176 clingArgsInterpreter.push_back("-Xclang");
4177 clingArgsInterpreter.push_back("msvc" + std::string(rootclingStringify(_MSC_VER)));
4178#endif
4179 clingArgsInterpreter.push_back("-fmodule-name=" + moduleName.str());
4180
4181 std::string moduleCachePath = llvm::sys::path::parent_path(gOptSharedLibFileName).str();
4182 // FIXME: This is a horrible workaround to fix the incremental builds.
4183 // The enumerated modules are built by clang impicitly based on #include of
4184 // a header which is contained within that module. The build system has
4185 // no way to track dependencies on them and trigger a rebuild.
4186 // A possible solution can be to disable completely the implicit build of
4187 // modules and each module to be built by rootcling. We need to teach
4188 // rootcling how to build modules with no IO support.
4189 if (moduleName == "Core") {
4190 assert(gDriverConfig->fBuildingROOTStage1);
4191 remove((moduleCachePath + llvm::sys::path::get_separator() + "_Builtin_intrinsics.pcm").str().c_str());
4192 remove((moduleCachePath + llvm::sys::path::get_separator() + "_Builtin_stddef_max_align_t.pcm").str().c_str());
4193 remove((moduleCachePath + llvm::sys::path::get_separator() + "Cling_Runtime.pcm").str().c_str());
4194 remove((moduleCachePath + llvm::sys::path::get_separator() + "Cling_Runtime_Extra.pcm").str().c_str());
4195#ifdef R__WIN32
4196 remove((moduleCachePath + llvm::sys::path::get_separator() + "vcruntime.pcm").str().c_str());
4197 remove((moduleCachePath + llvm::sys::path::get_separator() + "services.pcm").str().c_str());
4198#endif
4199
4200#ifdef R__MACOSX
4201 remove((moduleCachePath + llvm::sys::path::get_separator() + "Darwin.pcm").str().c_str());
4202#else
4203 remove((moduleCachePath + llvm::sys::path::get_separator() + "libc.pcm").str().c_str());
4204#endif
4205 remove((moduleCachePath + llvm::sys::path::get_separator() + "std.pcm").str().c_str());
4206 remove((moduleCachePath + llvm::sys::path::get_separator() + "boost.pcm").str().c_str());
4207 remove((moduleCachePath + llvm::sys::path::get_separator() + "tinyxml2.pcm").str().c_str());
4208 remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Config.pcm").str().c_str());
4209 remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Rtypes.pcm").str().c_str());
4210 remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Foundation_C.pcm").str().c_str());
4211 remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Foundation_Stage1_NoRTTI.pcm").str().c_str());
4212 } else if (moduleName == "MathCore") {
4213 remove((moduleCachePath + llvm::sys::path::get_separator() + "Vc.pcm").str().c_str());
4214 }
4215
4216 // Set the C++ modules output directory to the directory where we generate
4217 // the shared library.
4218 clingArgsInterpreter.push_back("-fmodules-cache-path=" + moduleCachePath);
4219 }
4220
4221 if (gOptVerboseLevel == v4)
4222 clingArgsInterpreter.push_back("-v");
4223
4224 // Convert arguments to a C array and check if they are sane
4225 std::vector<const char *> clingArgsC;
4226 for (auto const &clingArg : clingArgsInterpreter) {
4228 std::cerr << "Argument \""<< clingArg << "\" is not a supported cling argument. "
4229 << "This could be mistyped rootcling argument. Please check the commandline.\n";
4230 return 1;
4231 }
4232 clingArgsC.push_back(clingArg.c_str());
4233 }
4234
4235
4236 std::unique_ptr<cling::Interpreter> owningInterpPtr;
4237 cling::Interpreter* interpPtr = nullptr;
4238
4239 std::list<std::string> filesIncludedByLinkdef;
4240 if (gDriverConfig->fBuildingROOTStage1) {
4241#ifdef R__FAST_MATH
4242 // Same setting as in TCling.cxx.
4243 clingArgsC.push_back("-ffast-math");
4244#endif
4245
4246 owningInterpPtr.reset(new cling::Interpreter(clingArgsC.size(), &clingArgsC[0],
4247 llvmResourceDir.c_str()));
4248 interpPtr = owningInterpPtr.get();
4249 } else {
4250 // Pass the interpreter arguments to TCling's interpreter:
4251 clingArgsC.push_back("-resource-dir");
4252 clingArgsC.push_back(llvmResourceDir.c_str());
4253 clingArgsC.push_back(nullptr); // signal end of array
4254 const char ** &extraArgs = *gDriverConfig->fTROOT__GetExtraInterpreterArgs();
4255 extraArgs = &clingArgsC[1]; // skip binary name
4256 interpPtr = gDriverConfig->fTCling__GetInterpreter();
4257 if (!interpPtr->getCI()) // Compiler instance could not be created. See https://its.cern.ch/jira/browse/ROOT-10239
4258 return 1;
4259 if (!isGenreflex && !gOptGeneratePCH) {
4260 std::unique_ptr<TRootClingCallbacks> callBacks (new TRootClingCallbacks(interpPtr, filesIncludedByLinkdef));
4261 interpPtr->setCallbacks(std::move(callBacks));
4262 }
4263 }
4264 cling::Interpreter &interp = *interpPtr;
4265 clang::CompilerInstance *CI = interp.getCI();
4266 // FIXME: Remove this once we switch cling to use the driver. This would handle -fmodules-embed-all-files for us.
4267 CI->getFrontendOpts().ModulesEmbedAllFiles = true;
4268 CI->getSourceManager().setAllFilesAreTransient(true);
4269
4270 clang::Preprocessor &PP = CI->getPreprocessor();
4271 clang::HeaderSearch &headerSearch = PP.getHeaderSearchInfo();
4272 clang::ModuleMap &moduleMap = headerSearch.getModuleMap();
4273 auto &diags = interp.getDiagnostics();
4274
4275 // Manually enable the module build remarks. We don't enable them via the
4276 // normal clang command line arg because otherwise we would get remarks for
4277 // building STL/libc when starting the interpreter in rootcling_stage1.
4278 // We can't prevent these diags in any other way because we can only attach
4279 // our own diag client now after the interpreter has already started.
4280 diags.setSeverity(clang::diag::remark_module_build, clang::diag::Severity::Remark, clang::SourceLocation());
4281
4282 // Attach our own diag client that listens to the module_build remarks from
4283 // clang to check that we don't build dictionary C++ modules implicitly.
4284 auto recordingClient = new CheckModuleBuildClient(diags.getClient(), diags.ownsClient(), moduleMap);
4285 diags.setClient(recordingClient, true);
4286
4288 ROOT::TMetaUtils::Info(nullptr, "\n");
4289 ROOT::TMetaUtils::Info(nullptr, "==== INTERPRETER CONFIGURATION ====\n");
4290 ROOT::TMetaUtils::Info(nullptr, "== Include paths\n");
4291 interp.DumpIncludePath();
4292 printf("\n\n");
4293 fflush(stdout);
4294
4295 ROOT::TMetaUtils::Info(nullptr, "== Included files\n");
4296 interp.printIncludedFiles(llvm::outs());
4297 llvm::outs() << "\n\n";
4298 llvm::outs().flush();
4299
4300 ROOT::TMetaUtils::Info(nullptr, "== Language Options\n");
4301 const clang::LangOptions& LangOpts
4302 = interp.getCI()->getASTContext().getLangOpts();
4303
4304 // FIXME: Replace with C++20 `using enum LangOptions::CompatibilityKind`.
4305 using CK = clang::LangOptions::CompatibilityKind;
4306#define LANGOPT(Name, Bits, Default, Compatibility, Description) \
4307 if constexpr (CK::Compatibility != CK::Benign) \
4308 ROOT::TMetaUtils::Info(nullptr, "%s = %d // %s\n", #Name, (int)LangOpts.Name, Description);
4309#define ENUM_LANGOPT(Name, Type, Bits, Default, Compatibility, Description)
4310#include "clang/Basic/LangOptions.def"
4311 ROOT::TMetaUtils::Info(nullptr, "==== END interpreter configuration ====\n\n");
4312 }
4313
4314 interp.getOptions().ErrorOut = true;
4315 interp.enableRawInput(true);
4316
4317 if (gOptCxxModule) {
4318 for (llvm::StringRef DepMod : gOptModuleDependencies) {
4319 if (DepMod.ends_with("_rdict.pcm")) {
4320 ROOT::TMetaUtils::Warning(nullptr, "'%s' value is deprecated. Please use [<fullpath>]%s.pcm\n",
4321 DepMod.data(),
4323 }
4325 // We might deserialize.
4326 cling::Interpreter::PushTransactionRAII RAII(&interp);
4327 if (!interp.loadModule(DepMod.str(), /*complain*/false)) {
4328 ROOT::TMetaUtils::Error(nullptr, "Module '%s' failed to load.\n",
4329 DepMod.data());
4330 }
4331 }
4332 }
4333
4334 if (!isGenreflex) { // rootcling
4335 // ROOTCINT uses to define a few header implicitly, we need to do it explicitly.
4336 if (interp.declare("#include <cassert>\n"
4337 "#include \"Rtypes.h\"\n"
4338 "#include \"TObject.h\"") != cling::Interpreter::kSuccess
4339 ) {
4340 // There was an error.
4341 ROOT::TMetaUtils::Error(nullptr, "Error loading the default rootcling header files.\n");
4342 return 1;
4343 }
4344 }
4345
4346 if (interp.declare("#include <string>\n" // For the list of 'opaque' typedef to also include string.
4347 "#include <RtypesCore.h>\n" // For initializing TNormalizedCtxt.
4348 "namespace std {} using namespace std;") != cling::Interpreter::kSuccess) {
4349 ROOT::TMetaUtils::Error(nullptr, "Error loading the default header files.\n");
4350 return 1;
4351 }
4352
4353 // We are now ready (enough is loaded) to init the list of opaque typedefs.
4355 ROOT::TMetaUtils::TClingLookupHelper helper(interp, normCtxt, nullptr, nullptr, nullptr, nullptr);
4357
4358 // flags used only for the pragma parser:
4359 clingArgs.push_back("-D__CINT__"); // backward compatibility. Now __CLING__ should be used instead
4360 clingArgs.push_back("-D__MAKECINT__"); // backward compatibility. Now __ROOTCLING__ should used instead
4361
4363
4365
4366 std::string interpPragmaSource;
4367 std::string includeForSource;
4368 std::string interpreterDeclarations;
4369 std::string linkdef;
4370
4371 for (size_t i = 0, e = gOptDictionaryHeaderFiles.size(); i < e; ++i) {
4372 const std::string& optHeaderFileName = gOptDictionaryHeaderFiles[i];
4374
4375 if (isSelectionFile) {
4376 if (i == e - 1) {
4378 } else { // if the linkdef was not last, issue an error.
4379 ROOT::TMetaUtils::Error(nullptr, "%s: %s must be last file on command line\n",
4381 return 1;
4382 }
4383 }
4384
4385 // coverity[tainted_data] The OS should already limit the argument size, so we are safe here
4386 std::string fullheader(optHeaderFileName);
4387 // Strip any trailing + which is only used by GeneratedLinkdef.h which currently
4388 // use directly argv.
4389 if (fullheader[fullheader.length() - 1] == '+') {
4390 fullheader.erase(fullheader.length() - 1);
4391 }
4392 std::string header(
4394
4395 interpPragmaSource += std::string("#include \"") + header + "\"\n";
4396 if (!isSelectionFile) {
4397 // In order to not have to add the equivalent to -I${PWD} to the
4398 // command line, include the complete file name, even if it is a
4399 // full pathname, when we write it down in the dictionary.
4400 // Note: have -I${PWD} means in that (at least in the case of
4401 // ACLiC) we inadvertently pick local file that have the same
4402 // name as system header (e.g. new or list) and -iquote has not
4403 // equivalent on some platforms.
4404 includeForSource += std::string("#include \"") + fullheader + "\"\n";
4405 pcmArgs.push_back(header);
4406 } else if (!IsSelectionXml(optHeaderFileName.c_str())) {
4407 interpreterDeclarations += std::string("#include \"") + header + "\"\n";
4408 }
4409 }
4410
4411 if (gOptUmbrellaInput) {
4412 bool hasSelectionFile = !linkdef.empty();
4415 ROOT::TMetaUtils::Error(nullptr, "Option %s used but more than one header file specified.\n",
4416 gOptUmbrellaInput.ArgStr.data());
4417 }
4418
4419 // We have a multiDict request. This implies generating a pcm which is of the form
4420 // dictName_libname_rdict.pcm
4421 if (gOptMultiDict) {
4422
4423 std::string newName = llvm::sys::path::parent_path(gOptSharedLibFileName).str();
4424 if (!newName.empty())
4426 newName += llvm::sys::path::stem(gOptSharedLibFileName);
4427 newName += "_";
4428 newName += llvm::sys::path::stem(gOptDictionaryFileName);
4429 newName += llvm::sys::path::extension(gOptSharedLibFileName);
4431 }
4432
4433 // Until the module are actually enabled in ROOT, we need to register
4434 // the 'current' directory to make it relocatable (i.e. have a way
4435 // to find the headers).
4437 string incCurDir = "-I";
4439 pcmArgs.push_back(incCurDir);
4440 }
4441
4442 // Add the diagnostic pragmas distilled from the -Wno-xyz
4443 {
4444 std::stringstream res;
4445 const char* delim="\n";
4446 std::copy(diagnosticPragmas.begin(),
4448 std::ostream_iterator<std::string>(res, delim));
4449 if (interp.declare(res.str()) != cling::Interpreter::kSuccess) {
4450 ROOT::TMetaUtils::Error(nullptr, "Failed to parse -Wno-xyz flags as pragmas:\n%s", res.str().c_str());
4451 return 1;
4452 }
4453 }
4454
4455 class IgnoringPragmaHandler: public clang::PragmaNamespace {
4456 public:
4457 IgnoringPragmaHandler(const char* pragma):
4458 clang::PragmaNamespace(pragma) {}
4459 void HandlePragma(clang::Preprocessor &PP,
4460 clang::PragmaIntroducer Introducer,
4461 clang::Token &tok) override {
4462 PP.DiscardUntilEndOfDirective();
4463 }
4464 };
4465
4466 // Ignore these #pragmas to suppress "unknown pragma" warnings.
4467 // See LinkdefReader.cxx.
4468 PP.AddPragmaHandler(new IgnoringPragmaHandler("link"));
4469 PP.AddPragmaHandler(new IgnoringPragmaHandler("extra_include"));
4470 PP.AddPragmaHandler(new IgnoringPragmaHandler("read"));
4471 PP.AddPragmaHandler(new IgnoringPragmaHandler("create"));
4472
4473 if (!interpreterDeclarations.empty() &&
4474 interp.declare(interpreterDeclarations) != cling::Interpreter::kSuccess) {
4475 ROOT::TMetaUtils::Error(nullptr, "%s: Linkdef compilation failure\n", executableFileName);
4476 return 1;
4477 }
4478
4479
4484
4485 if (!gDriverConfig->fBuildingROOTStage1 && !filesIncludedByLinkdef.empty()) {
4486 pcmArgs.push_back(linkdef);
4487 }
4488
4489 modGen.ParseArgs(pcmArgs);
4490
4491 if (!gDriverConfig->fBuildingROOTStage1) {
4492 // Forward the -I, -D, -U
4493 for (const std::string & inclPath : modGen.GetIncludePaths()) {
4494 interp.AddIncludePath(inclPath);
4495 }
4496 std::stringstream definesUndefinesStr;
4497 modGen.WritePPDefines(definesUndefinesStr);
4498 modGen.WritePPUndefines(definesUndefinesStr);
4499 if (!definesUndefinesStr.str().empty()) {
4500 if (interp.declare(definesUndefinesStr.str()) != cling::Interpreter::kSuccess) {
4501 ROOT::TMetaUtils::Error(nullptr, "Failed to parse -D, -U flags as preprocessor directives:\n%s", definesUndefinesStr.str().c_str());
4502 return 1;
4503 }
4504 }
4505 }
4506
4509 return 1;
4510 }
4511
4512 // Check if code goes to stdout or rootcling file
4513 std::ofstream fileout;
4514 string main_dictname(gOptDictionaryFileName.getValue());
4515 // Keep the original dictionary output file name (with extension) for the
4516 // dependency file target: `main_dictname` gets its extension stripped below
4517 // and `gOptDictionaryFileName` is turned into a temporary name by the
4518 // tmpCatalog a few lines down.
4519 const std::string dictOutputFileName(gOptDictionaryFileName.getValue());
4520 std::ostream *splitDictStream = nullptr;
4521 std::unique_ptr<std::ostream> splitDeleter(nullptr);
4522 // Store the temp files
4524 if (!gOptDictionaryFileName.empty()) {
4525 tmpCatalog.addFileName(gOptDictionaryFileName.getValue());
4526 fileout.open(gOptDictionaryFileName.c_str());
4527 if (!fileout) {
4528 ROOT::TMetaUtils::Error(nullptr, "rootcling: failed to open %s in main\n",
4529 gOptDictionaryFileName.c_str());
4530 return 1;
4531 }
4532 }
4533
4534 std::ostream &dictStream = (!gOptDictionaryFileName.empty()) ? fileout : std::cout;
4535 bool isACLiC = gOptDictionaryFileName.getValue().find("_ACLiC_dict") != std::string::npos;
4536
4537 // Now generate a second stream for the split dictionary if it is necessary
4538 if (gOptSplit) {
4541 } else {
4543 }
4544
4545 size_t dh = main_dictname.rfind('.');
4546 if (dh != std::string::npos) {
4547 main_dictname.erase(dh);
4548 }
4549 // Need to replace all the characters not allowed in a symbol ...
4550 std::string main_dictname_copy(main_dictname);
4552
4554 if (gOptSplit)
4556
4557 if (!gOptNoGlobalUsingStd) {
4558 // ACLiC'ed macros might rely on `using namespace std` in front of user headers
4559 if (isACLiC) {
4561 if (gOptSplit) {
4563 }
4564 }
4565 }
4566
4567
4568 //---------------------------------------------------------------------------
4569 // Parse the linkdef or selection.xml file.
4570 /////////////////////////////////////////////////////////////////////////////
4571
4572 string linkdefFilename;
4573 if (linkdef.empty()) {
4574 linkdefFilename = "in memory";
4575 } else {
4576 bool found = Which(interp, linkdef.c_str(), linkdefFilename);
4577 if (!found) {
4578 ROOT::TMetaUtils::Error(nullptr, "%s: cannot open linkdef file %s\n", executableFileName, linkdef.c_str());
4579 return 1;
4580 }
4581 }
4582
4583 // Exclude string not to re-generate the dictionary
4584 std::vector<std::pair<std::string, std::string>> namesForExclusion;
4585 if (!gBuildingROOT) {
4586 namesForExclusion.push_back(std::make_pair(ROOT::TMetaUtils::propNames::name, "std::string"));
4587 namesForExclusion.push_back(std::make_pair(ROOT::TMetaUtils::propNames::pattern, "ROOT::Meta::Selection*"));
4588 }
4589
4591
4592 std::string extraIncludes;
4593
4595
4596 // Select using DictSelection
4597 const unsigned int selRulesInitialSize = selectionRules.Size();
4600
4602
4603 bool isSelXML = IsSelectionXml(linkdefFilename.c_str());
4604
4605 int rootclingRetCode(0);
4606
4609 std::ifstream file(linkdefFilename.c_str());
4610 if (file.is_open()) {
4611 ROOT::TMetaUtils::Info(nullptr, "Using linkdef file: %s\n", linkdefFilename.c_str());
4612 file.close();
4613 } else {
4614 ROOT::TMetaUtils::Error(nullptr, "Linkdef file %s couldn't be opened!\n", linkdefFilename.c_str());
4615 }
4616
4617 selectionRules.SetSelectionFileType(SelectionRules::kLinkdefFile);
4618 }
4619 // If there is no linkdef file, we added the 'default' #pragma to
4620 // interpPragmaSource and we still need to process it.
4621
4623
4625 llvmResourceDir.c_str())) {
4626 ROOT::TMetaUtils::Error(nullptr, "Parsing #pragma failed %s\n", linkdefFilename.c_str());
4627 rootclingRetCode += 1;
4628 } else {
4629 ROOT::TMetaUtils::Info(nullptr, "#pragma successfully parsed.\n");
4630 }
4631
4632 if (!ldefr.LoadIncludes(extraIncludes)) {
4633 ROOT::TMetaUtils::Error(nullptr, "Error loading the #pragma extra_include.\n");
4634 return 1;
4635 }
4636
4637 } else if (isSelXML) {
4638
4640
4641 std::ifstream file(linkdefFilename.c_str());
4642 if (file.is_open()) {
4643 ROOT::TMetaUtils::Info(nullptr, "Selection XML file\n");
4644
4646 if (!xmlr.Parse(linkdefFilename.c_str(), selectionRules)) {
4647 ROOT::TMetaUtils::Error(nullptr, "Parsing XML file %s\n", linkdefFilename.c_str());
4648 return 1; // Return here to propagate the failure up to the build system
4649 } else {
4650 ROOT::TMetaUtils::Info(nullptr, "XML file successfully parsed\n");
4651 }
4652 file.close();
4653 } else {
4654 ROOT::TMetaUtils::Error(nullptr, "XML file %s couldn't be opened!\n", linkdefFilename.c_str());
4655 }
4656
4657 } else {
4658
4659 ROOT::TMetaUtils::Error(nullptr, "Unrecognized selection file: %s\n", linkdefFilename.c_str());
4660
4661 }
4662
4663 // Speed up the operations with rules
4664 selectionRules.FillCache();
4665 selectionRules.Optimize();
4666
4667 // Addresses ROOT-5174
4668 if (gBuildingROOT? 0 : 2 >= selectionRules.Size() && !gOptCxxModule && !isGenreflex) {
4669 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");
4670 return 1;
4671 }
4672
4673 if (isGenreflex){
4674 if (0 != selectionRules.CheckDuplicates()){
4675 return 1;
4676 }
4677 }
4678
4679 // If we want to validate the selection only, we just quit.
4681 return 0;
4682
4683 //---------------------------------------------------------------------------
4684 // Write schema evolution related headers and declarations
4685 /////////////////////////////////////////////////////////////////////////////
4686
4687 if ((!ROOT::gReadRules.empty() || !ROOT::gReadRawRules.empty())) {
4688 dictStream << "#include \"TBuffer.h\"\n"
4689 << "#include \"TVirtualObject.h\"\n"
4690 << "#include <vector>\n"
4691 << "#include \"TSchemaHelper.h\"\n\n";
4692
4693 std::list<std::string> includes;
4694 GetRuleIncludes(includes);
4695 for (auto & incFile : includes) {
4696 dictStream << "#include <" << incFile << ">" << std::endl;
4697 }
4698 dictStream << std::endl;
4699 }
4700
4701 selectionRules.SearchNames(interp);
4702
4703 int scannerVerbLevel = 0;
4704 {
4705 using namespace ROOT::TMetaUtils;
4706 scannerVerbLevel = GetErrorIgnoreLevel() == kInfo; // 1 if true, 0 if false
4707 if (isGenreflex){
4708 scannerVerbLevel = GetErrorIgnoreLevel() < kWarning;
4709 }
4710 }
4711
4712 // Select the type of scan
4714 if (gOptGeneratePCH)
4716 if (dictSelection)
4718
4720 scanType,
4721 interp,
4722 normCtxt,
4724
4725 // If needed initialize the autoloading hook
4726 if (!gOptLibListPrefix.empty()) {
4729 }
4730
4731 scan.Scan(CI->getASTContext());
4732
4733 bool has_input_error = false;
4734
4736 selectionRules.PrintSelectionRules();
4737
4739 !gOptGeneratePCH &&
4741 !selectionRules.AreAllSelectionRulesUsed()) {
4742 ROOT::TMetaUtils::Warning(nullptr, "Not all selection rules are used!\n");
4743 }
4744
4745 if (!gOptGeneratePCH){
4748 }
4749
4750 // SELECTION LOOP
4751 // Check for error in the class layout before doing anything else.
4752 for (auto const & annRcd : scan.fSelectedClasses) {
4754 if (annRcd.RequestNoInputOperator()) {
4756 if (version != 0) {
4757 // Only Check for input operator is the object is I/O has
4758 // been requested.
4760 }
4761 }
4762 }
4764 }
4765
4766 if (has_input_error) {
4767 // Be a little bit makefile friendly and remove the dictionary in case of error.
4768 // We could add an option -k to keep the file even in case of error.
4769 exit(1);
4770 }
4771
4772 //---------------------------------------------------------------------------
4773 // Write all the necessary #include
4774 /////////////////////////////////////////////////////////////////////////////
4775 if (!gDriverConfig->fBuildingROOTStage1) {
4777 includeForSource += "#include \"" + includedFromLinkdef + "\"\n";
4778 }
4779 }
4780
4781 if (!gOptGeneratePCH) {
4783 if (gOptSplit) {
4785 }
4786 if (!gOptNoGlobalUsingStd) {
4787 // ACLiC'ed macros might have relied on `using namespace std` in front of user headers
4788 if (!isACLiC) {
4790 if (gOptSplit) {
4792 }
4793 }
4794 }
4795 if (gDriverConfig->fInitializeStreamerInfoROOTFile) {
4796 gDriverConfig->fInitializeStreamerInfoROOTFile(modGen.GetModuleFileName().c_str());
4797 }
4798
4799 // The order of addition to the list of constructor type
4800 // is significant. The list is sorted by with the highest
4801 // priority first.
4802 if (!gOptInterpreterOnly) {
4803 constructorTypes.emplace_back("TRootIOCtor", interp);
4804 constructorTypes.emplace_back("__void__", interp); // ROOT-7723
4805 constructorTypes.emplace_back("", interp);
4806 }
4807 }
4810
4811 if (gOptSplit && splitDictStream) {
4813 }
4814 }
4815
4816 if (gOptGeneratePCH) {
4818 } else if (gOptInterpreterOnly) {
4820 // generate an empty pcm nevertheless for consistency
4821 // Negate as true is 1 and true is returned in case of success.
4822 if (!gDriverConfig->fBuildingROOTStage1) {
4824 }
4825 } else {
4828 }
4829
4830 if (rootclingRetCode != 0) {
4831 return rootclingRetCode;
4832 }
4833
4834 // Now we have done all our looping and thus all the possible
4835 // annotation, let's write the pcms.
4838
4840
4842 scan.fSelectedTypedefs,
4843 scan.fSelectedFunctions,
4844 scan.fSelectedVariables,
4845 scan.fSelectedEnums,
4848 interp);
4849
4850 std::string detectedUmbrella;
4851 for (auto & arg : pcmArgs) {
4853 detectedUmbrella = arg;
4854 break;
4855 }
4856 }
4857
4859 headersDeclsMap.clear();
4860 }
4861
4862
4863 std::string headersClassesMapString = "\"\"";
4864 std::string fwdDeclsString = "\"\"";
4865 if (!gOptCxxModule) {
4868 true);
4869 if (!gDriverConfig->fBuildingROOTStage1) {
4872 }
4873 }
4876 // If we just want to inline the input header, we don't need
4877 // to generate any files.
4878 if (!gOptInlineInput) {
4879 // Write the module/PCH depending on what mode we are on
4880 if (modGen.IsPCH()) {
4881 if (!GenerateAllDict(modGen, CI, currentDirectory)) return 1;
4882 } else if (gOptCxxModule) {
4884 return 1;
4885 }
4886 }
4887
4888 if (!gOptLibListPrefix.empty()) {
4889 string liblist_filename = gOptLibListPrefix + ".out";
4890
4891 ofstream outputfile(liblist_filename.c_str(), ios::out);
4892 if (!outputfile) {
4893 ROOT::TMetaUtils::Error(nullptr, "%s: Unable to open output lib file %s\n",
4895 } else {
4896 const size_t endStr = gLibsNeeded.find_last_not_of(" \t");
4897 outputfile << gLibsNeeded.substr(0, endStr + 1) << endl;
4898 // Add explicit delimiter
4899 outputfile << "# Now the list of classes\n";
4900 // SELECTION LOOP
4901 for (auto const & annRcd : scan.fSelectedClasses) {
4902 // Shouldn't it be GetLong64_Name( cl_input.GetNormalizedName() )
4903 // or maybe we should be normalizing to turn directly all long long into Long64_t
4904 outputfile << annRcd.GetNormalizedName() << endl;
4905 }
4906 }
4907 }
4908
4909 // Check for errors in module generation
4910 rootclingRetCode += modGen.GetErrorCount();
4911 if (0 != rootclingRetCode) return rootclingRetCode;
4912
4913 // Create the rootmap file
4914 std::string rootmapLibName = std::accumulate(gOptRootmapLibNames.begin(),
4916 std::string(),
4917 [](const std::string & a, const std::string & b) -> std::string {
4918 if (a.empty()) return b;
4919 else return a + " " + b;
4920 });
4921
4922 bool rootMapNeeded = !gOptRootMapFileName.empty() || !rootmapLibName.empty();
4923
4924 std::list<std::string> classesNames;
4925 std::list<std::string> classesNamesForRootmap;
4926 std::list<std::string> classesDefsList;
4927
4932 interp);
4933
4934 std::list<std::string> enumNames;
4936 scan.fSelectedEnums,
4937 interp);
4938
4939 std::list<std::string> varNames;
4941 scan.fSelectedVariables,
4942 interp);
4943
4944 if (0 != rootclingRetCode) return rootclingRetCode;
4945
4946 // Create the rootmapfile if needed
4947 if (rootMapNeeded) {
4948
4949 std::list<std::string> nsNames;
4950
4952
4955
4956 ROOT::TMetaUtils::Info(nullptr, "Rootmap file name %s and lib name(s) \"%s\"\n",
4957 gOptRootMapFileName.c_str(),
4958 rootmapLibName.c_str());
4959
4960 tmpCatalog.addFileName(gOptRootMapFileName);
4961 std::unordered_set<std::string> headersToIgnore;
4962 if (gOptInlineInput)
4963 for (const std::string& optHeaderFileName : gOptDictionaryHeaderFiles)
4964 headersToIgnore.insert(optHeaderFileName.c_str());
4965
4966 std::list<std::string> typedefsRootmapLines;
4968 scan.fSelectedTypedefs,
4969 interp);
4970
4975 nsNames,
4977 enumNames,
4978 varNames,
4981
4982 if (0 != rootclingRetCode) return 1;
4983 }
4984
4986 tmpCatalog.dump();
4987
4988 // Manually call end of translation unit because we never call the
4989 // appropriate deconstructors in the interpreter. This writes out the C++
4990 // module file that we currently generate.
4991 {
4992 cling::Interpreter::PushTransactionRAII RAII(&interp);
4993 CI->getSema().getASTConsumer().HandleTranslationUnit(CI->getSema().getASTContext());
4994 }
4995
4996 // Add the warnings
4998
4999 // make sure the file is closed before committing
5000 fileout.close();
5001
5002 // Write the dependency file if requested (-MF <file>). It uses the
5003 // Makefile format understood by CMake's DEPFILE and Ninja's "deps = gcc",
5004 // listing every real header that was opened while generating the dictionary
5005 // so that incremental builds pick up changes to transitively included files.
5006 if (!gOptDepFile.empty() && rootclingRetCode == 0 && !dictOutputFileName.empty()) {
5007 std::ofstream depFile(gOptDepFile.c_str());
5008 if (!depFile) {
5010 "rootcling: failed to open dependency file %s\n",
5011 gOptDepFile.c_str());
5012 rootclingRetCode = 1;
5013 } else {
5014 // Escape a path for the Makefile-format dependency file: forward
5015 // slashes (needed on Windows) and backslash-escape the characters that
5016 // are special to make (space, tab, '#', ':').
5017 auto escapeForDepFile = [](std::string path) {
5018 std::replace(path.begin(), path.end(), '\\', '/');
5019 std::string escaped;
5020 escaped.reserve(path.size());
5021 for (char c : path) {
5022 if (c == ' ' || c == '\t' || c == '#' || c == ':')
5023 escaped += '\\';
5024 escaped += c;
5025 }
5026 return escaped;
5027 };
5028
5029 // The target is the final dictionary source file. Note that
5030 // gOptDictionaryFileName has been turned into a temporary name by the
5031 // tmpCatalog, so we use the original name captured earlier.
5033
5034 // Collect all files that were read by clang during dictionary
5035 // generation (headers included directly or indirectly).
5036 clang::SourceManager &SM = CI->getSourceManager();
5037 clang::FileManager &FM = SM.getFileManager();
5038
5039 llvm::SmallVector<clang::OptionalFileEntryRef, 64> files;
5040 FM.GetUniqueIDMapping(files);
5041
5042 llvm::SmallString<256> absDictOutput(dictOutputFileName);
5043 llvm::sys::fs::make_absolute(absDictOutput);
5044 llvm::SmallString<256> absDictTmp(gOptDictionaryFileName.getValue());
5045 llvm::sys::fs::make_absolute(absDictTmp);
5046
5047 std::set<std::string> includedFiles;
5048 for (const auto &FEOpt : files) {
5049 if (!FEOpt)
5050 continue;
5051 llvm::StringRef filename = FEOpt->getName();
5052 if (filename.empty())
5053 continue;
5054 // Skip cling's in-memory buffers, which the FileManager also
5055 // reports: "input_line_N", "<<< cling interactive line includer >>>",
5056 // "<built-in>", "<command line>", ... These are not real files;
5057 // some contain spaces or angle brackets that would corrupt the
5058 // dependency file, and all of them would make the dictionary appear
5059 // perpetually out of date. Requiring the entry to exist on disk
5060 // filters them out (together with the explicit angle-bracket check).
5061 if (filename.contains('<') || filename.contains('>'))
5062 continue;
5063 // Make the path absolute so it is unambiguous regardless of the
5064 // working directory: rootcling may run from a different directory
5065 // than the one the dependency file is later consumed from (with
5066 // CMP0116 OLD the depfile is not rewritten, and a relative entry
5067 // like "./Foo.hxx" would be resolved against the wrong base and
5068 // leave the dictionary permanently out of date).
5069 llvm::SmallString<256> absPath(filename);
5070 llvm::sys::fs::make_absolute(absPath);
5071 if (!llvm::sys::fs::exists(absPath))
5072 continue;
5073 std::string filenameStr(absPath.str());
5074 // Skip the output dictionary file itself (final or temporary name).
5076 continue;
5077 includedFiles.insert(std::move(filenameStr));
5078 }
5079
5080 // Each dependency line except the last ends with a backslash.
5081 for (const auto &file : includedFiles)
5082 depFile << " \\\n " << escapeForDepFile(file);
5083 if (!includedFiles.empty())
5084 depFile << "\n";
5085
5086 depFile.close();
5087 if (!depFile.good()) {
5088 ROOT::TMetaUtils::Error(nullptr, "rootcling: failed to write dependency file %s\n", gOptDepFile.c_str());
5089 rootclingRetCode = 1;
5090 }
5091 }
5092 }
5093
5094 // Before returning, rename the files if no errors occurred
5095 // otherwise clean them to avoid remnants (see ROOT-10015)
5096 if(rootclingRetCode == 0) {
5097 rootclingRetCode += tmpCatalog.commit();
5098 } else {
5099 tmpCatalog.clean();
5100 }
5101
5102 return rootclingRetCode;
5103
5104}
5105
5106namespace genreflex {
5107
5108////////////////////////////////////////////////////////////////////////////////
5109/// Loop on arguments: stop at the first which starts with -
5110
5111 unsigned int checkHeadersNames(std::vector<std::string> &headersNames)
5112 {
5113 unsigned int numberOfHeaders = 0;
5114 for (std::vector<std::string>::iterator it = headersNames.begin();
5115 it != headersNames.end(); ++it) {
5116 const std::string headername(*it);
5119 } else {
5121 "*** genreflex: %s is not a valid header name (.h and .hpp extensions expected)!\n",
5122 headername.c_str());
5123 }
5124 }
5125 return numberOfHeaders;
5126 }
5127
5128////////////////////////////////////////////////////////////////////////////////
5129/// Extract the arguments from the command line
5130
5131 unsigned int extractArgs(int argc, char **argv, std::vector<std::string> &args)
5132 {
5133 // loop on argv, spot strings which are not preceded by something
5134 unsigned int argvCounter = 0;
5135 for (int i = 1; i < argc; ++i) {
5136 if (!ROOT::TMetaUtils::BeginsWith(argv[i - 1], "-") && // so, if preceding element starts with -, this is a value for an option
5137 !ROOT::TMetaUtils::BeginsWith(argv[i], "-")) { // and the element itself is not an option
5138 args.push_back(argv[i]);
5139 argvCounter++;
5140 } else if (argvCounter) {
5141 argv[i - argvCounter] = argv[i];
5142 }
5143 }
5144
5145 // Some debug
5146 if (genreflex::verbose) {
5147 int i = 0;
5148 std::cout << "Args: \n";
5149 for (std::vector<std::string>::iterator it = args.begin();
5150 it < args.end(); ++it) {
5151 std::cout << i << ") " << *it << std::endl;
5152 ++i;
5153 }
5154
5155 }
5156
5157 return argvCounter;
5158 }
5159
5160////////////////////////////////////////////////////////////////////////////////
5161
5162 void changeExtension(std::string &filename, const std::string &newExtension)
5163 {
5164 size_t result = filename.find_last_of('.');
5165 if (std::string::npos != result) {
5166 filename.erase(result);
5167 filename.append(newExtension);
5168 }
5169
5170 }
5171
5172////////////////////////////////////////////////////////////////////////////////
5173/// The caller is responsible for deleting the string!
5174
5175 char *string2charptr(const std::string &str)
5176 {
5177 const unsigned int size(str.size());
5178 char *a = new char[size + 1];
5179 a[size] = 0;
5180 memcpy(a, str.c_str(), size);
5181 return a;
5182 }
5183
5184////////////////////////////////////////////////////////////////////////////////
5185/// Replace the extension with "_rflx.cpp"
5186
5187 void header2outputName(std::string &fileName)
5188 {
5189 changeExtension(fileName, "_rflx.cpp");
5190 }
5191
5192////////////////////////////////////////////////////////////////////////////////
5193/// Get a proper name for the output file
5194
5195 void headers2outputsNames(const std::vector<std::string> &headersNames,
5196 std::vector<std::string> &ofilesnames)
5197 {
5198 ofilesnames.reserve(headersNames.size());
5199
5200 for (std::vector<std::string>::const_iterator it = headersNames.begin();
5201 it != headersNames.end(); ++it) {
5202 std::string ofilename(*it);
5204 ofilesnames.push_back(ofilename);
5205 }
5206 }
5207
5208////////////////////////////////////////////////////////////////////////////////
5209
5210 void AddToArgVector(std::vector<char *> &argvVector,
5211 const std::vector<std::string> &argsToBeAdded,
5212 const std::string &optName = "")
5213 {
5214 for (std::vector<std::string>::const_iterator it = argsToBeAdded.begin();
5215 it != argsToBeAdded.end(); ++it) {
5216 argvVector.push_back(string2charptr(optName + *it));
5217 }
5218 }
5219
5220////////////////////////////////////////////////////////////////////////////////
5221
5222 void AddToArgVectorSplit(std::vector<char *> &argvVector,
5223 const std::vector<std::string> &argsToBeAdded,
5224 const std::string &optName = "")
5225 {
5226 for (std::vector<std::string>::const_iterator it = argsToBeAdded.begin();
5227 it != argsToBeAdded.end(); ++it) {
5228 if (optName.length()) {
5229 argvVector.push_back(string2charptr(optName));
5230 }
5231 argvVector.push_back(string2charptr(*it));
5232 }
5233 }
5234
5235////////////////////////////////////////////////////////////////////////////////
5236
5237 int invokeRootCling(const std::string &verbosity,
5238 const std::string &selectionFileName,
5239 const std::string &targetLibName,
5240 bool multiDict,
5241 const std::vector<std::string> &pcmsNames,
5242 const std::vector<std::string> &includes,
5243 const std::vector<std::string> &preprocDefines,
5244 const std::vector<std::string> &preprocUndefines,
5245 const std::vector<std::string> &warnings,
5246 const std::string &rootmapFileName,
5247 const std::string &rootmapLibName,
5248 bool interpreteronly,
5249 bool doSplit,
5250 bool isCxxmodule,
5251 bool writeEmptyRootPCM,
5252 bool selSyntaxOnly,
5253 bool noIncludePaths,
5254 bool noGlobalUsingStd,
5255 const std::vector<std::string> &headersNames,
5256 bool failOnWarnings,
5258 const std::string &ofilename)
5259 {
5260 // Prepare and invoke the commandline to invoke rootcling
5261
5262 std::vector<char *> argvVector;
5263
5264 argvVector.push_back(string2charptr("rootcling"));
5266 argvVector.push_back(string2charptr("-f"));
5268
5269 if (isCxxmodule)
5270 argvVector.push_back(string2charptr("-cxxmodule"));
5271
5272 // Extract the path to the dictionary
5273 std::string dictLocation;
5275
5276 // Rootmaps
5277
5278 // Prepare the correct rootmap libname if not already set.
5279 std::string newRootmapLibName(rootmapLibName);
5280 if (!rootmapFileName.empty() && newRootmapLibName.empty()) {
5281 if (headersNames.size() != 1) {
5283 "*** genreflex: No rootmap lib and several header specified!\n");
5284 }
5286 newRootmapLibName = "lib";
5289 }
5290
5291 // Prepend to the rootmap the designed directory of the dictionary
5292 // if no path is specified for the rootmap itself
5294 if (!newRootmapFileName.empty() && !HasPath(newRootmapFileName)) {
5296 }
5297
5298
5299 // RootMap filename
5300 if (!newRootmapFileName.empty()) {
5301 argvVector.push_back(string2charptr("-rmf"));
5303 }
5304
5305 // RootMap Lib filename
5306 if (!newRootmapLibName.empty()) {
5307 argvVector.push_back(string2charptr("-rml"));
5309 }
5310
5311 // Always use the -reflex option: we want rootcling to behave
5312 // like genreflex in this case
5313 argvVector.push_back(string2charptr("-reflex"));
5314
5315 // Interpreter only dictionaries
5316 if (interpreteronly)
5317 argvVector.push_back(string2charptr("-interpreteronly"));
5318
5319 // Split dictionaries
5320 if (doSplit)
5321 argvVector.push_back(string2charptr("-split"));
5322
5323 // Targetlib
5324 if (!targetLibName.empty()) {
5325 argvVector.push_back(string2charptr("-s"));
5327 }
5328
5329 // Multidict support
5330 if (multiDict)
5331 argvVector.push_back(string2charptr("-multiDict"));
5332
5333 // Don't declare "using namespace std"
5334 if (noGlobalUsingStd)
5335 argvVector.push_back(string2charptr("-noGlobalUsingStd"));
5336
5337
5339
5340 // Inline the input header
5341 argvVector.push_back(string2charptr("-inlineInputHeader"));
5342
5343 // Write empty root pcms
5345 argvVector.push_back(string2charptr("-writeEmptyRootPCM"));
5346
5347 // Just test the syntax of the selection file
5348 if (selSyntaxOnly)
5349 argvVector.push_back(string2charptr("-selSyntaxOnly"));
5350
5351 // No include paths
5352 if (noIncludePaths)
5353 argvVector.push_back(string2charptr("-noIncludePaths"));
5354
5355 // Fail on warnings
5356 if (failOnWarnings)
5357 argvVector.push_back(string2charptr("-failOnWarnings"));
5358
5359 // Clingargs
5360 AddToArgVector(argvVector, includes, "-I");
5364
5366
5367 if (!selectionFileName.empty()) {
5369 }
5370
5371 const int argc = argvVector.size();
5372
5373 // Output commandline for rootcling
5375 std::string cmd;
5376 for (int i = 0; i < argc; i++) {
5377 cmd += argvVector[i];
5378 cmd += " ";
5379 }
5380 cmd.pop_back();
5381 if (genreflex::verbose) std::cout << "Rootcling commandline: ";
5382 std::cout << cmd << std::endl;
5383 if (printRootclingInvocation) return 0; // we do not generate anything
5384 }
5385
5386 char **argv = & (argvVector[0]);
5388 argv,
5389 /*isGenReflex=*/true);
5390
5391 for (int i = 0; i < argc; i++)
5392 delete [] argvVector[i];
5393
5394 return rootclingReturnCode;
5395
5396 }
5397
5398////////////////////////////////////////////////////////////////////////////////
5399/// Get the right ofilenames and invoke several times rootcling
5400/// One invokation per header
5401
5402 int invokeManyRootCling(const std::string &verbosity,
5403 const std::string &selectionFileName,
5404 const std::string &targetLibName,
5405 bool multiDict,
5406 const std::vector<std::string> &pcmsNames,
5407 const std::vector<std::string> &includes,
5408 const std::vector<std::string> &preprocDefines,
5409 const std::vector<std::string> &preprocUndefines,
5410 const std::vector<std::string> &warnings,
5411 const std::string &rootmapFileName,
5412 const std::string &rootmapLibName,
5413 bool interpreteronly,
5414 bool doSplit,
5415 bool isCxxmodule,
5416 bool writeEmptyRootPCM,
5417 bool selSyntaxOnly,
5418 bool noIncludePaths,
5419 bool noGlobalUsingStd,
5420 const std::vector<std::string> &headersNames,
5421 bool failOnWarnings,
5423 const std::string &outputDirName_const = "")
5424 {
5426
5427 std::vector<std::string> ofilesNames;
5429
5432 }
5433
5434 std::vector<std::string> namesSingleton(1);
5435 for (unsigned int i = 0; i < headersNames.size(); ++i) {
5437 std::string ofilenameFullPath(ofilesNames[i]);
5438 if (llvm::sys::path::parent_path(ofilenameFullPath) == "")
5443 multiDict,
5444 pcmsNames,
5445 includes,
5448 warnings,
5452 doSplit,
5462 if (returnCode != 0)
5463 return returnCode;
5464 }
5465
5466 return 0;
5467 }
5468
5469
5470} // end genreflex namespace
5471
5472////////////////////////////////////////////////////////////////////////////////
5473/// Extract from options multiple values with the same option
5474
5475int extractMultipleOptions(std::vector<ROOT::option::Option> &options,
5476 int oIndex,
5477 std::vector<std::string> &values)
5478{
5479 int nValues = 0;
5480 if (options[oIndex]) {
5481 const int nVals = options[oIndex].count();
5482 values.reserve(nVals);
5483 int optionIndex = 0;
5484 for (ROOT::option::Option *opt = options[oIndex]; opt; opt = opt->next()) {
5485 if (genreflex::verbose) std::cout << "Extracting multiple args: "
5486 << optionIndex << "/" << nVals << " "
5487 << opt->arg << std::endl;
5488 optionIndex++;
5489 values.push_back(opt->arg);
5490 nValues++;
5491 }
5492 }
5493 return nValues;
5494}
5495
5496////////////////////////////////////////////////////////////////////////////////
5497
5498void RiseWarningIfPresent(std::vector<ROOT::option::Option> &options,
5499 int optionIndex,
5500 const char *descriptor)
5501{
5502 if (options[optionIndex]) {
5504 "*** genereflex: %s is not supported anymore.\n",
5505 descriptor);
5506 }
5507}
5508
5509////////////////////////////////////////////////////////////////////////////////
5510
5511bool IsGoodLibraryName(const std::string &name)
5512{
5513
5514
5516#ifdef __APPLE__
5518#endif
5519 return isGood;
5520}
5521
5522////////////////////////////////////////////////////////////////////////////////
5523/// Translate the arguments of genreflex into rootcling ones and forward them
5524/// to the RootCling function.
5525/// These are two typical genreflex and rootcling commandlines
5526/// 1) genreflex header1.h [header2.h ...] [options] [preprocessor options]
5527/// 2) rootcling [-v] [-v0-4] [-f] [out.cxx] [-s sharedlib.so] [-m pcmfilename]
5528/// header1.h[{+,-}][!] ..headerN.h[{+,-}][!] [{LinkDef.h,selectionRules.xml}]
5529/// The rules with which the arguments are translated are (1st column genreflex):
5530/// --debug -v4
5531/// --quiet -v0
5532/// -o ofile positional arg after -f
5533/// -s selection file Last argument of the call
5534/// --fail_on_warning Wrap ROOT::TMetaUtils::Warning and throw if selected
5535///
5536/// New arguments:
5537/// -l --library targetLib name (new) -s targetLib name
5538/// -m pcmname (can be many -m) (new) -m pcmname (can be many -m)
5539/// --rootmap -rmf (new)
5540/// --rootmap-lib -rml (new)
5541///
5542/// genreflex options which rise warnings (feedback is desirable)
5543/// --no_membertypedefs (it should be irrelevant)
5544/// --no_templatetypedefs (it should be irrelevant)
5545///
5546/// genreflex options which are ignored (know for sure they are not needed)
5547/// --pool, --dataonly
5548/// --interpreteronly
5549/// --gccxml{path,opt,post}
5550///
5551///
5552/// Exceptions
5553/// The --deep option of genreflex is passed as function parameter to rootcling
5554/// since it's not needed at the moment there.
5555
5556int GenReflexMain(int argc, char **argv)
5557{
5558 using namespace genreflex;
5559
5560 // Setup the options parser
5561 enum optionIndex { UNKNOWN,
5563 OFILENAME,
5564 TARGETLIB,
5565 MULTIDICT,
5568 ROOTMAP,
5569 ROOTMAPLIB,
5571 DEEP,
5572 DEBUG,
5573 VERBOSE,
5574 QUIET,
5575 SILENT,
5576 CXXMODULE,
5578 HELP,
5582 SPLIT,
5586 // Don't show up in the help
5589 INCLUDE,
5590 WARNING
5591 };
5592
5593 enum optionTypes { NOTYPE, STRING } ;
5594
5595 // Some long help strings
5596 const char *genreflexUsage =
5597 "********************************************************************************\n"
5598 "* The genreflex utility does not allow to generate C++ modules containing *\n"
5599 "* reflection information required at runtime. Please use rootcling instead *\n"
5600 "* To print the rootcling invocation that corresponds to the current genreflex *\n"
5601 "* invocation please use the --print-rootcling-invocation flag. *\n"
5602 "********************************************************************************\n"
5603 "\n"
5604 "Generates dictionary sources and related ROOT pcm starting from an header.\n"
5605 "Usage: genreflex headerfile.h [opts] [preproc. opts]\n\n"
5606 "Options:\n";
5607
5608 const char *printRootclingInvocationUsage =
5609 "--print-rootcling-invocation\n"
5610 " Print to screen the rootcling invocation corresponding to the current \n"
5611 " genreflex invocation.\n";
5612
5613 const char *selectionFilenameUsage =
5614 "-s, --selection_file\tSelection filename\n"
5615 " Class selection file to specify for which classes the dictionary\n"
5616 " will be generated. The final set can be crafted with exclusion and\n"
5617 " exclusion rules.\n"
5618 " Properties can be specified. Some have special meaning:\n"
5619 " - name [string] name of the entity to select with an exact matching\n"
5620 " - pattern [string] name with wildcards (*) to select entities\n"
5621 " - file_name/file_pattern [string]: as name/pattern but referring to\n"
5622 " file where the C++ entities reside and not to C++ entities themselves.\n"
5623 " - transient/persistent [string: true/false] The fields to which they are\n"
5624 " applied will not be persistified if requested.\n"
5625 " - comment [string]: what you could write in code after an inline comment\n"
5626 " without \"//\". For example comment=\"!\" or \"||\".\n"
5627 " - noStreamer [true/false]: turns off streamer generation if set to 'true.'\n"
5628 " Default value is 'false'\n"
5629 " - rntupleStreamerMode [true/false]: enforce streamed or native writing for RNTuple.\n"
5630 " If unset, RNTuple stores classes in split mode or fails if the class cannot be split.\n"
5631 " - rntupleSoARecord [class name]: marks the class as an RNTuple SoA layout for the underlying record\n"
5632 " - noInputOperator [true/false]: turns off input operator generation if set\n"
5633 " to 'true'. Default value is 'false'\n"
5634 " Example XML:\n"
5635 " <lcgdict>\n"
5636 " [<selection>]\n"
5637 " <class [name=\"classname\"] [pattern=\"wildname\"]\n"
5638 " [file_name=\"filename\"] [file_pattern=\"wildname\"]\n"
5639 " [id=\"xxxx\"] [noStreamer=\"true/false\"]\n"
5640 " [noInputOperator=\"true/false\"]\n"
5641 " [rntupleStreamerMode=\"true/false\"] />\n"
5642 " [rntupleSoARecord=\"class_name\"] />\n"
5643 " <class name=\"classname\" >\n"
5644 " <field name=\"m_transient\" transient=\"true\"/>\n"
5645 " <field name=\"m_anothertransient\" persistent=\"false\"/>\n"
5646 " <field name=\"m_anothertransient\" comment=\"||\"/>\n"
5647 " <properties prop1=\"value1\" [prop2=\"value2\"]/>\n"
5648 " </class>\n"
5649 " <function [name=\"funcname\"] [pattern=\"wildname\"] />\n"
5650 " <enum [name=\"enumname\"] [pattern=\"wildname\"] />\n"
5651 " <variable [name=\"varname\"] [pattern=\"wildname\"] />\n"
5652 " [</selection>]\n"
5653 " <exclusion>\n"
5654 " <class [name=\"classname\"] [pattern=\"wildname\"] />\n"
5655 " <method name=\"unwanted\" />\n"
5656 " </class>\n"
5657 " ...\n"
5658 " </lcgdict>\n"
5659 "\n"
5660 " If no selection file is specified, the class with the filename without\n"
5661 " extension will be selected, i.e. myClass.h as argument without any\n"
5662 " selection xml comes with an implicit selection rule for class \"myClass\".\n";
5663
5664 const char *outputFilenameUsage =
5665 "-o, --output\tOutput filename\n"
5666 " Output file name. If an existing directory is specified instead of a file,\n"
5667 " then a filename will be built using the name of the input file and will\n"
5668 " be placed in the given directory. <headerfile>_rflx.cpp.\n"
5669 " NOTA BENE: the dictionaries that will be used within the same project must\n"
5670 " have unique names.\n";
5671
5672
5673 const char *targetLib =
5674 "-l, --library\tTarget library\n"
5675 " The flag -l must be followed by the name of the library that will\n"
5676 " contain the object file corresponding to the dictionary produced by\n"
5677 " this invocation of genreflex.\n"
5678 " The name takes priority over the one specified for the rootmapfile.\n"
5679 " The name influences the name of the created pcm:\n"
5680 " 1) If it is not specified, the pcm is called libINPUTHEADER_rdict.pcm\n"
5681 " 2) If it is specified, the pcm is called libTARGETLIBRARY_rdict.pcm\n"
5682 " Any \"liblib\" occurrence is transformed in the expected \"lib\".\n"
5683 " 3) If this is specified in conjunction with --multiDict, the output is\n"
5684 " libTARGETLIBRARY_DICTIONARY_rdict.pcm\n";
5685
5686 const char *rootmapUsage =
5687 "--rootmap\tGenerate the rootmap file to be used by ROOT.\n"
5688 " This file lists the autoload keys. For example classes for which the\n"
5689 " reflection information is provided.\n"
5690 " The format of the rootmap is the following:\n"
5691 " - Forward declarations section\n"
5692 " - Libraries sections\n"
5693 " Rootmaps can be concatenated together, for example with the cat util.\n"
5694 " In order for ROOT to pick up the information in the rootmaps, they\n"
5695 " have to be located in the library path and have the .rootmap extension.\n"
5696 " An example rootmap file could be:\n"
5697 " { decls }\n"
5698 " template <class T> class A;\n"
5699 " [ libMyLib.so ]\n"
5700 " class A<double>\n"
5701 " class B\n"
5702 " typedef C\n"
5703 " header H.h\n";
5704
5705 const char *rootmapLibUsage =
5706 "--rootmap-lib\tLibrary name for the rootmap file.\n";
5707
5708 // The Descriptor
5709 const ROOT::option::Descriptor genreflexUsageDescriptor[] = {
5710
5711 {
5712 UNKNOWN,
5713 NOTYPE,
5714 "", "",
5715 ROOT::option::Arg::None,
5717 },
5718
5719 {
5721 NOTYPE,
5722 "", "print-rootcling-invocation",
5723 ROOT::option::Arg::None,
5725 },
5726
5727 {
5728 OFILENAME,
5729 STRING ,
5730 "o" , "output" ,
5731 ROOT::option::FullArg::Required,
5733 },
5734
5735 {
5736 TARGETLIB,
5737 STRING ,
5738 "l" , "library" ,
5739 ROOT::option::FullArg::Required,
5740 targetLib
5741 },
5742
5743 {
5744 MULTIDICT,
5745 NOTYPE ,
5746 "" , "multiDict" ,
5747 ROOT::option::FullArg::None,
5748 "--multiDict\tSupport for many dictionaries in one library\n"
5749 " Form correct pcm names if multiple dictionaries will be in the same\n"
5750 " library (needs target library switch. See its documentation).\n"
5751 },
5752
5753
5754 {
5756 NOTYPE ,
5757 "" , "noGlobalUsingStd" ,
5758 ROOT::option::FullArg::None,
5759 "--noGlobalUsingStd\tDo not declare {using namespace std} in the dictionary global scope\n"
5760 " All header files must have sumbols from std:: namespace fully qualified\n"
5761 },
5762
5763 {
5765 STRING ,
5766 "s" , "selection_file" ,
5767 ROOT::option::FullArg::Required,
5769 },
5770
5771 {
5772 ROOTMAP,
5773 STRING ,
5774 "" , "rootmap" ,
5775 ROOT::option::FullArg::Required,
5777 },
5778
5779 {
5780 ROOTMAPLIB,
5781 STRING ,
5782 "" , "rootmap-lib" ,
5783 ROOT::option::FullArg::Required,
5785 },
5786
5787 {
5789 NOTYPE,
5790 "" , "interpreteronly",
5791 ROOT::option::Arg::None,
5792 "--interpreteronly\tDo not generate I/O related information.\n"
5793 " Generate minimal dictionary required for interactivity.\n"
5794 },
5795
5796 {
5797 SPLIT,
5798 NOTYPE,
5799 "" , "split",
5800 ROOT::option::Arg::None,
5801 "--split\tSplit the dictionary\n"
5802 " Split in two the dictionary, isolating the part with\n"
5803 " ClassDef related functions in a separate file.\n"
5804 },
5805
5806 {
5808 STRING ,
5809 "m" , "" ,
5810 ROOT::option::FullArg::Required,
5811 "-m \tPcm file loaded before any header (option can be repeated).\n"
5812 },
5813
5814 {
5815 VERBOSE,
5816 NOTYPE ,
5817 "-v" , "verbose",
5818 ROOT::option::Arg::None,
5819 "-v, --verbose\tPrint some debug information.\n"
5820 },
5821
5822 {
5823 DEBUG,
5824 NOTYPE ,
5825 "" , "debug",
5826 ROOT::option::Arg::None,
5827 "--debug\tPrint all debug information.\n"
5828 },
5829
5830 {
5831 QUIET,
5832 NOTYPE ,
5833 "" , "quiet",
5834 ROOT::option::Arg::None,
5835 "--quiet\tPrint only warnings and errors (default).\n"
5836 },
5837
5838 {
5839 SILENT,
5840 NOTYPE ,
5841 "" , "silent",
5842 ROOT::option::Arg::None,
5843 "--silent\tPrint no information at all.\n"
5844 },
5845
5846 {
5848 NOTYPE ,
5849 "" , "writeEmptyPCM",
5850 ROOT::option::Arg::None,
5851 "--writeEmptyPCM\tWrite an empty ROOT pcm.\n"
5852 },
5853
5854 {
5855 CXXMODULE,
5856 NOTYPE ,
5857 "" , "cxxmodule",
5858 ROOT::option::Arg::None,
5859 "--cxxmodule\tGenerates a PCM for C++ Modules.\n"
5860 },
5861
5862
5863 {
5864 HELP,
5865 NOTYPE,
5866 "h" , "help",
5867 ROOT::option::Arg::None,
5868 "--help\tPrint usage and exit.\n"
5869 },
5870
5871 {
5873 NOTYPE,
5874 "", "fail_on_warnings",
5875 ROOT::option::Arg::None,
5876 "--fail_on_warnings\tFail on warnings and errors.\n"
5877 },
5878
5879 {
5881 NOTYPE,
5882 "", "selSyntaxOnly",
5883 ROOT::option::Arg::None,
5884 "--selSyntaxOnly\tValidate selection file w/o generating the dictionary.\n"
5885 },
5886
5887 {
5889 NOTYPE ,
5890 "" , "noIncludePaths",
5891 ROOT::option::Arg::None,
5892 "--noIncludePaths\tDo not store the headers' directories in the dictionary. Instead, rely on the environment variable $ROOT_INCLUDE_PATH at runtime.\n"
5893 },
5894
5895 // Left intentionally empty not to be shown in the help, like in the first genreflex
5896 {
5897 INCLUDE,
5898 STRING ,
5899 "I" , "" ,
5900 ROOT::option::FullArg::Required,
5901 ""
5902 },
5903
5904 {
5906 STRING ,
5907 "D" , "" ,
5908 ROOT::option::FullArg::Required,
5909 ""
5910 },
5911
5912 {
5914 STRING ,
5915 "U" , "" ,
5916 ROOT::option::FullArg::Required,
5917 ""
5918 },
5919
5920 {
5921 WARNING,
5922 STRING ,
5923 "W" , "" ,
5924 ROOT::option::FullArg::Required,
5925 ""
5926 },
5927
5928 {
5929 NOMEMBERTYPEDEFS, // Option which is not meant for the user: deprecated
5930 STRING ,
5931 "" , "no_membertypedefs" ,
5932 ROOT::option::FullArg::None,
5933 ""
5934 },
5935
5936 {
5937 NOTEMPLATETYPEDEFS, // Option which is not meant for the user: deprecated
5938 STRING ,
5939 "" , "no_templatetypedefs" ,
5940 ROOT::option::FullArg::None,
5941 ""
5942 },
5943
5944 {0, 0, nullptr, nullptr, nullptr, nullptr}
5945 };
5946
5947 std::vector<std::string> headersNames;
5948 const int originalArgc = argc;
5949 // The only args are the headers here
5950 const int extractedArgs = extractArgs(argc, argv, headersNames);
5951
5952 const int offset = 1; // skip argv[0]
5954 argv += offset;
5955
5956 // Parse the options
5957 ROOT::option::Stats stats(genreflexUsageDescriptor, argc, argv);
5958 std::vector<ROOT::option::Option> options(stats.options_max);// non POD var size arrays are not C++!
5959 std::vector<ROOT::option::Option> buffer(stats.buffer_max);
5960 // The 4 is the minimum size of the abbreviation length.
5961 // For example, --selection_file can be abbreviated with --sele at least.
5962
5963 ROOT::option::Parser parse(genreflexUsageDescriptor, argc, argv, &options[0], &buffer[0], 5);
5964
5965 if (parse.error()) {
5966 ROOT::TMetaUtils::Error(nullptr, "Argument parsing error!\n");
5967 return 1;
5968 }
5969
5970 // Print help if needed
5971 if (options[HELP] || originalArgc == 1) {
5972 ROOT::option::printUsage(std::cout, genreflexUsageDescriptor);
5973 return 0;
5974 }
5975 // See if no header was provided
5976 int numberOfHeaders = checkHeadersNames(headersNames);
5977 if (0 == numberOfHeaders) {
5978 ROOT::TMetaUtils::Error(nullptr, "No valid header was provided!\n");
5979 return 1;
5980 }
5981
5983
5984 if (options[DEEP])
5985 ROOT::TMetaUtils::Warning(nullptr, "--deep has no effect. Please remove the deprecated flag!\n");
5986 // The verbosity: debug wins over quiet
5987 //std::string verbosityOption("-v4"); // To be uncommented for the testing phase. It should be -v
5988 std::string verbosityOption("-v2");
5989 if (options[SILENT]) verbosityOption = "-v0";
5990 if (options[VERBOSE] || std::getenv ("VERBOSE")) verbosityOption = "-v3";
5991 if (options[DEBUG]) verbosityOption = "-v4";
5992
5994
5995 // The selection file
5996 std::string selectionFileName;
5997 if (options[SELECTIONFILENAME]) {
5998 selectionFileName = options[SELECTIONFILENAME].arg;
6001 "Invalid selection file extension: filename is %s and extension .xml is expected!\n",
6002 selectionFileName.c_str());
6003 return 1;
6004 }
6005 }
6006
6007// // Warn if a selection file is not present and exit
6008// if (NULL==options[SELECTIONFILENAME].arg){
6009// ROOT::TMetaUtils::Warning(0,"The usage of genreflex without a selection file is not yet supported.\n");
6010// return 1;
6011// }
6012
6013
6014 // Set the parameters for the rootmap file. If the libname is not set,
6015 // it will be set according to the header in invokeRootCling.
6016 // FIXME: treatment of directories
6017 std::string rootmapFileName(options[ROOTMAP].arg ? options[ROOTMAP].arg : "");
6018 std::string rootmapLibName(options[ROOTMAPLIB].arg ? options[ROOTMAPLIB].arg : "");
6019
6020 // The target lib name
6021 std::string targetLibName;
6022 if (options[TARGETLIB]) {
6023 targetLibName = options[TARGETLIB].arg;
6026 "Invalid target library extension: filename is %s and extension %s is expected!\n",
6027 targetLibName.c_str(),
6028 gLibraryExtension.c_str());
6029 }
6030 // Target lib has precedence over rootmap lib
6031 if (options[ROOTMAP]) {
6033 }
6034 }
6035
6036 bool isCxxmodule = options[CXXMODULE];
6037
6038 bool multidict = false;
6039 if (options[MULTIDICT]) multidict = true;
6040
6041 bool noGlobalUsingStd = false;
6042 if (options[NOGLOBALUSINGSTD]) noGlobalUsingStd = true;
6043
6044 if (multidict && targetLibName.empty()) {
6046 "Multilib support is requested but no target lib is specified. A sane pcm name cannot be formed.\n");
6047 return 1;
6048 }
6049
6050 bool printRootclingInvocation = false;
6051 if (options[PRINTROOTCLINGINVOCATION])
6053
6054 bool interpreteronly = false;
6055 if (options[INTERPRETERONLY])
6056 interpreteronly = true;
6057
6058 bool doSplit = false;
6059 if (options[SPLIT])
6060 doSplit = true;
6061
6062 bool writeEmptyRootPCM = false;
6063 if (options[WRITEEMPTYROOTPCM])
6064 writeEmptyRootPCM = true;
6065
6066 bool selSyntaxOnly = false;
6067 if (options[SELSYNTAXONLY]) {
6068 selSyntaxOnly = true;
6069 }
6070
6071 bool noIncludePaths = false;
6072 if (options[NOINCLUDEPATHS]) {
6073 noIncludePaths = true;
6074 }
6075
6076 bool failOnWarnings = false;
6077 if (options[FAILONWARNINGS]) {
6078 failOnWarnings = true;
6079 }
6080
6081 // Add the .so extension to the rootmap lib if not there
6084 }
6085
6086 // The list of pcms to be preloaded
6087 std::vector<std::string> pcmsNames;
6089
6090 // Preprocessor defines
6091 std::vector<std::string> preprocDefines;
6093
6094 // Preprocessor undefines
6095 std::vector<std::string> preprocUndefines;
6097
6098 // Includes
6099 std::vector<std::string> includes;
6100 extractMultipleOptions(options, INCLUDE, includes);
6101
6102 // Warnings
6103 std::vector<std::string> warnings;
6104 extractMultipleOptions(options, WARNING, warnings);
6105
6106 // The outputfilename(s)
6107 // There are two cases:
6108 // 1) The outputfilename is specified
6109 // --> The information of all headers will be in one single dictionary
6110 // (1 call to rootcling)
6111 // 2) The outputfilename is not specified
6112 // --> There will be a dictionary per header
6113 // (N calls to rootcling)
6114 int returnValue = 0;
6115 std::string ofileName(options[OFILENAME] ? options[OFILENAME].arg : "");
6116
6117 // If not empty and not a directory (therefore it's a file)
6118 // call rootcling directly. The number of headers files is irrelevant.
6119 if (!ofileName.empty() && !llvm::sys::fs::is_directory(ofileName)) {
6120 returnValue = invokeRootCling(verbosityOption,
6123 multidict,
6124 pcmsNames,
6125 includes,
6128 warnings,
6132 doSplit,
6141 ofileName);
6142 } else {
6143 // Here ofilename is either "" or a directory: this is irrelevant.
6144 returnValue = invokeManyRootCling(verbosityOption,
6147 multidict,
6148 pcmsNames,
6149 includes,
6152 warnings,
6156 doSplit,
6165 ofileName);
6166 }
6167
6168 return returnValue;
6169}
6170
6171
6172////////////////////////////////////////////////////////////////////////////////
6173
6174extern "C"
6176{
6177
6178 assert(!gDriverConfig && "Driver configuration already set!");
6179 gDriverConfig = &config;
6180
6181 gBuildingROOT = config.fBuildingROOTStage1; // gets refined later
6182
6183 std::string exeName = ExtractFileName(GetExePath());
6184#ifdef __APPLE__
6185 // _dyld_get_image_name() on macOS11 and later sometimes returns "rootcling" for "genreflex".
6186 // Fix that (while still initializing the binary path, needed for ROOTSYS) by updating the
6187 // exeName to argv[0]:
6189#endif
6190
6191 // Select according to the name of the executable the procedure to follow:
6192 // 1) RootCling
6193 // 2) GenReflex
6194 // The default is rootcling
6195
6196 int retVal = 0;
6197
6198 if (std::string::npos != exeName.find("genreflex"))
6200 else // rootcling or default
6202
6203 gDriverConfig = nullptr;
6204
6206 ROOT::TMetaUtils::Info(nullptr,"Problems have been detected during the generation of the dictionary.\n");
6207 return 1;
6208 }
6209 return retVal;
6210}
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