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()
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#if !defined(R__AIX)
1197 dictStream << " inline ::ROOT::TGenericClassInfo *GenerateInitInstance();" << std::endl;
1198#endif
1199
1200 if (!Namespace__HasMethod(cl, "Dictionary", interp))
1201 dictStream << " static TClass *" << mappedname.c_str() << "_Dictionary();" << std::endl;
1202 dictStream << std::endl
1203
1204 << " // Function generating the singleton type initializer" << std::endl
1205
1206#if !defined(R__AIX)
1207 << " inline ::ROOT::TGenericClassInfo *GenerateInitInstance()" << std::endl
1208 << " {" << std::endl
1209#else
1210 << " ::ROOT::TGenericClassInfo *GenerateInitInstance()" << std::endl
1211 << " {" << std::endl
1212#endif
1213
1214 << " static ::ROOT::TGenericClassInfo " << std::endl
1215
1216 << " instance(\"" << classname.c_str() << "\", ";
1217
1218 if (Namespace__HasMethod(cl, "Class_Version", interp)) {
1219 dictStream << "::" << classname.c_str() << "::Class_Version(), ";
1220 } else {
1221 dictStream << "0 /*version*/, ";
1222 }
1223
1224 std::string filename = ROOT::TMetaUtils::GetFileName(*cl, interp);
1225 for (unsigned int i = 0; i < filename.length(); i++) {
1226 if (filename[i] == '\\') filename[i] = '/';
1227 }
1228 dictStream << "\"" << filename << "\", " << ROOT::TMetaUtils::GetLineNumber(cl) << "," << std::endl
1229 << " ::ROOT::Internal::DefineBehavior((void*)nullptr,(void*)nullptr)," << std::endl
1230 << " ";
1231
1232 if (Namespace__HasMethod(cl, "Dictionary", interp)) {
1233 dictStream << "&::" << classname.c_str() << "::Dictionary, ";
1234 } else {
1235 dictStream << "&" << mappedname.c_str() << "_Dictionary, ";
1236 }
1237
1238 dictStream << 0 << ");" << std::endl
1239
1240 << " return &instance;" << std::endl
1241 << " }" << std::endl
1242 << " // Insure that the inline function is _not_ optimized away by the compiler\n"
1243 << " ::ROOT::TGenericClassInfo *(*_R__UNIQUE_DICT_(InitFunctionKeeper))() = &GenerateInitInstance; " << std::endl
1244 << " // Static variable to force the class initialization" << std::endl
1245 // must be one long line otherwise R__UseDummy does not work
1246 << " static ::ROOT::TGenericClassInfo *_R__UNIQUE_DICT_(Init) = GenerateInitInstance();"
1247 << " R__UseDummy(_R__UNIQUE_DICT_(Init));" << std::endl;
1248
1249 if (!Namespace__HasMethod(cl, "Dictionary", interp)) {
1250 dictStream << std::endl << " // Dictionary for non-ClassDef classes" << std::endl
1251 << " static TClass *" << mappedname.c_str() << "_Dictionary() {" << std::endl
1252 << " return GenerateInitInstance()->GetClass();" << std::endl
1253 << " }" << std::endl << std::endl;
1254 }
1255
1256 dictStream << " }" << std::endl;
1257 while (nesting--) {
1258 dictStream << "}" << std::endl;
1259 }
1260 dictStream << std::endl;
1261}
1262
1263////////////////////////////////////////////////////////////////////////////////
1264/// GrabIndex returns a static string (so use it or copy it immediately, do not
1265/// call GrabIndex twice in the same expression) containing the size of the
1266/// array data member.
1267/// In case of error, or if the size is not specified, GrabIndex returns 0.
1268
1269llvm::StringRef GrabIndex(const cling::Interpreter& interp, const clang::FieldDecl &member, int printError)
1270{
1271 int error;
1272 llvm::StringRef where;
1273
1275 if (index.size() == 0 && printError) {
1276 const char *errorstring;
1277 switch (error) {
1279 errorstring = "is not an integer";
1280 break;
1282 errorstring = "has not been defined before the array";
1283 break;
1285 errorstring = "is a private member of a parent class";
1286 break;
1288 errorstring = "is not known";
1289 break;
1290 default:
1291 errorstring = "UNKNOWN ERROR!!!!";
1292 }
1293
1294 if (where.size() == 0) {
1295 ROOT::TMetaUtils::Error(nullptr, "*** Datamember %s::%s: no size indication!\n",
1296 member.getParent()->getName().str().c_str(), member.getName().str().c_str());
1297 } else {
1298 ROOT::TMetaUtils::Error(nullptr, "*** Datamember %s::%s: size of array (%s) %s!\n",
1299 member.getParent()->getName().str().c_str(), member.getName().str().c_str(), where.str().c_str(), errorstring);
1300 }
1301 }
1302 return index;
1303}
1304
1305////////////////////////////////////////////////////////////////////////////////
1306
1308 const cling::Interpreter &interp,
1310 std::ostream &dictStream)
1311{
1312 const clang::CXXRecordDecl *clxx = llvm::dyn_cast<clang::CXXRecordDecl>(cl.GetRecordDecl());
1313 if (clxx == nullptr) return;
1314
1316
1317 string fullname;
1318 string clsname;
1319 string nsname;
1320 int enclSpaceNesting = 0;
1321
1324 }
1325
1326 dictStream << "//_______________________________________"
1327 << "_______________________________________" << std::endl;
1328 if (add_template_keyword) dictStream << "template <> ";
1329 dictStream << "void " << clsname << "::Streamer(TBuffer &R__b)" << std::endl << "{" << std::endl
1330 << " // Stream an object of class " << fullname << "." << std::endl << std::endl;
1331
1332 // In case of VersionID<=0 write dummy streamer only calling
1333 // its base class Streamer(s). If no base class(es) let Streamer
1334 // print error message, i.e. this Streamer should never have been called.
1336 if (version <= 0) {
1337 // We also need to look at the base classes.
1338 int basestreamer = 0;
1339 for (clang::CXXRecordDecl::base_class_const_iterator iter = clxx->bases_begin(), end = clxx->bases_end();
1340 iter != end;
1341 ++iter) {
1342 if (ROOT::TMetaUtils::ClassInfo__HasMethod(iter->getType()->getAsCXXRecordDecl(), "Streamer", interp)) {
1343 string base_fullname;
1344 ROOT::TMetaUtils::GetQualifiedName(base_fullname, * iter->getType()->getAsCXXRecordDecl());
1345
1346 if (strstr(base_fullname.c_str(), "::")) {
1347 // there is a namespace involved, trigger MS VC bug workaround
1348 dictStream << " //This works around a msvc bug and should be harmless on other platforms" << std::endl
1349 << " typedef " << base_fullname << " baseClass" << basestreamer << ";" << std::endl
1350 << " baseClass" << basestreamer << "::Streamer(R__b);" << std::endl;
1351 } else {
1352 dictStream << " " << base_fullname << "::Streamer(R__b);" << std::endl;
1353 }
1354 basestreamer++;
1355 }
1356 }
1357 if (!basestreamer) {
1358 dictStream << " ::Error(\"" << fullname << "::Streamer\", \"version id <=0 in ClassDef,"
1359 " dummy Streamer() called\"); if (R__b.IsReading()) { }" << std::endl;
1360 }
1361 dictStream << "}" << std::endl << std::endl;
1362 while (enclSpaceNesting) {
1363 dictStream << "} // namespace " << nsname.c_str() << std::endl;
1365 }
1366 return;
1367 }
1368
1369 // loop twice: first time write reading code, second time writing code
1370 string classname = fullname;
1371 if (strstr(fullname.c_str(), "::")) {
1372 // there is a namespace involved, trigger MS VC bug workaround
1373 dictStream << " //This works around a msvc bug and should be harmless on other platforms" << std::endl
1374 << " typedef ::" << fullname << " thisClass;" << std::endl;
1375 classname = "thisClass";
1376 }
1377 for (int i = 0; i < 2; i++) {
1378
1379 int decli = 0;
1380
1381 if (i == 0) {
1382 dictStream << " UInt_t R__s, R__c;" << std::endl;
1383 dictStream << " if (R__b.IsReading()) {" << std::endl;
1384 dictStream << " Version_t R__v = R__b.ReadVersion(&R__s, &R__c); if (R__v) { }" << std::endl;
1385 } else {
1386 dictStream << " R__b.CheckByteCount(R__s, R__c, " << classname.c_str() << "::IsA());" << std::endl;
1387 dictStream << " } else {" << std::endl;
1388 dictStream << " R__c = R__b.WriteVersion(" << classname.c_str() << "::IsA(), kTRUE);" << std::endl;
1389 }
1390
1391 // Stream base class(es) when they have the Streamer() method
1392 int base = 0;
1393 for (clang::CXXRecordDecl::base_class_const_iterator iter = clxx->bases_begin(), end = clxx->bases_end();
1394 iter != end;
1395 ++iter) {
1396 if (ROOT::TMetaUtils::ClassInfo__HasMethod(iter->getType()->getAsCXXRecordDecl(), "Streamer", interp)) {
1397 string base_fullname;
1398 ROOT::TMetaUtils::GetQualifiedName(base_fullname, * iter->getType()->getAsCXXRecordDecl());
1399
1400 if (strstr(base_fullname.c_str(), "::")) {
1401 // there is a namespace involved, trigger MS VC bug workaround
1402 dictStream << " //This works around a msvc bug and should be harmless on other platforms" << std::endl
1403 << " typedef " << base_fullname << " baseClass" << base << ";" << std::endl
1404 << " baseClass" << base << "::Streamer(R__b);" << std::endl;
1405 ++base;
1406 } else {
1407 dictStream << " " << base_fullname << "::Streamer(R__b);" << std::endl;
1408 }
1409 }
1410 }
1411 // Stream data members
1412 // Loop over the non static data member.
1413 for (clang::RecordDecl::field_iterator field_iter = clxx->field_begin(), end = clxx->field_end();
1414 field_iter != end;
1415 ++field_iter) {
1416 const char *comment = ROOT::TMetaUtils::GetComment(**field_iter).data();
1417
1418 clang::QualType type = field_iter->getType();
1419 std::string type_name = type.getAsString(clxx->getASTContext().getPrintingPolicy());
1420
1422
1423 // we skip:
1424 // - static members
1425 // - members with an ! as first character in the title (comment) field
1426
1427 //special case for Float16_t
1428 int isFloat16 = 0;
1429 if (strstr(type_name.c_str(), "Float16_t")) isFloat16 = 1;
1430
1431 //special case for Double32_t
1432 int isDouble32 = 0;
1433 if (strstr(type_name.c_str(), "Double32_t")) isDouble32 = 1;
1434
1435 // No need to test for static, there are not in this list.
1436 if (strncmp(comment, "!", 1)) {
1437
1438 // fundamental type: short, int, long, etc....
1439 if (underling_type->isFundamentalType() || underling_type->isEnumeralType()) {
1440 if (type.getTypePtr()->isConstantArrayType() &&
1441 type.getTypePtr()->getArrayElementTypeNoTypeQual()->isPointerType()) {
1442 const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(type.getTypePtr());
1444
1445 if (!decli) {
1446 dictStream << " int R__i;" << std::endl;
1447 decli = 1;
1448 }
1449 dictStream << " for (R__i = 0; R__i < " << s << "; R__i++)" << std::endl;
1450 if (i == 0) {
1451 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());
1452 dictStream << " ;//R__b.ReadArray(" << field_iter->getName().str() << ");" << std::endl;
1453 } else {
1454 dictStream << " ;//R__b.WriteArray(" << field_iter->getName().str() << ", __COUNTER__);" << std::endl;
1455 }
1456 } else if (type.getTypePtr()->isPointerType()) {
1457 llvm::StringRef indexvar = GrabIndex(interp, **field_iter, i == 0);
1458 if (indexvar.size() == 0) {
1459 if (i == 0) {
1460 ROOT::TMetaUtils::Error(nullptr, "*** Datamember %s::%s: pointer to fundamental type (need manual intervention)\n", fullname.c_str(), field_iter->getName().str().c_str());
1461 dictStream << " //R__b.ReadArray(" << field_iter->getName().str() << ");" << std::endl;
1462 } else {
1463 dictStream << " //R__b.WriteArray(" << field_iter->getName().str() << ", __COUNTER__);" << std::endl;
1464 }
1465 } else {
1466 if (i == 0) {
1467 dictStream << " delete [] " << field_iter->getName().str() << ";" << std::endl
1468 << " " << GetNonConstMemberName(**field_iter) << " = new "
1469 << ROOT::TMetaUtils::ShortTypeName(**field_iter) << "[" << indexvar.str() << "];" << std::endl;
1470 if (isFloat16) {
1471 dictStream << " R__b.ReadFastArrayFloat16(" << GetNonConstMemberName(**field_iter)
1472 << "," << indexvar.str() << ");" << std::endl;
1473 } else if (isDouble32) {
1474 dictStream << " R__b.ReadFastArrayDouble32(" << GetNonConstMemberName(**field_iter)
1475 << "," << indexvar.str() << ");" << std::endl;
1476 } else {
1477 dictStream << " R__b.ReadFastArray(" << GetNonConstMemberName(**field_iter)
1478 << "," << indexvar.str() << ");" << std::endl;
1479 }
1480 } else {
1481 if (isFloat16) {
1482 dictStream << " R__b.WriteFastArrayFloat16("
1483 << field_iter->getName().str() << "," << indexvar.str() << ");" << std::endl;
1484 } else if (isDouble32) {
1485 dictStream << " R__b.WriteFastArrayDouble32("
1486 << field_iter->getName().str() << "," << indexvar.str() << ");" << std::endl;
1487 } else {
1488 dictStream << " R__b.WriteFastArray("
1489 << field_iter->getName().str() << "," << indexvar.str() << ");" << std::endl;
1490 }
1491 }
1492 }
1493 } else if (type.getTypePtr()->isArrayType()) {
1494 if (i == 0) {
1495 if (type.getTypePtr()->getArrayElementTypeNoTypeQual()->isArrayType()) { // if (m.ArrayDim() > 1) {
1496 if (underling_type->isEnumeralType())
1497 dictStream << " R__b.ReadStaticArray((Int_t*)" << field_iter->getName().str() << ");" << std::endl;
1498 else {
1499 if (isFloat16) {
1500 dictStream << " R__b.ReadStaticArrayFloat16((" << ROOT::TMetaUtils::TrueName(**field_iter)
1501 << "*)" << field_iter->getName().str() << ");" << std::endl;
1502 } else if (isDouble32) {
1503 dictStream << " R__b.ReadStaticArrayDouble32((" << ROOT::TMetaUtils::TrueName(**field_iter)
1504 << "*)" << field_iter->getName().str() << ");" << std::endl;
1505 } else {
1506 dictStream << " R__b.ReadStaticArray((" << ROOT::TMetaUtils::TrueName(**field_iter)
1507 << "*)" << field_iter->getName().str() << ");" << std::endl;
1508 }
1509 }
1510 } else {
1511 if (underling_type->isEnumeralType()) {
1512 dictStream << " R__b.ReadStaticArray((Int_t*)" << field_iter->getName().str() << ");" << std::endl;
1513 } else {
1514 if (isFloat16) {
1515 dictStream << " R__b.ReadStaticArrayFloat16(" << field_iter->getName().str() << ");" << std::endl;
1516 } else if (isDouble32) {
1517 dictStream << " R__b.ReadStaticArrayDouble32(" << field_iter->getName().str() << ");" << std::endl;
1518 } else {
1519 dictStream << " R__b.ReadStaticArray((" << ROOT::TMetaUtils::TrueName(**field_iter)
1520 << "*)" << field_iter->getName().str() << ");" << std::endl;
1521 }
1522 }
1523 }
1524 } else {
1525 const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(type.getTypePtr());
1527
1528 if (type.getTypePtr()->getArrayElementTypeNoTypeQual()->isArrayType()) {// if (m.ArrayDim() > 1) {
1529 if (underling_type->isEnumeralType())
1530 dictStream << " R__b.WriteArray((Int_t*)" << field_iter->getName().str() << ", "
1531 << s << ");" << std::endl;
1532 else if (isFloat16) {
1533 dictStream << " R__b.WriteArrayFloat16((" << ROOT::TMetaUtils::TrueName(**field_iter)
1534 << "*)" << field_iter->getName().str() << ", " << s << ");" << std::endl;
1535 } else if (isDouble32) {
1536 dictStream << " R__b.WriteArrayDouble32((" << ROOT::TMetaUtils::TrueName(**field_iter)
1537 << "*)" << field_iter->getName().str() << ", " << s << ");" << std::endl;
1538 } else {
1539 dictStream << " R__b.WriteArray((" << ROOT::TMetaUtils::TrueName(**field_iter)
1540 << "*)" << field_iter->getName().str() << ", " << s << ");" << std::endl;
1541 }
1542 } else {
1543 if (underling_type->isEnumeralType())
1544 dictStream << " R__b.WriteArray((Int_t*)" << field_iter->getName().str() << ", " << s << ");" << std::endl;
1545 else if (isFloat16) {
1546 dictStream << " R__b.WriteArrayFloat16(" << field_iter->getName().str() << ", " << s << ");" << std::endl;
1547 } else if (isDouble32) {
1548 dictStream << " R__b.WriteArrayDouble32(" << field_iter->getName().str() << ", " << s << ");" << std::endl;
1549 } else {
1550 dictStream << " R__b.WriteArray(" << field_iter->getName().str() << ", " << s << ");" << std::endl;
1551 }
1552 }
1553 }
1554 } else if (underling_type->isEnumeralType()) {
1555 if (i == 0) {
1556 dictStream << " void *ptr_" << field_iter->getName().str() << " = (void*)&" << field_iter->getName().str() << ";\n";
1557 dictStream << " R__b >> *reinterpret_cast<Int_t*>(ptr_" << field_iter->getName().str() << ");" << std::endl;
1558 } else
1559 dictStream << " R__b << (Int_t)" << field_iter->getName().str() << ";" << std::endl;
1560 } else {
1561 if (isFloat16) {
1562 if (i == 0)
1563 dictStream << " {float R_Dummy; R__b >> R_Dummy; " << GetNonConstMemberName(**field_iter)
1564 << "=Float16_t(R_Dummy);}" << std::endl;
1565 else
1566 dictStream << " R__b << float(" << GetNonConstMemberName(**field_iter) << ");" << std::endl;
1567 } else if (isDouble32) {
1568 if (i == 0)
1569 dictStream << " {float R_Dummy; R__b >> R_Dummy; " << GetNonConstMemberName(**field_iter)
1570 << "=Double32_t(R_Dummy);}" << std::endl;
1571 else
1572 dictStream << " R__b << float(" << GetNonConstMemberName(**field_iter) << ");" << std::endl;
1573 } else {
1574 if (i == 0)
1575 dictStream << " R__b >> " << GetNonConstMemberName(**field_iter) << ";" << std::endl;
1576 else
1577 dictStream << " R__b << " << GetNonConstMemberName(**field_iter) << ";" << std::endl;
1578 }
1579 }
1580 } else {
1581 // we have an object...
1582
1583 // check if object is a standard string
1585 continue;
1586
1587 // check if object is an STL container
1589 continue;
1590
1591 // handle any other type of objects
1592 if (type.getTypePtr()->isConstantArrayType() &&
1593 type.getTypePtr()->getArrayElementTypeNoTypeQual()->isPointerType()) {
1594 const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(type.getTypePtr());
1596
1597 if (!decli) {
1598 dictStream << " int R__i;" << std::endl;
1599 decli = 1;
1600 }
1601 dictStream << " for (R__i = 0; R__i < " << s << "; R__i++)" << std::endl;
1602 if (i == 0)
1603 dictStream << " R__b >> " << GetNonConstMemberName(**field_iter);
1604 else {
1606 dictStream << " R__b << (TObject*)" << field_iter->getName().str();
1607 else
1608 dictStream << " R__b << " << GetNonConstMemberName(**field_iter);
1609 }
1611 dictStream << "[R__i];" << std::endl;
1612 } else if (type.getTypePtr()->isPointerType()) {
1613 // This is always good. However, in case of a pointer
1614 // to an object that is guaranteed to be there and not
1615 // being referenced by other objects we could use
1616 // xx->Streamer(b);
1617 // Optimize this with control statement in title.
1619 if (i == 0) {
1620 ROOT::TMetaUtils::Error(nullptr, "*** Datamember %s::%s: pointer to pointer (need manual intervention)\n", fullname.c_str(), field_iter->getName().str().c_str());
1621 dictStream << " //R__b.ReadArray(" << field_iter->getName().str() << ");" << std::endl;
1622 } else {
1623 dictStream << " //R__b.WriteArray(" << field_iter->getName().str() << ", __COUNTER__);";
1624 }
1625 } else {
1627 dictStream << " " << field_iter->getName().str() << "->Streamer(R__b);" << std::endl;
1628 } else {
1629 if (i == 0) {
1630 // The following:
1631 // if (strncmp(m.Title(),"->",2) != 0) fprintf(fp, " delete %s;\n", GetNonConstMemberName(**field_iter).c_str());
1632 // could be used to prevent a memory leak since the next statement could possibly create a new object.
1633 // In the TStreamerInfo based I/O we made the previous statement conditional on TStreamerInfo::CanDelete
1634 // to allow the user to prevent some inadvisable deletions. So we should be offering this flexibility
1635 // here to and should not (technically) rely on TStreamerInfo for it, so for now we leave it as is.
1636 // Note that the leak should happen from here only if the object is stored in an unsplit object
1637 // and either the user request an old branch or the streamer has been customized.
1638 dictStream << " R__b >> " << GetNonConstMemberName(**field_iter) << ";" << std::endl;
1639 } else {
1641 dictStream << " R__b << (TObject*)" << field_iter->getName().str() << ";" << std::endl;
1642 else
1643 dictStream << " R__b << " << GetNonConstMemberName(**field_iter) << ";" << std::endl;
1644 }
1645 }
1646 }
1647 } else if (const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(type.getTypePtr())) {
1649
1650 if (!decli) {
1651 dictStream << " int R__i;" << std::endl;
1652 decli = 1;
1653 }
1654 dictStream << " for (R__i = 0; R__i < " << s << "; R__i++)" << std::endl;
1655 std::string mTypeNameStr;
1657 const char *mTypeName = mTypeNameStr.c_str();
1658 const char *constwd = "const ";
1659 if (strncmp(constwd, mTypeName, strlen(constwd)) == 0) {
1661 dictStream << " const_cast< " << mTypeName << " &>(" << field_iter->getName().str();
1663 dictStream << "[R__i]).Streamer(R__b);" << std::endl;
1664 } else {
1667 dictStream << "[R__i].Streamer(R__b);" << std::endl;
1668 }
1669 } else {
1671 dictStream << " " << GetNonConstMemberName(**field_iter) << ".Streamer(R__b);" << std::endl;
1672 else {
1673 dictStream << " R__b.StreamObject(&(" << field_iter->getName().str() << "),typeid("
1674 << field_iter->getName().str() << "));" << std::endl; //R__t.Streamer(R__b);\n");
1675 //VP if (i == 0)
1676 //VP Error(0, "*** Datamember %s::%s: object has no Streamer() method (need manual intervention)\n",
1677 //VP fullname, field_iter->getName().str());
1678 //VP fprintf(fp, " //%s.Streamer(R__b);\n", m.Name());
1679 }
1680 }
1681 }
1682 }
1683 }
1684 }
1685 dictStream << " R__b.SetByteCount(R__c, kTRUE);" << std::endl
1686 << " }" << std::endl
1687 << "}" << std::endl << std::endl;
1688
1689 while (enclSpaceNesting) {
1690 dictStream << "} // namespace " << nsname.c_str() << std::endl;
1692 }
1693}
1694
1695////////////////////////////////////////////////////////////////////////////////
1696
1698 const cling::Interpreter &interp,
1700 std::ostream &dictStream)
1701{
1702 // Write Streamer() method suitable for automatic schema evolution.
1703
1704 const clang::CXXRecordDecl *clxx = llvm::dyn_cast<clang::CXXRecordDecl>(cl.GetRecordDecl());
1705 if (clxx == nullptr) return;
1706
1708
1709 // We also need to look at the base classes.
1710 for (clang::CXXRecordDecl::base_class_const_iterator iter = clxx->bases_begin(), end = clxx->bases_end();
1711 iter != end;
1712 ++iter) {
1713 int k = ROOT::TMetaUtils::IsSTLContainer(*iter);
1714 if (k != 0) {
1715 Internal::RStl::Instance().GenerateTClassFor(iter->getType(), interp, normCtxt);
1716 }
1717 }
1718
1719 string fullname;
1720 string clsname;
1721 string nsname;
1722 int enclSpaceNesting = 0;
1723
1726 }
1727
1728 dictStream << "//_______________________________________"
1729 << "_______________________________________" << std::endl;
1730 if (add_template_keyword) dictStream << "template <> ";
1731 dictStream << "void " << clsname << "::Streamer(TBuffer &R__b)" << std::endl
1732 << "{" << std::endl
1733 << " // Stream an object of class " << fullname << "." << std::endl << std::endl
1734 << " if (R__b.IsReading()) {" << std::endl
1735 << " R__b.ReadClassBuffer(" << fullname << "::Class(),this);" << std::endl
1736 << " } else {" << std::endl
1737 << " R__b.WriteClassBuffer(" << fullname << "::Class(),this);" << std::endl
1738 << " }" << std::endl
1739 << "}" << std::endl << std::endl;
1740
1741 while (enclSpaceNesting) {
1742 dictStream << "} // namespace " << nsname << std::endl;
1744 }
1745}
1746
1747////////////////////////////////////////////////////////////////////////////////
1748
1750 const cling::Interpreter &interp,
1752 std::ostream &dictStream,
1753 bool isAutoStreamer)
1754{
1755 if (isAutoStreamer) {
1757 } else {
1759 }
1760}
1761
1762////////////////////////////////////////////////////////////////////////////////
1763/// Find file name in path specified via -I statements to Cling.
1764/// Return false if the file can not be found.
1765/// If the file is found, set pname to the full path name and return true.
1766
1767bool Which(cling::Interpreter &interp, const char *fname, string &pname)
1768{
1769 FILE *fp = nullptr;
1770
1771#ifdef WIN32
1772 static const char *fopenopts = "rb";
1773#else
1774 static const char *fopenopts = "r";
1775#endif
1776
1777 pname = fname;
1778 fp = fopen(pname.c_str(), fopenopts);
1779 if (fp) {
1780 fclose(fp);
1781 return true;
1782 }
1783
1784 llvm::SmallVector<std::string, 10> includePaths;//Why 10? Hell if I know.
1785 //false - no system header, false - with flags.
1786 interp.GetIncludePaths(includePaths, false, false);
1787
1788 const size_t nPaths = includePaths.size();
1789 for (size_t i = 0; i < nPaths; i += 1 /* 2 */) {
1790
1791 pname = includePaths[i].c_str() + gPathSeparator + fname;
1792
1793 fp = fopen(pname.c_str(), fopenopts);
1794 if (fp) {
1795 fclose(fp);
1796 return true;
1797 }
1798 }
1799 pname = "";
1800 return false;
1801}
1802
1803////////////////////////////////////////////////////////////////////////////////
1804/// If the argument starts with MODULE/inc, strip it
1805/// to make it the name we can use in `#includes`.
1806
1807const char *CopyArg(const char *original)
1808{
1809 if (!gBuildingROOT)
1810 return original;
1811
1813 return original;
1814
1815 const char *inc = strstr(original, "\\inc\\");
1816 if (!inc)
1817 inc = strstr(original, "/inc/");
1818 if (inc && strlen(inc) > 5)
1819 return inc + 5;
1820 return original;
1821}
1822
1823////////////////////////////////////////////////////////////////////////////////
1824/// Copy the command line argument, stripping MODULE/inc if
1825/// necessary.
1826
1827void StrcpyArg(string &dest, const char *original)
1828{
1830}
1831
1832////////////////////////////////////////////////////////////////////////////////
1833/// Write the extra header injected into the module:
1834/// umbrella header if (umbrella) else content header.
1835
1836static bool InjectModuleUtilHeader(const char *argv0,
1838 cling::Interpreter &interp,
1839 bool umbrella)
1840{
1841 std::ostringstream out;
1842 if (umbrella) {
1843 // This will duplicate the -D,-U from clingArgs - but as they are surrounded
1844 // by #ifndef there is no problem here.
1845 modGen.WriteUmbrellaHeader(out);
1846 if (interp.declare(out.str()) != cling::Interpreter::kSuccess) {
1847 const std::string &hdrName
1848 = umbrella ? modGen.GetUmbrellaName() : modGen.GetContentName();
1849 ROOT::TMetaUtils::Error(nullptr, "%s: compilation failure (%s)\n", argv0,
1850 hdrName.c_str());
1851 return false;
1852 }
1853 } else {
1854 modGen.WriteContentHeader(out);
1855 }
1856 return true;
1857}
1858
1859////////////////////////////////////////////////////////////////////////////////
1860/// Write the AST of the given CompilerInstance to the given File while
1861/// respecting the given isysroot.
1862/// If module is not a null pointer, we only write the given module to the
1863/// given file and not the whole AST.
1864/// Returns true if the AST was successfully written.
1865static bool WriteAST(llvm::StringRef fileName, clang::CompilerInstance *compilerInstance,
1866 llvm::StringRef iSysRoot,
1867 clang::Module *module = nullptr)
1868{
1869 // From PCHGenerator and friends:
1870 llvm::SmallVector<char, 128> buffer;
1871 llvm::BitstreamWriter stream(buffer);
1872 clang::ASTWriter writer(stream, buffer, compilerInstance->getModuleCache(), compilerInstance->getCodeGenOpts(), /*Extensions=*/{});
1873 std::unique_ptr<llvm::raw_ostream> out =
1874 compilerInstance->createOutputFile(fileName, /*Binary=*/true,
1875 /*RemoveFileOnSignal=*/false,
1876 /*useTemporary=*/false,
1877 /*CreateMissingDirectories*/ false);
1878 if (!out) {
1879 ROOT::TMetaUtils::Error("WriteAST", "Couldn't open output stream to '%s'!\n", fileName.data());
1880 return false;
1881 }
1882
1883 compilerInstance->getFrontendOpts().RelocatablePCH = true;
1884
1885 writer.WriteAST(&compilerInstance->getSema(), fileName.str(), module, iSysRoot);
1886
1887 // Write the generated bitstream to "Out".
1888 out->write(&buffer.front(), buffer.size());
1889
1890 // Make sure it hits disk now.
1891 out->flush();
1892
1893 return true;
1894}
1895
1896////////////////////////////////////////////////////////////////////////////////
1897/// Generates a PCH from the given ModuleGenerator and CompilerInstance.
1898/// Returns true iff the PCH was successfully generated.
1899static bool GenerateAllDict(TModuleGenerator &modGen, clang::CompilerInstance *compilerInstance,
1900 const std::string &currentDirectory)
1901{
1902 assert(modGen.IsPCH() && "modGen must be in PCH mode");
1903
1904 std::string iSysRoot("/DUMMY_SYSROOT/include/");
1906 return WriteAST(modGen.GetModuleFileName(), compilerInstance, iSysRoot);
1907}
1908
1909////////////////////////////////////////////////////////////////////////////////
1910/// Includes all given headers in the interpreter. Returns true when we could
1911/// include the headers and otherwise false on an error when including.
1912static bool IncludeHeaders(const std::vector<std::string> &headers, cling::Interpreter &interpreter)
1913{
1914 // If no headers are given, this is a no-op.
1915 if (headers.empty())
1916 return true;
1917
1918 // Turn every header name into an include and parse it in the interpreter.
1919 std::stringstream includes;
1920 for (const std::string &header : headers) {
1921 includes << "#include \"" << header << "\"\n";
1922 }
1923 std::string includeListStr = includes.str();
1924 auto result = interpreter.declare(includeListStr);
1925 return result == cling::Interpreter::CompilationResult::kSuccess;
1926}
1927
1928
1929////////////////////////////////////////////////////////////////////////////////
1930
1931void AddPlatformDefines(std::vector<std::string> &clingArgs)
1932{
1933 char platformDefines[64] = {0};
1934#ifdef __INTEL_COMPILER
1935 snprintf(platformDefines, 64, "-DG__INTEL_COMPILER=%ld", (long)__INTEL_COMPILER);
1936 clingArgs.push_back(platformDefines);
1937#endif
1938#ifdef __xlC__
1939 snprintf(platformDefines, 64, "-DG__xlC=%ld", (long)__xlC__);
1940 clingArgs.push_back(platformDefines);
1941#endif
1942#ifdef __GNUC__
1943 snprintf(platformDefines, 64, "-DG__GNUC=%ld", (long)__GNUC__);
1944 snprintf(platformDefines, 64, "-DG__GNUC_VER=%ld", (long)__GNUC__ * 1000 + __GNUC_MINOR__);
1945 clingArgs.push_back(platformDefines);
1946#endif
1947#ifdef __GNUC_MINOR__
1948 snprintf(platformDefines, 64, "-DG__GNUC_MINOR=%ld", (long)__GNUC_MINOR__);
1949 clingArgs.push_back(platformDefines);
1950#endif
1951#ifdef __HP_aCC
1952 snprintf(platformDefines, 64, "-DG__HP_aCC=%ld", (long)__HP_aCC);
1953 clingArgs.push_back(platformDefines);
1954#endif
1955#ifdef __sun
1956 snprintf(platformDefines, 64, "-DG__sun=%ld", (long)__sun);
1957 clingArgs.push_back(platformDefines);
1958#endif
1959#ifdef __SUNPRO_CC
1960 snprintf(platformDefines, 64, "-DG__SUNPRO_CC=%ld", (long)__SUNPRO_CC);
1961 clingArgs.push_back(platformDefines);
1962#endif
1963#ifdef _STLPORT_VERSION
1964 // stlport version, used on e.g. SUN
1965 snprintf(platformDefines, 64, "-DG__STLPORT_VERSION=%ld", (long)_STLPORT_VERSION);
1966 clingArgs.push_back(platformDefines);
1967#endif
1968#ifdef __ia64__
1969 snprintf(platformDefines, 64, "-DG__ia64=%ld", (long)__ia64__);
1970 clingArgs.push_back(platformDefines);
1971#endif
1972#ifdef __x86_64__
1973 snprintf(platformDefines, 64, "-DG__x86_64=%ld", (long)__x86_64__);
1974 clingArgs.push_back(platformDefines);
1975#endif
1976#ifdef __i386__
1977 snprintf(platformDefines, 64, "-DG__i386=%ld", (long)__i386__);
1978 clingArgs.push_back(platformDefines);
1979#endif
1980#ifdef __arm__
1981 snprintf(platformDefines, 64, "-DG__arm=%ld", (long)__arm__);
1982 clingArgs.push_back(platformDefines);
1983#endif
1984#ifdef _WIN32
1985 snprintf(platformDefines, 64, "-DG__WIN32=%ld", (long)_WIN32);
1986 clingArgs.push_back(platformDefines);
1987#else
1988# ifdef WIN32
1989 snprintf(platformDefines, 64, "-DG__WIN32=%ld", (long)WIN32);
1990 clingArgs.push_back(platformDefines);
1991# endif
1992#endif
1993#ifdef _WIN64
1994 snprintf(platformDefines, 64, "-DG__WIN64=%ld", (long)_WIN64);
1995 clingArgs.push_back(platformDefines);
1996#endif
1997#ifdef _MSC_VER
1998 snprintf(platformDefines, 64, "-DG__MSC_VER=%ld", (long)_MSC_VER);
1999 clingArgs.push_back(platformDefines);
2000 snprintf(platformDefines, 64, "-DG__VISUAL=%ld", (long)_MSC_VER);
2001 clingArgs.push_back(platformDefines);
2002#if defined(_WIN64) && defined(_DEBUG)
2003 snprintf(platformDefines, 64, "-D_ITERATOR_DEBUG_LEVEL=0");
2004 clingArgs.push_back(platformDefines);
2005#endif
2006#endif
2007}
2008
2009////////////////////////////////////////////////////////////////////////////////
2010/// Extract the filename from a fullpath
2011
2012std::string ExtractFileName(const std::string &path)
2013{
2014 return llvm::sys::path::filename(path).str();
2015}
2016
2017////////////////////////////////////////////////////////////////////////////////
2018/// Extract the path from a fullpath finding the last \ or /
2019/// according to the content in gPathSeparator
2020
2021void ExtractFilePath(const std::string &path, std::string &dirname)
2022{
2023 const size_t pos = path.find_last_of(gPathSeparator);
2024 if (std::string::npos != pos) {
2025 dirname.assign(path.begin(), path.begin() + pos + 1);
2026 } else {
2027 dirname.assign("");
2028 }
2029}
2030
2031////////////////////////////////////////////////////////////////////////////////
2032/// Check if file has a path
2033
2034bool HasPath(const std::string &name)
2035{
2036 std::string dictLocation;
2038 return !dictLocation.empty();
2039}
2040
2041////////////////////////////////////////////////////////////////////////////////
2042
2044 std::string &rootmapLibName)
2045{
2046 // If the rootmap file name does not exist, create one following the libname
2047 // I.E. put into the directory of the lib the rootmap and within the rootmap the normalised path to the lib
2048 if (rootmapFileName.empty()) {
2049 size_t libExtensionPos = rootmapLibName.find_last_of(gLibraryExtension) - gLibraryExtension.size() + 1;
2050 rootmapFileName = rootmapLibName.substr(0, libExtensionPos) + ".rootmap";
2051 size_t libCleanNamePos = rootmapLibName.find_last_of(gPathSeparator) + 1;
2052 rootmapLibName = rootmapLibName.substr(libCleanNamePos, std::string::npos);
2053 ROOT::TMetaUtils::Info(nullptr, "Rootmap file name %s built from rootmap lib name %s",
2054 rootmapLibName.c_str(),
2055 rootmapFileName.c_str());
2056 }
2057}
2058
2059////////////////////////////////////////////////////////////////////////////////
2060/// Extract the proper autoload key for nested classes
2061/// The routine does not erase the name, just updates it
2062
2063void GetMostExternalEnclosingClassName(const clang::DeclContext &theContext,
2064 std::string &ctxtName,
2065 const cling::Interpreter &interpreter,
2066 bool treatParent = true)
2067{
2068 const clang::DeclContext *outerCtxt = treatParent ? theContext.getParent() : &theContext;
2069 // If the context has no outer context, we are finished
2070 if (!outerCtxt) return;
2071 // If the context is a class, we update the name
2072 if (const clang::RecordDecl *thisRcdDecl = llvm::dyn_cast<clang::RecordDecl>(outerCtxt)) {
2074 }
2075 // We recurse
2077}
2078
2079////////////////////////////////////////////////////////////////////////////////
2080
2082 std::string &ctxtName,
2083 const cling::Interpreter &interpreter)
2084{
2085 const clang::DeclContext *theContext = theDecl.getDeclContext();
2087}
2088
2089////////////////////////////////////////////////////////////////////////////////
2090template<class COLL>
2091int ExtractAutoloadKeys(std::list<std::string> &names,
2092 const COLL &decls,
2093 const cling::Interpreter &interp)
2094{
2095 if (!decls.empty()) {
2096 std::string autoLoadKey;
2097 for (auto & d : decls) {
2098 autoLoadKey = "";
2100 // If there is an outer class, it is already considered
2101 if (autoLoadKey.empty()) {
2102 names.push_back(d->getQualifiedNameAsString());
2103 }
2104 }
2105 }
2106 return 0;
2107}
2108
2109////////////////////////////////////////////////////////////////////////////////
2110/// Generate a rootmap file in the new format, like
2111/// { decls }
2112/// `namespace A { namespace B { template <typename T> class myTemplate; } }`
2113/// [libGpad.so libGraf.so libHist.so libMathCore.so]
2114/// class TAttCanvas
2115/// class TButton
2116/// (header1.h header2.h .. headerN.h)
2117/// class TMyClass
2118
2120 const std::string &rootmapLibName,
2121 const std::list<std::string> &classesDefsList,
2122 const std::list<std::string> &classesNames,
2123 const std::list<std::string> &nsNames,
2124 const std::list<std::string> &tdNames,
2125 const std::list<std::string> &enNames,
2126 const std::list<std::string> &varNames,
2128 const std::unordered_set<std::string> headersToIgnore)
2129{
2130 // Create the rootmap file from the selected classes and namespaces
2131 std::ofstream rootmapFile(rootmapFileName.c_str());
2132 if (!rootmapFile) {
2133 ROOT::TMetaUtils::Error(nullptr, "Opening new rootmap file %s\n", rootmapFileName.c_str());
2134 return 1;
2135 }
2136
2137 // Keep track of the classes keys
2138 // This is done to avoid duplications of keys with typedefs
2139 std::unordered_set<std::string> classesKeys;
2140
2141
2142 // Add the "section"
2143 if (!classesNames.empty() || !nsNames.empty() || !tdNames.empty() ||
2144 !enNames.empty() || !varNames.empty()) {
2145
2146 // Add the template definitions
2147 if (!classesDefsList.empty()) {
2148 rootmapFile << "{ decls }\n";
2149 for (auto & classDef : classesDefsList) {
2150 rootmapFile << classDef << std::endl;
2151 }
2152 rootmapFile << "\n";
2153 }
2154 rootmapFile << "[ " << rootmapLibName << " ]\n";
2155
2156 // Loop on selected classes and insert them in the rootmap
2157 if (!classesNames.empty()) {
2158 rootmapFile << "# List of selected classes\n";
2159 for (auto & className : classesNames) {
2160 rootmapFile << "class " << className << std::endl;
2161 classesKeys.insert(className);
2162 }
2163 // And headers
2164 std::unordered_set<std::string> treatedHeaders;
2165 for (auto & className : classesNames) {
2166 // Don't treat templates
2167 if (className.find("<") != std::string::npos) continue;
2168 if (headersClassesMap.count(className)) {
2169 auto &headers = headersClassesMap.at(className);
2170 if (!headers.empty()){
2171 auto &header = headers.front();
2172 if (treatedHeaders.insert(header).second &&
2173 headersToIgnore.find(header) == headersToIgnore.end() &&
2175 rootmapFile << "header " << header << std::endl;
2176 }
2177 }
2178 }
2179 }
2180 }
2181
2182 // Same for namespaces
2183 if (!nsNames.empty()) {
2184 rootmapFile << "# List of selected namespaces\n";
2185 for (auto & nsName : nsNames) {
2186 rootmapFile << "namespace " << nsName << std::endl;
2187 }
2188 }
2189
2190 // And typedefs. These are used just to trigger the autoload mechanism
2191 if (!tdNames.empty()) {
2192 rootmapFile << "# List of selected typedefs and outer classes\n";
2193 for (const auto & autoloadKey : tdNames)
2194 if (classesKeys.insert(autoloadKey).second)
2195 rootmapFile << "typedef " << autoloadKey << std::endl;
2196 }
2197
2198 // And Enums. There is no incomplete type for an enum but we can nevertheless
2199 // have the key for the cases where the root typesystem is interrogated.
2200 if (!enNames.empty()){
2201 rootmapFile << "# List of selected enums and outer classes\n";
2202 for (const auto & autoloadKey : enNames)
2203 if (classesKeys.insert(autoloadKey).second)
2204 rootmapFile << "enum " << autoloadKey << std::endl;
2205 }
2206
2207 // And variables.
2208 if (!varNames.empty()){
2209 rootmapFile << "# List of selected vars\n";
2210 for (const auto & autoloadKey : varNames)
2211 if (classesKeys.insert(autoloadKey).second)
2212 rootmapFile << "var " << autoloadKey << std::endl;
2213 }
2214
2215 }
2216
2217 return 0;
2218
2219}
2220
2221////////////////////////////////////////////////////////////////////////////////
2222/// Performance is not critical here.
2223
2224std::pair<std::string,std::string> GetExternalNamespaceAndContainedEntities(const std::string line)
2225{
2226 auto nsPattern = '{'; auto nsPatternLength = 1;
2227 auto foundNsPos = line.find_last_of(nsPattern);
2228 if (foundNsPos == std::string::npos) return {"",""};
2230 auto extNs = line.substr(0,foundNsPos);
2231
2232 auto nsEndPattern = '}';
2233 auto foundEndNsPos = line.find(nsEndPattern);
2235
2236 return {extNs, contained};
2237
2238
2239}
2240
2241////////////////////////////////////////////////////////////////////////////////
2242/// If two identical namespaces are there, just declare one only
2243/// Example:
2244/// namespace A { namespace B { fwd1; }}
2245/// namespace A { namespace B { fwd2; }}
2246/// get a namespace A { namespace B { fwd1; fwd2; }} line
2247
2248std::list<std::string> CollapseIdenticalNamespaces(const std::list<std::string>& fwdDeclarationsList)
2249{
2250 // Temp data structure holding the namespaces and the entities therewith
2251 // contained
2252 std::map<std::string, std::string> nsEntitiesMap;
2253 std::list<std::string> optFwdDeclList;
2254 for (auto const & fwdDecl : fwdDeclarationsList){
2255 // Check if the decl(s) are contained in a ns and which one
2257 if (extNsAndEntities.first.empty()) {
2258 // no namespace found. Just put this on top
2259 optFwdDeclList.push_front(fwdDecl);
2260 };
2263 }
2264
2265 // Now fill the new, optimised list
2266 std::string optFwdDecl;
2267 for (auto const & extNsAndEntities : nsEntitiesMap) {
2269 optFwdDecl += extNsAndEntities.second;
2270 for (int i = 0; i < std::count(optFwdDecl.begin(), optFwdDecl.end(), '{'); ++i ){
2271 optFwdDecl += " }";
2272 }
2273 optFwdDeclList.push_front(optFwdDecl);
2274 }
2275
2276 return optFwdDeclList;
2277
2278}
2279
2280////////////////////////////////////////////////////////////////////////////////
2281/// Separate multiline strings
2282
2283bool ProcessAndAppendIfNotThere(const std::string &el,
2284 std::list<std::string> &el_list,
2285 std::unordered_set<std::string> &el_set)
2286{
2287 std::stringstream elStream(el);
2288 std::string tmp;
2289 bool added = false;
2290 while (getline(elStream, tmp, '\n')) {
2291 // Add if not there
2292 if (el_set.insert(tmp).second && !tmp.empty()) {
2293 el_list.push_back(tmp);
2294 added = true;
2295 }
2296 }
2297
2298 return added;
2299}
2300
2301////////////////////////////////////////////////////////////////////////////////
2302
2304 std::list<std::string> &classesList,
2305 std::list<std::string> &classesListForRootmap,
2306 std::list<std::string> &fwdDeclarationsList,
2307 const cling::Interpreter &interpreter)
2308{
2309 // Loop on selected classes. If they don't have the attribute "rootmap"
2310 // set to "false", store them in the list of classes for the rootmap
2311 // Returns 0 in case of success and 1 in case of issues.
2312
2313 // An unordered_set to keep track of the existing classes.
2314 // We want to avoid duplicates there as they may hint to a serious corruption
2315 std::unordered_set<std::string> classesSet;
2316 std::unordered_set<std::string> outerMostClassesSet;
2317
2318 std::string attrName, attrValue;
2319 bool isClassSelected;
2320 std::unordered_set<std::string> availableFwdDecls;
2321 std::string fwdDeclaration;
2322 for (auto const & selVar : scan.fSelectedVariables) {
2323 fwdDeclaration = "";
2326 }
2327
2328 for (auto const & selEnum : scan.fSelectedEnums) {
2329 fwdDeclaration = "";
2332 }
2333
2334 // Loop on selected classes and put them in a list
2335 for (auto const & selClass : scan.fSelectedClasses) {
2336 isClassSelected = true;
2337 const clang::RecordDecl *rDecl = selClass.GetRecordDecl();
2338 std::string normalizedName;
2339 normalizedName = selClass.GetNormalizedName();
2340 if (!normalizedName.empty() &&
2341 !classesSet.insert(normalizedName).second &&
2342 outerMostClassesSet.count(normalizedName) == 0) {
2343 std::cerr << "FATAL: A class with normalized name " << normalizedName
2344 << " was already selected. This means that two different instances of"
2345 << " clang::RecordDecl had the same name, which is not possible."
2346 << " This can be a hint of a serious problem in the class selection."
2347 << " In addition, the generated dictionary would not even compile.\n";
2348 return 1;
2349 }
2350 classesList.push_back(normalizedName);
2351 // Allow to autoload with the name of the class as it was specified in the
2352 // selection xml or linkdef
2353 const char *reqName(selClass.GetRequestedName());
2354
2355 // Get always the containing namespace, put it in the list if not there
2356 fwdDeclaration = "";
2359
2360 // Get template definition and put it in if not there
2361 if (llvm::isa<clang::ClassTemplateSpecializationDecl>(rDecl)) {
2362 fwdDeclaration = "";
2364 if (retCode == 0) {
2365 std::string fwdDeclarationTemplateSpec;
2368 }
2369 if (retCode == 0)
2371 }
2372
2373
2374 // Loop on attributes, if rootmap=false, don't put it in the list!
2375 for (auto ait = rDecl->attr_begin(); ait != rDecl->attr_end(); ++ait) {
2377 attrName == "rootmap" &&
2378 attrValue == "false") {
2379 attrName = attrValue = "";
2380 isClassSelected = false;
2381 break;
2382 }
2383 }
2384 if (isClassSelected) {
2385 // Now, check if this is an internal class. If yes, we check the name of the outermost one
2386 // This is because of ROOT-6517. On the other hand, we exclude from this treatment
2387 // classes which are template instances which are nested in classes. For example:
2388 // class A{
2389 // class B{};
2390 // };
2391 // selection: <class name="A::B" />
2392 // Will result in a rootmap entry like "class A"
2393 // On the other hand, taking
2394 // class A{
2395 // public:
2396 // template <class T> class B{};
2397 // };
2398 // selection: <class name="A::B<int>" />
2399 // Would result in an entry like "class A::B<int>"
2400 std::string outerMostClassName;
2402 if (!outerMostClassName.empty() &&
2403 !llvm::isa<clang::ClassTemplateSpecializationDecl>(rDecl) &&
2404 classesSet.insert(outerMostClassName).second &&
2405 outerMostClassesSet.insert(outerMostClassName).second) {
2407 } else {
2409 if (reqName && reqName[0] && reqName != normalizedName) {
2410 classesListForRootmap.push_back(reqName);
2411 }
2412
2413 // Also register typeinfo::name(), unless we have pseudo-strong typedefs.
2414 // GetDemangledTypeInfo() checks for Double32_t etc already and returns an empty string.
2415 std::string demangledName = selClass.GetDemangledTypeInfo();
2416 if (!demangledName.empty()) {
2417 // See the operations in TCling::AutoLoad(type_info)
2420
2422 // if demangledName != other name
2424 }
2425 }
2426 }
2427 }
2428 }
2429 classesListForRootmap.sort();
2430
2431 // Disable for the moment
2432 // fwdDeclarationsList = CollapseIdenticalNamespaces(fwdDeclarationsList);
2433
2434 return 0;
2435}
2436
2437////////////////////////////////////////////////////////////////////////////////
2438/// Loop on selected classes and put them in a list
2439
2440void ExtractSelectedNamespaces(RScanner &scan, std::list<std::string> &nsList)
2441{
2442 for (RScanner::NamespaceColl_t::const_iterator selNsIter = scan.fSelectedNamespaces.begin();
2443 selNsIter != scan.fSelectedNamespaces.end(); ++selNsIter) {
2444 nsList.push_back(ROOT::TMetaUtils::GetQualifiedName(* selNsIter->GetNamespaceDecl()));
2445 }
2446}
2447
2448////////////////////////////////////////////////////////////////////////////////
2449/// We need annotations even in the PCH: // !, // || etc.
2450
2451void AnnotateAllDeclsForPCH(cling::Interpreter &interp,
2452 RScanner &scan)
2453{
2454 auto const & declSelRulesMap = scan.GetDeclsSelRulesMap();
2455 for (auto const & selClass : scan.fSelectedClasses) {
2456 // Very important: here we decide if we want to attach attributes to the decl.
2457 if (clang::CXXRecordDecl *CXXRD =
2458 llvm::dyn_cast<clang::CXXRecordDecl>(const_cast<clang::RecordDecl *>(selClass.GetRecordDecl()))) {
2460 }
2461 }
2462}
2463
2464////////////////////////////////////////////////////////////////////////////////
2465
2467 RScanner &scan)
2468{
2469 for (auto const & selClass : scan.fSelectedClasses) {
2470 if (!selClass.GetRecordDecl()->isCompleteDefinition() || selClass.RequestOnlyTClass()) {
2471 continue;
2472 }
2473 const clang::CXXRecordDecl *cxxdecl = llvm::dyn_cast<clang::CXXRecordDecl>(selClass.GetRecordDecl());
2475 ROOT::TMetaUtils::Error("CheckClassesForInterpreterOnlyDicts",
2476 "Interactivity only dictionaries are not supported for classes with ClassDef\n");
2477 return 1;
2478 }
2479 }
2480 return 0;
2481}
2482
2483////////////////////////////////////////////////////////////////////////////////
2484/// Make up for skipping RegisterModule, now that dictionary parsing
2485/// is done and these headers cannot be selected anymore.
2486
2487int FinalizeStreamerInfoWriting(cling::Interpreter &interp, bool writeEmptyRootPCM=false)
2488{
2489 if (!gDriverConfig->fCloseStreamerInfoROOTFile)
2490 return 0;
2491
2492 if (interp.parseForModule("#include \"TStreamerInfo.h\"\n"
2493 "#include \"TFile.h\"\n"
2494 "#include \"TObjArray.h\"\n"
2495 "#include \"TVirtualArray.h\"\n"
2496 "#include \"TStreamerElement.h\"\n"
2497 "#include \"TProtoClass.h\"\n"
2498 "#include \"TBaseClass.h\"\n"
2499 "#include \"TListOfDataMembers.h\"\n"
2500 "#include \"TListOfEnums.h\"\n"
2501 "#include \"TListOfEnumsWithLock.h\"\n"
2502 "#include \"TDataMember.h\"\n"
2503 "#include \"TEnum.h\"\n"
2504 "#include \"TEnumConstant.h\"\n"
2505 "#include \"TDictAttributeMap.h\"\n"
2506 "#include \"TMessageHandler.h\"\n"
2507 "#include \"TArray.h\"\n"
2508 "#include \"TRefArray.h\"\n"
2509 "#include \"root_std_complex.h\"\n")
2510 != cling::Interpreter::kSuccess)
2511 return 1;
2512 if (!gDriverConfig->fCloseStreamerInfoROOTFile(writeEmptyRootPCM)) {
2513 return 1;
2514 }
2515 return 0;
2516}
2517
2518////////////////////////////////////////////////////////////////////////////////
2519
2520int GenerateFullDict(std::ostream &dictStream, std::string dictName, cling::Interpreter &interp, RScanner &scan,
2522 bool isSelXML, bool writeEmptyRootPCM)
2523{
2525
2526 bool needsCollectionProxy = false;
2527
2528 //
2529 // We will loop over all the classes several times.
2530 // In order we will call
2531 //
2532 // WriteClassInit (code to create the TGenericClassInfo)
2533 // check for constructor and operator input
2534 // WriteClassFunctions (declared in ClassDef)
2535 // WriteClassCode (Streamer,ShowMembers,Auxiliary functions)
2536 //
2537
2538
2539 //
2540 // Loop over all classes and create Streamer() & Showmembers() methods
2541 //
2542
2543 // SELECTION LOOP
2544 for (auto const & ns : scan.fSelectedNamespaces) {
2546 auto nsName = ns.GetNamespaceDecl()->getQualifiedNameAsString();
2547 if (nsName.find("(anonymous)") == std::string::npos)
2548 EmitStreamerInfo(nsName.c_str());
2549 }
2550
2551 for (auto const & selClass : scan.fSelectedClasses) {
2552 if (!selClass.GetRecordDecl()->isCompleteDefinition()) {
2553 ROOT::TMetaUtils::Error(nullptr, "A dictionary has been requested for %s but there is no declaration!\n", ROOT::TMetaUtils::GetQualifiedName(selClass).c_str());
2554 continue;
2555 }
2556 if (selClass.RequestOnlyTClass()) {
2557 // fprintf(stderr,"rootcling: Skipping class %s\n",R__GetQualifiedName(* selClass.GetRecordDecl()).c_str());
2558 // For now delay those for later.
2559 continue;
2560 }
2561
2562 // Very important: here we decide if we want to attach attributes to the decl.
2563
2564 if (clang::CXXRecordDecl *CXXRD =
2565 llvm::dyn_cast<clang::CXXRecordDecl>(const_cast<clang::RecordDecl *>(selClass.GetRecordDecl()))) {
2567 }
2568
2569 const clang::CXXRecordDecl *CRD = llvm::dyn_cast<clang::CXXRecordDecl>(selClass.GetRecordDecl());
2570
2571 if (CRD) {
2572 ROOT::TMetaUtils::Info(nullptr, "Generating code for class %s\n", selClass.GetNormalizedName());
2573 if (TMetaUtils::IsStdClass(*CRD) && 0 != TClassEdit::STLKind(CRD->getName().str() /* unqualified name without template argument */)) {
2574 // Register the collections
2575 // coverity[fun_call_w_exception] - that's just fine.
2576 Internal::RStl::Instance().GenerateTClassFor(selClass.GetNormalizedName(), CRD, interp, normCtxt);
2577 } else if (CRD->getName() == "RVec") {
2578 static const clang::DeclContext *vecOpsDC = nullptr;
2579 if (!vecOpsDC)
2580 vecOpsDC = llvm::dyn_cast<clang::DeclContext>(
2581 interp.getLookupHelper().findScope("ROOT::VecOps", cling::LookupHelper::NoDiagnostics));
2582 if (vecOpsDC && vecOpsDC->Equals(CRD->getDeclContext())) {
2583 // Register the collections
2584 // coverity[fun_call_w_exception] - that's just fine.
2585 Internal::RStl::Instance().GenerateTClassFor(selClass.GetNormalizedName(), CRD, interp, normCtxt);
2586 }
2587 } else {
2590 EmitStreamerInfo(selClass.GetNormalizedName());
2591 }
2592 }
2593 }
2594
2595 //
2596 // Write all TBuffer &operator>>(...), Class_Name(), Dictionary(), etc.
2597 // first to allow template specialisation to occur before template
2598 // instantiation (STK)
2599 //
2600 // SELECTION LOOP
2601 for (auto const & selClass : scan.fSelectedClasses) {
2602
2603 if (!selClass.GetRecordDecl()->isCompleteDefinition() || selClass.RequestOnlyTClass()) {
2604 // For now delay those for later.
2605 continue;
2606 }
2607 const clang::CXXRecordDecl *cxxdecl = llvm::dyn_cast<clang::CXXRecordDecl>(selClass.GetRecordDecl());
2610 }
2611 }
2612
2613 // LINKDEF SELECTION LOOP
2614 // Loop to get the shadow class for the class marked 'RequestOnlyTClass' (but not the
2615 // STL class which is done via Internal::RStl::Instance().WriteClassInit(0);
2616 // and the ClassInit
2617
2618 for (auto const & selClass : scan.fSelectedClasses) {
2619 if (!selClass.GetRecordDecl()->isCompleteDefinition() || !selClass.RequestOnlyTClass()) {
2620 continue;
2621 }
2622
2623 const clang::CXXRecordDecl *CRD = llvm::dyn_cast<clang::CXXRecordDecl>(selClass.GetRecordDecl());
2624
2628 EmitStreamerInfo(selClass.GetNormalizedName());
2629 }
2630 }
2631 // Loop to write all the ClassCode
2632 for (auto const &selClass : scan.fSelectedClasses) {
2633 // The "isGenreflex" parameter allows the distinction between
2634 // genreflex and rootcling only for the treatment of collections which
2635 // are data members. To preserve the behaviour of the original
2636 // genreflex and rootcling tools, if the selection is performed with
2637 // genreflex, data members with collection type do not trigger the
2638 // selection of the collection type
2640 isGenreflex);
2641 }
2642
2643 // Loop on the registered collections internally
2644 // coverity[fun_call_w_exception] - that's just fine.
2647
2648 std::vector<std::string> standaloneTargets;
2652
2653 if (!gDriverConfig->fBuildingROOTStage1) {
2656 // Make up for skipping RegisterModule, now that dictionary parsing
2657 // is done and these headers cannot be selected anymore.
2659 if (finRetCode != 0) return finRetCode;
2660 }
2661
2662 return 0;
2663}
2664
2665////////////////////////////////////////////////////////////////////////////////
2666
2667void CreateDictHeader(std::ostream &dictStream, const std::string &main_dictname)
2668{
2669 dictStream << "// Do NOT change. Changes will be lost next time file is generated\n\n"
2670 << "#define R__DICTIONARY_FILENAME " << main_dictname << std::endl
2671
2672 // We do not want deprecation warnings to fire in dictionaries
2673 << "#define R__NO_DEPRECATION" << std::endl
2674
2675 // Now that CINT is not longer there to write the header file,
2676 // write one and include in there a few things for backward
2677 // compatibility.
2678 << "\n/*******************************************************************/\n"
2679 << "#include <cstddef>\n"
2680 << "#include <cstdio>\n"
2681 << "#include <cstdlib>\n"
2682 << "#include <cstring>\n"
2683 << "#include <cassert>\n"
2684 << "#define G__DICTIONARY\n"
2685 << "#include \"ROOT/RConfig.hxx\"\n"
2686 << "#include \"TClass.h\"\n"
2687 << "#include \"TDictAttributeMap.h\"\n"
2688 << "#include \"TInterpreter.h\"\n"
2689 << "#include \"TROOT.h\"\n"
2690 << "#include \"TBuffer.h\"\n"
2691 << "#include \"TMemberInspector.h\"\n"
2692 << "#include \"TInterpreter.h\"\n"
2693 << "#include \"TVirtualMutex.h\"\n"
2694 << "#include \"TError.h\"\n\n"
2695 << "#ifndef G__ROOT\n"
2696 << "#define G__ROOT\n"
2697 << "#endif\n\n"
2698 << "#include \"RtypesImp.h\"\n"
2699 << "#include \"TIsAProxy.h\"\n"
2700 << "#include \"TFileMergeInfo.h\"\n"
2701 << "#include <algorithm>\n"
2702 << "#include \"TCollectionProxyInfo.h\"\n"
2703 << "/*******************************************************************/\n\n"
2704 << "#include \"TDataMember.h\"\n\n"; // To set their transiency
2705}
2706
2707////////////////////////////////////////////////////////////////////////////////
2708
2710{
2711 dictStream << "// The generated code does not explicitly qualify STL entities\n"
2712 << "namespace std {} using namespace std;\n\n";
2713}
2714
2715////////////////////////////////////////////////////////////////////////////////
2716
2718 const std::string &includeForSource,
2719 const std::string &extraIncludes)
2720{
2721 dictStream << "// Header files passed as explicit arguments\n"
2722 << includeForSource << std::endl
2723 << "// Header files passed via #pragma extra_include\n"
2724 << extraIncludes << std::endl;
2725}
2726
2727//______________________________________________________________________________
2728
2729// cross-compiling for iOS and iOS simulator (assumes host is Intel Mac OS X)
2730#if defined(R__IOSSIM) || defined(R__IOS)
2731#ifdef __x86_64__
2732#undef __x86_64__
2733#endif
2734#ifdef __i386__
2735#undef __i386__
2736#endif
2737#ifdef R__IOSSIM
2738#define __i386__ 1
2739#endif
2740#ifdef R__IOS
2741#define __arm__ 1
2742#endif
2743#endif
2744
2745////////////////////////////////////////////////////////////////////////////////
2746/// Little helper class to bookkeep the files names which we want to make
2747/// temporary.
2748
2750public:
2751 //______________________________________________
2753
2754 std::string getTmpFileName(const std::string &filename) {
2755 return filename + "_tmp_" + std::to_string(getpid());
2756 }
2757 /////////////////////////////////////////////////////////////////////////////
2758 /// Adds the name and the associated temp name to the catalog.
2759 /// Changes the name into the temp name
2760
2761 void addFileName(std::string &nameStr) {
2762 if (nameStr.empty()) return;
2763
2764 std::string tmpNameStr(getTmpFileName(nameStr));
2765
2766 // For brevity
2767 const char *name(nameStr.c_str());
2768 const char *tmpName(tmpNameStr.c_str());
2769
2770 m_names.push_back(nameStr);
2771 m_tempNames.push_back(tmpNameStr);
2772 ROOT::TMetaUtils::Info(nullptr, "File %s added to the tmp catalog.\n", name);
2773
2774 // This is to allow update of existing files
2775 if (0 == std::rename(name , tmpName)) {
2776 ROOT::TMetaUtils::Info(nullptr, "File %s existing. Preserved as %s.\n", name, tmpName);
2777 }
2778
2779 // To change the name to its tmp version
2781
2782 m_size++;
2783
2784 }
2785
2786 /////////////////////////////////////////////////////////////////////////////
2787
2788 int clean() {
2789 int retval = 0;
2790 // rename the temp files into the normal ones
2791 for (unsigned int i = 0; i < m_size; ++i) {
2792 const char *tmpName = m_tempNames[i].c_str();
2793 // Check if the file exists
2794 std::ifstream ifile(tmpName);
2795 if (!ifile)
2796 ROOT::TMetaUtils::Error(nullptr, "Cannot find %s!\n", tmpName);
2797 // Make sure the file is closed, mostly for Windows FS, also when
2798 // accessing it from a Linux VM via a shared folder
2799 if (ifile.is_open())
2800 ifile.close();
2801 if (0 != std::remove(tmpName)) {
2802 ROOT::TMetaUtils::Error(nullptr, "Removing %s!\n", tmpName);
2803 retval++;
2804 }
2805 }
2806 return retval;
2807 }
2808
2809 /////////////////////////////////////////////////////////////////////////////
2810
2811 int commit() {
2812 int retval = 0;
2813 // rename the temp files into the normal ones
2814 for (unsigned int i = 0; i < m_size; ++i) {
2815 const char *tmpName = m_tempNames[i].c_str();
2816 const char *name = m_names[i].c_str();
2817 // Check if the file exists
2818 std::ifstream ifile(tmpName);
2819 if (!ifile)
2820 ROOT::TMetaUtils::Error(nullptr, "Cannot find %s!\n", tmpName);
2821 // Make sure the file is closed, mostly for Windows FS, also when
2822 // accessing it from a Linux VM via a shared folder
2823 if (ifile.is_open())
2824 ifile.close();
2825#ifdef WIN32
2826 // Sometimes files cannot be renamed on Windows if they don't have
2827 // been released by the system. So just copy them and try to delete
2828 // the old one afterwards.
2829 if (0 != std::rename(tmpName , name)) {
2830 if (llvm::sys::fs::copy_file(tmpName , name)) {
2831 llvm::sys::fs::remove(tmpName);
2832 }
2833 }
2834#else
2835 if (0 != std::rename(tmpName , name)) {
2836 ROOT::TMetaUtils::Error(nullptr, "Renaming %s into %s!\n", tmpName, name);
2837 retval++;
2838 }
2839#endif
2840 }
2841 return retval;
2842 }
2843
2844 /////////////////////////////////////////////////////////////////////////////
2845
2846 const std::string &getFileName(const std::string &tmpFileName) {
2847 size_t i = std::distance(m_tempNames.begin(),
2848 find(m_tempNames.begin(), m_tempNames.end(), tmpFileName));
2849 if (i == m_tempNames.size()) return m_emptyString;
2850 return m_names[i];
2851 }
2852
2853 /////////////////////////////////////////////////////////////////////////////
2854
2855 void dump() {
2856 std::cout << "Restoring files in temporary file catalog:\n";
2857 for (unsigned int i = 0; i < m_size; ++i) {
2858 std::cout << m_tempNames[i] << " --> " << m_names[i] << std::endl;
2859 }
2860 }
2861
2862private:
2863 unsigned int m_size;
2864 const std::string m_emptyString;
2865 std::vector<std::string> m_names;
2866 std::vector<std::string> m_tempNames;
2867};
2868
2869////////////////////////////////////////////////////////////////////////////////
2870/// Transform name of dictionary
2871
2872std::ostream *CreateStreamPtrForSplitDict(const std::string &dictpathname,
2874{
2875 std::string splitDictName(tmpCatalog.getFileName(dictpathname));
2876 const size_t dotPos = splitDictName.find_last_of(".");
2877 splitDictName.insert(dotPos, "_classdef");
2878 tmpCatalog.addFileName(splitDictName);
2879 return new std::ofstream(splitDictName.c_str());
2880}
2881
2882////////////////////////////////////////////////////////////////////////////////
2883/// Transform -W statements in diagnostic pragmas for cling reacting on "-Wno-"
2884/// For example
2885/// -Wno-deprecated-declarations --> `#pragma clang diagnostic ignored "-Wdeprecated-declarations"`
2886
2887static void CheckForMinusW(std::string arg,
2888 std::list<std::string> &diagnosticPragmas)
2889{
2890 static const std::string pattern("-Wno-");
2891
2892 if (arg.find(pattern) != 0)
2893 return;
2894
2895 ROOT::TMetaUtils::ReplaceAll(arg, pattern, "#pragma clang diagnostic ignored \"-W");
2896 arg += "\"";
2897 diagnosticPragmas.push_back(arg);
2898}
2899
2900////////////////////////////////////////////////////////////////////////////////
2901
2903 cling::Interpreter &interp)
2904{
2905 using namespace ROOT::TMetaUtils::AST2SourceTools;
2906 std::string fwdDecl;
2907 std::string initStr("{");
2908 auto &fwdDeclnArgsToSkipColl = normCtxt.GetTemplNargsToKeepMap();
2910 auto &clTemplDecl = *strigNargsToKeepPair.first;
2911 FwdDeclFromTmplDecl(clTemplDecl , interp, fwdDecl);
2912 initStr += "{\"" +
2913 fwdDecl + "\", "
2914 + std::to_string(strigNargsToKeepPair.second)
2915 + "},";
2916 }
2917 if (!fwdDeclnArgsToSkipColl.empty())
2918 initStr.pop_back();
2919 initStr += "}";
2920 return initStr;
2921}
2922
2923////////////////////////////////////////////////////////////////////////////////
2924/// Get the pointee type if possible
2925
2926clang::QualType GetPointeeTypeIfPossible(const clang::QualType &qt)
2927{
2928 if (qt.isNull()) return qt;
2929 clang::QualType thisQt(qt);
2930 while (thisQt->isPointerType() ||
2931 thisQt->isReferenceType()) {
2932 thisQt = thisQt->getPointeeType();
2933 }
2934 return thisQt;
2935
2936}
2937
2938////////////////////////////////////////////////////////////////////////////////
2939/// Extract the list of headers necessary for the Decl
2940
2941std::list<std::string> RecordDecl2Headers(const clang::CXXRecordDecl &rcd,
2942 const cling::Interpreter &interp,
2943 std::set<const clang::CXXRecordDecl *> &visitedDecls)
2944{
2945 std::list<std::string> headers;
2946
2947 // We push a new transaction because we could deserialize decls here
2948 cling::Interpreter::PushTransactionRAII RAII(&interp);
2949
2950 // Avoid infinite recursion
2951 if (!visitedDecls.insert(rcd.getCanonicalDecl()).second)
2952 return headers;
2953
2954 // If this is a template
2955 if (const clang::ClassTemplateSpecializationDecl *tsd = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(&rcd)) {
2956
2957 // Loop on the template args
2958 for (auto & tArg : tsd->getTemplateArgs().asArray()) {
2959 if (clang::TemplateArgument::ArgKind::Type != tArg.getKind()) continue;
2960 auto tArgQualType = GetPointeeTypeIfPossible(tArg.getAsType());
2961 if (tArgQualType.isNull()) continue;
2962 if (const clang::CXXRecordDecl *tArgCxxRcd = tArgQualType->getAsCXXRecordDecl()) {
2964 }
2965 }
2966
2967 if (!ROOT::TMetaUtils::IsStdClass(rcd) && rcd.hasDefinition()) {
2968
2969 // Loop on base classes - with a newer llvm, range based possible
2970 for (auto baseIt = tsd->bases_begin(); baseIt != tsd->bases_end(); baseIt++) {
2971 auto baseQualType = GetPointeeTypeIfPossible(baseIt->getType());
2972 if (baseQualType.isNull()) continue;
2973 if (const clang::CXXRecordDecl *baseRcdPtr = baseQualType->getAsCXXRecordDecl()) {
2975 }
2976 }
2977
2978 // Loop on the data members - with a newer llvm, range based possible
2979 for (auto declIt = tsd->decls_begin(); declIt != tsd->decls_end(); ++declIt) {
2980 if (const clang::FieldDecl *fieldDecl = llvm::dyn_cast<clang::FieldDecl>(*declIt)) {
2982 if (fieldQualType.isNull()) continue ;
2983 if (const clang::CXXRecordDecl *fieldCxxRcd = fieldQualType->getAsCXXRecordDecl()) {
2984 if (fieldCxxRcd->hasDefinition())
2986 }
2987 }
2988 }
2989
2990 // Loop on methods
2991 for (auto methodIt = tsd->method_begin(); methodIt != tsd->method_end(); ++methodIt) {
2992 // Check arguments
2993 for (auto & fPar : methodIt->parameters()) {
2994 auto fParQualType = GetPointeeTypeIfPossible(fPar->getOriginalType());
2995 if (fParQualType.isNull()) continue;
2996 if (const clang::CXXRecordDecl *fParCxxRcd = fParQualType->getAsCXXRecordDecl()) {
2997 if (fParCxxRcd->hasDefinition())
2999 }
3000 }
3001 // Check return value
3002 auto retQualType = GetPointeeTypeIfPossible(methodIt->getReturnType());
3003 if (retQualType.isNull()) continue;
3004 if (const clang::CXXRecordDecl *retCxxRcd = retQualType->getAsCXXRecordDecl()) {
3005 if (retCxxRcd->hasDefinition())
3007 }
3008 }
3009 }
3010
3011 } // End template instance
3012
3013 std::string header = ROOT::TMetaUtils::GetFileName(rcd, interp);
3014 headers.emplace_back(header);
3015 headers.reverse();
3016 return headers;
3017
3018}
3019
3020////////////////////////////////////////////////////////////////////////////////
3021/// Check if the class good for being an autoparse key.
3022/// We exclude from this set stl containers of pods/strings
3023/// TODO: we may use also __gnu_cxx::
3024bool IsGoodForAutoParseMap(const clang::RecordDecl& rcd){
3025
3026 // If it's not an std class, we just pick it up.
3027 if (auto dclCtxt= rcd.getDeclContext()){
3028 if (! dclCtxt->isStdNamespace()){
3029 return true;
3030 }
3031 } else {
3032 return true;
3033 }
3034
3035 // Now, we have a stl class. We now check if it's a template. If not, we
3036 // do not take it: bitset, string and so on.
3037 auto clAsTmplSpecDecl = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(&rcd);
3038 if (!clAsTmplSpecDecl) return false;
3039
3040 // Now we have a template in the stl. Let's see what the arguments are.
3041 // If they are not a POD or something which is good for autoparsing, we keep
3042 // them.
3043 auto& astCtxt = rcd.getASTContext();
3044 auto& templInstArgs = clAsTmplSpecDecl->getTemplateInstantiationArgs();
3045 for (auto&& arg : templInstArgs.asArray()){
3046
3047 auto argKind = arg.getKind();
3048 if (argKind != clang::TemplateArgument::Type){
3049 if (argKind == clang::TemplateArgument::Integral) continue;
3050 else return true;
3051 }
3052
3053 auto argQualType = arg.getAsType();
3054 auto isPOD = argQualType.isPODType(astCtxt);
3055 // This is a POD, we can inspect the next arg
3056 if (isPOD) continue;
3057
3058 auto argType = argQualType.getTypePtr();
3059 if (auto recType = llvm::dyn_cast<clang::RecordType>(argType)){
3061 // The arg is a class but good for the map
3062 if (isArgGoodForAutoParseMap) continue;
3063 } else {
3064 // The class is not a POD nor a class we can skip
3065 return true;
3066 }
3067 }
3068
3069 return false;
3070}
3071
3072////////////////////////////////////////////////////////////////////////////////
3073
3081 const cling::Interpreter &interp)
3082{
3083 std::set<const clang::CXXRecordDecl *> visitedDecls;
3084 std::unordered_set<std::string> buffer;
3085 std::string autoParseKey;
3086
3087 // Add some manip of headers
3088 for (auto & annotatedRcd : annotatedRcds) {
3089 if (const clang::CXXRecordDecl *cxxRcd =
3090 llvm::dyn_cast_or_null<clang::CXXRecordDecl>(annotatedRcd.GetRecordDecl())) {
3091 autoParseKey = "";
3092 visitedDecls.clear();
3093 std::list<std::string> headers(RecordDecl2Headers(*cxxRcd, interp, visitedDecls));
3094 // remove duplicates, also if not subsequent
3095 buffer.clear();
3096 headers.remove_if([&buffer](const std::string & s) {
3097 return !buffer.insert(s).second;
3098 });
3100 if (autoParseKey.empty()) autoParseKey = annotatedRcd.GetNormalizedName();
3103 headersDeclsMap[annotatedRcd.GetRequestedName()] = headers;
3104 } else {
3105 ROOT::TMetaUtils::Info(nullptr, "Class %s is not included in the set of autoparse keys.\n", autoParseKey.c_str());
3106 }
3107
3108 // Propagate to the classes map only if this is not a template.
3109 // The header is then used as autoload key and we want to avoid duplicates.
3110 if (!llvm::isa<clang::ClassTemplateSpecializationDecl>(cxxRcd)){
3112 headersClassesMap[annotatedRcd.GetRequestedName()] = headersDeclsMap[annotatedRcd.GetRequestedName()];
3113 }
3114 }
3115 }
3116
3117 // The same for the typedefs:
3118 for (auto & tDef : tDefDecls) {
3119 if (clang::CXXRecordDecl *cxxRcd = tDef->getUnderlyingType()->getAsCXXRecordDecl()) {
3120 autoParseKey = "";
3121 visitedDecls.clear();
3122 std::list<std::string> headers(RecordDecl2Headers(*cxxRcd, interp, visitedDecls));
3124 // remove duplicates, also if not subsequent
3125 buffer.clear();
3126 headers.remove_if([&buffer](const std::string & s) {
3127 return !buffer.insert(s).second;
3128 });
3130 if (autoParseKey.empty()) autoParseKey = tDef->getQualifiedNameAsString();
3132 }
3133 }
3134
3135 // The same for the functions:
3136 for (auto & func : funcDecls) {
3137 std::list<std::string> headers = {ROOT::TMetaUtils::GetFileName(*func, interp)};
3139 }
3140
3141 // The same for the variables:
3142 for (auto & var : varDecls) {
3143 std::list<std::string> headers = {ROOT::TMetaUtils::GetFileName(*var, interp)};
3145 }
3146
3147 // The same for the enums:
3148 for (auto & en : enumDecls) {
3149 std::list<std::string> headers = {ROOT::TMetaUtils::GetFileName(*en, interp)};
3151 }
3152}
3153
3154////////////////////////////////////////////////////////////////////////////////
3155/// Generate the fwd declarations of the selected entities
3156
3157static std::string GenerateFwdDeclString(const RScanner &scan,
3158 const cling::Interpreter &interp)
3159{
3160 std::string newFwdDeclString;
3161
3162 using namespace ROOT::TMetaUtils::AST2SourceTools;
3163
3164 std::string fwdDeclString;
3165 std::string buffer;
3166 std::unordered_set<std::string> fwdDecls;
3167
3168 // Classes
3169/*
3170 for (auto const & annRcd : scan.fSelectedClasses) {
3171 const auto rcdDeclPtr = annRcd.GetRecordDecl();
3172
3173 int retCode = FwdDeclFromRcdDecl(*rcdDeclPtr, interp, buffer);
3174 if (-1 == retCode) {
3175 ROOT::TMetaUtils::Error("GenerateFwdDeclString",
3176 "Error generating fwd decl for class %s\n",
3177 annRcd.GetNormalizedName());
3178 return emptyString;
3179 }
3180 if (retCode == 0 && fwdDecls.insert(buffer).second)
3181 fwdDeclString += "\"" + buffer + "\"\n";
3182 }
3183*/
3184 // Build the input for a transaction containing all of the selected declarations
3185 // Cling will produce the fwd declaration payload.
3186
3187 std::vector<const clang::Decl *> selectedDecls(scan.fSelectedClasses.size());
3188
3189 // Pick only RecordDecls
3190 std::transform (scan.fSelectedClasses.begin(),
3191 scan.fSelectedClasses.end(),
3193 [](const ROOT::TMetaUtils::AnnotatedRecordDecl& rcd){return rcd.GetRecordDecl();});
3194
3195 for (auto* TD: scan.fSelectedTypedefs)
3196 selectedDecls.push_back(TD);
3197
3198// for (auto* VAR: scan.fSelectedVariables)
3199// selectedDecls.push_back(VAR);
3200
3201 std::string fwdDeclLogs;
3202
3203 // The "R\"DICTFWDDCLS(\n" ")DICTFWDDCLS\"" pieces have been moved to
3204 // TModuleGenerator to be able to make the diagnostics more telling in presence
3205 // of an issue ROOT-6752.
3207
3208 if (genreflex::verbose && !fwdDeclLogs.empty())
3209 std::cout << "Logs from forward decl printer: \n"
3210 << fwdDeclLogs;
3211
3212 // Functions
3213// for (auto const& fcnDeclPtr : scan.fSelectedFunctions){
3214// int retCode = FwdDeclFromFcnDecl(*fcnDeclPtr, interp, buffer);
3215// newFwdDeclString += Decl2FwdDecl(*fcnDeclPtr,interp);
3216// if (-1 == retCode){
3217// ROOT::TMetaUtils::Error("GenerateFwdDeclString",
3218// "Error generating fwd decl for function %s\n",
3219// fcnDeclPtr->getNameAsString().c_str());
3220// return emptyString;
3221// }
3222// if (retCode == 0 && fwdDecls.insert(buffer).second)
3223// fwdDeclString+="\""+buffer+"\"\n";
3224// }
3225
3226 if (fwdDeclString.empty()) fwdDeclString = "";
3227 return fwdDeclString;
3228}
3229
3230////////////////////////////////////////////////////////////////////////////////
3231/// Generate a string for the dictionary from the headers-classes map.
3232
3234 const std::string &detectedUmbrella,
3235 bool payLoadOnly = false)
3236{
3237 std::string headerName;
3238
3240 std::cout << "Class-headers Mapping:\n";
3241 std::string headersClassesMapString = "";
3242 for (auto const & classHeaders : headersClassesMap) {
3244 std::cout << " o " << classHeaders.first << " --> ";
3246 headersClassesMapString += classHeaders.first + "\"";
3247 for (auto const & header : classHeaders.second) {
3248 headerName = (detectedUmbrella == header || payLoadOnly) ? "payloadCode" : "\"" + header + "\"";
3251 std::cout << ", " << headerName;
3252 if (payLoadOnly)
3253 break;
3254 }
3256 std::cout << std::endl;
3257 headersClassesMapString += ", \"@\",\n";
3258 }
3259 headersClassesMapString += "nullptr";
3261}
3262
3263////////////////////////////////////////////////////////////////////////////////
3264
3265bool IsImplementationName(const std::string &filename)
3266{
3268}
3269
3270////////////////////////////////////////////////////////////////////////////////
3271/// Check if the argument is a sane cling argument. Performing the following checks:
3272/// 1) It does not start with "--" and is not the --param option.
3273
3274bool IsCorrectClingArgument(const std::string& argument)
3275{
3276 if (ROOT::TMetaUtils::BeginsWith(argument,"--") && !ROOT::TMetaUtils::BeginsWith(argument,"--param")) return false;
3277 return true;
3278}
3279
3280////////////////////////////////////////////////////////////////////////////////
3281bool NeedsSelection(const char* name)
3282{
3283 static const std::vector<std::string> namePrfxes {
3284 "array<",
3285 "unique_ptr<"};
3286 auto pos = find_if(namePrfxes.begin(),
3287 namePrfxes.end(),
3288 [&](const std::string& str){return ROOT::TMetaUtils::BeginsWith(name,str);});
3289 return namePrfxes.end() == pos;
3290}
3291
3292////////////////////////////////////////////////////////////////////////////////
3293
3295{
3296 static const std::vector<std::string> uclNamePrfxes {
3297 "chrono:",
3298 "ratio<",
3299 "shared_ptr<"};
3300 static const std::set<std::string> unsupportedClassesNormNames{
3301 "regex",
3302 "thread"};
3303 if ( unsupportedClassesNormNames.count(name) == 1) return false;
3304 auto pos = find_if(uclNamePrfxes.begin(),
3306 [&](const std::string& str){return ROOT::TMetaUtils::BeginsWith(name,str);});
3307 return uclNamePrfxes.end() == pos;
3308}
3309
3310////////////////////////////////////////////////////////////////////////////////
3311/// Check if the list of selected classes contains any class which is not
3312/// supported. Return the number of unsupported classes in the selection.
3313
3315{
3316 int nerrors = 0;
3317 for (auto&& aRcd : annotatedRcds){
3318 auto clName = aRcd.GetNormalizedName();
3320 std::cerr << "Error: Class " << clName << " has been selected but "
3321 << "currently the support for its I/O is not yet available. Note that "
3322 << clName << ", even if not selected, will be available for "
3323 << "interpreted code.\n";
3324 nerrors++;
3325 }
3326 if (!NeedsSelection(clName)){
3327 std::cerr << "Error: It is not necessary to explicitly select class "
3328 << clName << ". I/O is supported for it transparently.\n";
3329 nerrors++;
3330 }
3331 }
3332 return nerrors;
3333}
3334
3335////////////////////////////////////////////////////////////////////////////////
3336
3337class TRootClingCallbacks : public cling::InterpreterCallbacks {
3338private:
3339 std::list<std::string>& fFilesIncludedByLinkdef;
3340 bool isLocked = false;
3341public:
3342 TRootClingCallbacks(cling::Interpreter* interp, std::list<std::string>& filesIncludedByLinkdef):
3343 InterpreterCallbacks(interp),
3345
3347
3348 void InclusionDirective(clang::SourceLocation /*HashLoc*/, const clang::Token & /*IncludeTok*/,
3349 llvm::StringRef FileName, bool IsAngled, clang::CharSourceRange /*FilenameRange*/,
3350 clang::OptionalFileEntryRef /*File*/, llvm::StringRef /*SearchPath*/,
3351 llvm::StringRef /*RelativePath*/, const clang::Module * /*Imported*/, bool /*ModuleImported*/,
3352 clang::SrcMgr::CharacteristicKind /*FileType*/) override
3353 {
3354 if (isLocked) return;
3355 if (IsAngled) return;
3356 auto& PP = m_Interpreter->getCI()->getPreprocessor();
3357 auto curLexer = PP.getCurrentFileLexer();
3358 if (!curLexer) return;
3359 auto fileEntry = curLexer->getFileEntry();
3360 if (!fileEntry) return;
3361 auto thisFileName = fileEntry->getName();
3362 auto fileNameAsString = FileName.str();
3364 if (isThisLinkdef) {
3368 isLocked = true;
3369 } else {
3370 fFilesIncludedByLinkdef.emplace_back(fileNameAsString.c_str());
3371 }
3372 }
3373 }
3374
3375 // rootcling pre-includes things such as Rtypes.h. This means that ACLiC can
3376 // call rootcling asking it to create a module for a file with no #includes
3377 // but relying on things from Rtypes.h such as the ClassDef macro.
3378 //
3379 // When rootcling starts building a module, it becomes resilient to the
3380 // outside environment and pre-included files have no effect. This hook
3381 // informs rootcling when a new submodule is being built so that it can
3382 // make Core.Rtypes.h visible.
3383 void EnteredSubmodule(clang::Module* M,
3384 clang::SourceLocation ImportLoc,
3385 bool ForPragma) override {
3386 assert(M);
3387 using namespace clang;
3388 if (llvm::StringRef(M->Name).ends_with("ACLiC_dict")) {
3389 Preprocessor& PP = m_Interpreter->getCI()->getPreprocessor();
3390 HeaderSearch& HS = PP.getHeaderSearchInfo();
3391 // FIXME: Reduce to Core.Rtypes.h.
3392 Module* CoreModule = HS.lookupModule("Core", SourceLocation(),
3393 /*AllowSearch*/false);
3394 assert(M && "Must have module Core");
3395 PP.makeModuleVisible(CoreModule, ImportLoc);
3396 }
3397 }
3398};
3399
3400static llvm::cl::opt<bool> gOptSystemModuleByproducts("mSystemByproducts", llvm::cl::Hidden,
3401 llvm::cl::desc("Allow implicit build of system modules."),
3402 llvm::cl::cat(gRootclingOptions));
3403static llvm::cl::list<std::string>
3404gOptModuleByproducts("mByproduct", llvm::cl::ZeroOrMore,
3405 llvm::cl::Hidden,
3406 llvm::cl::desc("The list of the expected implicit modules build as part of building the current module."),
3407 llvm::cl::cat(gRootclingOptions));
3408// Really llvm::cl::Required, will be changed in RootClingMain below.
3409static llvm::cl::opt<std::string>
3410gOptDictionaryFileName(llvm::cl::Positional,
3411 llvm::cl::desc("<output dictionary file>"),
3412 llvm::cl::cat(gRootclingOptions));
3413
3414////////////////////////////////////////////////////////////////////////////////
3415/// Custom diag client for clang that verifies that each implicitly build module
3416/// is a system module. If not, it will let the current rootcling invocation
3417/// fail with an error. All other diags beside module build remarks will be
3418/// forwarded to the passed child diag client.
3419///
3420/// The reason why we need this is that if we built implicitly a C++ module
3421/// that belongs to a ROOT dictionary, then we will miss information generated
3422/// by rootcling in this file (e.g. the source code comments to annotation
3423/// attributes transformation will be missing in the module file).
3424class CheckModuleBuildClient : public clang::DiagnosticConsumer {
3425 clang::DiagnosticConsumer *fChild;
3427 clang::ModuleMap &fMap;
3428
3429public:
3430 CheckModuleBuildClient(clang::DiagnosticConsumer *Child, bool OwnsChild, clang::ModuleMap &Map)
3432 {
3433 }
3434
3436 {
3437 if (fOwnsChild)
3438 delete fChild;
3439 }
3440
3441 void HandleDiagnostic(clang::DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &Info) override
3442 {
3443 using namespace clang::diag;
3444
3445 // This method catches the module_build remark from clang and checks if
3446 // the implicitly built module is a system module or not. We only support
3447 // building system modules implicitly.
3448
3449 std::string moduleName;
3450 const clang::Module *module = nullptr;
3451
3452 // Extract the module from the diag argument with index 0.
3453 const auto &ID = Info.getID();
3454 if (ID == remark_module_build || ID == remark_module_build_done) {
3455 moduleName = Info.getArgStdStr(0);
3456 module = fMap.findModule(moduleName);
3457 // We should never be able to build a module without having it in the
3458 // modulemap. Still, let's print a warning that we at least tell the
3459 // user that this could lead to problems.
3460 if (!module) {
3462 "Couldn't find module %s in the available modulemaps. This"
3463 "prevents us from correctly diagnosing wrongly built modules.\n",
3464 moduleName.c_str());
3465 }
3466 }
3467
3468 // A dictionary module could build implicitly a set of implicit modules.
3469 // For example, the Core module builds libc.pcm and std.pcm implicitly.
3470 // Those modules do not require I/O information and it is okay to build
3471 // them as part of another module.
3472 // However, we can build a module which requires I/O implictly which is
3473 // an error because rootcling is not able to generate the corresponding
3474 // dictionary.
3475 // If we build a I/O requiring module implicitly we should display
3476 // an error unless -mSystemByproducts or -mByproduct were specified.
3477 bool isByproductModule = false;
3478 if (module) {
3479 // -mSystemByproducts allows implicit building of any system module.
3480 if (module->IsSystem && gOptSystemModuleByproducts) {
3481 isByproductModule = true;
3482 }
3483 // -mByproduct lists concrete module names that are allowed.
3486 isByproductModule = true;
3487 }
3488 }
3489 if (!isByproductModule)
3490 fChild->HandleDiagnostic(DiagLevel, Info);
3491
3492 if (ID == remark_module_build && !isByproductModule) {
3494 "Building module '%s' implicitly. If '%s' requires a \n"
3495 "dictionary please specify build dependency: '%s' depends on '%s'.\n"
3496 "Otherwise, specify '-mByproduct %s' to disable this diagnostic.\n",
3497 moduleName.c_str(), moduleName.c_str(), gOptDictionaryFileName.c_str(),
3498 moduleName.c_str(), moduleName.c_str());
3499 }
3500 }
3501
3502 // All methods below just forward to the child and the default method.
3503 void clear() override
3504 {
3505 fChild->clear();
3506 DiagnosticConsumer::clear();
3507 }
3508
3509 void BeginSourceFile(const clang::LangOptions &LangOpts, const clang::Preprocessor *PP) override
3510 {
3511 fChild->BeginSourceFile(LangOpts, PP);
3512 DiagnosticConsumer::BeginSourceFile(LangOpts, PP);
3513 }
3514
3515 void EndSourceFile() override
3516 {
3517 fChild->EndSourceFile();
3518 DiagnosticConsumer::EndSourceFile();
3519 }
3520
3521 void finish() override
3522 {
3523 fChild->finish();
3524 DiagnosticConsumer::finish();
3525 }
3526
3527 bool IncludeInDiagnosticCounts() const override { return fChild->IncludeInDiagnosticCounts(); }
3528};
3529
3531#if defined(_WIN32) && defined(_MSC_VER)
3532 // Suppress error dialogs to avoid hangs on build nodes.
3533 // One can use an environment variable (Cling_GuiOnAssert) to enable
3534 // the error dialogs.
3535 const char *EnablePopups = std::getenv("Cling_GuiOnAssert");
3536 if (EnablePopups == nullptr || EnablePopups[0] == '0') {
3544 }
3545#endif
3546}
3547
3548static llvm::cl::opt<bool> gOptForce("f", llvm::cl::desc("Overwrite <file>s."),
3549 llvm::cl::cat(gRootclingOptions));
3550static llvm::cl::opt<bool> gOptRootBuild("rootbuild", llvm::cl::desc("If we are building ROOT."),
3551 llvm::cl::Hidden,
3552 llvm::cl::cat(gRootclingOptions));
3561static llvm::cl::opt<VerboseLevel>
3562gOptVerboseLevel(llvm::cl::desc("Choose verbosity level:"),
3563 llvm::cl::values(clEnumVal(v, "Show errors."),
3564 clEnumVal(v0, "Show only fatal errors."),
3565 clEnumVal(v1, "Show errors (the same as -v)."),
3566 clEnumVal(v2, "Show warnings (default)."),
3567 clEnumVal(v3, "Show notes."),
3568 clEnumVal(v4, "Show information.")),
3569 llvm::cl::init(v2),
3570 llvm::cl::cat(gRootclingOptions));
3571
3572static llvm::cl::opt<bool>
3573gOptCint("cint", llvm::cl::desc("Deprecated, legacy flag which is ignored."),
3574 llvm::cl::Hidden,
3575 llvm::cl::cat(gRootclingOptions));
3576static llvm::cl::opt<bool>
3577gOptReflex("reflex", llvm::cl::desc("Behave internally like genreflex."),
3578 llvm::cl::cat(gRootclingOptions));
3579static llvm::cl::opt<bool>
3580gOptGccXml("gccxml", llvm::cl::desc("Deprecated, legacy flag which is ignored."),
3581 llvm::cl::Hidden,
3582 llvm::cl::cat(gRootclingOptions));
3583static llvm::cl::opt<std::string>
3584gOptLibListPrefix("lib-list-prefix",
3585 llvm::cl::desc("An ACLiC feature which exports the list of dependent libraries."),
3586 llvm::cl::Hidden,
3587 llvm::cl::cat(gRootclingOptions));
3588static llvm::cl::opt<bool>
3589gOptGeneratePCH("generate-pch",
3590 llvm::cl::desc("Generates a pch file from a predefined set of headers. See makepch.py."),
3591 llvm::cl::Hidden,
3592 llvm::cl::cat(gRootclingOptions));
3593static llvm::cl::opt<bool>
3594gOptC("c", llvm::cl::desc("Deprecated, legacy flag which is ignored."),
3595 llvm::cl::cat(gRootclingOptions));
3596static llvm::cl::opt<bool>
3597gOptP("p", llvm::cl::desc("Deprecated, legacy flag which is ignored."),
3598 llvm::cl::cat(gRootclingOptions));
3599static llvm::cl::list<std::string>
3600gOptRootmapLibNames("rml", llvm::cl::ZeroOrMore,
3601 llvm::cl::desc("Generate rootmap file."),
3602 llvm::cl::cat(gRootclingOptions));
3603static llvm::cl::opt<std::string>
3605 llvm::cl::desc("Generate a rootmap file with the specified name."),
3606 llvm::cl::cat(gRootclingOptions));
3607static llvm::cl::opt<bool>
3608gOptCxxModule("cxxmodule",
3609 llvm::cl::desc("Generate a C++ module."),
3610 llvm::cl::cat(gRootclingOptions));
3611static llvm::cl::list<std::string>
3612gOptModuleMapFiles("moduleMapFile",
3613 llvm::cl::desc("Specify a C++ modulemap file."),
3614 llvm::cl::cat(gRootclingOptions));
3615// FIXME: Figure out how to combine the code of -umbrellaHeader and inlineInputHeader
3616static llvm::cl::opt<bool>
3617gOptUmbrellaInput("umbrellaHeader",
3618 llvm::cl::desc("A single header including all headers instead of specifying them on the command line."),
3619 llvm::cl::cat(gRootclingOptions));
3620static llvm::cl::opt<bool>
3621gOptMultiDict("multiDict",
3622 llvm::cl::desc("If this library has multiple separate LinkDef files."),
3623 llvm::cl::cat(gRootclingOptions));
3624static llvm::cl::opt<bool>
3625gOptNoGlobalUsingStd("noGlobalUsingStd",
3626 llvm::cl::desc("Do not declare {using namespace std} in dictionary global scope."),
3627 llvm::cl::cat(gRootclingOptions));
3628static llvm::cl::opt<bool>
3629gOptInterpreterOnly("interpreteronly",
3630 llvm::cl::desc("Generate minimal dictionary for interactivity (without IO information)."),
3631 llvm::cl::cat(gRootclingOptions));
3632static llvm::cl::opt<bool>
3634 llvm::cl::desc("Split the dictionary into two parts: one containing the IO (ClassDef)\
3635information and another the interactivity support."),
3636 llvm::cl::cat(gRootclingOptions));
3637static llvm::cl::opt<bool>
3638gOptNoDictSelection("noDictSelection",
3639 llvm::cl::Hidden,
3640 llvm::cl::desc("Do not run the selection rules. Useful when in -onepcm mode."),
3641 llvm::cl::cat(gRootclingOptions));
3642static llvm::cl::opt<std::string>
3644 llvm::cl::desc("The path to the library of the built dictionary."),
3645 llvm::cl::cat(gRootclingOptions));
3646static llvm::cl::list<std::string>
3648 llvm::cl::desc("The list of dependent modules of the dictionary."),
3649 llvm::cl::cat(gRootclingOptions));
3650static llvm::cl::list<std::string>
3651gOptExcludePaths("excludePath", llvm::cl::ZeroOrMore,
3652 llvm::cl::desc("Do not store the <path> in the dictionary."),
3653 llvm::cl::cat(gRootclingOptions));
3654// FIXME: This does not seem to work. We have one use of -inlineInputHeader in
3655// ROOT and it does not produce the expected result.
3656static llvm::cl::opt<bool>
3657gOptInlineInput("inlineInputHeader",
3658 llvm::cl::desc("Does not generate #include <header> but expands the header content."),
3659 llvm::cl::cat(gRootclingOptions));
3660// FIXME: This is totally the wrong concept. We should not expose an interface
3661// to be able to tell which component is in the pch and which needs extra
3662// scaffolding for interactive use. Moreover, some of the ROOT components are
3663// partially in the pch and this option makes it impossible to express that.
3664// We should be able to get the list of headers in the pch early and scan
3665// through them.
3666static llvm::cl::opt<bool>
3667gOptWriteEmptyRootPCM("writeEmptyRootPCM",
3668 llvm::cl::Hidden,
3669 llvm::cl::desc("Does not include the header files as it assumes they exist in the pch."),
3670 llvm::cl::cat(gRootclingOptions));
3671static llvm::cl::opt<bool>
3673 llvm::cl::desc("Check the selection syntax only."),
3674 llvm::cl::cat(gRootclingOptions));
3675static llvm::cl::opt<bool>
3676gOptFailOnWarnings("failOnWarnings",
3677 llvm::cl::desc("Fail if there are warnings."),
3678 llvm::cl::cat(gRootclingOptions));
3679static llvm::cl::opt<bool>
3680gOptNoIncludePaths("noIncludePaths",
3681 llvm::cl::desc("Do not store include paths but rely on the env variable ROOT_INCLUDE_PATH."),
3682 llvm::cl::cat(gRootclingOptions));
3683static llvm::cl::opt<std::string>
3684gOptISysRoot("isysroot", llvm::cl::Prefix, llvm::cl::Hidden,
3685 llvm::cl::desc("Specify an isysroot."),
3686 llvm::cl::cat(gRootclingOptions),
3687 llvm::cl::init("-"));
3688static llvm::cl::list<std::string>
3689gOptIncludePaths("I", llvm::cl::Prefix, llvm::cl::ZeroOrMore,
3690 llvm::cl::desc("Specify an include path."),
3691 llvm::cl::cat(gRootclingOptions));
3692static llvm::cl::list<std::string>
3693gOptCompDefaultIncludePaths("compilerI", llvm::cl::Prefix, llvm::cl::ZeroOrMore,
3694 llvm::cl::desc("Specify a compiler default include path, to suppress unneeded `-isystem` arguments."),
3695 llvm::cl::cat(gRootclingOptions));
3696static llvm::cl::list<std::string>
3697gOptSysIncludePaths("isystem", llvm::cl::ZeroOrMore,
3698 llvm::cl::desc("Specify a system include path."),
3699 llvm::cl::cat(gRootclingOptions));
3700static llvm::cl::list<std::string>
3701gOptPPDefines("D", llvm::cl::Prefix, llvm::cl::ZeroOrMore,
3702 llvm::cl::desc("Specify defined macros."),
3703 llvm::cl::cat(gRootclingOptions));
3704static llvm::cl::list<std::string>
3705gOptPPUndefines("U", llvm::cl::Prefix, llvm::cl::ZeroOrMore,
3706 llvm::cl::desc("Specify undefined macros."),
3707 llvm::cl::cat(gRootclingOptions));
3708static llvm::cl::list<std::string>
3709gOptWDiags("W", llvm::cl::Prefix, llvm::cl::ZeroOrMore,
3710 llvm::cl::desc("Specify compiler diagnostics options."),
3711 llvm::cl::cat(gRootclingOptions));
3712static llvm::cl::opt<std::string>
3714 llvm::cl::desc("Write dependency output to the specified file."),
3715 llvm::cl::cat(gRootclingOptions));
3716// Really OneOrMore, will be changed in RootClingMain below.
3717static llvm::cl::list<std::string>
3718gOptDictionaryHeaderFiles(llvm::cl::Positional, llvm::cl::ZeroOrMore,
3719 llvm::cl::desc("<list of dictionary header files> <LinkDef file | selection xml file>"),
3720 llvm::cl::cat(gRootclingOptions));
3721static llvm::cl::list<std::string>
3722gOptSink(llvm::cl::ZeroOrMore, llvm::cl::Sink,
3723 llvm::cl::desc("Consumes all unrecognized options."),
3724 llvm::cl::cat(gRootclingOptions));
3725
3726static llvm::cl::SubCommand
3727gBareClingSubcommand("bare-cling", "Call directly cling and exit.");
3728
3729static llvm::cl::list<std::string>
3730gOptBareClingSink(llvm::cl::OneOrMore, llvm::cl::Sink,
3731 llvm::cl::desc("Consumes options and sends them to cling."),
3732 llvm::cl::cat(gRootclingOptions), llvm::cl::sub(gBareClingSubcommand));
3733
3734////////////////////////////////////////////////////////////////////////////////
3735/// Returns true iff a given module (and its submodules) contains all headers
3736/// needed by the given ModuleGenerator.
3737/// The names of all header files that are needed by the ModuleGenerator but are
3738/// not in the given module will be inserted into the MissingHeader variable.
3739/// Returns true iff the PCH was successfully generated.
3741 clang::Module *module, std::vector<std::array<std::string, 2>> &missingHeaders)
3742{
3743 // Now we collect all header files from the previously collected modules.
3744 std::vector<clang::Module::Header> moduleHeaders;
3746 [&moduleHeaders](const clang::Module::Header &h) { moduleHeaders.push_back(h); });
3747
3748 bool foundAllHeaders = true;
3749
3750 auto isHeaderInModule = [&moduleHeaders](const std::string &header) {
3751 for (const clang::Module::Header &moduleHeader : moduleHeaders)
3752 if (header == moduleHeader.NameAsWritten)
3753 return true;
3754 return false;
3755 };
3756
3757 // Go through the list of headers that are required by the ModuleGenerator
3758 // and check for each header if it's in one of the modules we loaded.
3759 // If not, make sure we fail at the end and mark the header as missing.
3760 for (const std::string &header : modGen.GetHeaders()) {
3761 if (isHeaderInModule(header))
3762 continue;
3763
3764 clang::ModuleMap::KnownHeader SuggestedModule;
3765 clang::ConstSearchDirIterator *CurDir = nullptr;
3766 if (auto FE = headerSearch.LookupFile(
3767 header, clang::SourceLocation(),
3768 /*isAngled*/ false,
3769 /*FromDir*/ nullptr, CurDir,
3770 clang::ArrayRef<std::pair<clang::OptionalFileEntryRef, clang::DirectoryEntryRef>>(),
3771 /*SearchPath*/ nullptr,
3772 /*RelativePath*/ nullptr,
3773 /*RequestingModule*/ nullptr, &SuggestedModule,
3774 /*IsMapped*/ nullptr,
3775 /*IsFrameworkFound*/ nullptr,
3776 /*SkipCache*/ false,
3777 /*BuildSystemModule*/ false,
3778 /*OpenFile*/ false,
3779 /*CacheFail*/ false)) {
3780 if (auto OtherModule = SuggestedModule.getModule()) {
3781 std::string OtherModuleName;
3782 auto TLM = OtherModule->getTopLevelModuleName();
3783 if (!TLM.empty())
3784 OtherModuleName = TLM.str();
3785 else
3787
3788 // Don't complain about headers that are actually in by-products:
3791 continue;
3792
3793 missingHeaders.push_back({header, OtherModuleName});
3794 }
3795 } else {
3796 missingHeaders.push_back({header, {}});
3797 }
3798 foundAllHeaders = false;
3799 }
3800 return foundAllHeaders;
3801}
3802
3803////////////////////////////////////////////////////////////////////////////////
3804/// Check moduleName validity from modulemap. Check if this module is defined or not.
3805static bool CheckModuleValid(TModuleGenerator &modGen, const std::string &resourceDir, cling::Interpreter &interpreter,
3806 llvm::StringRef LinkdefPath, const std::string &moduleName)
3807{
3808 clang::CompilerInstance *CI = interpreter.getCI();
3809 clang::HeaderSearch &headerSearch = CI->getPreprocessor().getHeaderSearchInfo();
3810 headerSearch.loadTopLevelSystemModules();
3811
3812 // Actually lookup the module on the computed module name.
3813 clang::Module *module = headerSearch.lookupModule(llvm::StringRef(moduleName));
3814
3815 // Inform the user and abort if we can't find a module with a given name.
3816 if (!module) {
3817 ROOT::TMetaUtils::Error("CheckModuleValid", "Couldn't find module with name '%s' in modulemap!\n",
3818 moduleName.c_str());
3819 return false;
3820 }
3821
3822 // Check if the loaded module covers all headers that were specified
3823 // by the user on the command line. This is an integrity check to
3824 // ensure that our used module map is not containing extraneous headers.
3825 std::vector<std::array<std::string, 2>> missingHdrMod;
3827 // FIXME: Upgrade this to an error once modules are stable.
3828 std::stringstream msgStream;
3829 msgStream << "after creating module \"" << module->Name << "\" ";
3830 if (!module->PresumedModuleMapFile.empty())
3831 msgStream << "using modulemap \"" << module->PresumedModuleMapFile << "\" ";
3832 msgStream << "the following headers are not part of that module:\n";
3833 for (auto &H : missingHdrMod) {
3834 msgStream << " " << H[0];
3835 if (!H[1].empty())
3836 msgStream << " (already part of module \"" << H[1] << "\")";
3837 msgStream << "\n";
3838 }
3839 std::string warningMessage = msgStream.str();
3840
3841 bool maybeUmbrella = modGen.GetHeaders().size() == 1;
3842 // We may have an umbrella and forgot to add the flag. Downgrade the
3843 // warning into an information message.
3844 // FIXME: We should open the umbrella, extract the set of header files
3845 // and check if they exist in the modulemap.
3846 // FIXME: We should also check if the header files are specified in the
3847 // modulemap file as they appeared in the rootcling invocation, i.e.
3848 // if we passed rootcling ... -I/some/path somedir/some/header, the
3849 // modulemap should contain module M { header "somedir/some/header" }
3850 // This way we will make sure the module is properly activated.
3852 ROOT::TMetaUtils::Info("CheckModuleValid, %s. You can silence this message by adding %s to the invocation.",
3853 warningMessage.c_str(),
3854 gOptUmbrellaInput.ArgStr.data());
3855 return true;
3856 }
3857
3858 ROOT::TMetaUtils::Warning("CheckModuleValid", warningMessage.c_str());
3859 // We include the missing headers to fix the module for the user.
3860 std::vector<std::string> missingHeaders;
3862 [](const std::array<std::string, 2>& HdrMod) { return HdrMod[0];});
3864 ROOT::TMetaUtils::Error("CheckModuleValid", "Couldn't include missing module headers for module '%s'!\n",
3865 module->Name.c_str());
3866 }
3867 }
3868
3869 return true;
3870}
3871
3872static llvm::StringRef GetModuleNameFromRdictName(llvm::StringRef rdictName)
3873{
3874 // Try to get the module name in the modulemap based on the filepath.
3875 llvm::StringRef moduleName = llvm::sys::path::filename(rdictName);
3876 moduleName.consume_front("lib");
3877 moduleName.consume_back(".pcm");
3878 moduleName.consume_back("_rdict");
3879 return moduleName;
3880}
3881
3882////////////////////////////////////////////////////////////////////////////////
3883
3885 char **argv,
3886 bool isGenreflex = false)
3887{
3888 // Set number of required arguments. We cannot do this globally since it
3889 // would interfere with LLVM's option parsing.
3890 gOptDictionaryFileName.setNumOccurrencesFlag(llvm::cl::Required);
3891 gOptDictionaryHeaderFiles.setNumOccurrencesFlag(llvm::cl::OneOrMore);
3892
3893 // Copied from cling driver.
3894 // FIXME: Uncomment once we fix ROOT's teardown order.
3895 //llvm::llvm_shutdown_obj shutdownTrigger;
3896
3897 const char *executableFileName = argv[0];
3898
3899 llvm::sys::PrintStackTraceOnErrorSignal(executableFileName);
3900 llvm::PrettyStackTraceProgram X(argc, argv);
3902
3903#if defined(R__WIN32) && !defined(R__WINGCC)
3904 // FIXME: This is terrible hack allocating and changing the argument set.
3905 // We should remove it and use standard llvm facilities to convert the paths.
3906 // cygwin's make is presenting us some cygwin paths even though
3907 // we are windows native. Convert them as good as we can.
3908 for (int iic = 1 /* ignore binary file name in argv[0] */; iic < argc; ++iic) {
3909 std::string iiarg(argv[iic]);
3911 size_t len = iiarg.length();
3912 // yes, we leak.
3913 char *argviic = new char[len + 1];
3914 strlcpy(argviic, iiarg.c_str(), len + 1);
3915 argv[iic] = argviic;
3916 }
3917 }
3918#endif
3919
3920 // Hide options from llvm which we got from static initialization of libCling.
3921 llvm::cl::HideUnrelatedOptions(/*keep*/gRootclingOptions);
3922
3923 // Define Options aliasses
3924 auto &opts = llvm::cl::getRegisteredOptions();
3925 llvm::cl::Option* optHelp = opts["help"];
3926 llvm::cl::alias optHelpAlias1("h",
3927 llvm::cl::desc("Alias for -help"),
3928 llvm::cl::aliasopt(*optHelp));
3929 llvm::cl::alias optHelpAlias2("?",
3930 llvm::cl::desc("Alias for -help"),
3931 llvm::cl::aliasopt(*optHelp));
3932
3933 llvm::cl::ParseCommandLineOptions(argc, argv, "rootcling");
3934
3935 const char *etcDir = gDriverConfig->fTROOT__GetEtcDir();
3936 std::string llvmResourceDir = etcDir ? std::string(etcDir) + "/cling" : "";
3937
3939 std::vector<const char *> clingArgsC;
3940 clingArgsC.push_back(executableFileName);
3941 // Help cling finds its runtime (RuntimeUniverse.h and such).
3942 if (etcDir) {
3943 clingArgsC.push_back("-I");
3944 clingArgsC.push_back(etcDir);
3945 }
3946
3947 //clingArgsC.push_back("-resource-dir");
3948 //clingArgsC.push_back(llvmResourceDir.c_str());
3949
3950 for (const std::string& Opt : gOptBareClingSink)
3951 clingArgsC.push_back(Opt.c_str());
3952
3953 auto interp = std::make_unique<cling::Interpreter>(clingArgsC.size(),
3954 &clingArgsC[0],
3955 llvmResourceDir.c_str());
3956 // FIXME: Diagnose when we have misspelled a flag. Currently we show no
3957 // diagnostic and report exit as success.
3958 return interp->getDiagnostics().hasFatalErrorOccurred();
3959 }
3960
3961 std::string dictname;
3962
3963 if (!gDriverConfig->fBuildingROOTStage1) {
3964 if (gOptRootBuild) {
3965 // running rootcling as part of the ROOT build for ROOT libraries.
3966 gBuildingROOT = true;
3967 }
3968 }
3969
3970 if (!gOptModuleMapFiles.empty() && !gOptCxxModule) {
3971 ROOT::TMetaUtils::Error("", "Option %s can be used only when option %s is specified.\n",
3972 gOptModuleMapFiles.ArgStr.str().c_str(),
3973 gOptCxxModule.ArgStr.str().c_str());
3974 std::cout << "\n";
3975 llvm::cl::PrintHelpMessage();
3976 return 1;
3977 }
3978
3979 // Set the default verbosity
3981 if (gOptVerboseLevel == v4)
3982 genreflex::verbose = true;
3983
3984 if (gOptReflex)
3985 isGenreflex = true;
3986
3987 if (!gOptLibListPrefix.empty()) {
3988 string filein = gOptLibListPrefix + ".in";
3989 FILE *fp;
3990 if ((fp = fopen(filein.c_str(), "r")) == nullptr) {
3991 ROOT::TMetaUtils::Error(nullptr, "%s: The input list file %s does not exist\n", executableFileName, filein.c_str());
3992 return 1;
3993 }
3994 fclose(fp);
3995 }
3996
3998 FILE *fp;
3999 if ((fp = fopen(gOptDictionaryFileName.c_str(), "r")) != nullptr) {
4000 fclose(fp);
4001 if (!gOptForce) {
4002 ROOT::TMetaUtils::Error(nullptr, "%s: output file %s already exists\n", executableFileName, gOptDictionaryFileName.c_str());
4003 return 1;
4004 }
4005 }
4006
4007 // remove possible pathname to get the dictionary name
4008 if (gOptDictionaryFileName.size() > (PATH_MAX - 1)) {
4009 ROOT::TMetaUtils::Error(nullptr, "rootcling: dictionary name too long (more than %d characters): %s\n",
4010 (PATH_MAX - 1), gOptDictionaryFileName.c_str());
4011 return 1;
4012 }
4013
4014 dictname = llvm::sys::path::filename(gOptDictionaryFileName).str();
4015 }
4016
4017 if (gOptForce && dictname.empty()) {
4018 ROOT::TMetaUtils::Error(nullptr, "Inconsistent set of arguments detected: overwrite of dictionary file forced but no filename specified.\n");
4019 llvm::cl::PrintHelpMessage();
4020 return 1;
4021 }
4022
4023 std::vector<std::string> clingArgs;
4024 clingArgs.push_back(executableFileName);
4025 clingArgs.push_back("-iquote.");
4026
4028
4029 // Collect the diagnostic pragmas linked to the usage of -W
4030 // Workaround for ROOT-5656
4031 std::list<std::string> diagnosticPragmas = {"#pragma clang diagnostic ignored \"-Wdeprecated-declarations\""};
4032
4033 if (gOptFailOnWarnings) {
4034 using namespace ROOT::TMetaUtils;
4035 // If warnings are disabled with the current verbosity settings, lower
4036 // it so that the user sees the warning that caused the failure.
4037 if (GetErrorIgnoreLevel() > kWarning)
4038 GetErrorIgnoreLevel() = kWarning;
4039 GetWarningsAreErrors() = true;
4040 }
4041
4042 if (gOptISysRoot != "-") {
4043 if (gOptISysRoot.empty()) {
4044 ROOT::TMetaUtils::Error("", "isysroot specified without a value.\n");
4045 return 1;
4046 }
4047 clingArgs.push_back(gOptISysRoot.ArgStr.str());
4048 clingArgs.push_back(gOptISysRoot.ValueStr.str());
4049 }
4050
4051 // Check if we have a multi dict request but no target library
4052 if (gOptMultiDict && gOptSharedLibFileName.empty()) {
4053 ROOT::TMetaUtils::Error("", "Multidict requested but no target library. Please specify one with the -s argument.\n");
4054 return 1;
4055 }
4056
4057 for (const std::string &PPDefine : gOptPPDefines)
4058 clingArgs.push_back(std::string("-D") + PPDefine);
4059
4060 for (const std::string &PPUndefine : gOptPPUndefines)
4061 clingArgs.push_back(std::string("-U") + PPUndefine);
4062
4063 for (const std::string &IncludePath : gOptIncludePaths)
4064 clingArgs.push_back(std::string("-I") + llvm::sys::path::convert_to_slash(IncludePath));
4065
4066 for (const std::string &IncludePath : gOptSysIncludePaths) {
4067 // Prevent mentioning compiler default include directories as -isystem
4068 // (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70129)
4071 clingArgs.push_back("-isystem");
4072 clingArgs.push_back(llvm::sys::path::convert_to_slash(IncludePath));
4073 }
4074 }
4075
4076 for (const std::string &WDiag : gOptWDiags) {
4077 const std::string FullWDiag = std::string("-W") + WDiag;
4078 // Suppress warning when compiling the dictionary, eg. gcc G__xxx.cxx
4080 // Suppress warning when compiling the input headers by cling.
4081 clingArgs.push_back(FullWDiag);
4082 }
4083
4084 const char *includeDir = gDriverConfig->fTROOT__GetIncludeDir();
4085 if (includeDir) {
4086 clingArgs.push_back(std::string("-I") + llvm::sys::path::convert_to_slash(includeDir));
4087 }
4088
4089 std::vector<std::string> pcmArgs;
4090 for (size_t parg = 0, n = clingArgs.size(); parg < n; ++parg) {
4091 auto thisArg = clingArgs[parg];
4093 if (thisArg == "-c" ||
4094 (gOptNoIncludePaths && isInclude)) continue;
4095 // We now check if the include directories are not excluded
4096 if (isInclude) {
4097 unsigned int offset = 2; // -I is two characters. Now account for spaces
4098 char c = thisArg[offset];
4099 while (c == ' ') c = thisArg[++offset];
4101 auto excludePathPos = std::find_if(gOptExcludePaths.begin(),
4103 [&](const std::string& path){
4104 return ROOT::TMetaUtils::BeginsWith(&thisArg[offset], path);});
4105 if (excludePathsEnd != excludePathPos) continue;
4106 }
4107 pcmArgs.push_back(thisArg);
4108 }
4109
4110 // cling-only arguments
4111 if (etcDir)
4112 clingArgs.push_back(std::string("-I") + llvm::sys::path::convert_to_slash(etcDir));
4113
4114 // We do not want __ROOTCLING__ in the pch!
4115 if (!gOptGeneratePCH) {
4116 clingArgs.push_back("-D__ROOTCLING__");
4117 }
4118#ifdef R__MACOSX
4119 clingArgs.push_back("-DSYSTEM_TYPE_macosx");
4120#elif defined(R__WIN32)
4121 clingArgs.push_back("-DSYSTEM_TYPE_winnt");
4122
4123 // Prevent the following #error: The C++ Standard Library forbids macroizing keywords.
4124 clingArgs.push_back("-D_XKEYCHECK_H");
4125 // Tell windows.h not to #define min and max, it clashes with numerical_limits.
4126 clingArgs.push_back("-DNOMINMAX");
4127#else // assume UNIX
4128 clingArgs.push_back("-DSYSTEM_TYPE_unix");
4129#endif
4130
4131 clingArgs.push_back("-fsyntax-only");
4132#ifndef R__WIN32
4133 clingArgs.push_back("-fPIC");
4134#endif
4135 clingArgs.push_back("-Xclang");
4136 clingArgs.push_back("-fmodules-embed-all-files");
4137 clingArgs.push_back("-Xclang");
4138 clingArgs.push_back("-main-file-name");
4139 clingArgs.push_back("-Xclang");
4140 clingArgs.push_back((dictname + ".h").c_str());
4141
4143
4144 // FIXME: This line is from TModuleGenerator, but we can't reuse this code
4145 // at this point because TModuleGenerator needs a CompilerInstance (and we
4146 // currently create the arguments for creating said CompilerInstance).
4147 bool isPCH = (gOptDictionaryFileName.getValue() == "allDict.cxx");
4148 std::string outputFile;
4149 // Data is in 'outputFile', therefore in the same scope.
4150 llvm::StringRef moduleName;
4151 std::string vfsArg;
4152 // Adding -fmodules to the args will break lexing with __CLING__ defined,
4153 // and we actually do lex with __CLING__ and reuse this variable later,
4154 // we have to copy it now.
4156
4157 if (gOptSharedLibFileName.empty()) {
4159 }
4160
4161 if (!isPCH && gOptCxxModule) {
4162 // We just pass -fmodules, the CIFactory will do the rest and configure
4163 // clang correctly once it sees this flag.
4164 clingArgsInterpreter.push_back("-fmodules");
4165 clingArgsInterpreter.push_back("-fno-implicit-module-maps");
4166
4167 for (const std::string &modulemap : gOptModuleMapFiles)
4168 clingArgsInterpreter.push_back("-fmodule-map-file=" + modulemap);
4169
4170 if (includeDir) {
4171 clingArgsInterpreter.push_back("-fmodule-map-file=" + std::string(includeDir) + "/ROOT.modulemap");
4172 }
4173 std::string ModuleMapCWD = ROOT::FoundationUtils::GetCurrentDir() + "/module.modulemap";
4174 if (llvm::sys::fs::exists(ModuleMapCWD))
4175 clingArgsInterpreter.push_back("-fmodule-map-file=" + ModuleMapCWD);
4176
4177 // Specify the module name that we can lookup the module in the modulemap.
4178 outputFile = llvm::sys::path::stem(gOptSharedLibFileName).str();
4179 // Try to get the module name in the modulemap based on the filepath.
4181
4182#ifdef _MSC_VER
4183 clingArgsInterpreter.push_back("-Xclang");
4184 clingArgsInterpreter.push_back("-fmodule-feature");
4185 clingArgsInterpreter.push_back("-Xclang");
4186 clingArgsInterpreter.push_back("msvc" + std::string(rootclingStringify(_MSC_VER)));
4187#endif
4188 clingArgsInterpreter.push_back("-fmodule-name=" + moduleName.str());
4189
4190 std::string moduleCachePath = llvm::sys::path::parent_path(gOptSharedLibFileName).str();
4191 // FIXME: This is a horrible workaround to fix the incremental builds.
4192 // The enumerated modules are built by clang impicitly based on #include of
4193 // a header which is contained within that module. The build system has
4194 // no way to track dependencies on them and trigger a rebuild.
4195 // A possible solution can be to disable completely the implicit build of
4196 // modules and each module to be built by rootcling. We need to teach
4197 // rootcling how to build modules with no IO support.
4198 if (moduleName == "Core") {
4199 assert(gDriverConfig->fBuildingROOTStage1);
4200 remove((moduleCachePath + llvm::sys::path::get_separator() + "_Builtin_intrinsics.pcm").str().c_str());
4201 remove((moduleCachePath + llvm::sys::path::get_separator() + "_Builtin_stddef_max_align_t.pcm").str().c_str());
4202 remove((moduleCachePath + llvm::sys::path::get_separator() + "Cling_Runtime.pcm").str().c_str());
4203 remove((moduleCachePath + llvm::sys::path::get_separator() + "Cling_Runtime_Extra.pcm").str().c_str());
4204#ifdef R__WIN32
4205 remove((moduleCachePath + llvm::sys::path::get_separator() + "vcruntime.pcm").str().c_str());
4206 remove((moduleCachePath + llvm::sys::path::get_separator() + "services.pcm").str().c_str());
4207#endif
4208
4209#ifdef R__MACOSX
4210 remove((moduleCachePath + llvm::sys::path::get_separator() + "Darwin.pcm").str().c_str());
4211#else
4212 remove((moduleCachePath + llvm::sys::path::get_separator() + "libc.pcm").str().c_str());
4213#endif
4214 remove((moduleCachePath + llvm::sys::path::get_separator() + "std.pcm").str().c_str());
4215 remove((moduleCachePath + llvm::sys::path::get_separator() + "boost.pcm").str().c_str());
4216 remove((moduleCachePath + llvm::sys::path::get_separator() + "tinyxml2.pcm").str().c_str());
4217 remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Config.pcm").str().c_str());
4218 remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Rtypes.pcm").str().c_str());
4219 remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Foundation_C.pcm").str().c_str());
4220 remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Foundation_Stage1_NoRTTI.pcm").str().c_str());
4221 } else if (moduleName == "MathCore") {
4222 remove((moduleCachePath + llvm::sys::path::get_separator() + "Vc.pcm").str().c_str());
4223 }
4224
4225 // Set the C++ modules output directory to the directory where we generate
4226 // the shared library.
4227 clingArgsInterpreter.push_back("-fmodules-cache-path=" + moduleCachePath);
4228 }
4229
4230 if (gOptVerboseLevel == v4)
4231 clingArgsInterpreter.push_back("-v");
4232
4233 // Convert arguments to a C array and check if they are sane
4234 std::vector<const char *> clingArgsC;
4235 for (auto const &clingArg : clingArgsInterpreter) {
4237 std::cerr << "Argument \""<< clingArg << "\" is not a supported cling argument. "
4238 << "This could be mistyped rootcling argument. Please check the commandline.\n";
4239 return 1;
4240 }
4241 clingArgsC.push_back(clingArg.c_str());
4242 }
4243
4244
4245 std::unique_ptr<cling::Interpreter> owningInterpPtr;
4246 cling::Interpreter* interpPtr = nullptr;
4247
4248 std::list<std::string> filesIncludedByLinkdef;
4249 if (gDriverConfig->fBuildingROOTStage1) {
4250#ifdef R__FAST_MATH
4251 // Same setting as in TCling.cxx.
4252 clingArgsC.push_back("-ffast-math");
4253#endif
4254
4255 owningInterpPtr.reset(new cling::Interpreter(clingArgsC.size(), &clingArgsC[0],
4256 llvmResourceDir.c_str()));
4257 interpPtr = owningInterpPtr.get();
4258 } else {
4259 // Pass the interpreter arguments to TCling's interpreter:
4260 clingArgsC.push_back("-resource-dir");
4261 clingArgsC.push_back(llvmResourceDir.c_str());
4262 clingArgsC.push_back(nullptr); // signal end of array
4263 const char ** &extraArgs = *gDriverConfig->fTROOT__GetExtraInterpreterArgs();
4264 extraArgs = &clingArgsC[1]; // skip binary name
4265 interpPtr = gDriverConfig->fTCling__GetInterpreter();
4266 if (!interpPtr->getCI()) // Compiler instance could not be created. See https://its.cern.ch/jira/browse/ROOT-10239
4267 return 1;
4268 if (!isGenreflex && !gOptGeneratePCH) {
4269 std::unique_ptr<TRootClingCallbacks> callBacks (new TRootClingCallbacks(interpPtr, filesIncludedByLinkdef));
4270 interpPtr->setCallbacks(std::move(callBacks));
4271 }
4272 }
4273 cling::Interpreter &interp = *interpPtr;
4274 clang::CompilerInstance *CI = interp.getCI();
4275 // FIXME: Remove this once we switch cling to use the driver. This would handle -fmodules-embed-all-files for us.
4276 CI->getFrontendOpts().ModulesEmbedAllFiles = true;
4277 CI->getSourceManager().setAllFilesAreTransient(true);
4278
4279 clang::Preprocessor &PP = CI->getPreprocessor();
4280 clang::HeaderSearch &headerSearch = PP.getHeaderSearchInfo();
4281 clang::ModuleMap &moduleMap = headerSearch.getModuleMap();
4282 auto &diags = interp.getDiagnostics();
4283
4284 // Manually enable the module build remarks. We don't enable them via the
4285 // normal clang command line arg because otherwise we would get remarks for
4286 // building STL/libc when starting the interpreter in rootcling_stage1.
4287 // We can't prevent these diags in any other way because we can only attach
4288 // our own diag client now after the interpreter has already started.
4289 diags.setSeverity(clang::diag::remark_module_build, clang::diag::Severity::Remark, clang::SourceLocation());
4290
4291 // Attach our own diag client that listens to the module_build remarks from
4292 // clang to check that we don't build dictionary C++ modules implicitly.
4293 auto recordingClient = new CheckModuleBuildClient(diags.getClient(), diags.ownsClient(), moduleMap);
4294 diags.setClient(recordingClient, true);
4295
4297 ROOT::TMetaUtils::Info(nullptr, "\n");
4298 ROOT::TMetaUtils::Info(nullptr, "==== INTERPRETER CONFIGURATION ====\n");
4299 ROOT::TMetaUtils::Info(nullptr, "== Include paths\n");
4300 interp.DumpIncludePath();
4301 printf("\n\n");
4302 fflush(stdout);
4303
4304 ROOT::TMetaUtils::Info(nullptr, "== Included files\n");
4305 interp.printIncludedFiles(llvm::outs());
4306 llvm::outs() << "\n\n";
4307 llvm::outs().flush();
4308
4309 ROOT::TMetaUtils::Info(nullptr, "== Language Options\n");
4310 const clang::LangOptions& LangOpts
4311 = interp.getCI()->getASTContext().getLangOpts();
4312
4313 // FIXME: Replace with C++20 `using enum LangOptions::CompatibilityKind`.
4314 using CK = clang::LangOptions::CompatibilityKind;
4315#define LANGOPT(Name, Bits, Default, Compatibility, Description) \
4316 if constexpr (CK::Compatibility != CK::Benign) \
4317 ROOT::TMetaUtils::Info(nullptr, "%s = %d // %s\n", #Name, (int)LangOpts.Name, Description);
4318#define ENUM_LANGOPT(Name, Type, Bits, Default, Compatibility, Description)
4319#include "clang/Basic/LangOptions.def"
4320 ROOT::TMetaUtils::Info(nullptr, "==== END interpreter configuration ====\n\n");
4321 }
4322
4323 interp.getOptions().ErrorOut = true;
4324 interp.enableRawInput(true);
4325
4326 if (gOptCxxModule) {
4327 for (llvm::StringRef DepMod : gOptModuleDependencies) {
4328 if (DepMod.ends_with("_rdict.pcm")) {
4329 ROOT::TMetaUtils::Warning(nullptr, "'%s' value is deprecated. Please use [<fullpath>]%s.pcm\n",
4330 DepMod.data(),
4332 }
4334 // We might deserialize.
4335 cling::Interpreter::PushTransactionRAII RAII(&interp);
4336 if (!interp.loadModule(DepMod.str(), /*complain*/false)) {
4337 ROOT::TMetaUtils::Error(nullptr, "Module '%s' failed to load.\n",
4338 DepMod.data());
4339 }
4340 }
4341 }
4342
4343 if (!isGenreflex) { // rootcling
4344 // ROOTCINT uses to define a few header implicitly, we need to do it explicitly.
4345 if (interp.declare("#include <cassert>\n"
4346 "#include \"Rtypes.h\"\n"
4347 "#include \"TObject.h\"") != cling::Interpreter::kSuccess
4348 ) {
4349 // There was an error.
4350 ROOT::TMetaUtils::Error(nullptr, "Error loading the default rootcling header files.\n");
4351 return 1;
4352 }
4353 }
4354
4355 if (interp.declare("#include <string>\n" // For the list of 'opaque' typedef to also include string.
4356 "#include <RtypesCore.h>\n" // For initializing TNormalizedCtxt.
4357 "namespace std {} using namespace std;") != cling::Interpreter::kSuccess) {
4358 ROOT::TMetaUtils::Error(nullptr, "Error loading the default header files.\n");
4359 return 1;
4360 }
4361
4362 // We are now ready (enough is loaded) to init the list of opaque typedefs.
4364 ROOT::TMetaUtils::TClingLookupHelper helper(interp, normCtxt, nullptr, nullptr, nullptr, nullptr);
4366
4367 // flags used only for the pragma parser:
4368 clingArgs.push_back("-D__CINT__"); // backward compatibility. Now __CLING__ should be used instead
4369 clingArgs.push_back("-D__MAKECINT__"); // backward compatibility. Now __ROOTCLING__ should used instead
4370
4372
4374
4375 std::string interpPragmaSource;
4376 std::string includeForSource;
4377 std::string interpreterDeclarations;
4378 std::string linkdef;
4379
4380 for (size_t i = 0, e = gOptDictionaryHeaderFiles.size(); i < e; ++i) {
4381 const std::string& optHeaderFileName = gOptDictionaryHeaderFiles[i];
4383
4384 if (isSelectionFile) {
4385 if (i == e - 1) {
4387 } else { // if the linkdef was not last, issue an error.
4388 ROOT::TMetaUtils::Error(nullptr, "%s: %s must be last file on command line\n",
4390 return 1;
4391 }
4392 }
4393
4394 // coverity[tainted_data] The OS should already limit the argument size, so we are safe here
4395 std::string fullheader(optHeaderFileName);
4396 // Strip any trailing + which is only used by GeneratedLinkdef.h which currently
4397 // use directly argv.
4398 if (fullheader[fullheader.length() - 1] == '+') {
4399 fullheader.erase(fullheader.length() - 1);
4400 }
4401 std::string header(
4403
4404 interpPragmaSource += std::string("#include \"") + header + "\"\n";
4405 if (!isSelectionFile) {
4406 // In order to not have to add the equivalent to -I${PWD} to the
4407 // command line, include the complete file name, even if it is a
4408 // full pathname, when we write it down in the dictionary.
4409 // Note: have -I${PWD} means in that (at least in the case of
4410 // ACLiC) we inadvertently pick local file that have the same
4411 // name as system header (e.g. new or list) and -iquote has not
4412 // equivalent on some platforms.
4413 includeForSource += std::string("#include \"") + fullheader + "\"\n";
4414 pcmArgs.push_back(header);
4415 } else if (!IsSelectionXml(optHeaderFileName.c_str())) {
4416 interpreterDeclarations += std::string("#include \"") + header + "\"\n";
4417 }
4418 }
4419
4420 if (gOptUmbrellaInput) {
4421 bool hasSelectionFile = !linkdef.empty();
4424 ROOT::TMetaUtils::Error(nullptr, "Option %s used but more than one header file specified.\n",
4425 gOptUmbrellaInput.ArgStr.data());
4426 }
4427
4428 // We have a multiDict request. This implies generating a pcm which is of the form
4429 // dictName_libname_rdict.pcm
4430 if (gOptMultiDict) {
4431
4432 std::string newName = llvm::sys::path::parent_path(gOptSharedLibFileName).str();
4433 if (!newName.empty())
4435 newName += llvm::sys::path::stem(gOptSharedLibFileName);
4436 newName += "_";
4437 newName += llvm::sys::path::stem(gOptDictionaryFileName);
4438 newName += llvm::sys::path::extension(gOptSharedLibFileName);
4440 }
4441
4442 // Until the module are actually enabled in ROOT, we need to register
4443 // the 'current' directory to make it relocatable (i.e. have a way
4444 // to find the headers).
4446 string incCurDir = "-I";
4448 pcmArgs.push_back(incCurDir);
4449 }
4450
4451 // Add the diagnostic pragmas distilled from the -Wno-xyz
4452 {
4453 std::stringstream res;
4454 const char* delim="\n";
4455 std::copy(diagnosticPragmas.begin(),
4457 std::ostream_iterator<std::string>(res, delim));
4458 if (interp.declare(res.str()) != cling::Interpreter::kSuccess) {
4459 ROOT::TMetaUtils::Error(nullptr, "Failed to parse -Wno-xyz flags as pragmas:\n%s", res.str().c_str());
4460 return 1;
4461 }
4462 }
4463
4464 class IgnoringPragmaHandler: public clang::PragmaNamespace {
4465 public:
4466 IgnoringPragmaHandler(const char* pragma):
4467 clang::PragmaNamespace(pragma) {}
4468 void HandlePragma(clang::Preprocessor &PP,
4469 clang::PragmaIntroducer Introducer,
4470 clang::Token &tok) override {
4471 PP.DiscardUntilEndOfDirective();
4472 }
4473 };
4474
4475 // Ignore these #pragmas to suppress "unknown pragma" warnings.
4476 // See LinkdefReader.cxx.
4477 PP.AddPragmaHandler(new IgnoringPragmaHandler("link"));
4478 PP.AddPragmaHandler(new IgnoringPragmaHandler("extra_include"));
4479 PP.AddPragmaHandler(new IgnoringPragmaHandler("read"));
4480 PP.AddPragmaHandler(new IgnoringPragmaHandler("create"));
4481
4482 if (!interpreterDeclarations.empty() &&
4483 interp.declare(interpreterDeclarations) != cling::Interpreter::kSuccess) {
4484 ROOT::TMetaUtils::Error(nullptr, "%s: Linkdef compilation failure\n", executableFileName);
4485 return 1;
4486 }
4487
4488
4493
4494 if (!gDriverConfig->fBuildingROOTStage1 && !filesIncludedByLinkdef.empty()) {
4495 pcmArgs.push_back(linkdef);
4496 }
4497
4498 modGen.ParseArgs(pcmArgs);
4499
4500 if (!gDriverConfig->fBuildingROOTStage1) {
4501 // Forward the -I, -D, -U
4502 for (const std::string & inclPath : modGen.GetIncludePaths()) {
4503 interp.AddIncludePath(inclPath);
4504 }
4505 std::stringstream definesUndefinesStr;
4506 modGen.WritePPDefines(definesUndefinesStr);
4507 modGen.WritePPUndefines(definesUndefinesStr);
4508 if (!definesUndefinesStr.str().empty()) {
4509 if (interp.declare(definesUndefinesStr.str()) != cling::Interpreter::kSuccess) {
4510 ROOT::TMetaUtils::Error(nullptr, "Failed to parse -D, -U flags as preprocessor directives:\n%s", definesUndefinesStr.str().c_str());
4511 return 1;
4512 }
4513 }
4514 }
4515
4518 return 1;
4519 }
4520
4521 // Check if code goes to stdout or rootcling file
4522 std::ofstream fileout;
4523 string main_dictname(gOptDictionaryFileName.getValue());
4524 // Keep the original dictionary output file name (with extension) for the
4525 // dependency file target: `main_dictname` gets its extension stripped below
4526 // and `gOptDictionaryFileName` is turned into a temporary name by the
4527 // tmpCatalog a few lines down.
4528 const std::string dictOutputFileName(gOptDictionaryFileName.getValue());
4529 std::ostream *splitDictStream = nullptr;
4530 std::unique_ptr<std::ostream> splitDeleter(nullptr);
4531 // Store the temp files
4533 if (!gOptDictionaryFileName.empty()) {
4534 tmpCatalog.addFileName(gOptDictionaryFileName.getValue());
4535 fileout.open(gOptDictionaryFileName.c_str());
4536 if (!fileout) {
4537 ROOT::TMetaUtils::Error(nullptr, "rootcling: failed to open %s in main\n",
4538 gOptDictionaryFileName.c_str());
4539 return 1;
4540 }
4541 }
4542
4543 std::ostream &dictStream = (!gOptDictionaryFileName.empty()) ? fileout : std::cout;
4544 bool isACLiC = gOptDictionaryFileName.getValue().find("_ACLiC_dict") != std::string::npos;
4545
4546 // Now generate a second stream for the split dictionary if it is necessary
4547 if (gOptSplit) {
4550 } else {
4552 }
4553
4554 size_t dh = main_dictname.rfind('.');
4555 if (dh != std::string::npos) {
4556 main_dictname.erase(dh);
4557 }
4558 // Need to replace all the characters not allowed in a symbol ...
4559 std::string main_dictname_copy(main_dictname);
4561
4563 if (gOptSplit)
4565
4566 if (!gOptNoGlobalUsingStd) {
4567 // ACLiC'ed macros might rely on `using namespace std` in front of user headers
4568 if (isACLiC) {
4570 if (gOptSplit) {
4572 }
4573 }
4574 }
4575
4576
4577 //---------------------------------------------------------------------------
4578 // Parse the linkdef or selection.xml file.
4579 /////////////////////////////////////////////////////////////////////////////
4580
4581 string linkdefFilename;
4582 if (linkdef.empty()) {
4583 linkdefFilename = "in memory";
4584 } else {
4585 bool found = Which(interp, linkdef.c_str(), linkdefFilename);
4586 if (!found) {
4587 ROOT::TMetaUtils::Error(nullptr, "%s: cannot open linkdef file %s\n", executableFileName, linkdef.c_str());
4588 return 1;
4589 }
4590 }
4591
4592 // Exclude string not to re-generate the dictionary
4593 std::vector<std::pair<std::string, std::string>> namesForExclusion;
4594 if (!gBuildingROOT) {
4595 namesForExclusion.push_back(std::make_pair(ROOT::TMetaUtils::propNames::name, "std::string"));
4596 namesForExclusion.push_back(std::make_pair(ROOT::TMetaUtils::propNames::pattern, "ROOT::Meta::Selection*"));
4597 }
4598
4600
4601 std::string extraIncludes;
4602
4604
4605 // Select using DictSelection
4606 const unsigned int selRulesInitialSize = selectionRules.Size();
4609
4611
4612 bool isSelXML = IsSelectionXml(linkdefFilename.c_str());
4613
4614 int rootclingRetCode(0);
4615
4618 std::ifstream file(linkdefFilename.c_str());
4619 if (file.is_open()) {
4620 ROOT::TMetaUtils::Info(nullptr, "Using linkdef file: %s\n", linkdefFilename.c_str());
4621 file.close();
4622 } else {
4623 ROOT::TMetaUtils::Error(nullptr, "Linkdef file %s couldn't be opened!\n", linkdefFilename.c_str());
4624 }
4625
4626 selectionRules.SetSelectionFileType(SelectionRules::kLinkdefFile);
4627 }
4628 // If there is no linkdef file, we added the 'default' #pragma to
4629 // interpPragmaSource and we still need to process it.
4630
4632
4634 llvmResourceDir.c_str())) {
4635 ROOT::TMetaUtils::Error(nullptr, "Parsing #pragma failed %s\n", linkdefFilename.c_str());
4636 rootclingRetCode += 1;
4637 } else {
4638 ROOT::TMetaUtils::Info(nullptr, "#pragma successfully parsed.\n");
4639 }
4640
4641 if (!ldefr.LoadIncludes(extraIncludes)) {
4642 ROOT::TMetaUtils::Error(nullptr, "Error loading the #pragma extra_include.\n");
4643 return 1;
4644 }
4645
4646 } else if (isSelXML) {
4647
4649
4650 std::ifstream file(linkdefFilename.c_str());
4651 if (file.is_open()) {
4652 ROOT::TMetaUtils::Info(nullptr, "Selection XML file\n");
4653
4655 if (!xmlr.Parse(linkdefFilename.c_str(), selectionRules)) {
4656 ROOT::TMetaUtils::Error(nullptr, "Parsing XML file %s\n", linkdefFilename.c_str());
4657 return 1; // Return here to propagate the failure up to the build system
4658 } else {
4659 ROOT::TMetaUtils::Info(nullptr, "XML file successfully parsed\n");
4660 }
4661 file.close();
4662 } else {
4663 ROOT::TMetaUtils::Error(nullptr, "XML file %s couldn't be opened!\n", linkdefFilename.c_str());
4664 }
4665
4666 } else {
4667
4668 ROOT::TMetaUtils::Error(nullptr, "Unrecognized selection file: %s\n", linkdefFilename.c_str());
4669
4670 }
4671
4672 // Speed up the operations with rules
4673 selectionRules.FillCache();
4674 selectionRules.Optimize();
4675
4676 // Addresses ROOT-5174
4677 if (gBuildingROOT? 0 : 2 >= selectionRules.Size() && !gOptCxxModule && !isGenreflex) {
4678 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");
4679 return 1;
4680 }
4681
4682 if (isGenreflex){
4683 if (0 != selectionRules.CheckDuplicates()){
4684 return 1;
4685 }
4686 }
4687
4688 // If we want to validate the selection only, we just quit.
4690 return 0;
4691
4692 //---------------------------------------------------------------------------
4693 // Write schema evolution related headers and declarations
4694 /////////////////////////////////////////////////////////////////////////////
4695
4696 if ((!ROOT::gReadRules.empty() || !ROOT::gReadRawRules.empty())) {
4697 dictStream << "#include \"TBuffer.h\"\n"
4698 << "#include \"TVirtualObject.h\"\n"
4699 << "#include <vector>\n"
4700 << "#include \"TSchemaHelper.h\"\n\n";
4701
4702 std::list<std::string> includes;
4703 GetRuleIncludes(includes);
4704 for (auto & incFile : includes) {
4705 dictStream << "#include <" << incFile << ">" << std::endl;
4706 }
4707 dictStream << std::endl;
4708 }
4709
4710 selectionRules.SearchNames(interp);
4711
4712 int scannerVerbLevel = 0;
4713 {
4714 using namespace ROOT::TMetaUtils;
4715 scannerVerbLevel = GetErrorIgnoreLevel() == kInfo; // 1 if true, 0 if false
4716 if (isGenreflex){
4717 scannerVerbLevel = GetErrorIgnoreLevel() < kWarning;
4718 }
4719 }
4720
4721 // Select the type of scan
4723 if (gOptGeneratePCH)
4725 if (dictSelection)
4727
4729 scanType,
4730 interp,
4731 normCtxt,
4733
4734 // If needed initialize the autoloading hook
4735 if (!gOptLibListPrefix.empty()) {
4738 }
4739
4740 scan.Scan(CI->getASTContext());
4741
4742 bool has_input_error = false;
4743
4745 selectionRules.PrintSelectionRules();
4746
4748 !gOptGeneratePCH &&
4750 !selectionRules.AreAllSelectionRulesUsed()) {
4751 ROOT::TMetaUtils::Warning(nullptr, "Not all selection rules are used!\n");
4752 }
4753
4754 if (!gOptGeneratePCH){
4757 }
4758
4759 // SELECTION LOOP
4760 // Check for error in the class layout before doing anything else.
4761 for (auto const & annRcd : scan.fSelectedClasses) {
4763 if (annRcd.RequestNoInputOperator()) {
4765 if (version != 0) {
4766 // Only Check for input operator is the object is I/O has
4767 // been requested.
4769 }
4770 }
4771 }
4773 }
4774
4775 if (has_input_error) {
4776 // Be a little bit makefile friendly and remove the dictionary in case of error.
4777 // We could add an option -k to keep the file even in case of error.
4778 exit(1);
4779 }
4780
4781 //---------------------------------------------------------------------------
4782 // Write all the necessary #include
4783 /////////////////////////////////////////////////////////////////////////////
4784 if (!gDriverConfig->fBuildingROOTStage1) {
4786 includeForSource += "#include \"" + includedFromLinkdef + "\"\n";
4787 }
4788 }
4789
4790 if (!gOptGeneratePCH) {
4792 if (gOptSplit) {
4794 }
4795 if (!gOptNoGlobalUsingStd) {
4796 // ACLiC'ed macros might have relied on `using namespace std` in front of user headers
4797 if (!isACLiC) {
4799 if (gOptSplit) {
4801 }
4802 }
4803 }
4804 if (gDriverConfig->fInitializeStreamerInfoROOTFile) {
4805 gDriverConfig->fInitializeStreamerInfoROOTFile(modGen.GetModuleFileName().c_str());
4806 }
4807
4808 // The order of addition to the list of constructor type
4809 // is significant. The list is sorted by with the highest
4810 // priority first.
4811 if (!gOptInterpreterOnly) {
4812 constructorTypes.emplace_back("TRootIOCtor", interp);
4813 constructorTypes.emplace_back("__void__", interp); // ROOT-7723
4814 constructorTypes.emplace_back("", interp);
4815 }
4816 }
4819
4820 if (gOptSplit && splitDictStream) {
4822 }
4823 }
4824
4825 if (gOptGeneratePCH) {
4827 } else if (gOptInterpreterOnly) {
4829 // generate an empty pcm nevertheless for consistency
4830 // Negate as true is 1 and true is returned in case of success.
4831 if (!gDriverConfig->fBuildingROOTStage1) {
4833 }
4834 } else {
4837 }
4838
4839 if (rootclingRetCode != 0) {
4840 return rootclingRetCode;
4841 }
4842
4843 // Now we have done all our looping and thus all the possible
4844 // annotation, let's write the pcms.
4847
4849
4851 scan.fSelectedTypedefs,
4852 scan.fSelectedFunctions,
4853 scan.fSelectedVariables,
4854 scan.fSelectedEnums,
4857 interp);
4858
4859 std::string detectedUmbrella;
4860 for (auto & arg : pcmArgs) {
4862 detectedUmbrella = arg;
4863 break;
4864 }
4865 }
4866
4868 headersDeclsMap.clear();
4869 }
4870
4871
4872 std::string headersClassesMapString = "\"\"";
4873 std::string fwdDeclsString = "\"\"";
4874 if (!gOptCxxModule) {
4877 true);
4878 if (!gDriverConfig->fBuildingROOTStage1) {
4881 }
4882 }
4885 // If we just want to inline the input header, we don't need
4886 // to generate any files.
4887 if (!gOptInlineInput) {
4888 // Write the module/PCH depending on what mode we are on
4889 if (modGen.IsPCH()) {
4890 if (!GenerateAllDict(modGen, CI, currentDirectory)) return 1;
4891 } else if (gOptCxxModule) {
4893 return 1;
4894 }
4895 }
4896
4897 if (!gOptLibListPrefix.empty()) {
4898 string liblist_filename = gOptLibListPrefix + ".out";
4899
4900 ofstream outputfile(liblist_filename.c_str(), ios::out);
4901 if (!outputfile) {
4902 ROOT::TMetaUtils::Error(nullptr, "%s: Unable to open output lib file %s\n",
4904 } else {
4905 const size_t endStr = gLibsNeeded.find_last_not_of(" \t");
4906 outputfile << gLibsNeeded.substr(0, endStr + 1) << endl;
4907 // Add explicit delimiter
4908 outputfile << "# Now the list of classes\n";
4909 // SELECTION LOOP
4910 for (auto const & annRcd : scan.fSelectedClasses) {
4911 // Shouldn't it be GetLong64_Name( cl_input.GetNormalizedName() )
4912 // or maybe we should be normalizing to turn directly all long long into Long64_t
4913 outputfile << annRcd.GetNormalizedName() << endl;
4914 }
4915 }
4916 }
4917
4918 // Check for errors in module generation
4919 rootclingRetCode += modGen.GetErrorCount();
4920 if (0 != rootclingRetCode) return rootclingRetCode;
4921
4922 // Create the rootmap file
4923 std::string rootmapLibName = std::accumulate(gOptRootmapLibNames.begin(),
4925 std::string(),
4926 [](const std::string & a, const std::string & b) -> std::string {
4927 if (a.empty()) return b;
4928 else return a + " " + b;
4929 });
4930
4931 bool rootMapNeeded = !gOptRootMapFileName.empty() || !rootmapLibName.empty();
4932
4933 std::list<std::string> classesNames;
4934 std::list<std::string> classesNamesForRootmap;
4935 std::list<std::string> classesDefsList;
4936
4941 interp);
4942
4943 std::list<std::string> enumNames;
4945 scan.fSelectedEnums,
4946 interp);
4947
4948 std::list<std::string> varNames;
4950 scan.fSelectedVariables,
4951 interp);
4952
4953 if (0 != rootclingRetCode) return rootclingRetCode;
4954
4955 // Create the rootmapfile if needed
4956 if (rootMapNeeded) {
4957
4958 std::list<std::string> nsNames;
4959
4961
4964
4965 ROOT::TMetaUtils::Info(nullptr, "Rootmap file name %s and lib name(s) \"%s\"\n",
4966 gOptRootMapFileName.c_str(),
4967 rootmapLibName.c_str());
4968
4969 tmpCatalog.addFileName(gOptRootMapFileName);
4970 std::unordered_set<std::string> headersToIgnore;
4971 if (gOptInlineInput)
4972 for (const std::string& optHeaderFileName : gOptDictionaryHeaderFiles)
4973 headersToIgnore.insert(optHeaderFileName.c_str());
4974
4975 std::list<std::string> typedefsRootmapLines;
4977 scan.fSelectedTypedefs,
4978 interp);
4979
4984 nsNames,
4986 enumNames,
4987 varNames,
4990
4991 if (0 != rootclingRetCode) return 1;
4992 }
4993
4995 tmpCatalog.dump();
4996
4997 // Manually call end of translation unit because we never call the
4998 // appropriate deconstructors in the interpreter. This writes out the C++
4999 // module file that we currently generate.
5000 {
5001 cling::Interpreter::PushTransactionRAII RAII(&interp);
5002 CI->getSema().getASTConsumer().HandleTranslationUnit(CI->getSema().getASTContext());
5003 }
5004
5005 // Add the warnings
5007
5008 // make sure the file is closed before committing
5009 fileout.close();
5010
5011 // Write the dependency file if requested (-MF <file>). It uses the
5012 // Makefile format understood by CMake's DEPFILE and Ninja's "deps = gcc",
5013 // listing every real header that was opened while generating the dictionary
5014 // so that incremental builds pick up changes to transitively included files.
5015 if (!gOptDepFile.empty() && rootclingRetCode == 0 && !dictOutputFileName.empty()) {
5016 std::ofstream depFile(gOptDepFile.c_str());
5017 if (!depFile) {
5019 "rootcling: failed to open dependency file %s\n",
5020 gOptDepFile.c_str());
5021 rootclingRetCode = 1;
5022 } else {
5023 // Escape a path for the Makefile-format dependency file: forward
5024 // slashes (needed on Windows) and backslash-escape the characters that
5025 // are special to make (space, tab, '#', ':').
5026 auto escapeForDepFile = [](std::string path) {
5027 std::replace(path.begin(), path.end(), '\\', '/');
5028 std::string escaped;
5029 escaped.reserve(path.size());
5030 for (char c : path) {
5031 if (c == ' ' || c == '\t' || c == '#' || c == ':')
5032 escaped += '\\';
5033 escaped += c;
5034 }
5035 return escaped;
5036 };
5037
5038 // The target is the final dictionary source file. Note that
5039 // gOptDictionaryFileName has been turned into a temporary name by the
5040 // tmpCatalog, so we use the original name captured earlier.
5042
5043 // Collect all files that were read by clang during dictionary
5044 // generation (headers included directly or indirectly).
5045 clang::SourceManager &SM = CI->getSourceManager();
5046 clang::FileManager &FM = SM.getFileManager();
5047
5048 llvm::SmallVector<clang::OptionalFileEntryRef, 64> files;
5049 FM.GetUniqueIDMapping(files);
5050
5051 std::set<std::string> includedFiles;
5052 for (const auto &FEOpt : files) {
5053 if (!FEOpt)
5054 continue;
5055 llvm::StringRef filename = FEOpt->getName();
5056 if (filename.empty())
5057 continue;
5058 // Skip cling's in-memory buffers, which the FileManager also
5059 // reports: "input_line_N", "<<< cling interactive line includer >>>",
5060 // "<built-in>", "<command line>", ... These are not real files;
5061 // some contain spaces or angle brackets that would corrupt the
5062 // dependency file, and all of them would make the dictionary appear
5063 // perpetually out of date. Requiring the entry to exist on disk
5064 // filters them out (together with the explicit angle-bracket check).
5065 if (filename.contains('<') || filename.contains('>'))
5066 continue;
5067 // Make the path absolute so it is unambiguous regardless of the
5068 // working directory: rootcling may run from a different directory
5069 // than the one the dependency file is later consumed from (with
5070 // CMP0116 OLD the depfile is not rewritten, and a relative entry
5071 // like "./Foo.hxx" would be resolved against the wrong base and
5072 // leave the dictionary permanently out of date).
5073 llvm::SmallString<256> absPath(filename);
5074 llvm::sys::fs::make_absolute(absPath);
5075 if (!llvm::sys::fs::exists(absPath))
5076 continue;
5077 std::string filenameStr(absPath.str());
5078 // Skip the output dictionary file itself (final or temporary name).
5080 continue;
5081 includedFiles.insert(std::move(filenameStr));
5082 }
5083
5084 // Each dependency line except the last ends with a backslash.
5085 for (const auto &file : includedFiles)
5086 depFile << " \\\n " << escapeForDepFile(file);
5087 if (!includedFiles.empty())
5088 depFile << "\n";
5089
5090 depFile.close();
5091 if (!depFile.good()) {
5092 ROOT::TMetaUtils::Error(nullptr, "rootcling: failed to write dependency file %s\n", gOptDepFile.c_str());
5093 rootclingRetCode = 1;
5094 }
5095 }
5096 }
5097
5098 // Before returning, rename the files if no errors occurred
5099 // otherwise clean them to avoid remnants (see ROOT-10015)
5100 if(rootclingRetCode == 0) {
5101 rootclingRetCode += tmpCatalog.commit();
5102 } else {
5103 tmpCatalog.clean();
5104 }
5105
5106 return rootclingRetCode;
5107
5108}
5109
5110namespace genreflex {
5111
5112////////////////////////////////////////////////////////////////////////////////
5113/// Loop on arguments: stop at the first which starts with -
5114
5115 unsigned int checkHeadersNames(std::vector<std::string> &headersNames)
5116 {
5117 unsigned int numberOfHeaders = 0;
5118 for (std::vector<std::string>::iterator it = headersNames.begin();
5119 it != headersNames.end(); ++it) {
5120 const std::string headername(*it);
5123 } else {
5125 "*** genreflex: %s is not a valid header name (.h and .hpp extensions expected)!\n",
5126 headername.c_str());
5127 }
5128 }
5129 return numberOfHeaders;
5130 }
5131
5132////////////////////////////////////////////////////////////////////////////////
5133/// Extract the arguments from the command line
5134
5135 unsigned int extractArgs(int argc, char **argv, std::vector<std::string> &args)
5136 {
5137 // loop on argv, spot strings which are not preceded by something
5138 unsigned int argvCounter = 0;
5139 for (int i = 1; i < argc; ++i) {
5140 if (!ROOT::TMetaUtils::BeginsWith(argv[i - 1], "-") && // so, if preceding element starts with -, this is a value for an option
5141 !ROOT::TMetaUtils::BeginsWith(argv[i], "-")) { // and the element itself is not an option
5142 args.push_back(argv[i]);
5143 argvCounter++;
5144 } else if (argvCounter) {
5145 argv[i - argvCounter] = argv[i];
5146 }
5147 }
5148
5149 // Some debug
5150 if (genreflex::verbose) {
5151 int i = 0;
5152 std::cout << "Args: \n";
5153 for (std::vector<std::string>::iterator it = args.begin();
5154 it < args.end(); ++it) {
5155 std::cout << i << ") " << *it << std::endl;
5156 ++i;
5157 }
5158
5159 }
5160
5161 return argvCounter;
5162 }
5163
5164////////////////////////////////////////////////////////////////////////////////
5165
5166 void changeExtension(std::string &filename, const std::string &newExtension)
5167 {
5168 size_t result = filename.find_last_of('.');
5169 if (std::string::npos != result) {
5170 filename.erase(result);
5171 filename.append(newExtension);
5172 }
5173
5174 }
5175
5176////////////////////////////////////////////////////////////////////////////////
5177/// The caller is responsible for deleting the string!
5178
5179 char *string2charptr(const std::string &str)
5180 {
5181 const unsigned int size(str.size());
5182 char *a = new char[size + 1];
5183 a[size] = 0;
5184 memcpy(a, str.c_str(), size);
5185 return a;
5186 }
5187
5188////////////////////////////////////////////////////////////////////////////////
5189/// Replace the extension with "_rflx.cpp"
5190
5191 void header2outputName(std::string &fileName)
5192 {
5193 changeExtension(fileName, "_rflx.cpp");
5194 }
5195
5196////////////////////////////////////////////////////////////////////////////////
5197/// Get a proper name for the output file
5198
5199 void headers2outputsNames(const std::vector<std::string> &headersNames,
5200 std::vector<std::string> &ofilesnames)
5201 {
5202 ofilesnames.reserve(headersNames.size());
5203
5204 for (std::vector<std::string>::const_iterator it = headersNames.begin();
5205 it != headersNames.end(); ++it) {
5206 std::string ofilename(*it);
5208 ofilesnames.push_back(ofilename);
5209 }
5210 }
5211
5212////////////////////////////////////////////////////////////////////////////////
5213
5214 void AddToArgVector(std::vector<char *> &argvVector,
5215 const std::vector<std::string> &argsToBeAdded,
5216 const std::string &optName = "")
5217 {
5218 for (std::vector<std::string>::const_iterator it = argsToBeAdded.begin();
5219 it != argsToBeAdded.end(); ++it) {
5220 argvVector.push_back(string2charptr(optName + *it));
5221 }
5222 }
5223
5224////////////////////////////////////////////////////////////////////////////////
5225
5226 void AddToArgVectorSplit(std::vector<char *> &argvVector,
5227 const std::vector<std::string> &argsToBeAdded,
5228 const std::string &optName = "")
5229 {
5230 for (std::vector<std::string>::const_iterator it = argsToBeAdded.begin();
5231 it != argsToBeAdded.end(); ++it) {
5232 if (optName.length()) {
5233 argvVector.push_back(string2charptr(optName));
5234 }
5235 argvVector.push_back(string2charptr(*it));
5236 }
5237 }
5238
5239////////////////////////////////////////////////////////////////////////////////
5240
5241 int invokeRootCling(const std::string &verbosity,
5242 const std::string &selectionFileName,
5243 const std::string &targetLibName,
5244 bool multiDict,
5245 const std::vector<std::string> &pcmsNames,
5246 const std::vector<std::string> &includes,
5247 const std::vector<std::string> &preprocDefines,
5248 const std::vector<std::string> &preprocUndefines,
5249 const std::vector<std::string> &warnings,
5250 const std::string &rootmapFileName,
5251 const std::string &rootmapLibName,
5252 bool interpreteronly,
5253 bool doSplit,
5254 bool isCxxmodule,
5255 bool writeEmptyRootPCM,
5256 bool selSyntaxOnly,
5257 bool noIncludePaths,
5258 bool noGlobalUsingStd,
5259 const std::vector<std::string> &headersNames,
5260 bool failOnWarnings,
5262 const std::string &ofilename)
5263 {
5264 // Prepare and invoke the commandline to invoke rootcling
5265
5266 std::vector<char *> argvVector;
5267
5268 argvVector.push_back(string2charptr("rootcling"));
5270 argvVector.push_back(string2charptr("-f"));
5272
5273 if (isCxxmodule)
5274 argvVector.push_back(string2charptr("-cxxmodule"));
5275
5276 // Extract the path to the dictionary
5277 std::string dictLocation;
5279
5280 // Rootmaps
5281
5282 // Prepare the correct rootmap libname if not already set.
5283 std::string newRootmapLibName(rootmapLibName);
5284 if (!rootmapFileName.empty() && newRootmapLibName.empty()) {
5285 if (headersNames.size() != 1) {
5287 "*** genreflex: No rootmap lib and several header specified!\n");
5288 }
5290 newRootmapLibName = "lib";
5293 }
5294
5295 // Prepend to the rootmap the designed directory of the dictionary
5296 // if no path is specified for the rootmap itself
5298 if (!newRootmapFileName.empty() && !HasPath(newRootmapFileName)) {
5300 }
5301
5302
5303 // RootMap filename
5304 if (!newRootmapFileName.empty()) {
5305 argvVector.push_back(string2charptr("-rmf"));
5307 }
5308
5309 // RootMap Lib filename
5310 if (!newRootmapLibName.empty()) {
5311 argvVector.push_back(string2charptr("-rml"));
5313 }
5314
5315 // Always use the -reflex option: we want rootcling to behave
5316 // like genreflex in this case
5317 argvVector.push_back(string2charptr("-reflex"));
5318
5319 // Interpreter only dictionaries
5320 if (interpreteronly)
5321 argvVector.push_back(string2charptr("-interpreteronly"));
5322
5323 // Split dictionaries
5324 if (doSplit)
5325 argvVector.push_back(string2charptr("-split"));
5326
5327 // Targetlib
5328 if (!targetLibName.empty()) {
5329 argvVector.push_back(string2charptr("-s"));
5331 }
5332
5333 // Multidict support
5334 if (multiDict)
5335 argvVector.push_back(string2charptr("-multiDict"));
5336
5337 // Don't declare "using namespace std"
5338 if (noGlobalUsingStd)
5339 argvVector.push_back(string2charptr("-noGlobalUsingStd"));
5340
5341
5343
5344 // Inline the input header
5345 argvVector.push_back(string2charptr("-inlineInputHeader"));
5346
5347 // Write empty root pcms
5349 argvVector.push_back(string2charptr("-writeEmptyRootPCM"));
5350
5351 // Just test the syntax of the selection file
5352 if (selSyntaxOnly)
5353 argvVector.push_back(string2charptr("-selSyntaxOnly"));
5354
5355 // No include paths
5356 if (noIncludePaths)
5357 argvVector.push_back(string2charptr("-noIncludePaths"));
5358
5359 // Fail on warnings
5360 if (failOnWarnings)
5361 argvVector.push_back(string2charptr("-failOnWarnings"));
5362
5363 // Clingargs
5364 AddToArgVector(argvVector, includes, "-I");
5368
5370
5371 if (!selectionFileName.empty()) {
5373 }
5374
5375 const int argc = argvVector.size();
5376
5377 // Output commandline for rootcling
5379 std::string cmd;
5380 for (int i = 0; i < argc; i++) {
5381 cmd += argvVector[i];
5382 cmd += " ";
5383 }
5384 cmd.pop_back();
5385 if (genreflex::verbose) std::cout << "Rootcling commandline: ";
5386 std::cout << cmd << std::endl;
5387 if (printRootclingInvocation) return 0; // we do not generate anything
5388 }
5389
5390 char **argv = & (argvVector[0]);
5392 argv,
5393 /*isGenReflex=*/true);
5394
5395 for (int i = 0; i < argc; i++)
5396 delete [] argvVector[i];
5397
5398 return rootclingReturnCode;
5399
5400 }
5401
5402////////////////////////////////////////////////////////////////////////////////
5403/// Get the right ofilenames and invoke several times rootcling
5404/// One invokation per header
5405
5406 int invokeManyRootCling(const std::string &verbosity,
5407 const std::string &selectionFileName,
5408 const std::string &targetLibName,
5409 bool multiDict,
5410 const std::vector<std::string> &pcmsNames,
5411 const std::vector<std::string> &includes,
5412 const std::vector<std::string> &preprocDefines,
5413 const std::vector<std::string> &preprocUndefines,
5414 const std::vector<std::string> &warnings,
5415 const std::string &rootmapFileName,
5416 const std::string &rootmapLibName,
5417 bool interpreteronly,
5418 bool doSplit,
5419 bool isCxxmodule,
5420 bool writeEmptyRootPCM,
5421 bool selSyntaxOnly,
5422 bool noIncludePaths,
5423 bool noGlobalUsingStd,
5424 const std::vector<std::string> &headersNames,
5425 bool failOnWarnings,
5427 const std::string &outputDirName_const = "")
5428 {
5430
5431 std::vector<std::string> ofilesNames;
5433
5436 }
5437
5438 std::vector<std::string> namesSingleton(1);
5439 for (unsigned int i = 0; i < headersNames.size(); ++i) {
5441 std::string ofilenameFullPath(ofilesNames[i]);
5442 if (llvm::sys::path::parent_path(ofilenameFullPath) == "")
5447 multiDict,
5448 pcmsNames,
5449 includes,
5452 warnings,
5456 doSplit,
5466 if (returnCode != 0)
5467 return returnCode;
5468 }
5469
5470 return 0;
5471 }
5472
5473
5474} // end genreflex namespace
5475
5476////////////////////////////////////////////////////////////////////////////////
5477/// Extract from options multiple values with the same option
5478
5479int extractMultipleOptions(std::vector<ROOT::option::Option> &options,
5480 int oIndex,
5481 std::vector<std::string> &values)
5482{
5483 int nValues = 0;
5484 if (options[oIndex]) {
5485 const int nVals = options[oIndex].count();
5486 values.reserve(nVals);
5487 int optionIndex = 0;
5488 for (ROOT::option::Option *opt = options[oIndex]; opt; opt = opt->next()) {
5489 if (genreflex::verbose) std::cout << "Extracting multiple args: "
5490 << optionIndex << "/" << nVals << " "
5491 << opt->arg << std::endl;
5492 optionIndex++;
5493 values.push_back(opt->arg);
5494 nValues++;
5495 }
5496 }
5497 return nValues;
5498}
5499
5500////////////////////////////////////////////////////////////////////////////////
5501
5502void RiseWarningIfPresent(std::vector<ROOT::option::Option> &options,
5503 int optionIndex,
5504 const char *descriptor)
5505{
5506 if (options[optionIndex]) {
5508 "*** genereflex: %s is not supported anymore.\n",
5509 descriptor);
5510 }
5511}
5512
5513////////////////////////////////////////////////////////////////////////////////
5514
5515bool IsGoodLibraryName(const std::string &name)
5516{
5517
5518
5520#ifdef __APPLE__
5522#endif
5523 return isGood;
5524}
5525
5526////////////////////////////////////////////////////////////////////////////////
5527/// Translate the arguments of genreflex into rootcling ones and forward them
5528/// to the RootCling function.
5529/// These are two typical genreflex and rootcling commandlines
5530/// 1) genreflex header1.h [header2.h ...] [options] [preprocessor options]
5531/// 2) rootcling [-v] [-v0-4] [-f] [out.cxx] [-s sharedlib.so] [-m pcmfilename]
5532/// header1.h[{+,-}][!] ..headerN.h[{+,-}][!] [{LinkDef.h,selectionRules.xml}]
5533/// The rules with which the arguments are translated are (1st column genreflex):
5534/// --debug -v4
5535/// --quiet -v0
5536/// -o ofile positional arg after -f
5537/// -s selection file Last argument of the call
5538/// --fail_on_warning Wrap ROOT::TMetaUtils::Warning and throw if selected
5539///
5540/// New arguments:
5541/// -l --library targetLib name (new) -s targetLib name
5542/// -m pcmname (can be many -m) (new) -m pcmname (can be many -m)
5543/// --rootmap -rmf (new)
5544/// --rootmap-lib -rml (new)
5545///
5546/// genreflex options which rise warnings (feedback is desirable)
5547/// --no_membertypedefs (it should be irrelevant)
5548/// --no_templatetypedefs (it should be irrelevant)
5549///
5550/// genreflex options which are ignored (know for sure they are not needed)
5551/// --pool, --dataonly
5552/// --interpreteronly
5553/// --gccxml{path,opt,post}
5554///
5555///
5556/// Exceptions
5557/// The --deep option of genreflex is passed as function parameter to rootcling
5558/// since it's not needed at the moment there.
5559
5560int GenReflexMain(int argc, char **argv)
5561{
5562 using namespace genreflex;
5563
5564 // Setup the options parser
5565 enum optionIndex { UNKNOWN,
5567 OFILENAME,
5568 TARGETLIB,
5569 MULTIDICT,
5572 ROOTMAP,
5573 ROOTMAPLIB,
5575 DEEP,
5576 DEBUG,
5577 VERBOSE,
5578 QUIET,
5579 SILENT,
5580 CXXMODULE,
5582 HELP,
5586 SPLIT,
5590 // Don't show up in the help
5593 INCLUDE,
5594 WARNING
5595 };
5596
5597 enum optionTypes { NOTYPE, STRING } ;
5598
5599 // Some long help strings
5600 const char *genreflexUsage =
5601 "********************************************************************************\n"
5602 "* The genreflex utility does not allow to generate C++ modules containing *\n"
5603 "* reflection information required at runtime. Please use rootcling instead *\n"
5604 "* To print the rootcling invocation that corresponds to the current genreflex *\n"
5605 "* invocation please use the --print-rootcling-invocation flag. *\n"
5606 "********************************************************************************\n"
5607 "\n"
5608 "Generates dictionary sources and related ROOT pcm starting from an header.\n"
5609 "Usage: genreflex headerfile.h [opts] [preproc. opts]\n\n"
5610 "Options:\n";
5611
5612 const char *printRootclingInvocationUsage =
5613 "--print-rootcling-invocation\n"
5614 " Print to screen the rootcling invocation corresponding to the current \n"
5615 " genreflex invocation.\n";
5616
5617 const char *selectionFilenameUsage =
5618 "-s, --selection_file\tSelection filename\n"
5619 " Class selection file to specify for which classes the dictionary\n"
5620 " will be generated. The final set can be crafted with exclusion and\n"
5621 " exclusion rules.\n"
5622 " Properties can be specified. Some have special meaning:\n"
5623 " - name [string] name of the entity to select with an exact matching\n"
5624 " - pattern [string] name with wildcards (*) to select entities\n"
5625 " - file_name/file_pattern [string]: as name/pattern but referring to\n"
5626 " file where the C++ entities reside and not to C++ entities themselves.\n"
5627 " - transient/persistent [string: true/false] The fields to which they are\n"
5628 " applied will not be persistified if requested.\n"
5629 " - comment [string]: what you could write in code after an inline comment\n"
5630 " without \"//\". For example comment=\"!\" or \"||\".\n"
5631 " - noStreamer [true/false]: turns off streamer generation if set to 'true.'\n"
5632 " Default value is 'false'\n"
5633 " - rntupleStreamerMode [true/false]: enforce streamed or native writing for RNTuple.\n"
5634 " If unset, RNTuple stores classes in split mode or fails if the class cannot be split.\n"
5635 " - rntupleSoARecord [class name]: marks the class as an RNTuple SoA layout for the underlying record\n"
5636 " - noInputOperator [true/false]: turns off input operator generation if set\n"
5637 " to 'true'. Default value is 'false'\n"
5638 " Example XML:\n"
5639 " <lcgdict>\n"
5640 " [<selection>]\n"
5641 " <class [name=\"classname\"] [pattern=\"wildname\"]\n"
5642 " [file_name=\"filename\"] [file_pattern=\"wildname\"]\n"
5643 " [id=\"xxxx\"] [noStreamer=\"true/false\"]\n"
5644 " [noInputOperator=\"true/false\"]\n"
5645 " [rntupleStreamerMode=\"true/false\"] />\n"
5646 " [rntupleSoARecord=\"class_name\"] />\n"
5647 " <class name=\"classname\" >\n"
5648 " <field name=\"m_transient\" transient=\"true\"/>\n"
5649 " <field name=\"m_anothertransient\" persistent=\"false\"/>\n"
5650 " <field name=\"m_anothertransient\" comment=\"||\"/>\n"
5651 " <properties prop1=\"value1\" [prop2=\"value2\"]/>\n"
5652 " </class>\n"
5653 " <function [name=\"funcname\"] [pattern=\"wildname\"] />\n"
5654 " <enum [name=\"enumname\"] [pattern=\"wildname\"] />\n"
5655 " <variable [name=\"varname\"] [pattern=\"wildname\"] />\n"
5656 " [</selection>]\n"
5657 " <exclusion>\n"
5658 " <class [name=\"classname\"] [pattern=\"wildname\"] />\n"
5659 " <method name=\"unwanted\" />\n"
5660 " </class>\n"
5661 " ...\n"
5662 " </lcgdict>\n"
5663 "\n"
5664 " If no selection file is specified, the class with the filename without\n"
5665 " extension will be selected, i.e. myClass.h as argument without any\n"
5666 " selection xml comes with an implicit selection rule for class \"myClass\".\n";
5667
5668 const char *outputFilenameUsage =
5669 "-o, --output\tOutput filename\n"
5670 " Output file name. If an existing directory is specified instead of a file,\n"
5671 " then a filename will be built using the name of the input file and will\n"
5672 " be placed in the given directory. <headerfile>_rflx.cpp.\n"
5673 " NOTA BENE: the dictionaries that will be used within the same project must\n"
5674 " have unique names.\n";
5675
5676
5677 const char *targetLib =
5678 "-l, --library\tTarget library\n"
5679 " The flag -l must be followed by the name of the library that will\n"
5680 " contain the object file corresponding to the dictionary produced by\n"
5681 " this invocation of genreflex.\n"
5682 " The name takes priority over the one specified for the rootmapfile.\n"
5683 " The name influences the name of the created pcm:\n"
5684 " 1) If it is not specified, the pcm is called libINPUTHEADER_rdict.pcm\n"
5685 " 2) If it is specified, the pcm is called libTARGETLIBRARY_rdict.pcm\n"
5686 " Any \"liblib\" occurrence is transformed in the expected \"lib\".\n"
5687 " 3) If this is specified in conjunction with --multiDict, the output is\n"
5688 " libTARGETLIBRARY_DICTIONARY_rdict.pcm\n";
5689
5690 const char *rootmapUsage =
5691 "--rootmap\tGenerate the rootmap file to be used by ROOT.\n"
5692 " This file lists the autoload keys. For example classes for which the\n"
5693 " reflection information is provided.\n"
5694 " The format of the rootmap is the following:\n"
5695 " - Forward declarations section\n"
5696 " - Libraries sections\n"
5697 " Rootmaps can be concatenated together, for example with the cat util.\n"
5698 " In order for ROOT to pick up the information in the rootmaps, they\n"
5699 " have to be located in the library path and have the .rootmap extension.\n"
5700 " An example rootmap file could be:\n"
5701 " { decls }\n"
5702 " template <class T> class A;\n"
5703 " [ libMyLib.so ]\n"
5704 " class A<double>\n"
5705 " class B\n"
5706 " typedef C\n"
5707 " header H.h\n";
5708
5709 const char *rootmapLibUsage =
5710 "--rootmap-lib\tLibrary name for the rootmap file.\n";
5711
5712 // The Descriptor
5714
5715 {
5716 UNKNOWN,
5717 NOTYPE,
5718 "", "",
5721 },
5722
5723 {
5725 NOTYPE,
5726 "", "print-rootcling-invocation",
5729 },
5730
5731 {
5732 OFILENAME,
5733 STRING ,
5734 "o" , "output" ,
5737 },
5738
5739 {
5740 TARGETLIB,
5741 STRING ,
5742 "l" , "library" ,
5744 targetLib
5745 },
5746
5747 {
5748 MULTIDICT,
5749 NOTYPE ,
5750 "" , "multiDict" ,
5752 "--multiDict\tSupport for many dictionaries in one library\n"
5753 " Form correct pcm names if multiple dictionaries will be in the same\n"
5754 " library (needs target library switch. See its documentation).\n"
5755 },
5756
5757
5758 {
5760 NOTYPE ,
5761 "" , "noGlobalUsingStd" ,
5763 "--noGlobalUsingStd\tDo not declare {using namespace std} in the dictionary global scope\n"
5764 " All header files must have sumbols from std:: namespace fully qualified\n"
5765 },
5766
5767 {
5769 STRING ,
5770 "s" , "selection_file" ,
5773 },
5774
5775 {
5776 ROOTMAP,
5777 STRING ,
5778 "" , "rootmap" ,
5781 },
5782
5783 {
5784 ROOTMAPLIB,
5785 STRING ,
5786 "" , "rootmap-lib" ,
5789 },
5790
5791 {
5793 NOTYPE,
5794 "" , "interpreteronly",
5796 "--interpreteronly\tDo not generate I/O related information.\n"
5797 " Generate minimal dictionary required for interactivity.\n"
5798 },
5799
5800 {
5801 SPLIT,
5802 NOTYPE,
5803 "" , "split",
5805 "--split\tSplit the dictionary\n"
5806 " Split in two the dictionary, isolating the part with\n"
5807 " ClassDef related functions in a separate file.\n"
5808 },
5809
5810 {
5812 STRING ,
5813 "m" , "" ,
5815 "-m \tPcm file loaded before any header (option can be repeated).\n"
5816 },
5817
5818 {
5819 VERBOSE,
5820 NOTYPE ,
5821 "-v" , "verbose",
5823 "-v, --verbose\tPrint some debug information.\n"
5824 },
5825
5826 {
5827 DEBUG,
5828 NOTYPE ,
5829 "" , "debug",
5831 "--debug\tPrint all debug information.\n"
5832 },
5833
5834 {
5835 QUIET,
5836 NOTYPE ,
5837 "" , "quiet",
5839 "--quiet\tPrint only warnings and errors (default).\n"
5840 },
5841
5842 {
5843 SILENT,
5844 NOTYPE ,
5845 "" , "silent",
5847 "--silent\tPrint no information at all.\n"
5848 },
5849
5850 {
5852 NOTYPE ,
5853 "" , "writeEmptyPCM",
5855 "--writeEmptyPCM\tWrite an empty ROOT pcm.\n"
5856 },
5857
5858 {
5859 CXXMODULE,
5860 NOTYPE ,
5861 "" , "cxxmodule",
5863 "--cxxmodule\tGenerates a PCM for C++ Modules.\n"
5864 },
5865
5866
5867 {
5868 HELP,
5869 NOTYPE,
5870 "h" , "help",
5872 "--help\tPrint usage and exit.\n"
5873 },
5874
5875 {
5877 NOTYPE,
5878 "", "fail_on_warnings",
5880 "--fail_on_warnings\tFail on warnings and errors.\n"
5881 },
5882
5883 {
5885 NOTYPE,
5886 "", "selSyntaxOnly",
5888 "--selSyntaxOnly\tValidate selection file w/o generating the dictionary.\n"
5889 },
5890
5891 {
5893 NOTYPE ,
5894 "" , "noIncludePaths",
5896 "--noIncludePaths\tDo not store the headers' directories in the dictionary. Instead, rely on the environment variable $ROOT_INCLUDE_PATH at runtime.\n"
5897 },
5898
5899 // Left intentionally empty not to be shown in the help, like in the first genreflex
5900 {
5901 INCLUDE,
5902 STRING ,
5903 "I" , "" ,
5905 ""
5906 },
5907
5908 {
5910 STRING ,
5911 "D" , "" ,
5913 ""
5914 },
5915
5916 {
5918 STRING ,
5919 "U" , "" ,
5921 ""
5922 },
5923
5924 {
5925 WARNING,
5926 STRING ,
5927 "W" , "" ,
5929 ""
5930 },
5931
5932 {
5933 NOMEMBERTYPEDEFS, // Option which is not meant for the user: deprecated
5934 STRING ,
5935 "" , "no_membertypedefs" ,
5937 ""
5938 },
5939
5940 {
5941 NOTEMPLATETYPEDEFS, // Option which is not meant for the user: deprecated
5942 STRING ,
5943 "" , "no_templatetypedefs" ,
5945 ""
5946 },
5947
5948 {0, 0, nullptr, nullptr, nullptr, nullptr}
5949 };
5950
5951 std::vector<std::string> headersNames;
5952 const int originalArgc = argc;
5953 // The only args are the headers here
5954 const int extractedArgs = extractArgs(argc, argv, headersNames);
5955
5956 const int offset = 1; // skip argv[0]
5958 argv += offset;
5959
5960 // Parse the options
5962 std::vector<ROOT::option::Option> options(stats.options_max);// non POD var size arrays are not C++!
5963 std::vector<ROOT::option::Option> buffer(stats.buffer_max);
5964 // The 4 is the minimum size of the abbreviation length.
5965 // For example, --selection_file can be abbreviated with --sele at least.
5966
5967 ROOT::option::Parser parse(genreflexUsageDescriptor, argc, argv, &options[0], &buffer[0], 5);
5968
5969 if (parse.error()) {
5970 ROOT::TMetaUtils::Error(nullptr, "Argument parsing error!\n");
5971 return 1;
5972 }
5973
5974 // Print help if needed
5975 if (options[HELP] || originalArgc == 1) {
5977 return 0;
5978 }
5979 // See if no header was provided
5980 int numberOfHeaders = checkHeadersNames(headersNames);
5981 if (0 == numberOfHeaders) {
5982 ROOT::TMetaUtils::Error(nullptr, "No valid header was provided!\n");
5983 return 1;
5984 }
5985
5987
5988 if (options[DEEP])
5989 ROOT::TMetaUtils::Warning(nullptr, "--deep has no effect. Please remove the deprecated flag!\n");
5990 // The verbosity: debug wins over quiet
5991 //std::string verbosityOption("-v4"); // To be uncommented for the testing phase. It should be -v
5992 std::string verbosityOption("-v2");
5993 if (options[SILENT]) verbosityOption = "-v0";
5994 if (options[VERBOSE] || std::getenv ("VERBOSE")) verbosityOption = "-v3";
5995 if (options[DEBUG]) verbosityOption = "-v4";
5996
5998
5999 // The selection file
6000 std::string selectionFileName;
6001 if (options[SELECTIONFILENAME]) {
6002 selectionFileName = options[SELECTIONFILENAME].arg;
6005 "Invalid selection file extension: filename is %s and extension .xml is expected!\n",
6006 selectionFileName.c_str());
6007 return 1;
6008 }
6009 }
6010
6011// // Warn if a selection file is not present and exit
6012// if (NULL==options[SELECTIONFILENAME].arg){
6013// ROOT::TMetaUtils::Warning(0,"The usage of genreflex without a selection file is not yet supported.\n");
6014// return 1;
6015// }
6016
6017
6018 // Set the parameters for the rootmap file. If the libname is not set,
6019 // it will be set according to the header in invokeRootCling.
6020 // FIXME: treatment of directories
6021 std::string rootmapFileName(options[ROOTMAP].arg ? options[ROOTMAP].arg : "");
6022 std::string rootmapLibName(options[ROOTMAPLIB].arg ? options[ROOTMAPLIB].arg : "");
6023
6024 // The target lib name
6025 std::string targetLibName;
6026 if (options[TARGETLIB]) {
6027 targetLibName = options[TARGETLIB].arg;
6030 "Invalid target library extension: filename is %s and extension %s is expected!\n",
6031 targetLibName.c_str(),
6032 gLibraryExtension.c_str());
6033 }
6034 // Target lib has precedence over rootmap lib
6035 if (options[ROOTMAP]) {
6037 }
6038 }
6039
6040 bool isCxxmodule = options[CXXMODULE];
6041
6042 bool multidict = false;
6043 if (options[MULTIDICT]) multidict = true;
6044
6045 bool noGlobalUsingStd = false;
6046 if (options[NOGLOBALUSINGSTD]) noGlobalUsingStd = true;
6047
6048 if (multidict && targetLibName.empty()) {
6050 "Multilib support is requested but no target lib is specified. A sane pcm name cannot be formed.\n");
6051 return 1;
6052 }
6053
6054 bool printRootclingInvocation = false;
6055 if (options[PRINTROOTCLINGINVOCATION])
6057
6058 bool interpreteronly = false;
6059 if (options[INTERPRETERONLY])
6060 interpreteronly = true;
6061
6062 bool doSplit = false;
6063 if (options[SPLIT])
6064 doSplit = true;
6065
6066 bool writeEmptyRootPCM = false;
6067 if (options[WRITEEMPTYROOTPCM])
6068 writeEmptyRootPCM = true;
6069
6070 bool selSyntaxOnly = false;
6071 if (options[SELSYNTAXONLY]) {
6072 selSyntaxOnly = true;
6073 }
6074
6075 bool noIncludePaths = false;
6076 if (options[NOINCLUDEPATHS]) {
6077 noIncludePaths = true;
6078 }
6079
6080 bool failOnWarnings = false;
6081 if (options[FAILONWARNINGS]) {
6082 failOnWarnings = true;
6083 }
6084
6085 // Add the .so extension to the rootmap lib if not there
6088 }
6089
6090 // The list of pcms to be preloaded
6091 std::vector<std::string> pcmsNames;
6093
6094 // Preprocessor defines
6095 std::vector<std::string> preprocDefines;
6097
6098 // Preprocessor undefines
6099 std::vector<std::string> preprocUndefines;
6101
6102 // Includes
6103 std::vector<std::string> includes;
6104 extractMultipleOptions(options, INCLUDE, includes);
6105
6106 // Warnings
6107 std::vector<std::string> warnings;
6108 extractMultipleOptions(options, WARNING, warnings);
6109
6110 // The outputfilename(s)
6111 // There are two cases:
6112 // 1) The outputfilename is specified
6113 // --> The information of all headers will be in one single dictionary
6114 // (1 call to rootcling)
6115 // 2) The outputfilename is not specified
6116 // --> There will be a dictionary per header
6117 // (N calls to rootcling)
6118 int returnValue = 0;
6119 std::string ofileName(options[OFILENAME] ? options[OFILENAME].arg : "");
6120
6121 // If not empty and not a directory (therefore it's a file)
6122 // call rootcling directly. The number of headers files is irrelevant.
6123 if (!ofileName.empty() && !llvm::sys::fs::is_directory(ofileName)) {
6124 returnValue = invokeRootCling(verbosityOption,
6127 multidict,
6128 pcmsNames,
6129 includes,
6132 warnings,
6136 doSplit,
6145 ofileName);
6146 } else {
6147 // Here ofilename is either "" or a directory: this is irrelevant.
6148 returnValue = invokeManyRootCling(verbosityOption,
6151 multidict,
6152 pcmsNames,
6153 includes,
6156 warnings,
6160 doSplit,
6169 ofileName);
6170 }
6171
6172 return returnValue;
6173}
6174
6175
6176////////////////////////////////////////////////////////////////////////////////
6177
6178extern "C"
6180{
6181
6182 assert(!gDriverConfig && "Driver configuration already set!");
6183 gDriverConfig = &config;
6184
6185 gBuildingROOT = config.fBuildingROOTStage1; // gets refined later
6186
6187 std::string exeName = ExtractFileName(GetExePath());
6188#ifdef __APPLE__
6189 // _dyld_get_image_name() on macOS11 and later sometimes returns "rootcling" for "genreflex".
6190 // Fix that (while still initializing the binary path, needed for ROOTSYS) by updating the
6191 // exeName to argv[0]:
6193#endif
6194
6195 // Select according to the name of the executable the procedure to follow:
6196 // 1) RootCling
6197 // 2) GenReflex
6198 // The default is rootcling
6199
6200 int retVal = 0;
6201
6202 if (std::string::npos != exeName.find("genreflex"))
6204 else // rootcling or default
6206
6207 gDriverConfig = nullptr;
6208
6210 ROOT::TMetaUtils::Info(nullptr,"Problems have been detected during the generation of the dictionary.\n");
6211 return 1;
6212 }
6213 return retVal;
6214}
Select classes and assign properties using C++ syntax.
The file contains utilities which are foundational and could be used across the core component of ROO...
This is the only file required to use The Lean Mean C++ Option Parser.
#define DEBUG
#define d(i)
Definition RSha256.hxx:102
#define b(i)
Definition RSha256.hxx:100
#define c(i)
Definition RSha256.hxx:101
#define a(i)
Definition RSha256.hxx:99
#define h(i)
Definition RSha256.hxx:106
#define e(i)
Definition RSha256.hxx:103
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
Basic types used by ROOT and required by TInterpreter.
#define X(type, name)
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
void Info(const char *location, const char *msgfmt,...)
Use this function for informational messages.
Definition TError.cxx:241
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t dest
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char filename
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h offset
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t UChar_t len
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t attr
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
char name[80]
Definition TGX11.cxx:148
const char * proto
Definition civetweb.c:18822
#define free
Definition civetweb.c:1578
#define snprintf
Definition civetweb.c:1579
std::unordered_map< std::string, std::string > AttributesMap_t
Custom diag client for clang that verifies that each implicitly build module is a system module.
void HandleDiagnostic(clang::DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &Info) override
CheckModuleBuildClient(clang::DiagnosticConsumer *Child, bool OwnsChild, clang::ModuleMap &Map)
clang::DiagnosticConsumer * fChild
bool IncludeInDiagnosticCounts() const override
void EndSourceFile() override
void BeginSourceFile(const clang::LangOptions &LangOpts, const clang::Preprocessor *PP) override
clang::ModuleMap & fMap
static RStl & Instance()
Definition RStl.cxx:40
const_iterator begin() const
const_iterator end() const
const clang::RecordDecl * GetRecordDecl() const
A parsed option from the command line together with its argument if it has one.
Checks argument vectors for validity and parses them into data structures that are easier to work wit...
bool error()
Returns true if an unrecoverable error occurred while parsing options.
void Scan(const clang::ASTContext &C)
Definition Scanner.cxx: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
#define I(x, y, z)
#define H(x, y, z)
std::string MakePathRelative(const std::string &path, const std::string &base, bool isBuildingROOT=false)
int EncloseInNamespaces(const clang::Decl &decl, std::string &defString)
Take the namespaces which enclose the decl and put them around the definition string.
int FwdDeclFromRcdDecl(const clang::RecordDecl &recordDecl, const cling::Interpreter &interpreter, std::string &defString, bool acceptStl=false)
Convert a rcd decl to its fwd decl If this is a template specialisation, treat in the proper way.
int FwdDeclIfTmplSpec(const clang::RecordDecl &recordDecl, const cling::Interpreter &interpreter, std::string &defString, const std::string &normalizedName)
Convert a tmplt decl to its fwd decl.
static const std::string name("name")
static const std::string separator("@@@")
static const std::string pattern("pattern")
bool HasClassDefMacro(const clang::Decl *decl, const cling::Interpreter &interpreter)
Return true if class has any of class declarations like ClassDef, ClassDefNV, ClassDefOverride.
clang::RecordDecl * GetUnderlyingRecordDecl(clang::QualType type)
bool BeginsWith(const std::string &theString, const std::string &theSubstring)
const clang::FunctionDecl * ClassInfo__HasMethod(const clang::DeclContext *cl, char const *, const cling::Interpreter &interp)
bool GetNameWithinNamespace(std::string &, std::string &, std::string &, clang::CXXRecordDecl const *)
Return true if one of the class' enclosing scope is a namespace and set fullname to the fully qualifi...
void Error(const char *location, const char *fmt,...)
void WriteClassInit(std::ostream &finalString, const AnnotatedRecordDecl &cl, const clang::CXXRecordDecl *decl, const cling::Interpreter &interp, const TNormalizedCtxt &normCtxt, const RConstructorTypes &ctorTypes, bool &needCollectionProxy)
FIXME: a function of 450+ lines!
void Info(const char *location, const char *fmt,...)
int WriteNamespaceHeader(std::ostream &, const clang::RecordDecl *)
int GetClassVersion(const clang::RecordDecl *cl, const cling::Interpreter &interp)
Return the version number of the class or -1 if the function Class_Version does not exist.
void GetNormalizedName(std::string &norm_name, const clang::QualType &type, const cling::Interpreter &interpreter, const TNormalizedCtxt &normCtxt)
Return the type name normalized for ROOT, keeping only the ROOT opaque typedef (Double32_t,...
std::string GetFileName(const clang::Decl &decl, const cling::Interpreter &interp)
Return the header file to be included to declare the Decl.
void WriteStandaloneReadRules(std::ostream &finalString, bool rawrules, std::vector< std::string > &standaloneTargets, const cling::Interpreter &interp)
int IsSTLContainer(const AnnotatedRecordDecl &annotated)
Is this an STL container.
std::list< RConstructorType > RConstructorTypes
int extractPropertyNameVal(clang::Attr *attribute, std::string &attrName, std::string &attrValue)
const int kWarning
bool EndsWith(const std::string &theString, const std::string &theSubstring)
bool NeedTemplateKeyword(clang::CXXRecordDecl const *)
const clang::FunctionDecl * GetFuncWithProto(const clang::Decl *cinfo, const char *method, const char *proto, const cling::Interpreter &gInterp, bool diagnose)
int ElementStreamer(std::ostream &finalString, const clang::NamedDecl &forcontext, const clang::QualType &qti, const char *t, int rwmode, const cling::Interpreter &interp, const char *tcl=nullptr)
const char * ShortTypeName(const char *typeDesc)
Return the absolute type of typeDesc.
void GetCppName(std::string &output, const char *input)
Return (in the argument 'output') a valid name of the C++ symbol/type (pass as 'input') that can be u...
bool IsStdClass(const clang::RecordDecl &cl)
Return true, if the decl is part of the std namespace.
void WriteClassCode(CallWriteStreamer_t WriteStreamerFunc, const AnnotatedRecordDecl &cl, const cling::Interpreter &interp, const TNormalizedCtxt &normCtxt, std::ostream &finalString, const RConstructorTypes &ctorTypes, bool isGenreflex)
Generate the code of the class If the requestor is genreflex, request the new streamer format.
long GetLineNumber(clang::Decl const *)
It looks like the template specialization decl actually contains less information on the location of ...
void foreachHeaderInModule(const clang::Module &module, const std::function< void(const clang::Module::Header &)> &closure, bool includeDirectlyUsedModules=true)
Calls the given lambda on every header in the given module.
bool IsBase(const clang::CXXRecordDecl *cl, const clang::CXXRecordDecl *base, const clang::CXXRecordDecl *context, const cling::Interpreter &interp)
void GetQualifiedName(std::string &qual_name, const clang::QualType &type, const clang::NamedDecl &forcontext)
Main implementation relying on GetFullyQualifiedTypeName All other GetQualifiedName functions leverag...
bool IsLinkdefFile(const char *filename)
unsigned int & GetNumberOfErrors()
void WriteRulesRegistration(std::ostream &finalString, const std::string &dictName, const std::vector< std::string > &standaloneTargets)
llvm::StringRef GetComment(const clang::Decl &decl, clang::SourceLocation *loc=nullptr)
Returns the comment (// striped away), annotating declaration in a meaningful for ROOT IO way.
void SetPathsForRelocatability(std::vector< std::string > &clingArgs)
Organise the parameters for cling in order to guarantee relocatability It treats the gcc toolchain an...
void ReplaceAll(std::string &str, const std::string &from, const std::string &to, bool recurse=false)
std::string TrueName(const clang::FieldDecl &m)
TrueName strips the typedefs and array dimensions.
const clang::Type * GetUnderlyingType(clang::QualType type)
Return the base/underlying type of a chain of array or pointers type.
bool IsHeaderName(const std::string &filename)
void Warning(const char *location, const char *fmt,...)
const std::string & GetPathSeparator()
Return the separator suitable for this platform.
const clang::CXXRecordDecl * ScopeSearch(const char *name, const cling::Interpreter &gInterp, bool diagnose, const clang::Type **resultType)
Return the scope corresponding to 'name' or std::'name'.
int & GetErrorIgnoreLevel()
llvm::StringRef DataMemberInfo__ValidArrayIndex(const cling::Interpreter &interp, const clang::DeclaratorDecl &m, int *errnum=nullptr, llvm::StringRef *errstr=nullptr)
ValidArrayIndex return a static string (so use it or copy it immediatly, do not call GrabIndex twice ...
void printUsage(OStream &prn, const Descriptor usage[], int width=80, int last_column_min_percent=50, int last_column_own_line_max_percent=75)
Outputs a nicely formatted usage string with support for multi-column formatting and line-wrapping.
@ 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
static ArgStatus None(const Option &, bool)
For options that don't take an argument: Returns ARG_NONE.
Describes an option, its help text (usage) and how it should be parsed.
static option::ArgStatus Required(const option::Option &option, bool msg)
Determines the minimum lengths of the buffer and options arrays used for Parser.
unsigned options_max
Number of elements needed for an options[] array to be used for parsing the same argument vectors tha...
unsigned buffer_max
Number of elements needed for a buffer[] array to be used for parsing the same argument vectors that ...
TMarker m
Definition textangle.C:8