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(), /*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));
3712// Really OneOrMore, will be changed in RootClingMain below.
3713static llvm::cl::list<std::string>
3714gOptDictionaryHeaderFiles(llvm::cl::Positional, llvm::cl::ZeroOrMore,
3715 llvm::cl::desc("<list of dictionary header files> <LinkDef file | selection xml file>"),
3716 llvm::cl::cat(gRootclingOptions));
3717static llvm::cl::list<std::string>
3718gOptSink(llvm::cl::ZeroOrMore, llvm::cl::Sink,
3719 llvm::cl::desc("Consumes all unrecognized options."),
3720 llvm::cl::cat(gRootclingOptions));
3721
3722static llvm::cl::SubCommand
3723gBareClingSubcommand("bare-cling", "Call directly cling and exit.");
3724
3725static llvm::cl::list<std::string>
3726gOptBareClingSink(llvm::cl::OneOrMore, llvm::cl::Sink,
3727 llvm::cl::desc("Consumes options and sends them to cling."),
3728 llvm::cl::cat(gRootclingOptions), llvm::cl::sub(gBareClingSubcommand));
3729
3730////////////////////////////////////////////////////////////////////////////////
3731/// Returns true iff a given module (and its submodules) contains all headers
3732/// needed by the given ModuleGenerator.
3733/// The names of all header files that are needed by the ModuleGenerator but are
3734/// not in the given module will be inserted into the MissingHeader variable.
3735/// Returns true iff the PCH was successfully generated.
3737 clang::Module *module, std::vector<std::array<std::string, 2>> &missingHeaders)
3738{
3739 // Now we collect all header files from the previously collected modules.
3740 std::vector<clang::Module::Header> moduleHeaders;
3742 [&moduleHeaders](const clang::Module::Header &h) { moduleHeaders.push_back(h); });
3743
3744 bool foundAllHeaders = true;
3745
3746 auto isHeaderInModule = [&moduleHeaders](const std::string &header) {
3747 for (const clang::Module::Header &moduleHeader : moduleHeaders)
3748 if (header == moduleHeader.NameAsWritten)
3749 return true;
3750 return false;
3751 };
3752
3753 // Go through the list of headers that are required by the ModuleGenerator
3754 // and check for each header if it's in one of the modules we loaded.
3755 // If not, make sure we fail at the end and mark the header as missing.
3756 for (const std::string &header : modGen.GetHeaders()) {
3757 if (isHeaderInModule(header))
3758 continue;
3759
3760 clang::ModuleMap::KnownHeader SuggestedModule;
3761 clang::ConstSearchDirIterator *CurDir = nullptr;
3762 if (auto FE = headerSearch.LookupFile(
3763 header, clang::SourceLocation(),
3764 /*isAngled*/ false,
3765 /*FromDir*/ nullptr, CurDir,
3766 clang::ArrayRef<std::pair<clang::OptionalFileEntryRef, clang::DirectoryEntryRef>>(),
3767 /*SearchPath*/ nullptr,
3768 /*RelativePath*/ nullptr,
3769 /*RequestingModule*/ nullptr, &SuggestedModule,
3770 /*IsMapped*/ nullptr,
3771 /*IsFrameworkFound*/ nullptr,
3772 /*SkipCache*/ false,
3773 /*BuildSystemModule*/ false,
3774 /*OpenFile*/ false,
3775 /*CacheFail*/ false)) {
3776 if (auto OtherModule = SuggestedModule.getModule()) {
3777 std::string OtherModuleName;
3778 auto TLM = OtherModule->getTopLevelModuleName();
3779 if (!TLM.empty())
3780 OtherModuleName = TLM.str();
3781 else
3783
3784 // Don't complain about headers that are actually in by-products:
3787 continue;
3788
3789 missingHeaders.push_back({header, OtherModuleName});
3790 }
3791 } else {
3792 missingHeaders.push_back({header, {}});
3793 }
3794 foundAllHeaders = false;
3795 }
3796 return foundAllHeaders;
3797}
3798
3799////////////////////////////////////////////////////////////////////////////////
3800/// Check moduleName validity from modulemap. Check if this module is defined or not.
3801static bool CheckModuleValid(TModuleGenerator &modGen, const std::string &resourceDir, cling::Interpreter &interpreter,
3802 llvm::StringRef LinkdefPath, const std::string &moduleName)
3803{
3804 clang::CompilerInstance *CI = interpreter.getCI();
3805 clang::HeaderSearch &headerSearch = CI->getPreprocessor().getHeaderSearchInfo();
3806 headerSearch.loadTopLevelSystemModules();
3807
3808 // Actually lookup the module on the computed module name.
3809 clang::Module *module = headerSearch.lookupModule(llvm::StringRef(moduleName));
3810
3811 // Inform the user and abort if we can't find a module with a given name.
3812 if (!module) {
3813 ROOT::TMetaUtils::Error("CheckModuleValid", "Couldn't find module with name '%s' in modulemap!\n",
3814 moduleName.c_str());
3815 return false;
3816 }
3817
3818 // Check if the loaded module covers all headers that were specified
3819 // by the user on the command line. This is an integrity check to
3820 // ensure that our used module map is not containing extraneous headers.
3821 std::vector<std::array<std::string, 2>> missingHdrMod;
3823 // FIXME: Upgrade this to an error once modules are stable.
3824 std::stringstream msgStream;
3825 msgStream << "after creating module \"" << module->Name << "\" ";
3826 if (!module->PresumedModuleMapFile.empty())
3827 msgStream << "using modulemap \"" << module->PresumedModuleMapFile << "\" ";
3828 msgStream << "the following headers are not part of that module:\n";
3829 for (auto &H : missingHdrMod) {
3830 msgStream << " " << H[0];
3831 if (!H[1].empty())
3832 msgStream << " (already part of module \"" << H[1] << "\")";
3833 msgStream << "\n";
3834 }
3835 std::string warningMessage = msgStream.str();
3836
3837 bool maybeUmbrella = modGen.GetHeaders().size() == 1;
3838 // We may have an umbrella and forgot to add the flag. Downgrade the
3839 // warning into an information message.
3840 // FIXME: We should open the umbrella, extract the set of header files
3841 // and check if they exist in the modulemap.
3842 // FIXME: We should also check if the header files are specified in the
3843 // modulemap file as they appeared in the rootcling invocation, i.e.
3844 // if we passed rootcling ... -I/some/path somedir/some/header, the
3845 // modulemap should contain module M { header "somedir/some/header" }
3846 // This way we will make sure the module is properly activated.
3848 ROOT::TMetaUtils::Info("CheckModuleValid, %s. You can silence this message by adding %s to the invocation.",
3849 warningMessage.c_str(),
3850 gOptUmbrellaInput.ArgStr.data());
3851 return true;
3852 }
3853
3854 ROOT::TMetaUtils::Warning("CheckModuleValid", warningMessage.c_str());
3855 // We include the missing headers to fix the module for the user.
3856 std::vector<std::string> missingHeaders;
3858 [](const std::array<std::string, 2>& HdrMod) { return HdrMod[0];});
3860 ROOT::TMetaUtils::Error("CheckModuleValid", "Couldn't include missing module headers for module '%s'!\n",
3861 module->Name.c_str());
3862 }
3863 }
3864
3865 return true;
3866}
3867
3868static llvm::StringRef GetModuleNameFromRdictName(llvm::StringRef rdictName)
3869{
3870 // Try to get the module name in the modulemap based on the filepath.
3871 llvm::StringRef moduleName = llvm::sys::path::filename(rdictName);
3872 moduleName.consume_front("lib");
3873 moduleName.consume_back(".pcm");
3874 moduleName.consume_back("_rdict");
3875 return moduleName;
3876}
3877
3878////////////////////////////////////////////////////////////////////////////////
3879
3881 char **argv,
3882 bool isGenreflex = false)
3883{
3884 // Set number of required arguments. We cannot do this globally since it
3885 // would interfere with LLVM's option parsing.
3886 gOptDictionaryFileName.setNumOccurrencesFlag(llvm::cl::Required);
3887 gOptDictionaryHeaderFiles.setNumOccurrencesFlag(llvm::cl::OneOrMore);
3888
3889 // Copied from cling driver.
3890 // FIXME: Uncomment once we fix ROOT's teardown order.
3891 //llvm::llvm_shutdown_obj shutdownTrigger;
3892
3893 const char *executableFileName = argv[0];
3894
3895 llvm::sys::PrintStackTraceOnErrorSignal(executableFileName);
3896 llvm::PrettyStackTraceProgram X(argc, argv);
3898
3899#if defined(R__WIN32) && !defined(R__WINGCC)
3900 // FIXME: This is terrible hack allocating and changing the argument set.
3901 // We should remove it and use standard llvm facilities to convert the paths.
3902 // cygwin's make is presenting us some cygwin paths even though
3903 // we are windows native. Convert them as good as we can.
3904 for (int iic = 1 /* ignore binary file name in argv[0] */; iic < argc; ++iic) {
3905 std::string iiarg(argv[iic]);
3907 size_t len = iiarg.length();
3908 // yes, we leak.
3909 char *argviic = new char[len + 1];
3910 strlcpy(argviic, iiarg.c_str(), len + 1);
3911 argv[iic] = argviic;
3912 }
3913 }
3914#endif
3915
3916 // Hide options from llvm which we got from static initialization of libCling.
3917 llvm::cl::HideUnrelatedOptions(/*keep*/gRootclingOptions);
3918
3919 // Define Options aliasses
3920 auto &opts = llvm::cl::getRegisteredOptions();
3921 llvm::cl::Option* optHelp = opts["help"];
3922 llvm::cl::alias optHelpAlias1("h",
3923 llvm::cl::desc("Alias for -help"),
3924 llvm::cl::aliasopt(*optHelp));
3925 llvm::cl::alias optHelpAlias2("?",
3926 llvm::cl::desc("Alias for -help"),
3927 llvm::cl::aliasopt(*optHelp));
3928
3929 llvm::cl::ParseCommandLineOptions(argc, argv, "rootcling");
3930
3931 const char *etcDir = gDriverConfig->fTROOT__GetEtcDir();
3932 std::string llvmResourceDir = etcDir ? std::string(etcDir) + "/cling" : "";
3933
3935 std::vector<const char *> clingArgsC;
3936 clingArgsC.push_back(executableFileName);
3937 // Help cling finds its runtime (RuntimeUniverse.h and such).
3938 if (etcDir) {
3939 clingArgsC.push_back("-I");
3940 clingArgsC.push_back(etcDir);
3941 }
3942
3943 //clingArgsC.push_back("-resource-dir");
3944 //clingArgsC.push_back(llvmResourceDir.c_str());
3945
3946 for (const std::string& Opt : gOptBareClingSink)
3947 clingArgsC.push_back(Opt.c_str());
3948
3949 auto interp = std::make_unique<cling::Interpreter>(clingArgsC.size(),
3950 &clingArgsC[0],
3951 llvmResourceDir.c_str());
3952 // FIXME: Diagnose when we have misspelled a flag. Currently we show no
3953 // diagnostic and report exit as success.
3954 return interp->getDiagnostics().hasFatalErrorOccurred();
3955 }
3956
3957 std::string dictname;
3958
3959 if (!gDriverConfig->fBuildingROOTStage1) {
3960 if (gOptRootBuild) {
3961 // running rootcling as part of the ROOT build for ROOT libraries.
3962 gBuildingROOT = true;
3963 }
3964 }
3965
3966 if (!gOptModuleMapFiles.empty() && !gOptCxxModule) {
3967 ROOT::TMetaUtils::Error("", "Option %s can be used only when option %s is specified.\n",
3968 gOptModuleMapFiles.ArgStr.str().c_str(),
3969 gOptCxxModule.ArgStr.str().c_str());
3970 std::cout << "\n";
3971 llvm::cl::PrintHelpMessage();
3972 return 1;
3973 }
3974
3975 // Set the default verbosity
3977 if (gOptVerboseLevel == v4)
3978 genreflex::verbose = true;
3979
3980 if (gOptReflex)
3981 isGenreflex = true;
3982
3983 if (!gOptLibListPrefix.empty()) {
3984 string filein = gOptLibListPrefix + ".in";
3985 FILE *fp;
3986 if ((fp = fopen(filein.c_str(), "r")) == nullptr) {
3987 ROOT::TMetaUtils::Error(nullptr, "%s: The input list file %s does not exist\n", executableFileName, filein.c_str());
3988 return 1;
3989 }
3990 fclose(fp);
3991 }
3992
3994 FILE *fp;
3995 if ((fp = fopen(gOptDictionaryFileName.c_str(), "r")) != nullptr) {
3996 fclose(fp);
3997 if (!gOptForce) {
3998 ROOT::TMetaUtils::Error(nullptr, "%s: output file %s already exists\n", executableFileName, gOptDictionaryFileName.c_str());
3999 return 1;
4000 }
4001 }
4002
4003 // remove possible pathname to get the dictionary name
4004 if (gOptDictionaryFileName.size() > (PATH_MAX - 1)) {
4005 ROOT::TMetaUtils::Error(nullptr, "rootcling: dictionary name too long (more than %d characters): %s\n",
4006 (PATH_MAX - 1), gOptDictionaryFileName.c_str());
4007 return 1;
4008 }
4009
4010 dictname = llvm::sys::path::filename(gOptDictionaryFileName).str();
4011 }
4012
4013 if (gOptForce && dictname.empty()) {
4014 ROOT::TMetaUtils::Error(nullptr, "Inconsistent set of arguments detected: overwrite of dictionary file forced but no filename specified.\n");
4015 llvm::cl::PrintHelpMessage();
4016 return 1;
4017 }
4018
4019 std::vector<std::string> clingArgs;
4020 clingArgs.push_back(executableFileName);
4021 clingArgs.push_back("-iquote.");
4022
4024
4025 // Collect the diagnostic pragmas linked to the usage of -W
4026 // Workaround for ROOT-5656
4027 std::list<std::string> diagnosticPragmas = {"#pragma clang diagnostic ignored \"-Wdeprecated-declarations\""};
4028
4029 if (gOptFailOnWarnings) {
4030 using namespace ROOT::TMetaUtils;
4031 // If warnings are disabled with the current verbosity settings, lower
4032 // it so that the user sees the warning that caused the failure.
4033 if (GetErrorIgnoreLevel() > kWarning)
4034 GetErrorIgnoreLevel() = kWarning;
4035 GetWarningsAreErrors() = true;
4036 }
4037
4038 if (gOptISysRoot != "-") {
4039 if (gOptISysRoot.empty()) {
4040 ROOT::TMetaUtils::Error("", "isysroot specified without a value.\n");
4041 return 1;
4042 }
4043 clingArgs.push_back(gOptISysRoot.ArgStr.str());
4044 clingArgs.push_back(gOptISysRoot.ValueStr.str());
4045 }
4046
4047 // Check if we have a multi dict request but no target library
4048 if (gOptMultiDict && gOptSharedLibFileName.empty()) {
4049 ROOT::TMetaUtils::Error("", "Multidict requested but no target library. Please specify one with the -s argument.\n");
4050 return 1;
4051 }
4052
4053 for (const std::string &PPDefine : gOptPPDefines)
4054 clingArgs.push_back(std::string("-D") + PPDefine);
4055
4056 for (const std::string &PPUndefine : gOptPPUndefines)
4057 clingArgs.push_back(std::string("-U") + PPUndefine);
4058
4059 for (const std::string &IncludePath : gOptIncludePaths)
4060 clingArgs.push_back(std::string("-I") + llvm::sys::path::convert_to_slash(IncludePath));
4061
4062 for (const std::string &IncludePath : gOptSysIncludePaths) {
4063 // Prevent mentioning compiler default include directories as -isystem
4064 // (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70129)
4067 clingArgs.push_back("-isystem");
4068 clingArgs.push_back(llvm::sys::path::convert_to_slash(IncludePath));
4069 }
4070 }
4071
4072 for (const std::string &WDiag : gOptWDiags) {
4073 const std::string FullWDiag = std::string("-W") + WDiag;
4074 // Suppress warning when compiling the dictionary, eg. gcc G__xxx.cxx
4076 // Suppress warning when compiling the input headers by cling.
4077 clingArgs.push_back(FullWDiag);
4078 }
4079
4080 const char *includeDir = gDriverConfig->fTROOT__GetIncludeDir();
4081 if (includeDir) {
4082 clingArgs.push_back(std::string("-I") + llvm::sys::path::convert_to_slash(includeDir));
4083 }
4084
4085 std::vector<std::string> pcmArgs;
4086 for (size_t parg = 0, n = clingArgs.size(); parg < n; ++parg) {
4087 auto thisArg = clingArgs[parg];
4089 if (thisArg == "-c" ||
4090 (gOptNoIncludePaths && isInclude)) continue;
4091 // We now check if the include directories are not excluded
4092 if (isInclude) {
4093 unsigned int offset = 2; // -I is two characters. Now account for spaces
4094 char c = thisArg[offset];
4095 while (c == ' ') c = thisArg[++offset];
4097 auto excludePathPos = std::find_if(gOptExcludePaths.begin(),
4099 [&](const std::string& path){
4100 return ROOT::TMetaUtils::BeginsWith(&thisArg[offset], path);});
4101 if (excludePathsEnd != excludePathPos) continue;
4102 }
4103 pcmArgs.push_back(thisArg);
4104 }
4105
4106 // cling-only arguments
4107 if (etcDir)
4108 clingArgs.push_back(std::string("-I") + llvm::sys::path::convert_to_slash(etcDir));
4109
4110 // We do not want __ROOTCLING__ in the pch!
4111 if (!gOptGeneratePCH) {
4112 clingArgs.push_back("-D__ROOTCLING__");
4113 }
4114#ifdef R__MACOSX
4115 clingArgs.push_back("-DSYSTEM_TYPE_macosx");
4116#elif defined(R__WIN32)
4117 clingArgs.push_back("-DSYSTEM_TYPE_winnt");
4118
4119 // Prevent the following #error: The C++ Standard Library forbids macroizing keywords.
4120 clingArgs.push_back("-D_XKEYCHECK_H");
4121 // Tell windows.h not to #define min and max, it clashes with numerical_limits.
4122 clingArgs.push_back("-DNOMINMAX");
4123#else // assume UNIX
4124 clingArgs.push_back("-DSYSTEM_TYPE_unix");
4125#endif
4126
4127 clingArgs.push_back("-fsyntax-only");
4128#ifndef R__WIN32
4129 clingArgs.push_back("-fPIC");
4130#endif
4131 clingArgs.push_back("-Xclang");
4132 clingArgs.push_back("-fmodules-embed-all-files");
4133 clingArgs.push_back("-Xclang");
4134 clingArgs.push_back("-main-file-name");
4135 clingArgs.push_back("-Xclang");
4136 clingArgs.push_back((dictname + ".h").c_str());
4137
4139
4140 // FIXME: This line is from TModuleGenerator, but we can't reuse this code
4141 // at this point because TModuleGenerator needs a CompilerInstance (and we
4142 // currently create the arguments for creating said CompilerInstance).
4143 bool isPCH = (gOptDictionaryFileName.getValue() == "allDict.cxx");
4144 std::string outputFile;
4145 // Data is in 'outputFile', therefore in the same scope.
4146 llvm::StringRef moduleName;
4147 std::string vfsArg;
4148 // Adding -fmodules to the args will break lexing with __CLING__ defined,
4149 // and we actually do lex with __CLING__ and reuse this variable later,
4150 // we have to copy it now.
4152
4153 if (gOptSharedLibFileName.empty()) {
4155 }
4156
4157 if (!isPCH && gOptCxxModule) {
4158 // We just pass -fmodules, the CIFactory will do the rest and configure
4159 // clang correctly once it sees this flag.
4160 clingArgsInterpreter.push_back("-fmodules");
4161 clingArgsInterpreter.push_back("-fno-implicit-module-maps");
4162
4163 for (const std::string &modulemap : gOptModuleMapFiles)
4164 clingArgsInterpreter.push_back("-fmodule-map-file=" + modulemap);
4165
4166 if (includeDir) {
4167 clingArgsInterpreter.push_back("-fmodule-map-file=" + std::string(includeDir) + "/ROOT.modulemap");
4168 }
4169 std::string ModuleMapCWD = ROOT::FoundationUtils::GetCurrentDir() + "/module.modulemap";
4170 if (llvm::sys::fs::exists(ModuleMapCWD))
4171 clingArgsInterpreter.push_back("-fmodule-map-file=" + ModuleMapCWD);
4172
4173 // Specify the module name that we can lookup the module in the modulemap.
4174 outputFile = llvm::sys::path::stem(gOptSharedLibFileName).str();
4175 // Try to get the module name in the modulemap based on the filepath.
4177
4178#ifdef _MSC_VER
4179 clingArgsInterpreter.push_back("-Xclang");
4180 clingArgsInterpreter.push_back("-fmodule-feature");
4181 clingArgsInterpreter.push_back("-Xclang");
4182 clingArgsInterpreter.push_back("msvc" + std::string(rootclingStringify(_MSC_VER)));
4183#endif
4184 clingArgsInterpreter.push_back("-fmodule-name=" + moduleName.str());
4185
4186 std::string moduleCachePath = llvm::sys::path::parent_path(gOptSharedLibFileName).str();
4187 // FIXME: This is a horrible workaround to fix the incremental builds.
4188 // The enumerated modules are built by clang impicitly based on #include of
4189 // a header which is contained within that module. The build system has
4190 // no way to track dependencies on them and trigger a rebuild.
4191 // A possible solution can be to disable completely the implicit build of
4192 // modules and each module to be built by rootcling. We need to teach
4193 // rootcling how to build modules with no IO support.
4194 if (moduleName == "Core") {
4195 assert(gDriverConfig->fBuildingROOTStage1);
4196 remove((moduleCachePath + llvm::sys::path::get_separator() + "_Builtin_intrinsics.pcm").str().c_str());
4197 remove((moduleCachePath + llvm::sys::path::get_separator() + "_Builtin_stddef_max_align_t.pcm").str().c_str());
4198 remove((moduleCachePath + llvm::sys::path::get_separator() + "Cling_Runtime.pcm").str().c_str());
4199 remove((moduleCachePath + llvm::sys::path::get_separator() + "Cling_Runtime_Extra.pcm").str().c_str());
4200#ifdef R__WIN32
4201 remove((moduleCachePath + llvm::sys::path::get_separator() + "vcruntime.pcm").str().c_str());
4202 remove((moduleCachePath + llvm::sys::path::get_separator() + "services.pcm").str().c_str());
4203#endif
4204
4205#ifdef R__MACOSX
4206 remove((moduleCachePath + llvm::sys::path::get_separator() + "Darwin.pcm").str().c_str());
4207#else
4208 remove((moduleCachePath + llvm::sys::path::get_separator() + "libc.pcm").str().c_str());
4209#endif
4210 remove((moduleCachePath + llvm::sys::path::get_separator() + "std.pcm").str().c_str());
4211 remove((moduleCachePath + llvm::sys::path::get_separator() + "boost.pcm").str().c_str());
4212 remove((moduleCachePath + llvm::sys::path::get_separator() + "tinyxml2.pcm").str().c_str());
4213 remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Config.pcm").str().c_str());
4214 remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Rtypes.pcm").str().c_str());
4215 remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Foundation_C.pcm").str().c_str());
4216 remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Foundation_Stage1_NoRTTI.pcm").str().c_str());
4217 } else if (moduleName == "MathCore") {
4218 remove((moduleCachePath + llvm::sys::path::get_separator() + "Vc.pcm").str().c_str());
4219 }
4220
4221 // Set the C++ modules output directory to the directory where we generate
4222 // the shared library.
4223 clingArgsInterpreter.push_back("-fmodules-cache-path=" + moduleCachePath);
4224 }
4225
4226 if (gOptVerboseLevel == v4)
4227 clingArgsInterpreter.push_back("-v");
4228
4229 // Convert arguments to a C array and check if they are sane
4230 std::vector<const char *> clingArgsC;
4231 for (auto const &clingArg : clingArgsInterpreter) {
4233 std::cerr << "Argument \""<< clingArg << "\" is not a supported cling argument. "
4234 << "This could be mistyped rootcling argument. Please check the commandline.\n";
4235 return 1;
4236 }
4237 clingArgsC.push_back(clingArg.c_str());
4238 }
4239
4240
4241 std::unique_ptr<cling::Interpreter> owningInterpPtr;
4242 cling::Interpreter* interpPtr = nullptr;
4243
4244 std::list<std::string> filesIncludedByLinkdef;
4245 if (gDriverConfig->fBuildingROOTStage1) {
4246#ifdef R__FAST_MATH
4247 // Same setting as in TCling.cxx.
4248 clingArgsC.push_back("-ffast-math");
4249#endif
4250
4251 owningInterpPtr.reset(new cling::Interpreter(clingArgsC.size(), &clingArgsC[0],
4252 llvmResourceDir.c_str()));
4253 interpPtr = owningInterpPtr.get();
4254 } else {
4255 // Pass the interpreter arguments to TCling's interpreter:
4256 clingArgsC.push_back("-resource-dir");
4257 clingArgsC.push_back(llvmResourceDir.c_str());
4258 clingArgsC.push_back(nullptr); // signal end of array
4259 const char ** &extraArgs = *gDriverConfig->fTROOT__GetExtraInterpreterArgs();
4260 extraArgs = &clingArgsC[1]; // skip binary name
4261 interpPtr = gDriverConfig->fTCling__GetInterpreter();
4262 if (!interpPtr->getCI()) // Compiler instance could not be created. See https://its.cern.ch/jira/browse/ROOT-10239
4263 return 1;
4264 if (!isGenreflex && !gOptGeneratePCH) {
4265 std::unique_ptr<TRootClingCallbacks> callBacks (new TRootClingCallbacks(interpPtr, filesIncludedByLinkdef));
4266 interpPtr->setCallbacks(std::move(callBacks));
4267 }
4268 }
4269 cling::Interpreter &interp = *interpPtr;
4270 clang::CompilerInstance *CI = interp.getCI();
4271 // FIXME: Remove this once we switch cling to use the driver. This would handle -fmodules-embed-all-files for us.
4272 CI->getFrontendOpts().ModulesEmbedAllFiles = true;
4273 CI->getSourceManager().setAllFilesAreTransient(true);
4274
4275 clang::Preprocessor &PP = CI->getPreprocessor();
4276 clang::HeaderSearch &headerSearch = PP.getHeaderSearchInfo();
4277 clang::ModuleMap &moduleMap = headerSearch.getModuleMap();
4278 auto &diags = interp.getDiagnostics();
4279
4280 // Manually enable the module build remarks. We don't enable them via the
4281 // normal clang command line arg because otherwise we would get remarks for
4282 // building STL/libc when starting the interpreter in rootcling_stage1.
4283 // We can't prevent these diags in any other way because we can only attach
4284 // our own diag client now after the interpreter has already started.
4285 diags.setSeverity(clang::diag::remark_module_build, clang::diag::Severity::Remark, clang::SourceLocation());
4286
4287 // Attach our own diag client that listens to the module_build remarks from
4288 // clang to check that we don't build dictionary C++ modules implicitly.
4289 auto recordingClient = new CheckModuleBuildClient(diags.getClient(), diags.ownsClient(), moduleMap);
4290 diags.setClient(recordingClient, true);
4291
4293 ROOT::TMetaUtils::Info(nullptr, "\n");
4294 ROOT::TMetaUtils::Info(nullptr, "==== INTERPRETER CONFIGURATION ====\n");
4295 ROOT::TMetaUtils::Info(nullptr, "== Include paths\n");
4296 interp.DumpIncludePath();
4297 printf("\n\n");
4298 fflush(stdout);
4299
4300 ROOT::TMetaUtils::Info(nullptr, "== Included files\n");
4301 interp.printIncludedFiles(llvm::outs());
4302 llvm::outs() << "\n\n";
4303 llvm::outs().flush();
4304
4305 ROOT::TMetaUtils::Info(nullptr, "== Language Options\n");
4306 const clang::LangOptions& LangOpts
4307 = interp.getCI()->getASTContext().getLangOpts();
4308#define LANGOPT(Name, Bits, Default, Description) \
4309 ROOT::TMetaUtils::Info(nullptr, "%s = %d // %s\n", #Name, (int)LangOpts.Name, Description);
4310#define ENUM_LANGOPT(Name, Type, Bits, Default, Description)
4311#include "clang/Basic/LangOptions.def"
4312 ROOT::TMetaUtils::Info(nullptr, "==== END interpreter configuration ====\n\n");
4313 }
4314
4315 interp.getOptions().ErrorOut = true;
4316 interp.enableRawInput(true);
4317
4318 if (gOptCxxModule) {
4319 for (llvm::StringRef DepMod : gOptModuleDependencies) {
4320 if (DepMod.ends_with("_rdict.pcm")) {
4321 ROOT::TMetaUtils::Warning(nullptr, "'%s' value is deprecated. Please use [<fullpath>]%s.pcm\n",
4322 DepMod.data(),
4324 }
4326 // We might deserialize.
4327 cling::Interpreter::PushTransactionRAII RAII(&interp);
4328 if (!interp.loadModule(DepMod.str(), /*complain*/false)) {
4329 ROOT::TMetaUtils::Error(nullptr, "Module '%s' failed to load.\n",
4330 DepMod.data());
4331 }
4332 }
4333 }
4334
4335 if (!isGenreflex) { // rootcling
4336 // ROOTCINT uses to define a few header implicitly, we need to do it explicitly.
4337 if (interp.declare("#include <cassert>\n"
4338 "#include \"Rtypes.h\"\n"
4339 "#include \"TObject.h\"") != cling::Interpreter::kSuccess
4340 ) {
4341 // There was an error.
4342 ROOT::TMetaUtils::Error(nullptr, "Error loading the default rootcling header files.\n");
4343 return 1;
4344 }
4345 }
4346
4347 if (interp.declare("#include <string>\n" // For the list of 'opaque' typedef to also include string.
4348 "#include <RtypesCore.h>\n" // For initializing TNormalizedCtxt.
4349 "namespace std {} using namespace std;") != cling::Interpreter::kSuccess) {
4350 ROOT::TMetaUtils::Error(nullptr, "Error loading the default header files.\n");
4351 return 1;
4352 }
4353
4354 // We are now ready (enough is loaded) to init the list of opaque typedefs.
4356 ROOT::TMetaUtils::TClingLookupHelper helper(interp, normCtxt, nullptr, nullptr, nullptr, nullptr);
4358
4359 // flags used only for the pragma parser:
4360 clingArgs.push_back("-D__CINT__"); // backward compatibility. Now __CLING__ should be used instead
4361 clingArgs.push_back("-D__MAKECINT__"); // backward compatibility. Now __ROOTCLING__ should used instead
4362
4364
4366
4367 std::string interpPragmaSource;
4368 std::string includeForSource;
4369 std::string interpreterDeclarations;
4370 std::string linkdef;
4371
4372 for (size_t i = 0, e = gOptDictionaryHeaderFiles.size(); i < e; ++i) {
4373 const std::string& optHeaderFileName = gOptDictionaryHeaderFiles[i];
4375
4376 if (isSelectionFile) {
4377 if (i == e - 1) {
4379 } else { // if the linkdef was not last, issue an error.
4380 ROOT::TMetaUtils::Error(nullptr, "%s: %s must be last file on command line\n",
4382 return 1;
4383 }
4384 }
4385
4386 // coverity[tainted_data] The OS should already limit the argument size, so we are safe here
4387 std::string fullheader(optHeaderFileName);
4388 // Strip any trailing + which is only used by GeneratedLinkdef.h which currently
4389 // use directly argv.
4390 if (fullheader[fullheader.length() - 1] == '+') {
4391 fullheader.erase(fullheader.length() - 1);
4392 }
4393 std::string header(
4395
4396 interpPragmaSource += std::string("#include \"") + header + "\"\n";
4397 if (!isSelectionFile) {
4398 // In order to not have to add the equivalent to -I${PWD} to the
4399 // command line, include the complete file name, even if it is a
4400 // full pathname, when we write it down in the dictionary.
4401 // Note: have -I${PWD} means in that (at least in the case of
4402 // ACLiC) we inadvertently pick local file that have the same
4403 // name as system header (e.g. new or list) and -iquote has not
4404 // equivalent on some platforms.
4405 includeForSource += std::string("#include \"") + fullheader + "\"\n";
4406 pcmArgs.push_back(header);
4407 } else if (!IsSelectionXml(optHeaderFileName.c_str())) {
4408 interpreterDeclarations += std::string("#include \"") + header + "\"\n";
4409 }
4410 }
4411
4412 if (gOptUmbrellaInput) {
4413 bool hasSelectionFile = !linkdef.empty();
4416 ROOT::TMetaUtils::Error(nullptr, "Option %s used but more than one header file specified.\n",
4417 gOptUmbrellaInput.ArgStr.data());
4418 }
4419
4420 // We have a multiDict request. This implies generating a pcm which is of the form
4421 // dictName_libname_rdict.pcm
4422 if (gOptMultiDict) {
4423
4424 std::string newName = llvm::sys::path::parent_path(gOptSharedLibFileName).str();
4425 if (!newName.empty())
4427 newName += llvm::sys::path::stem(gOptSharedLibFileName);
4428 newName += "_";
4429 newName += llvm::sys::path::stem(gOptDictionaryFileName);
4430 newName += llvm::sys::path::extension(gOptSharedLibFileName);
4432 }
4433
4434 // Until the module are actually enabled in ROOT, we need to register
4435 // the 'current' directory to make it relocatable (i.e. have a way
4436 // to find the headers).
4438 string incCurDir = "-I";
4440 pcmArgs.push_back(incCurDir);
4441 }
4442
4443 // Add the diagnostic pragmas distilled from the -Wno-xyz
4444 {
4445 std::stringstream res;
4446 const char* delim="\n";
4447 std::copy(diagnosticPragmas.begin(),
4449 std::ostream_iterator<std::string>(res, delim));
4450 if (interp.declare(res.str()) != cling::Interpreter::kSuccess) {
4451 ROOT::TMetaUtils::Error(nullptr, "Failed to parse -Wno-xyz flags as pragmas:\n%s", res.str().c_str());
4452 return 1;
4453 }
4454 }
4455
4456 class IgnoringPragmaHandler: public clang::PragmaNamespace {
4457 public:
4458 IgnoringPragmaHandler(const char* pragma):
4459 clang::PragmaNamespace(pragma) {}
4460 void HandlePragma(clang::Preprocessor &PP,
4461 clang::PragmaIntroducer Introducer,
4462 clang::Token &tok) override {
4463 PP.DiscardUntilEndOfDirective();
4464 }
4465 };
4466
4467 // Ignore these #pragmas to suppress "unknown pragma" warnings.
4468 // See LinkdefReader.cxx.
4469 PP.AddPragmaHandler(new IgnoringPragmaHandler("link"));
4470 PP.AddPragmaHandler(new IgnoringPragmaHandler("extra_include"));
4471 PP.AddPragmaHandler(new IgnoringPragmaHandler("read"));
4472 PP.AddPragmaHandler(new IgnoringPragmaHandler("create"));
4473
4474 if (!interpreterDeclarations.empty() &&
4475 interp.declare(interpreterDeclarations) != cling::Interpreter::kSuccess) {
4476 ROOT::TMetaUtils::Error(nullptr, "%s: Linkdef compilation failure\n", executableFileName);
4477 return 1;
4478 }
4479
4480
4485
4486 if (!gDriverConfig->fBuildingROOTStage1 && !filesIncludedByLinkdef.empty()) {
4487 pcmArgs.push_back(linkdef);
4488 }
4489
4490 modGen.ParseArgs(pcmArgs);
4491
4492 if (!gDriverConfig->fBuildingROOTStage1) {
4493 // Forward the -I, -D, -U
4494 for (const std::string & inclPath : modGen.GetIncludePaths()) {
4495 interp.AddIncludePath(inclPath);
4496 }
4497 std::stringstream definesUndefinesStr;
4498 modGen.WritePPDefines(definesUndefinesStr);
4499 modGen.WritePPUndefines(definesUndefinesStr);
4500 if (!definesUndefinesStr.str().empty()) {
4501 if (interp.declare(definesUndefinesStr.str()) != cling::Interpreter::kSuccess) {
4502 ROOT::TMetaUtils::Error(nullptr, "Failed to parse -D, -U flags as preprocessor directives:\n%s", definesUndefinesStr.str().c_str());
4503 return 1;
4504 }
4505 }
4506 }
4507
4510 return 1;
4511 }
4512
4513 // Check if code goes to stdout or rootcling file
4514 std::ofstream fileout;
4515 string main_dictname(gOptDictionaryFileName.getValue());
4516 std::ostream *splitDictStream = nullptr;
4517 std::unique_ptr<std::ostream> splitDeleter(nullptr);
4518 // Store the temp files
4520 if (!gOptDictionaryFileName.empty()) {
4521 tmpCatalog.addFileName(gOptDictionaryFileName.getValue());
4522 fileout.open(gOptDictionaryFileName.c_str());
4523 if (!fileout) {
4524 ROOT::TMetaUtils::Error(nullptr, "rootcling: failed to open %s in main\n",
4525 gOptDictionaryFileName.c_str());
4526 return 1;
4527 }
4528 }
4529
4530 std::ostream &dictStream = (!gOptDictionaryFileName.empty()) ? fileout : std::cout;
4531 bool isACLiC = gOptDictionaryFileName.getValue().find("_ACLiC_dict") != std::string::npos;
4532
4533 // Now generate a second stream for the split dictionary if it is necessary
4534 if (gOptSplit) {
4537 } else {
4539 }
4540
4541 size_t dh = main_dictname.rfind('.');
4542 if (dh != std::string::npos) {
4543 main_dictname.erase(dh);
4544 }
4545 // Need to replace all the characters not allowed in a symbol ...
4546 std::string main_dictname_copy(main_dictname);
4548
4550 if (gOptSplit)
4552
4553 if (!gOptNoGlobalUsingStd) {
4554 // ACLiC'ed macros might rely on `using namespace std` in front of user headers
4555 if (isACLiC) {
4557 if (gOptSplit) {
4559 }
4560 }
4561 }
4562
4563
4564 //---------------------------------------------------------------------------
4565 // Parse the linkdef or selection.xml file.
4566 /////////////////////////////////////////////////////////////////////////////
4567
4568 string linkdefFilename;
4569 if (linkdef.empty()) {
4570 linkdefFilename = "in memory";
4571 } else {
4572 bool found = Which(interp, linkdef.c_str(), linkdefFilename);
4573 if (!found) {
4574 ROOT::TMetaUtils::Error(nullptr, "%s: cannot open linkdef file %s\n", executableFileName, linkdef.c_str());
4575 return 1;
4576 }
4577 }
4578
4579 // Exclude string not to re-generate the dictionary
4580 std::vector<std::pair<std::string, std::string>> namesForExclusion;
4581 if (!gBuildingROOT) {
4582 namesForExclusion.push_back(std::make_pair(ROOT::TMetaUtils::propNames::name, "std::string"));
4583 namesForExclusion.push_back(std::make_pair(ROOT::TMetaUtils::propNames::pattern, "ROOT::Meta::Selection*"));
4584 }
4585
4587
4588 std::string extraIncludes;
4589
4591
4592 // Select using DictSelection
4593 const unsigned int selRulesInitialSize = selectionRules.Size();
4596
4598
4599 bool isSelXML = IsSelectionXml(linkdefFilename.c_str());
4600
4601 int rootclingRetCode(0);
4602
4605 std::ifstream file(linkdefFilename.c_str());
4606 if (file.is_open()) {
4607 ROOT::TMetaUtils::Info(nullptr, "Using linkdef file: %s\n", linkdefFilename.c_str());
4608 file.close();
4609 } else {
4610 ROOT::TMetaUtils::Error(nullptr, "Linkdef file %s couldn't be opened!\n", linkdefFilename.c_str());
4611 }
4612
4613 selectionRules.SetSelectionFileType(SelectionRules::kLinkdefFile);
4614 }
4615 // If there is no linkdef file, we added the 'default' #pragma to
4616 // interpPragmaSource and we still need to process it.
4617
4619
4621 llvmResourceDir.c_str())) {
4622 ROOT::TMetaUtils::Error(nullptr, "Parsing #pragma failed %s\n", linkdefFilename.c_str());
4623 rootclingRetCode += 1;
4624 } else {
4625 ROOT::TMetaUtils::Info(nullptr, "#pragma successfully parsed.\n");
4626 }
4627
4628 if (!ldefr.LoadIncludes(extraIncludes)) {
4629 ROOT::TMetaUtils::Error(nullptr, "Error loading the #pragma extra_include.\n");
4630 return 1;
4631 }
4632
4633 } else if (isSelXML) {
4634
4636
4637 std::ifstream file(linkdefFilename.c_str());
4638 if (file.is_open()) {
4639 ROOT::TMetaUtils::Info(nullptr, "Selection XML file\n");
4640
4642 if (!xmlr.Parse(linkdefFilename.c_str(), selectionRules)) {
4643 ROOT::TMetaUtils::Error(nullptr, "Parsing XML file %s\n", linkdefFilename.c_str());
4644 return 1; // Return here to propagate the failure up to the build system
4645 } else {
4646 ROOT::TMetaUtils::Info(nullptr, "XML file successfully parsed\n");
4647 }
4648 file.close();
4649 } else {
4650 ROOT::TMetaUtils::Error(nullptr, "XML file %s couldn't be opened!\n", linkdefFilename.c_str());
4651 }
4652
4653 } else {
4654
4655 ROOT::TMetaUtils::Error(nullptr, "Unrecognized selection file: %s\n", linkdefFilename.c_str());
4656
4657 }
4658
4659 // Speed up the operations with rules
4660 selectionRules.FillCache();
4661 selectionRules.Optimize();
4662
4663 // Addresses ROOT-5174
4664 if (gBuildingROOT? 0 : 2 >= selectionRules.Size() && !gOptCxxModule && !isGenreflex) {
4665 ROOT::TMetaUtils::Error(nullptr, "No selection rules specified and creation of C++ module not requested: did you forget to specify a selection file or to request the creation of a C++ module?\n");
4666 return 1;
4667 }
4668
4669 if (isGenreflex){
4670 if (0 != selectionRules.CheckDuplicates()){
4671 return 1;
4672 }
4673 }
4674
4675 // If we want to validate the selection only, we just quit.
4677 return 0;
4678
4679 //---------------------------------------------------------------------------
4680 // Write schema evolution related headers and declarations
4681 /////////////////////////////////////////////////////////////////////////////
4682
4683 if ((!ROOT::gReadRules.empty() || !ROOT::gReadRawRules.empty())) {
4684 dictStream << "#include \"TBuffer.h\"\n"
4685 << "#include \"TVirtualObject.h\"\n"
4686 << "#include <vector>\n"
4687 << "#include \"TSchemaHelper.h\"\n\n";
4688
4689 std::list<std::string> includes;
4691 for (auto & incFile : includes) {
4692 dictStream << "#include <" << incFile << ">" << std::endl;
4693 }
4694 dictStream << std::endl;
4695 }
4696
4697 selectionRules.SearchNames(interp);
4698
4699 int scannerVerbLevel = 0;
4700 {
4701 using namespace ROOT::TMetaUtils;
4702 scannerVerbLevel = GetErrorIgnoreLevel() == kInfo; // 1 if true, 0 if false
4703 if (isGenreflex){
4704 scannerVerbLevel = GetErrorIgnoreLevel() < kWarning;
4705 }
4706 }
4707
4708 // Select the type of scan
4710 if (gOptGeneratePCH)
4712 if (dictSelection)
4714
4716 scanType,
4717 interp,
4718 normCtxt,
4720
4721 // If needed initialize the autoloading hook
4722 if (!gOptLibListPrefix.empty()) {
4725 }
4726
4727 scan.Scan(CI->getASTContext());
4728
4729 bool has_input_error = false;
4730
4732 selectionRules.PrintSelectionRules();
4733
4735 !gOptGeneratePCH &&
4737 !selectionRules.AreAllSelectionRulesUsed()) {
4738 ROOT::TMetaUtils::Warning(nullptr, "Not all selection rules are used!\n");
4739 }
4740
4741 if (!gOptGeneratePCH){
4744 }
4745
4746 // SELECTION LOOP
4747 // Check for error in the class layout before doing anything else.
4748 for (auto const & annRcd : scan.fSelectedClasses) {
4750 if (annRcd.RequestNoInputOperator()) {
4752 if (version != 0) {
4753 // Only Check for input operator is the object is I/O has
4754 // been requested.
4756 }
4757 }
4758 }
4760 }
4761
4762 if (has_input_error) {
4763 // Be a little bit makefile friendly and remove the dictionary in case of error.
4764 // We could add an option -k to keep the file even in case of error.
4765 exit(1);
4766 }
4767
4768 //---------------------------------------------------------------------------
4769 // Write all the necessary #include
4770 /////////////////////////////////////////////////////////////////////////////
4771 if (!gDriverConfig->fBuildingROOTStage1) {
4773 includeForSource += "#include \"" + includedFromLinkdef + "\"\n";
4774 }
4775 }
4776
4777 if (!gOptGeneratePCH) {
4779 if (gOptSplit) {
4781 }
4782 if (!gOptNoGlobalUsingStd) {
4783 // ACLiC'ed macros might have relied on `using namespace std` in front of user headers
4784 if (!isACLiC) {
4786 if (gOptSplit) {
4788 }
4789 }
4790 }
4791 if (gDriverConfig->fInitializeStreamerInfoROOTFile) {
4792 gDriverConfig->fInitializeStreamerInfoROOTFile(modGen.GetModuleFileName().c_str());
4793 }
4794
4795 // The order of addition to the list of constructor type
4796 // is significant. The list is sorted by with the highest
4797 // priority first.
4798 if (!gOptInterpreterOnly) {
4799 constructorTypes.emplace_back("TRootIOCtor", interp);
4800 constructorTypes.emplace_back("__void__", interp); // ROOT-7723
4801 constructorTypes.emplace_back("", interp);
4802 }
4803 }
4806
4807 if (gOptSplit && splitDictStream) {
4809 }
4810 }
4811
4812 if (gOptGeneratePCH) {
4814 } else if (gOptInterpreterOnly) {
4816 // generate an empty pcm nevertheless for consistency
4817 // Negate as true is 1 and true is returned in case of success.
4818 if (!gDriverConfig->fBuildingROOTStage1) {
4820 }
4821 } else {
4824 }
4825
4826 if (rootclingRetCode != 0) {
4827 return rootclingRetCode;
4828 }
4829
4830 // Now we have done all our looping and thus all the possible
4831 // annotation, let's write the pcms.
4834
4836
4838 scan.fSelectedTypedefs,
4839 scan.fSelectedFunctions,
4840 scan.fSelectedVariables,
4841 scan.fSelectedEnums,
4844 interp);
4845
4846 std::string detectedUmbrella;
4847 for (auto & arg : pcmArgs) {
4849 detectedUmbrella = arg;
4850 break;
4851 }
4852 }
4853
4855 headersDeclsMap.clear();
4856 }
4857
4858
4859 std::string headersClassesMapString = "\"\"";
4860 std::string fwdDeclsString = "\"\"";
4861 if (!gOptCxxModule) {
4864 true);
4865 if (!gDriverConfig->fBuildingROOTStage1) {
4868 }
4869 }
4872 // If we just want to inline the input header, we don't need
4873 // to generate any files.
4874 if (!gOptInlineInput) {
4875 // Write the module/PCH depending on what mode we are on
4876 if (modGen.IsPCH()) {
4877 if (!GenerateAllDict(modGen, CI, currentDirectory)) return 1;
4878 } else if (gOptCxxModule) {
4880 return 1;
4881 }
4882 }
4883
4884 if (!gOptLibListPrefix.empty()) {
4885 string liblist_filename = gOptLibListPrefix + ".out";
4886
4887 ofstream outputfile(liblist_filename.c_str(), ios::out);
4888 if (!outputfile) {
4889 ROOT::TMetaUtils::Error(nullptr, "%s: Unable to open output lib file %s\n",
4891 } else {
4892 const size_t endStr = gLibsNeeded.find_last_not_of(" \t");
4893 outputfile << gLibsNeeded.substr(0, endStr + 1) << endl;
4894 // Add explicit delimiter
4895 outputfile << "# Now the list of classes\n";
4896 // SELECTION LOOP
4897 for (auto const & annRcd : scan.fSelectedClasses) {
4898 // Shouldn't it be GetLong64_Name( cl_input.GetNormalizedName() )
4899 // or maybe we should be normalizing to turn directly all long long into Long64_t
4900 outputfile << annRcd.GetNormalizedName() << endl;
4901 }
4902 }
4903 }
4904
4905 // Check for errors in module generation
4906 rootclingRetCode += modGen.GetErrorCount();
4907 if (0 != rootclingRetCode) return rootclingRetCode;
4908
4909 // Create the rootmap file
4910 std::string rootmapLibName = std::accumulate(gOptRootmapLibNames.begin(),
4912 std::string(),
4913 [](const std::string & a, const std::string & b) -> std::string {
4914 if (a.empty()) return b;
4915 else return a + " " + b;
4916 });
4917
4918 bool rootMapNeeded = !gOptRootMapFileName.empty() || !rootmapLibName.empty();
4919
4920 std::list<std::string> classesNames;
4921 std::list<std::string> classesNamesForRootmap;
4922 std::list<std::string> classesDefsList;
4923
4928 interp);
4929
4930 std::list<std::string> enumNames;
4932 scan.fSelectedEnums,
4933 interp);
4934
4935 std::list<std::string> varNames;
4937 scan.fSelectedVariables,
4938 interp);
4939
4940 if (0 != rootclingRetCode) return rootclingRetCode;
4941
4942 // Create the rootmapfile if needed
4943 if (rootMapNeeded) {
4944
4945 std::list<std::string> nsNames;
4946
4948
4951
4952 ROOT::TMetaUtils::Info(nullptr, "Rootmap file name %s and lib name(s) \"%s\"\n",
4953 gOptRootMapFileName.c_str(),
4954 rootmapLibName.c_str());
4955
4956 tmpCatalog.addFileName(gOptRootMapFileName);
4957 std::unordered_set<std::string> headersToIgnore;
4958 if (gOptInlineInput)
4959 for (const std::string& optHeaderFileName : gOptDictionaryHeaderFiles)
4960 headersToIgnore.insert(optHeaderFileName.c_str());
4961
4962 std::list<std::string> typedefsRootmapLines;
4964 scan.fSelectedTypedefs,
4965 interp);
4966
4971 nsNames,
4973 enumNames,
4974 varNames,
4977
4978 if (0 != rootclingRetCode) return 1;
4979 }
4980
4982 tmpCatalog.dump();
4983
4984 // Manually call end of translation unit because we never call the
4985 // appropriate deconstructors in the interpreter. This writes out the C++
4986 // module file that we currently generate.
4987 {
4988 cling::Interpreter::PushTransactionRAII RAII(&interp);
4989 CI->getSema().getASTConsumer().HandleTranslationUnit(CI->getSema().getASTContext());
4990 }
4991
4992 // Add the warnings
4994
4995 // make sure the file is closed before committing
4996 fileout.close();
4997
4998 // Before returning, rename the files if no errors occurred
4999 // otherwise clean them to avoid remnants (see ROOT-10015)
5000 if(rootclingRetCode == 0) {
5001 rootclingRetCode += tmpCatalog.commit();
5002 } else {
5003 tmpCatalog.clean();
5004 }
5005
5006 return rootclingRetCode;
5007
5008}
5009
5010namespace genreflex {
5011
5012////////////////////////////////////////////////////////////////////////////////
5013/// Loop on arguments: stop at the first which starts with -
5014
5015 unsigned int checkHeadersNames(std::vector<std::string> &headersNames)
5016 {
5017 unsigned int numberOfHeaders = 0;
5018 for (std::vector<std::string>::iterator it = headersNames.begin();
5019 it != headersNames.end(); ++it) {
5020 const std::string headername(*it);
5023 } else {
5025 "*** genreflex: %s is not a valid header name (.h and .hpp extensions expected)!\n",
5026 headername.c_str());
5027 }
5028 }
5029 return numberOfHeaders;
5030 }
5031
5032////////////////////////////////////////////////////////////////////////////////
5033/// Extract the arguments from the command line
5034
5035 unsigned int extractArgs(int argc, char **argv, std::vector<std::string> &args)
5036 {
5037 // loop on argv, spot strings which are not preceded by something
5038 unsigned int argvCounter = 0;
5039 for (int i = 1; i < argc; ++i) {
5040 if (!ROOT::TMetaUtils::BeginsWith(argv[i - 1], "-") && // so, if preceding element starts with -, this is a value for an option
5041 !ROOT::TMetaUtils::BeginsWith(argv[i], "-")) { // and the element itself is not an option
5042 args.push_back(argv[i]);
5043 argvCounter++;
5044 } else if (argvCounter) {
5045 argv[i - argvCounter] = argv[i];
5046 }
5047 }
5048
5049 // Some debug
5050 if (genreflex::verbose) {
5051 int i = 0;
5052 std::cout << "Args: \n";
5053 for (std::vector<std::string>::iterator it = args.begin();
5054 it < args.end(); ++it) {
5055 std::cout << i << ") " << *it << std::endl;
5056 ++i;
5057 }
5058
5059 }
5060
5061 return argvCounter;
5062 }
5063
5064////////////////////////////////////////////////////////////////////////////////
5065
5066 void changeExtension(std::string &filename, const std::string &newExtension)
5067 {
5068 size_t result = filename.find_last_of('.');
5069 if (std::string::npos != result) {
5070 filename.erase(result);
5071 filename.append(newExtension);
5072 }
5073
5074 }
5075
5076////////////////////////////////////////////////////////////////////////////////
5077/// The caller is responsible for deleting the string!
5078
5079 char *string2charptr(const std::string &str)
5080 {
5081 const unsigned int size(str.size());
5082 char *a = new char[size + 1];
5083 a[size] = 0;
5084 memcpy(a, str.c_str(), size);
5085 return a;
5086 }
5087
5088////////////////////////////////////////////////////////////////////////////////
5089/// Replace the extension with "_rflx.cpp"
5090
5091 void header2outputName(std::string &fileName)
5092 {
5093 changeExtension(fileName, "_rflx.cpp");
5094 }
5095
5096////////////////////////////////////////////////////////////////////////////////
5097/// Get a proper name for the output file
5098
5099 void headers2outputsNames(const std::vector<std::string> &headersNames,
5100 std::vector<std::string> &ofilesnames)
5101 {
5102 ofilesnames.reserve(headersNames.size());
5103
5104 for (std::vector<std::string>::const_iterator it = headersNames.begin();
5105 it != headersNames.end(); ++it) {
5106 std::string ofilename(*it);
5108 ofilesnames.push_back(ofilename);
5109 }
5110 }
5111
5112////////////////////////////////////////////////////////////////////////////////
5113
5114 void AddToArgVector(std::vector<char *> &argvVector,
5115 const std::vector<std::string> &argsToBeAdded,
5116 const std::string &optName = "")
5117 {
5118 for (std::vector<std::string>::const_iterator it = argsToBeAdded.begin();
5119 it != argsToBeAdded.end(); ++it) {
5120 argvVector.push_back(string2charptr(optName + *it));
5121 }
5122 }
5123
5124////////////////////////////////////////////////////////////////////////////////
5125
5126 void AddToArgVectorSplit(std::vector<char *> &argvVector,
5127 const std::vector<std::string> &argsToBeAdded,
5128 const std::string &optName = "")
5129 {
5130 for (std::vector<std::string>::const_iterator it = argsToBeAdded.begin();
5131 it != argsToBeAdded.end(); ++it) {
5132 if (optName.length()) {
5133 argvVector.push_back(string2charptr(optName));
5134 }
5135 argvVector.push_back(string2charptr(*it));
5136 }
5137 }
5138
5139////////////////////////////////////////////////////////////////////////////////
5140
5141 int invokeRootCling(const std::string &verbosity,
5142 const std::string &selectionFileName,
5143 const std::string &targetLibName,
5144 bool multiDict,
5145 const std::vector<std::string> &pcmsNames,
5146 const std::vector<std::string> &includes,
5147 const std::vector<std::string> &preprocDefines,
5148 const std::vector<std::string> &preprocUndefines,
5149 const std::vector<std::string> &warnings,
5150 const std::string &rootmapFileName,
5151 const std::string &rootmapLibName,
5152 bool interpreteronly,
5153 bool doSplit,
5154 bool isCxxmodule,
5155 bool writeEmptyRootPCM,
5156 bool selSyntaxOnly,
5157 bool noIncludePaths,
5158 bool noGlobalUsingStd,
5159 const std::vector<std::string> &headersNames,
5160 bool failOnWarnings,
5162 const std::string &ofilename)
5163 {
5164 // Prepare and invoke the commandline to invoke rootcling
5165
5166 std::vector<char *> argvVector;
5167
5168 argvVector.push_back(string2charptr("rootcling"));
5170 argvVector.push_back(string2charptr("-f"));
5172
5173 if (isCxxmodule)
5174 argvVector.push_back(string2charptr("-cxxmodule"));
5175
5176 // Extract the path to the dictionary
5177 std::string dictLocation;
5179
5180 // Rootmaps
5181
5182 // Prepare the correct rootmap libname if not already set.
5183 std::string newRootmapLibName(rootmapLibName);
5184 if (!rootmapFileName.empty() && newRootmapLibName.empty()) {
5185 if (headersNames.size() != 1) {
5187 "*** genreflex: No rootmap lib and several header specified!\n");
5188 }
5190 newRootmapLibName = "lib";
5193 }
5194
5195 // Prepend to the rootmap the designed directory of the dictionary
5196 // if no path is specified for the rootmap itself
5198 if (!newRootmapFileName.empty() && !HasPath(newRootmapFileName)) {
5200 }
5201
5202
5203 // RootMap filename
5204 if (!newRootmapFileName.empty()) {
5205 argvVector.push_back(string2charptr("-rmf"));
5207 }
5208
5209 // RootMap Lib filename
5210 if (!newRootmapLibName.empty()) {
5211 argvVector.push_back(string2charptr("-rml"));
5213 }
5214
5215 // Always use the -reflex option: we want rootcling to behave
5216 // like genreflex in this case
5217 argvVector.push_back(string2charptr("-reflex"));
5218
5219 // Interpreter only dictionaries
5220 if (interpreteronly)
5221 argvVector.push_back(string2charptr("-interpreteronly"));
5222
5223 // Split dictionaries
5224 if (doSplit)
5225 argvVector.push_back(string2charptr("-split"));
5226
5227 // Targetlib
5228 if (!targetLibName.empty()) {
5229 argvVector.push_back(string2charptr("-s"));
5231 }
5232
5233 // Multidict support
5234 if (multiDict)
5235 argvVector.push_back(string2charptr("-multiDict"));
5236
5237 // Don't declare "using namespace std"
5238 if (noGlobalUsingStd)
5239 argvVector.push_back(string2charptr("-noGlobalUsingStd"));
5240
5241
5243
5244 // Inline the input header
5245 argvVector.push_back(string2charptr("-inlineInputHeader"));
5246
5247 // Write empty root pcms
5249 argvVector.push_back(string2charptr("-writeEmptyRootPCM"));
5250
5251 // Just test the syntax of the selection file
5252 if (selSyntaxOnly)
5253 argvVector.push_back(string2charptr("-selSyntaxOnly"));
5254
5255 // No include paths
5256 if (noIncludePaths)
5257 argvVector.push_back(string2charptr("-noIncludePaths"));
5258
5259 // Fail on warnings
5260 if (failOnWarnings)
5261 argvVector.push_back(string2charptr("-failOnWarnings"));
5262
5263 // Clingargs
5268
5270
5271 if (!selectionFileName.empty()) {
5273 }
5274
5275 const int argc = argvVector.size();
5276
5277 // Output commandline for rootcling
5279 std::string cmd;
5280 for (int i = 0; i < argc; i++) {
5281 cmd += argvVector[i];
5282 cmd += " ";
5283 }
5284 cmd.pop_back();
5285 if (genreflex::verbose) std::cout << "Rootcling commandline: ";
5286 std::cout << cmd << std::endl;
5287 if (printRootclingInvocation) return 0; // we do not generate anything
5288 }
5289
5290 char **argv = & (argvVector[0]);
5292 argv,
5293 /*isGenReflex=*/true);
5294
5295 for (int i = 0; i < argc; i++)
5296 delete [] argvVector[i];
5297
5298 return rootclingReturnCode;
5299
5300 }
5301
5302////////////////////////////////////////////////////////////////////////////////
5303/// Get the right ofilenames and invoke several times rootcling
5304/// One invokation per header
5305
5306 int invokeManyRootCling(const std::string &verbosity,
5307 const std::string &selectionFileName,
5308 const std::string &targetLibName,
5309 bool multiDict,
5310 const std::vector<std::string> &pcmsNames,
5311 const std::vector<std::string> &includes,
5312 const std::vector<std::string> &preprocDefines,
5313 const std::vector<std::string> &preprocUndefines,
5314 const std::vector<std::string> &warnings,
5315 const std::string &rootmapFileName,
5316 const std::string &rootmapLibName,
5317 bool interpreteronly,
5318 bool doSplit,
5319 bool isCxxmodule,
5320 bool writeEmptyRootPCM,
5321 bool selSyntaxOnly,
5322 bool noIncludePaths,
5323 bool noGlobalUsingStd,
5324 const std::vector<std::string> &headersNames,
5325 bool failOnWarnings,
5327 const std::string &outputDirName_const = "")
5328 {
5330
5331 std::vector<std::string> ofilesNames;
5333
5336 }
5337
5338 std::vector<std::string> namesSingleton(1);
5339 for (unsigned int i = 0; i < headersNames.size(); ++i) {
5341 std::string ofilenameFullPath(ofilesNames[i]);
5342 if (llvm::sys::path::parent_path(ofilenameFullPath) == "")
5347 multiDict,
5348 pcmsNames,
5349 includes,
5352 warnings,
5356 doSplit,
5366 if (returnCode != 0)
5367 return returnCode;
5368 }
5369
5370 return 0;
5371 }
5372
5373
5374} // end genreflex namespace
5375
5376////////////////////////////////////////////////////////////////////////////////
5377/// Extract from options multiple values with the same option
5378
5379int extractMultipleOptions(std::vector<ROOT::option::Option> &options,
5380 int oIndex,
5381 std::vector<std::string> &values)
5382{
5383 int nValues = 0;
5384 if (options[oIndex]) {
5385 const int nVals = options[oIndex].count();
5386 values.reserve(nVals);
5387 int optionIndex = 0;
5388 for (ROOT::option::Option *opt = options[oIndex]; opt; opt = opt->next()) {
5389 if (genreflex::verbose) std::cout << "Extracting multiple args: "
5390 << optionIndex << "/" << nVals << " "
5391 << opt->arg << std::endl;
5392 optionIndex++;
5393 values.push_back(opt->arg);
5394 nValues++;
5395 }
5396 }
5397 return nValues;
5398}
5399
5400////////////////////////////////////////////////////////////////////////////////
5401
5402void RiseWarningIfPresent(std::vector<ROOT::option::Option> &options,
5403 int optionIndex,
5404 const char *descriptor)
5405{
5406 if (options[optionIndex]) {
5408 "*** genereflex: %s is not supported anymore.\n",
5409 descriptor);
5410 }
5411}
5412
5413////////////////////////////////////////////////////////////////////////////////
5414
5415bool IsGoodLibraryName(const std::string &name)
5416{
5417
5418
5420#ifdef __APPLE__
5422#endif
5423 return isGood;
5424}
5425
5426////////////////////////////////////////////////////////////////////////////////
5427/// Translate the arguments of genreflex into rootcling ones and forward them
5428/// to the RootCling function.
5429/// These are two typical genreflex and rootcling commandlines
5430/// 1) genreflex header1.h [header2.h ...] [options] [preprocessor options]
5431/// 2) rootcling [-v] [-v0-4] [-f] [out.cxx] [-s sharedlib.so] [-m pcmfilename]
5432/// header1.h[{+,-}][!] ..headerN.h[{+,-}][!] [{LinkDef.h,selectionRules.xml}]
5433/// The rules with which the arguments are translated are (1st column genreflex):
5434/// --debug -v4
5435/// --quiet -v0
5436/// -o ofile positional arg after -f
5437/// -s selection file Last argument of the call
5438/// --fail_on_warning Wrap ROOT::TMetaUtils::Warning and throw if selected
5439///
5440/// New arguments:
5441/// -l --library targetLib name (new) -s targetLib name
5442/// -m pcmname (can be many -m) (new) -m pcmname (can be many -m)
5443/// --rootmap -rmf (new)
5444/// --rootmap-lib -rml (new)
5445///
5446/// genreflex options which rise warnings (feedback is desirable)
5447/// --no_membertypedefs (it should be irrelevant)
5448/// --no_templatetypedefs (it should be irrelevant)
5449///
5450/// genreflex options which are ignored (know for sure they are not needed)
5451/// --pool, --dataonly
5452/// --interpreteronly
5453/// --gccxml{path,opt,post}
5454///
5455///
5456/// Exceptions
5457/// The --deep option of genreflex is passed as function parameter to rootcling
5458/// since it's not needed at the moment there.
5459
5460int GenReflexMain(int argc, char **argv)
5461{
5462 using namespace genreflex;
5463
5464 // Setup the options parser
5465 enum optionIndex { UNKNOWN,
5467 OFILENAME,
5468 TARGETLIB,
5469 MULTIDICT,
5472 ROOTMAP,
5473 ROOTMAPLIB,
5475 DEEP,
5476 DEBUG,
5477 VERBOSE,
5478 QUIET,
5479 SILENT,
5480 CXXMODULE,
5482 HELP,
5486 SPLIT,
5490 // Don't show up in the help
5493 INCLUDE,
5494 WARNING
5495 };
5496
5497 enum optionTypes { NOTYPE, STRING } ;
5498
5499 // Some long help strings
5500 const char *genreflexUsage =
5501 "********************************************************************************\n"
5502 "* The genreflex utility does not allow to generate C++ modules containing *\n"
5503 "* reflection information required at runtime. Please use rootcling instead *\n"
5504 "* To print the rootcling invocation that corresponds to the current genreflex *\n"
5505 "* invocation please use the --print-rootcling-invocation flag. *\n"
5506 "********************************************************************************\n"
5507 "\n"
5508 "Generates dictionary sources and related ROOT pcm starting from an header.\n"
5509 "Usage: genreflex headerfile.h [opts] [preproc. opts]\n\n"
5510 "Options:\n";
5511
5512 const char *printRootclingInvocationUsage =
5513 "--print-rootcling-invocation\n"
5514 " Print to screen the rootcling invocation corresponding to the current \n"
5515 " genreflex invocation.\n";
5516
5517 const char *selectionFilenameUsage =
5518 "-s, --selection_file\tSelection filename\n"
5519 " Class selection file to specify for which classes the dictionary\n"
5520 " will be generated. The final set can be crafted with exclusion and\n"
5521 " exclusion rules.\n"
5522 " Properties can be specified. Some have special meaning:\n"
5523 " - name [string] name of the entity to select with an exact matching\n"
5524 " - pattern [string] name with wildcards (*) to select entities\n"
5525 " - file_name/file_pattern [string]: as name/pattern but referring to\n"
5526 " file where the C++ entities reside and not to C++ entities themselves.\n"
5527 " - transient/persistent [string: true/false] The fields to which they are\n"
5528 " applied will not be persistified if requested.\n"
5529 " - comment [string]: what you could write in code after an inline comment\n"
5530 " without \"//\". For example comment=\"!\" or \"||\".\n"
5531 " - noStreamer [true/false]: turns off streamer generation if set to 'true.'\n"
5532 " Default value is 'false'\n"
5533 " - rntupleStreamerMode [true/false]: enforce streamed or native writing for RNTuple.\n"
5534 " If unset, RNTuple stores classes in split mode or fails if the class cannot be split.\n"
5535 " - noInputOperator [true/false]: turns off input operator generation if set\n"
5536 " to 'true'. Default value is 'false'\n"
5537 " Example XML:\n"
5538 " <lcgdict>\n"
5539 " [<selection>]\n"
5540 " <class [name=\"classname\"] [pattern=\"wildname\"]\n"
5541 " [file_name=\"filename\"] [file_pattern=\"wildname\"]\n"
5542 " [id=\"xxxx\"] [noStreamer=\"true/false\"]\n"
5543 " [noInputOperator=\"true/false\"]\n"
5544 " [rntupleStreamerMode=\"true/false\"] />\n"
5545 " <class name=\"classname\" >\n"
5546 " <field name=\"m_transient\" transient=\"true\"/>\n"
5547 " <field name=\"m_anothertransient\" persistent=\"false\"/>\n"
5548 " <field name=\"m_anothertransient\" comment=\"||\"/>\n"
5549 " <properties prop1=\"value1\" [prop2=\"value2\"]/>\n"
5550 " </class>\n"
5551 " <function [name=\"funcname\"] [pattern=\"wildname\"] />\n"
5552 " <enum [name=\"enumname\"] [pattern=\"wildname\"] />\n"
5553 " <variable [name=\"varname\"] [pattern=\"wildname\"] />\n"
5554 " [</selection>]\n"
5555 " <exclusion>\n"
5556 " <class [name=\"classname\"] [pattern=\"wildname\"] />\n"
5557 " <method name=\"unwanted\" />\n"
5558 " </class>\n"
5559 " ...\n"
5560 " </lcgdict>\n"
5561 "\n"
5562 " If no selection file is specified, the class with the filename without\n"
5563 " extension will be selected, i.e. myClass.h as argument without any\n"
5564 " selection xml comes with an implicit selection rule for class \"myClass\".\n";
5565
5566 const char *outputFilenameUsage =
5567 "-o, --output\tOutput filename\n"
5568 " Output file name. If an existing directory is specified instead of a file,\n"
5569 " then a filename will be built using the name of the input file and will\n"
5570 " be placed in the given directory. <headerfile>_rflx.cpp.\n"
5571 " NOTA BENE: the dictionaries that will be used within the same project must\n"
5572 " have unique names.\n";
5573
5574
5575 const char *targetLib =
5576 "-l, --library\tTarget library\n"
5577 " The flag -l must be followed by the name of the library that will\n"
5578 " contain the object file corresponding to the dictionary produced by\n"
5579 " this invocation of genreflex.\n"
5580 " The name takes priority over the one specified for the rootmapfile.\n"
5581 " The name influences the name of the created pcm:\n"
5582 " 1) If it is not specified, the pcm is called libINPUTHEADER_rdict.pcm\n"
5583 " 2) If it is specified, the pcm is called libTARGETLIBRARY_rdict.pcm\n"
5584 " Any \"liblib\" occurrence is transformed in the expected \"lib\".\n"
5585 " 3) If this is specified in conjunction with --multiDict, the output is\n"
5586 " libTARGETLIBRARY_DICTIONARY_rdict.pcm\n";
5587
5588 const char *rootmapUsage =
5589 "--rootmap\tGenerate the rootmap file to be used by ROOT.\n"
5590 " This file lists the autoload keys. For example classes for which the\n"
5591 " reflection information is provided.\n"
5592 " The format of the rootmap is the following:\n"
5593 " - Forward declarations section\n"
5594 " - Libraries sections\n"
5595 " Rootmaps can be concatenated together, for example with the cat util.\n"
5596 " In order for ROOT to pick up the information in the rootmaps, they\n"
5597 " have to be located in the library path and have the .rootmap extension.\n"
5598 " An example rootmap file could be:\n"
5599 " { decls }\n"
5600 " template <class T> class A;\n"
5601 " [ libMyLib.so ]\n"
5602 " class A<double>\n"
5603 " class B\n"
5604 " typedef C\n"
5605 " header H.h\n";
5606
5607 const char *rootmapLibUsage =
5608 "--rootmap-lib\tLibrary name for the rootmap file.\n";
5609
5610 // The Descriptor
5612
5613 {
5614 UNKNOWN,
5615 NOTYPE,
5616 "", "",
5619 },
5620
5621 {
5623 NOTYPE,
5624 "", "print-rootcling-invocation",
5627 },
5628
5629 {
5630 OFILENAME,
5631 STRING ,
5632 "o" , "output" ,
5635 },
5636
5637 {
5638 TARGETLIB,
5639 STRING ,
5640 "l" , "library" ,
5642 targetLib
5643 },
5644
5645 {
5646 MULTIDICT,
5647 NOTYPE ,
5648 "" , "multiDict" ,
5650 "--multiDict\tSupport for many dictionaries in one library\n"
5651 " Form correct pcm names if multiple dictionaries will be in the same\n"
5652 " library (needs target library switch. See its documentation).\n"
5653 },
5654
5655
5656 {
5658 NOTYPE ,
5659 "" , "noGlobalUsingStd" ,
5661 "--noGlobalUsingStd\tDo not declare {using namespace std} in the dictionary global scope\n"
5662 " All header files must have sumbols from std:: namespace fully qualified\n"
5663 },
5664
5665 {
5667 STRING ,
5668 "s" , "selection_file" ,
5671 },
5672
5673 {
5674 ROOTMAP,
5675 STRING ,
5676 "" , "rootmap" ,
5679 },
5680
5681 {
5682 ROOTMAPLIB,
5683 STRING ,
5684 "" , "rootmap-lib" ,
5687 },
5688
5689 {
5691 NOTYPE,
5692 "" , "interpreteronly",
5694 "--interpreteronly\tDo not generate I/O related information.\n"
5695 " Generate minimal dictionary required for interactivity.\n"
5696 },
5697
5698 {
5699 SPLIT,
5700 NOTYPE,
5701 "" , "split",
5703 "--split\tSplit the dictionary\n"
5704 " Split in two the dictionary, isolating the part with\n"
5705 " ClassDef related functions in a separate file.\n"
5706 },
5707
5708 {
5710 STRING ,
5711 "m" , "" ,
5713 "-m \tPcm file loaded before any header (option can be repeated).\n"
5714 },
5715
5716 {
5717 VERBOSE,
5718 NOTYPE ,
5719 "-v" , "verbose",
5721 "-v, --verbose\tPrint some debug information.\n"
5722 },
5723
5724 {
5725 DEBUG,
5726 NOTYPE ,
5727 "" , "debug",
5729 "--debug\tPrint all debug information.\n"
5730 },
5731
5732 {
5733 QUIET,
5734 NOTYPE ,
5735 "" , "quiet",
5737 "--quiet\tPrint only warnings and errors (default).\n"
5738 },
5739
5740 {
5741 SILENT,
5742 NOTYPE ,
5743 "" , "silent",
5745 "--silent\tPrint no information at all.\n"
5746 },
5747
5748 {
5750 NOTYPE ,
5751 "" , "writeEmptyPCM",
5753 "--writeEmptyPCM\tWrite an empty ROOT pcm.\n"
5754 },
5755
5756 {
5757 CXXMODULE,
5758 NOTYPE ,
5759 "" , "cxxmodule",
5761 "--cxxmodule\tGenerates a PCM for C++ Modules.\n"
5762 },
5763
5764
5765 {
5766 HELP,
5767 NOTYPE,
5768 "h" , "help",
5770 "--help\tPrint usage and exit.\n"
5771 },
5772
5773 {
5775 NOTYPE,
5776 "", "fail_on_warnings",
5778 "--fail_on_warnings\tFail on warnings and errors.\n"
5779 },
5780
5781 {
5783 NOTYPE,
5784 "", "selSyntaxOnly",
5786 "--selSyntaxOnly\tValidate selection file w/o generating the dictionary.\n"
5787 },
5788
5789 {
5791 NOTYPE ,
5792 "" , "noIncludePaths",
5794 "--noIncludePaths\tDo not store the headers' directories in the dictionary. Instead, rely on the environment variable $ROOT_INCLUDE_PATH at runtime.\n"
5795 },
5796
5797 // Left intentionally empty not to be shown in the help, like in the first genreflex
5798 {
5799 INCLUDE,
5800 STRING ,
5801 "I" , "" ,
5803 ""
5804 },
5805
5806 {
5808 STRING ,
5809 "D" , "" ,
5811 ""
5812 },
5813
5814 {
5816 STRING ,
5817 "U" , "" ,
5819 ""
5820 },
5821
5822 {
5823 WARNING,
5824 STRING ,
5825 "W" , "" ,
5827 ""
5828 },
5829
5830 {
5831 NOMEMBERTYPEDEFS, // Option which is not meant for the user: deprecated
5832 STRING ,
5833 "" , "no_membertypedefs" ,
5835 ""
5836 },
5837
5838 {
5839 NOTEMPLATETYPEDEFS, // Option which is not meant for the user: deprecated
5840 STRING ,
5841 "" , "no_templatetypedefs" ,
5843 ""
5844 },
5845
5846 {0, 0, nullptr, nullptr, nullptr, nullptr}
5847 };
5848
5849 std::vector<std::string> headersNames;
5850 const int originalArgc = argc;
5851 // The only args are the headers here
5852 const int extractedArgs = extractArgs(argc, argv, headersNames);
5853
5854 const int offset = 1; // skip argv[0]
5856 argv += offset;
5857
5858 // Parse the options
5860 std::vector<ROOT::option::Option> options(stats.options_max);// non POD var size arrays are not C++!
5861 std::vector<ROOT::option::Option> buffer(stats.buffer_max);
5862 // The 4 is the minimum size of the abbreviation length.
5863 // For example, --selection_file can be abbreviated with --sele at least.
5864
5865 ROOT::option::Parser parse(genreflexUsageDescriptor, argc, argv, &options[0], &buffer[0], 5);
5866
5867 if (parse.error()) {
5868 ROOT::TMetaUtils::Error(nullptr, "Argument parsing error!\n");
5869 return 1;
5870 }
5871
5872 // Print help if needed
5873 if (options[HELP] || originalArgc == 1) {
5875 return 0;
5876 }
5877 // See if no header was provided
5878 int numberOfHeaders = checkHeadersNames(headersNames);
5879 if (0 == numberOfHeaders) {
5880 ROOT::TMetaUtils::Error(nullptr, "No valid header was provided!\n");
5881 return 1;
5882 }
5883
5885
5886 if (options[DEEP])
5887 ROOT::TMetaUtils::Warning(nullptr, "--deep has no effect. Please remove the deprecated flag!\n");
5888 // The verbosity: debug wins over quiet
5889 //std::string verbosityOption("-v4"); // To be uncommented for the testing phase. It should be -v
5890 std::string verbosityOption("-v2");
5891 if (options[SILENT]) verbosityOption = "-v0";
5892 if (options[VERBOSE] || std::getenv ("VERBOSE")) verbosityOption = "-v3";
5893 if (options[DEBUG]) verbosityOption = "-v4";
5894
5896
5897 // The selection file
5898 std::string selectionFileName;
5899 if (options[SELECTIONFILENAME]) {
5900 selectionFileName = options[SELECTIONFILENAME].arg;
5903 "Invalid selection file extension: filename is %s and extension .xml is expected!\n",
5904 selectionFileName.c_str());
5905 return 1;
5906 }
5907 }
5908
5909// // Warn if a selection file is not present and exit
5910// if (NULL==options[SELECTIONFILENAME].arg){
5911// ROOT::TMetaUtils::Warning(0,"The usage of genreflex without a selection file is not yet supported.\n");
5912// return 1;
5913// }
5914
5915
5916 // Set the parameters for the rootmap file. If the libname is not set,
5917 // it will be set according to the header in invokeRootCling.
5918 // FIXME: treatment of directories
5919 std::string rootmapFileName(options[ROOTMAP].arg ? options[ROOTMAP].arg : "");
5920 std::string rootmapLibName(options[ROOTMAPLIB].arg ? options[ROOTMAPLIB].arg : "");
5921
5922 // The target lib name
5923 std::string targetLibName;
5924 if (options[TARGETLIB]) {
5925 targetLibName = options[TARGETLIB].arg;
5928 "Invalid target library extension: filename is %s and extension %s is expected!\n",
5929 targetLibName.c_str(),
5930 gLibraryExtension.c_str());
5931 }
5932 // Target lib has precedence over rootmap lib
5933 if (options[ROOTMAP]) {
5935 }
5936 }
5937
5938 bool isCxxmodule = options[CXXMODULE];
5939
5940 bool multidict = false;
5941 if (options[MULTIDICT]) multidict = true;
5942
5943 bool noGlobalUsingStd = false;
5944 if (options[NOGLOBALUSINGSTD]) noGlobalUsingStd = true;
5945
5946 if (multidict && targetLibName.empty()) {
5948 "Multilib support is requested but no target lib is specified. A sane pcm name cannot be formed.\n");
5949 return 1;
5950 }
5951
5952 bool printRootclingInvocation = false;
5953 if (options[PRINTROOTCLINGINVOCATION])
5955
5956 bool interpreteronly = false;
5957 if (options[INTERPRETERONLY])
5958 interpreteronly = true;
5959
5960 bool doSplit = false;
5961 if (options[SPLIT])
5962 doSplit = true;
5963
5964 bool writeEmptyRootPCM = false;
5965 if (options[WRITEEMPTYROOTPCM])
5966 writeEmptyRootPCM = true;
5967
5968 bool selSyntaxOnly = false;
5969 if (options[SELSYNTAXONLY]) {
5970 selSyntaxOnly = true;
5971 }
5972
5973 bool noIncludePaths = false;
5974 if (options[NOINCLUDEPATHS]) {
5975 noIncludePaths = true;
5976 }
5977
5978 bool failOnWarnings = false;
5979 if (options[FAILONWARNINGS]) {
5980 failOnWarnings = true;
5981 }
5982
5983 // Add the .so extension to the rootmap lib if not there
5986 }
5987
5988 // The list of pcms to be preloaded
5989 std::vector<std::string> pcmsNames;
5991
5992 // Preprocessor defines
5993 std::vector<std::string> preprocDefines;
5995
5996 // Preprocessor undefines
5997 std::vector<std::string> preprocUndefines;
5999
6000 // Includes
6001 std::vector<std::string> includes;
6003
6004 // Warnings
6005 std::vector<std::string> warnings;
6006 extractMultipleOptions(options, WARNING, warnings);
6007
6008 // The outputfilename(s)
6009 // There are two cases:
6010 // 1) The outputfilename is specified
6011 // --> The information of all headers will be in one single dictionary
6012 // (1 call to rootcling)
6013 // 2) The outputfilename is not specified
6014 // --> There will be a dictionary per header
6015 // (N calls to rootcling)
6016 int returnValue = 0;
6017 std::string ofileName(options[OFILENAME] ? options[OFILENAME].arg : "");
6018
6019 // If not empty and not a directory (therefore it's a file)
6020 // call rootcling directly. The number of headers files is irrelevant.
6021 if (!ofileName.empty() && !llvm::sys::fs::is_directory(ofileName)) {
6022 returnValue = invokeRootCling(verbosityOption,
6025 multidict,
6026 pcmsNames,
6027 includes,
6030 warnings,
6034 doSplit,
6043 ofileName);
6044 } else {
6045 // Here ofilename is either "" or a directory: this is irrelevant.
6046 returnValue = invokeManyRootCling(verbosityOption,
6049 multidict,
6050 pcmsNames,
6051 includes,
6054 warnings,
6058 doSplit,
6067 ofileName);
6068 }
6069
6070 return returnValue;
6071}
6072
6073
6074////////////////////////////////////////////////////////////////////////////////
6075
6076extern "C"
6078{
6079
6080 assert(!gDriverConfig && "Driver configuration already set!");
6081 gDriverConfig = &config;
6082
6083 gBuildingROOT = config.fBuildingROOTStage1; // gets refined later
6084
6085 std::string exeName = ExtractFileName(GetExePath());
6086#ifdef __APPLE__
6087 // _dyld_get_image_name() on macOS11 and later sometimes returns "rootcling" for "genreflex".
6088 // Fix that (while still initializing the binary path, needed for ROOTSYS) by updating the
6089 // exeName to argv[0]:
6091#endif
6092
6093 // Select according to the name of the executable the procedure to follow:
6094 // 1) RootCling
6095 // 2) GenReflex
6096 // The default is rootcling
6097
6098 int retVal = 0;
6099
6100 if (std::string::npos != exeName.find("genreflex"))
6102 else // rootcling or default
6104
6105 gDriverConfig = nullptr;
6106
6108 ROOT::TMetaUtils::Info(nullptr,"Problems have been detected during the generation of the dictionary.\n");
6109 return 1;
6110 }
6111 return retVal;
6112}
Select classes and assign properties using C++ syntax.
The file contains utilities which are foundational and could be used across the core component of ROO...
This is the only file required to use The Lean Mean C++ Option Parser.
#define DEBUG
#define d(i)
Definition RSha256.hxx:102
#define b(i)
Definition RSha256.hxx:100
#define c(i)
Definition RSha256.hxx:101
#define a(i)
Definition RSha256.hxx:99
#define h(i)
Definition RSha256.hxx:106
#define e(i)
Definition RSha256.hxx:103
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
Basic types used by ROOT and required by TInterpreter.
#define X(type, name)
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
void Info(const char *location, const char *msgfmt,...)
Use this function for informational messages.
Definition TError.cxx:241
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t dest
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char filename
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h offset
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t UChar_t len
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t attr
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
char name[80]
Definition TGX11.cxx:110
const char * proto
Definition civetweb.c:18822
#define free
Definition civetweb.c:1578
#define snprintf
Definition civetweb.c:1579
std::unordered_map< std::string, std::string > AttributesMap_t
Custom diag client for clang that verifies that each implicitly build module is a system module.
void HandleDiagnostic(clang::DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &Info) override
CheckModuleBuildClient(clang::DiagnosticConsumer *Child, bool OwnsChild, clang::ModuleMap &Map)
clang::DiagnosticConsumer * fChild
bool IncludeInDiagnosticCounts() const override
void EndSourceFile() override
void BeginSourceFile(const clang::LangOptions &LangOpts, const clang::Preprocessor *PP) override
clang::ModuleMap & fMap
static RStl & Instance()
Definition RStl.cxx:40
const_iterator begin() const
const_iterator end() const
const clang::RecordDecl * GetRecordDecl() const
A parsed option from the command line together with its argument if it has one.
Checks argument vectors for validity and parses them into data structures that are easier to work wit...
bool error()
Returns true if an unrecoverable error occurred while parsing options.
void Scan(const clang::ASTContext &C)
Definition Scanner.cxx:1050
std::vector< ROOT::TMetaUtils::AnnotatedRecordDecl > ClassColl_t
Definition Scanner.h:72
const DeclsSelRulesMap_t & GetDeclsSelRulesMap() const
Definition Scanner.h:125
FunctionColl_t fSelectedFunctions
Definition Scanner.h:131
std::vector< const clang::FunctionDecl * > FunctionColl_t
Definition Scanner.h:74
NamespaceColl_t fSelectedNamespaces
Definition Scanner.h:129
TypedefColl_t fSelectedTypedefs
Definition Scanner.h:130
DeclCallback SetRecordDeclCallback(DeclCallback callback)
Set the callback to the RecordDecl and return the previous one.
Definition Scanner.cxx:1083
std::map< const clang::Decl *, const BaseSelectionRule * > DeclsSelRulesMap_t
Definition Scanner.h:78
EnumColl_t fSelectedEnums
Definition Scanner.h:133
std::vector< const clang::TypedefNameDecl * > TypedefColl_t
Definition Scanner.h:73
std::vector< const clang::VarDecl * > VariableColl_t
Definition Scanner.h:75
static bool GetDeclQualName(const clang::Decl *D, std::string &qual_name)
Definition Scanner.cxx:998
VariableColl_t fSelectedVariables
Definition Scanner.h:132
std::vector< const clang::EnumDecl * > EnumColl_t
Definition Scanner.h:76
ClassColl_t fSelectedClasses
Definition Scanner.h:128
The class representing the collection of selection rules.
void InclusionDirective(clang::SourceLocation, const clang::Token &, llvm::StringRef FileName, bool IsAngled, clang::CharSourceRange, clang::OptionalFileEntryRef, llvm::StringRef, llvm::StringRef, const clang::Module *, 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.
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