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