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