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