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