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