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