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