Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
rootcling_impl.cxx
Go to the documentation of this file.
1// Authors: Axel Naumann, Philippe Canal, Danilo Piparo
2
3/*************************************************************************
4 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
5 * All rights reserved. *
6 * *
7 * For the licensing terms see $ROOTSYS/LICENSE. *
8 * For the list of contributors see $ROOTSYS/README/CREDITS. *
9 *************************************************************************/
10
11#include "rootcling_impl.h"
12#include "rootclingCommandLineOptionsHelp.h"
13
14#include "RConfigure.h"
15#include <ROOT/RConfig.hxx>
17#include "snprintf.h"
18
19#include <iostream>
20#include <iomanip>
21#include <memory>
22#include <vector>
23#include <algorithm>
24#include <cstdio>
25
26#include <errno.h>
27#include <string>
28#include <list>
29#include <sstream>
30#include <map>
31#include <fstream>
32#include <sys/stat.h>
33#include <unordered_map>
34#include <unordered_set>
35#include <numeric>
36
37
38#ifdef _WIN32
39#ifdef system
40#undef system
41#endif
42#undef UNICODE
43#include <windows.h>
44#include <Tlhelp32.h> // for MAX_MODULE_NAME32
45#include <process.h>
46#define PATH_MAX _MAX_PATH
47#ifdef interface
48// prevent error coming from clang/AST/Attrs.inc
49#undef interface
50#endif
51#endif
52
53#ifdef __APPLE__
54#include <mach-o/dyld.h>
55#endif
56
57#ifdef R__FBSD
58#include <sys/param.h>
59#include <sys/user.h>
60#include <sys/types.h>
61#include <libutil.h>
62#include <libprocstat.h>
63#endif // R__FBSD
64
65#if !defined(R__WIN32)
66#include <limits.h>
67#include <unistd.h>
68#endif
69
70
71#include "cling/Interpreter/Interpreter.h"
72#include "cling/Interpreter/InterpreterCallbacks.h"
73#include "cling/Interpreter/LookupHelper.h"
74#include "cling/Interpreter/Value.h"
75#include "clang/AST/CXXInheritance.h"
76#include "clang/Basic/Diagnostic.h"
77#include "clang/Frontend/CompilerInstance.h"
78#include "clang/Frontend/FrontendActions.h"
79#include "clang/Frontend/FrontendDiagnostic.h"
80#include "clang/Lex/HeaderSearch.h"
81#include "clang/Lex/Preprocessor.h"
82#include "clang/Lex/ModuleMap.h"
83#include "clang/Lex/Pragma.h"
84#include "clang/Sema/Sema.h"
85#include "clang/Serialization/ASTWriter.h"
86#include "cling/Utils/AST.h"
87
88#include "llvm/ADT/StringRef.h"
89
90#include "llvm/Support/CommandLine.h"
91#include "llvm/Support/Path.h"
92#include "llvm/Support/PrettyStackTrace.h"
93#include "llvm/Support/Signals.h"
94
95#include "RtypesCore.h"
96#include "TModuleGenerator.h"
97#include "TClassEdit.h"
98#include "TClingUtils.h"
99#include "RStl.h"
100#include "XMLReader.h"
101#include "LinkdefReader.h"
102#include "DictSelectionReader.h"
103#include "SelectionRules.h"
104#include "Scanner.h"
105#include "strlcpy.h"
106
107#include "OptionParser.h"
108
109#ifdef WIN32
110const std::string gLibraryExtension(".dll");
111#else
112const std::string gLibraryExtension(".so"); // no dylib for the moment
113#endif
115
116#ifdef __APPLE__
117#include <mach-o/dyld.h>
118#endif
119
120#if defined(R__WIN32)
121#include "cygpath.h"
122#define strcasecmp _stricmp
123#define strncasecmp _strnicmp
124#else
125#include <unistd.h>
126#endif
127
128bool gBuildingROOT = false;
130
131#define rootclingStringify(s) rootclingStringifyx(s)
132#define rootclingStringifyx(s) #s
133
134// Maybe too ugly? let's see how it performs.
135using HeadersDeclsMap_t = std::map<std::string, std::list<std::string>>;
136
137using namespace ROOT;
138
139using std::string, std::map, std::ifstream, std::ofstream, std::endl, std::ios, std::vector;
140
141namespace genreflex {
142 bool verbose = false;
143}
144
145////////////////////////////////////////////////////////////////////////////////
146
147static llvm::cl::OptionCategory gRootclingOptions("rootcling common options");
148
149 // FIXME: We should remove after removal of r flag.
150static llvm::cl::opt<bool>
152 llvm::cl::desc("Deprecated. Similar to -f but it ignores the dictionary generation. \
153When -r is present rootcling becomes a tool to generate rootmaps (and capability files)."),
154 llvm::cl::Hidden,
155 llvm::cl::cat(gRootclingOptions));
156
157////////////////////////////////////////////////////////////////////////////////
158
159void SetRootSys();
160
162 // rootcling's libCore needs "our" ROOTSYS:
163 SetRootSys();
164};
165
166////////////////////////////////////////////////////////////////////////////////
167
168void EmitStreamerInfo(const char *normName)
169{
170 if (gDriverConfig->fAddStreamerInfoToROOTFile)
171 gDriverConfig->fAddStreamerInfoToROOTFile(normName);
172}
173static void EmitTypedefs(const std::vector<const clang::TypedefNameDecl *> &tdvec)
174{
175 if (!gDriverConfig->fAddTypedefToROOTFile)
176 return;
177 for (const auto td : tdvec)
178 gDriverConfig->fAddTypedefToROOTFile(td->getQualifiedNameAsString().c_str());
179}
180static void EmitEnums(const std::vector<const clang::EnumDecl *> &enumvec)
181{
182 if (!gDriverConfig->fAddEnumToROOTFile)
183 return;
184 for (const auto en : enumvec) {
185 // Enums within tag decls are processed as part of the tag.
186 if (clang::isa<clang::TranslationUnitDecl>(en->getDeclContext())
187 || clang::isa<clang::LinkageSpecDecl>(en->getDeclContext())
188 || clang::isa<clang::NamespaceDecl>(en->getDeclContext()))
189 gDriverConfig->fAddEnumToROOTFile(en->getQualifiedNameAsString().c_str());
190 }
191}
192
193////////////////////////////////////////////////////////////////////////////////
194/// Returns the executable path name, used e.g. by SetRootSys().
195
196const char *GetExePath()
197{
198 static std::string exepath;
199 if (exepath == "") {
200#ifdef __APPLE__
202#endif
203#if defined(__linux) || defined(__linux__)
204 char linkname[PATH_MAX]; // /proc/<pid>/exe
205 char buf[PATH_MAX]; // exe path name
206 pid_t pid;
207
208 // get our pid and build the name of the link in /proc
209 pid = getpid();
210 snprintf(linkname, PATH_MAX, "/proc/%i/exe", pid);
211 int ret = readlink(linkname, buf, 1024);
212 if (ret > 0 && ret < 1024) {
213 buf[ret] = 0;
214 exepath = buf;
215 }
216#endif
217#if defined(R__FBSD)
220
221 if (kp!=NULL) {
222 char path_str[PATH_MAX] = "";
225 }
226
227 free(kp);
228 procstat_close(ps);
229#endif
230#ifdef _WIN32
231 char *buf = new char[MAX_MODULE_NAME32 + 1];
232 ::GetModuleFileName(NULL, buf, MAX_MODULE_NAME32 + 1);
233 char *p = buf;
234 while ((p = strchr(p, '\\')))
235 * (p++) = '/';
236 exepath = buf;
237 delete[] buf;
238#endif
239 }
240 return exepath.c_str();
241}
242
243////////////////////////////////////////////////////////////////////////////////
244
245bool Namespace__HasMethod(const clang::NamespaceDecl *cl, const char *name,
246 const cling::Interpreter &interp)
247{
249}
250
251////////////////////////////////////////////////////////////////////////////////
252
253static void AnnotateFieldDecl(clang::FieldDecl &decl,
254 const std::list<VariableSelectionRule> &fieldSelRules)
255{
256 using namespace ROOT::TMetaUtils;
257 // See if in the VariableSelectionRules there are attributes and names with
258 // which we can annotate.
259 // We may look for a smarter algorithm.
260
261 // Nothing to do then ...
262 if (fieldSelRules.empty()) return;
263
264 clang::ASTContext &C = decl.getASTContext();
265
266 const std::string declName(decl.getNameAsString());
267 std::string varName;
268 for (std::list<VariableSelectionRule>::const_iterator it = fieldSelRules.begin();
269 it != fieldSelRules.end(); ++it) {
270 if (! it->GetAttributeValue(propNames::name, varName)) continue;
271 if (declName == varName) { // we have the rule!
272 // Let's extract the attributes
273 BaseSelectionRule::AttributesMap_t attrMap(it->GetAttributes());
274 BaseSelectionRule::AttributesMap_t::iterator iter;
275 std::string userDefinedProperty;
276 for (iter = attrMap.begin(); iter != attrMap.end(); ++iter) {
277 const std::string &name = iter->first;
278 const std::string &value = iter->second;
279
280 if (name == propNames::name) continue;
281
282 /* This test is here since in ROOT5, when using genreflex,
283 * for pods, iotype is ignored */
284
285 if (name == propNames::iotype &&
286 (decl.getType()->isArrayType() || decl.getType()->isPointerType())) {
287 const char *msg = "Data member \"%s\" is an array or a pointer. "
288 "It is not possible to assign to it the iotype \"%s\". "
289 "This transformation is possible only with data members "
290 "which are not pointers or arrays.\n";
291 ROOT::TMetaUtils::Error("AnnotateFieldDecl",
292 msg, varName.c_str(), value.c_str());
293 continue;
294 }
295
296
297 // These lines are here to use the root pcms. Indeed we need to annotate the AST
298 // before persisting the ProtoClasses in the root pcms.
299 // BEGIN ROOT PCMS
300 if (name == propNames::comment) {
301 decl.addAttr(clang::AnnotateAttr::CreateImplicit(C, value, nullptr, 0));
302 }
303 // END ROOT PCMS
304
305 if ((name == propNames::transient && value == "true") ||
306 (name == propNames::persistent && value == "false")) { // special case
307 userDefinedProperty = propNames::comment + propNames::separator + "!";
308 // This next line is here to use the root pcms. Indeed we need to annotate the AST
309 // before persisting the ProtoClasses in the root pcms.
310 // BEGIN ROOT PCMS
311 decl.addAttr(clang::AnnotateAttr::CreateImplicit(C, "!", nullptr, 0));
312 // END ROOT PCMS
313 // The rest of the lines are not changed to leave in place the system which
314 // works with bulk header parsing on library load.
315 } else {
316 userDefinedProperty = name + propNames::separator + value;
317 }
318 ROOT::TMetaUtils::Info(nullptr, "%s %s\n", varName.c_str(), userDefinedProperty.c_str());
319 decl.addAttr(clang::AnnotateAttr::CreateImplicit(C, userDefinedProperty, nullptr, 0));
320 }
321 }
322 }
323}
324
325////////////////////////////////////////////////////////////////////////////////
326
327void AnnotateDecl(clang::CXXRecordDecl &CXXRD,
329 cling::Interpreter &interpreter,
330 bool isGenreflex)
331{
332 // In order to store the meaningful for the IO comments we have to transform
333 // the comment into annotation of the given decl.
334 // This works only with comments in the headers, so no selection rules in an
335 // xml file.
336
337 using namespace clang;
339 llvm::StringRef comment;
340
341 ASTContext &C = CXXRD.getASTContext();
342
343 // Fetch the selection rule associated to this class
344 clang::Decl *declBaseClassPtr = static_cast<clang::Decl *>(&CXXRD);
345 auto declSelRulePair = declSelRulesMap.find(declBaseClassPtr->getCanonicalDecl());
347 const std::string thisClassName(CXXRD.getName());
348 ROOT::TMetaUtils::Error("AnnotateDecl","Cannot find class %s in the list of selected classes.\n",thisClassName.c_str());
349 return;
350 }
352 // If the rule is there
354 // Fetch and loop over Class attributes
355 // if the name of the attribute is not "name", add attr to the ast.
356 BaseSelectionRule::AttributesMap_t::iterator iter;
357 std::string userDefinedProperty;
358 for (auto const & attr : thisClassBaseSelectionRule->GetAttributes()) {
359 const std::string &name = attr.first;
361 const std::string &value = attr.second;
363 if (genreflex::verbose) std::cout << " * " << userDefinedProperty << std::endl;
364 CXXRD.addAttr(AnnotateAttr::CreateImplicit(C, userDefinedProperty, nullptr, 0));
365 }
366 }
367
368 // See if the rule is a class selection rule (FIX dynamic_cast)
370
371 for (CXXRecordDecl::decl_iterator I = CXXRD.decls_begin(),
372 E = CXXRD.decls_end(); I != E; ++I) {
373
374 // CXXMethodDecl,FieldDecl and VarDecl inherit from NamedDecl
375 // See: http://clang.llvm.org/doxygen/classclang_1_1DeclaratorDecl.html
376 if (!(*I)->isImplicit()
378
379 // For now we allow only a special macro (ClassDef) to have meaningful comments
381 if (isClassDefMacro) {
382 while (isa<NamedDecl>(*I) && cast<NamedDecl>(*I)->getName() != "DeclFileLine") {
383 ++I;
384 }
385 }
386
388 if (comment.size()) {
389 // The ClassDef annotation is for the class itself
390 if (isClassDefMacro) {
391 CXXRD.addAttr(AnnotateAttr::CreateImplicit(C, comment.str(), nullptr, 0));
392 } else if (!isGenreflex) {
393 // Here we check if we are in presence of a selection file so that
394 // the comment does not ends up as a decoration in the AST,
395 // Nevertheless, w/o PCMS this has no effect, since the headers
396 // are parsed at runtime and the information in the AST dumped by
397 // rootcling is not relevant.
398 (*I)->addAttr(AnnotateAttr::CreateImplicit(C, comment.str(), nullptr, 0));
399 }
400 }
401 // Match decls with sel rules if we are in presence of a selection file
402 // and the cast was successful
403 if (isGenreflex && thisClassSelectionRule != nullptr) {
404 const std::list<VariableSelectionRule> &fieldSelRules = thisClassSelectionRule->GetFieldSelectionRules();
405
406 // This check is here to avoid asserts in debug mode (LLVMDEV env variable set)
409 }
410 } // End presence of XML selection file
411 }
412 }
413}
414
415////////////////////////////////////////////////////////////////////////////////
416
417size_t GetFullArrayLength(const clang::ConstantArrayType *arrayType)
418{
419 if (!arrayType)
420 return 0;
421 llvm::APInt len = arrayType->getSize();
422 while (const clang::ConstantArrayType *subArrayType = llvm::dyn_cast<clang::ConstantArrayType>(arrayType->getArrayElementTypeNoTypeQual())) {
423 len *= subArrayType->getSize();
425 }
426 return len.getLimitedValue();
427}
428
429////////////////////////////////////////////////////////////////////////////////
430
431bool InheritsFromTObject(const clang::RecordDecl *cl,
432 const cling::Interpreter &interp)
433{
434 static const clang::CXXRecordDecl *TObject_decl
435 = ROOT::TMetaUtils::ScopeSearch("TObject", interp, true /*diag*/, nullptr);
436
437 const clang::CXXRecordDecl *clxx = llvm::dyn_cast<clang::CXXRecordDecl>(cl);
439}
440
441////////////////////////////////////////////////////////////////////////////////
442
443bool InheritsFromTSelector(const clang::RecordDecl *cl,
444 const cling::Interpreter &interp)
445{
446 static const clang::CXXRecordDecl *TObject_decl
447 = ROOT::TMetaUtils::ScopeSearch("TSelector", interp, false /*diag*/, nullptr);
448
449 return ROOT::TMetaUtils::IsBase(llvm::dyn_cast<clang::CXXRecordDecl>(cl), TObject_decl, nullptr, interp);
450}
451
452////////////////////////////////////////////////////////////////////////////////
453
454bool IsSelectionXml(const char *filename)
455{
456 size_t len = strlen(filename);
457 size_t xmllen = 4; /* strlen(".xml"); */
458 if (strlen(filename) >= xmllen) {
459 return (0 == strcasecmp(filename + (len - xmllen), ".xml"));
460 } else {
461 return false;
462 }
463}
464
465////////////////////////////////////////////////////////////////////////////////
466
467bool IsLinkdefFile(const clang::PresumedLoc& PLoc)
468{
469 return ROOT::TMetaUtils::IsLinkdefFile(PLoc.getFilename());
470}
471
472////////////////////////////////////////////////////////////////////////////////
473
478
479////////////////////////////////////////////////////////////////////////////////
480/// Set the ROOTSYS env var based on the executable location.
481
483{
484 const char *exepath = GetExePath();
485 if (exepath && *exepath) {
486#if !defined(_WIN32)
487 char *ep = new char[PATH_MAX];
488 if (!realpath(exepath, ep)) {
489 fprintf(stderr, "rootcling: error getting realpath of rootcling!");
491 }
492#else
493 int nche = strlen(exepath) + 1;
494 char *ep = new char[nche];
496#endif
497 char *s;
498
499 if ((s = strrchr(ep, '/'))) {
500 // $ROOTSYS/bin/rootcling
501 int removesubdirs = 2;
502 if (!strncmp(s + 1, "rootcling_stage1.exe", 20)) {
503 // $ROOTSYS/bin/rootcling_stage1.exe
504 removesubdirs = 2;
505 gBuildingROOT = true;
506 } else if (!strncmp(s + 1, "rootcling_stage1", 16)) {
507 // $ROOTSYS/core/rootcling_stage1/src/rootcling_stage1
508 removesubdirs = 4;
509 gBuildingROOT = true;
510 }
511 for (int i = 1; s && i < removesubdirs; ++i) {
512 *s = 0;
513 s = strrchr(ep, '/');
514 }
515 if (s) *s = 0;
516 } else {
517 // There was no slashes at all let now change ROOTSYS
518 delete [] ep;
519 return;
520 }
521
522 if (!gBuildingROOT) {
523 delete [] ep;
524 return; // don't mess with user's ROOTSYS.
525 }
526
527 int ncha = strlen(ep) + 10;
528 char *env = new char[ncha];
529 snprintf(env, ncha, "ROOTSYS=%s", ep);
530
531 if (gDriverConfig) {
532 // After the putenv below, gRootDir might point to the old ROOTSYS
533 // entry, i.e. to deleted memory. Update it.
534 const char** pRootDir = gDriverConfig->fPRootDir;
535 if (pRootDir) {
536 *pRootDir = env + 8;
537 }
538 }
539
540 putenv(env);
541 // intentionally not call delete [] env, while GLIBC keep use pointer
542 delete [] ep;
543 }
544}
545
546////////////////////////////////////////////////////////////////////////////////
547/// Check whether the `#pragma` line contains expectedTokens (0-terminated array).
548
549bool ParsePragmaLine(const std::string &line,
550 const char *expectedTokens[],
551 size_t *end = nullptr)
552{
553 if (end) *end = 0;
554 if (line[0] != '#') return false;
555 size_t pos = 1;
556 for (const char **iToken = expectedTokens; *iToken; ++iToken) {
557 while (isspace(line[pos])) ++pos;
558 size_t lenToken = strlen(*iToken);
559 if (line.compare(pos, lenToken, *iToken)) {
560 if (end) *end = pos;
561 return false;
562 }
563 pos += lenToken;
564 }
565 if (end) *end = pos;
566 return true;
567}
568
569
572
573////////////////////////////////////////////////////////////////////////////////
574
575void RecordDeclCallback(const clang::RecordDecl* recordDecl)
576{
577 std::string need;
578 if (recordDecl->hasOwningModule()) {
579 clang::Module *M = recordDecl->getOwningModule()->getTopLevelModule();
580 need = "lib" + M->Name + gLibraryExtension;
581 } else {
582 std::string qual_name;
584
586 }
587
588 if (need.length() && gLibsNeeded.find(need) == string::npos) {
589 gLibsNeeded += " " + need;
590 }
591}
592
593////////////////////////////////////////////////////////////////////////////////
594
595void CheckClassNameForRootMap(const std::string &classname, map<string, string> &autoloads)
596{
597 if (classname.find(':') == std::string::npos) return;
598
599 // We have a namespace and we have to check it first
600 int slen = classname.size();
601 for (int k = 0; k < slen; ++k) {
602 if (classname[k] == ':') {
603 if (k + 1 >= slen || classname[k + 1] != ':') {
604 // we expected another ':'
605 break;
606 }
607 if (k) {
608 string base = classname.substr(0, k);
609 if (base == "std") {
610 // std is not declared but is also ignored by CINT!
611 break;
612 } else {
613 autoloads[base] = ""; // We never load namespaces on their own.
614 }
615 ++k;
616 }
617 } else if (classname[k] == '<') {
618 // We do not want to look at the namespace inside the template parameters!
619 break;
620 }
621 }
622}
623
624////////////////////////////////////////////////////////////////////////////////
625/// Parse the rootmap and add entries to the autoload map
626
628{
629 std::string classname;
630 std::string line;
631 while (file >> line) {
632
633 if (line.find("Library.") != 0) continue;
634
635 int pos = line.find(":", 8);
636 classname = line.substr(8, pos - 8);
637
638 ROOT::TMetaUtils::ReplaceAll(classname, "@@", "::");
639 ROOT::TMetaUtils::ReplaceAll(classname, "-", " ");
640
641 getline(file, line, '\n');
642 while (line[0] == ' ') line.replace(0, 1, "");
643
645
646 if (classname == "ROOT::TImpProxy") {
647 // Do not register the ROOT::TImpProxy so that they can be instantiated.
648 continue;
649 }
650 autoloads[classname] = line;
651 }
652
653}
654
655////////////////////////////////////////////////////////////////////////////////
656/// Parse the rootmap and add entries to the autoload map, using the new format
657
659{
660 std::string keyname;
661 std::string libs;
662 std::string line;
663
664 // For "class ", "namespace " and "typedef " respectively
665 const std::unordered_map<char, unsigned int> keyLenMap = {{'c', 6}, {'n', 10}, {'t', 8}};
666
667 while (getline(file, line, '\n')) {
668 if (line == "{ decls }") {
669 while (getline(file, line, '\n')) {
670 if (line[0] == '[') break;
671 }
672 }
673 const char firstChar = line[0];
674 if (firstChar == '[') {
675 // new section
676 libs = line.substr(1, line.find(']') - 1);
677 while (libs[0] == ' ') libs.replace(0, 1, "");
678 } else if (0 != keyLenMap.count(firstChar)) {
679 unsigned int keyLen = keyLenMap.at(firstChar);
680 keyname = line.substr(keyLen, line.length() - keyLen);
683 }
684 }
685
686}
687
688////////////////////////////////////////////////////////////////////////////////
689/// Fill the map of libraries to be loaded in presence of a class
690/// Transparently support the old and new rootmap file format
691
693{
694 std::ifstream filelist(fileListName.c_str());
695
696 std::string filename;
697 std::string line;
698
699 while (filelist >> filename) {
700
701 if (llvm::sys::fs::is_directory(filename)) continue;
702
703 ifstream file(filename.c_str());
704
705 // Check which format is this
706 file >> line;
707 bool new_format = (line[0] == '[' || line[0] == '{') ;
708 file.clear();
709 file.seekg(0, std::ios::beg);
710
711 // Now act
712 if (new_format) {
714 } else {
716 }
717
718 file.close();
719
720 } // end loop on files
721 filelist.close();
722}
723
724////////////////////////////////////////////////////////////////////////////////
725/// Check if the specified operator (what) has been properly declared if the user has
726/// requested a custom version.
727
728bool CheckInputOperator(const char *what,
729 const char *proto,
730 const string &fullname,
731 const clang::RecordDecl *cl,
732 cling::Interpreter &interp)
733{
734
735 const clang::FunctionDecl *method
736 = ROOT::TMetaUtils::GetFuncWithProto(llvm::dyn_cast<clang::Decl>(cl->getDeclContext()), what, proto, interp,
737 false /*diags*/);
738 if (!method) {
739 // This intended to find the global scope.
740 clang::TranslationUnitDecl *TU =
741 cl->getASTContext().getTranslationUnitDecl();
743 false /*diags*/);
744 }
745 bool has_input_error = false;
746 if (method != nullptr && (method->getAccess() == clang::AS_public || method->getAccess() == clang::AS_none)) {
748 if (strstr(filename.c_str(), "TBuffer.h") != nullptr ||
749 strstr(filename.c_str(), "Rtypes.h") != nullptr) {
750
751 has_input_error = true;
752 }
753 } else {
754 has_input_error = true;
755 }
756 if (has_input_error) {
757 // We don't want to generate duplicated error messages in several dictionaries (when generating temporaries)
758 const char *maybeconst = "";
759 const char *mayberef = "&";
760 if (what[strlen(what) - 1] == '<') {
761 maybeconst = "const ";
762 mayberef = "";
763 }
765 "in this version of ROOT, the option '!' used in a linkdef file\n"
766 " implies the actual existence of customized operators.\n"
767 " The following declaration is now required:\n"
768 " TBuffer &%s(TBuffer &,%s%s *%s);\n", what, maybeconst, fullname.c_str(), mayberef);
769 }
770 return has_input_error;
771
772}
773
774////////////////////////////////////////////////////////////////////////////////
775/// Check if the operator>> has been properly declared if the user has
776/// requested a custom version.
777
778bool CheckInputOperator(const clang::RecordDecl *cl, cling::Interpreter &interp)
779{
780 string fullname;
782 int ncha = fullname.length() + 13;
783 char *proto = new char[ncha];
784 snprintf(proto, ncha, "TBuffer&,%s*&", fullname.c_str());
785
786 ROOT::TMetaUtils::Info(nullptr, "Class %s: Do not generate operator>>()\n",
787 fullname.c_str());
788
789 // We do want to call both CheckInputOperator all the times.
790 bool has_input_error = CheckInputOperator("operator>>", proto, fullname, cl, interp);
791 has_input_error = CheckInputOperator("operator<<", proto, fullname, cl, interp) || has_input_error;
792
793 delete [] proto;
794
795 return has_input_error;
796}
797
798////////////////////////////////////////////////////////////////////////////////
799/// Return false if the class does not have ClassDef even-though it should.
800
801bool CheckClassDef(const clang::RecordDecl &cl, const cling::Interpreter &interp)
802{
803
804 // Detect if the class has a ClassDef
805 bool hasClassDef = ROOT::TMetaUtils::ClassInfo__HasMethod(&cl, "Class_Version", interp);
806
807 const clang::CXXRecordDecl *clxx = llvm::dyn_cast<clang::CXXRecordDecl>(&cl);
808 if (!clxx) {
809 return false;
810 }
811 bool isAbstract = clxx->isAbstract();
812
814 std::string qualName;
816 const char *qualName_c = qualName.c_str();
817 ROOT::TMetaUtils::Warning(qualName_c, "The data members of %s will not be stored, "
818 "because it inherits from TObject but does not "
819 "have its own ClassDef.\n",
820 qualName_c);
821 }
822
823 return true;
824}
825
826////////////////////////////////////////////////////////////////////////////////
827/// Return the name of the data member so that it can be used
828/// by non-const operation (so it includes a const_cast if necessary).
829
830string GetNonConstMemberName(const clang::FieldDecl &m, const string &prefix = "")
831{
832 if (m.getType().isConstQualified()) {
833 string ret = "const_cast< ";
834 string type_name;
836 if (type_name.substr(0,6)=="const ") {
837 ret += type_name.c_str()+6;
838 } else {
839 ret += type_name;
840 }
841 ret += " &>( ";
842 ret += prefix;
843 ret += m.getName().str();
844 ret += " )";
845 return ret;
846 } else {
847 return prefix + m.getName().str();
848 }
849}
850
851////////////////////////////////////////////////////////////////////////////////
852/// Create Streamer code for an STL container. Returns 1 if data member
853/// was an STL container and if Streamer code has been created, 0 otherwise.
854
855int STLContainerStreamer(const clang::FieldDecl &m,
856 int rwmode,
857 const cling::Interpreter &interp,
859 std::ostream &dictStream)
860{
862 std::string mTypename;
864
865 const clang::CXXRecordDecl *clxx = llvm::dyn_cast_or_null<clang::CXXRecordDecl>(ROOT::TMetaUtils::GetUnderlyingRecordDecl(m.getType()));
866
867 if (stltype == ROOT::kNotSTL) {
868 return 0;
869 }
870 // fprintf(stderr,"Add %s (%d) which is also %s\n",
871 // m.Type()->Name(), stltype, m.Type()->TrueName() );
872 clang::QualType utype(ROOT::TMetaUtils::GetUnderlyingType(m.getType()), 0);
873 Internal::RStl::Instance().GenerateTClassFor(utype, interp, normCtxt);
874
875 if (!clxx || clxx->getTemplateSpecializationKind() == clang::TSK_Undeclared) return 0;
876
877 const clang::ClassTemplateSpecializationDecl *tmplt_specialization = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl> (clxx);
878 if (!tmplt_specialization) return 0;
879
881 string stlName;
882 stlName = ROOT::TMetaUtils::ShortTypeName(m.getName().str().c_str());
883
884 string fulName1, fulName2;
885 const char *tcl1 = nullptr, *tcl2 = nullptr;
886 const clang::TemplateArgument &arg0(tmplt_specialization->getTemplateArgs().get(0));
887 clang::QualType ti = arg0.getAsType();
888
890 tcl1 = "R__tcl1";
891 fulName1 = ti.getAsString(); // Should we be passing a context?
892 }
893 if (stltype == kSTLmap || stltype == kSTLmultimap) {
894 const clang::TemplateArgument &arg1(tmplt_specialization->getTemplateArgs().get(1));
895 clang::QualType tmplti = arg1.getAsType();
897 tcl2 = "R__tcl2";
898 fulName2 = tmplti.getAsString(); // Should we be passing a context?
899 }
900 }
901
902 int isArr = 0;
903 int len = 1;
904 int pa = 0;
905 const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(m.getType().getTypePtr());
906 if (arrayType) {
907 isArr = 1;
909 pa = 1;
910 while (arrayType) {
911 if (arrayType->getArrayElementTypeNoTypeQual()->isPointerType()) {
912 pa = 3;
913 break;
914 }
915 arrayType = llvm::dyn_cast<clang::ConstantArrayType>(arrayType->getArrayElementTypeNoTypeQual());
916 }
917 } else if (m.getType()->isPointerType()) {
918 pa = 2;
919 }
920 if (rwmode == 0) {
921 // create read code
922 dictStream << " {" << std::endl;
923 if (isArr) {
924 dictStream << " for (Int_t R__l = 0; R__l < " << len << "; R__l++) {" << std::endl;
925 }
926
927 switch (pa) {
928 case 0: //No pointer && No array
929 dictStream << " " << stlType.c_str() << " &R__stl = " << stlName.c_str() << ";" << std::endl;
930 break;
931 case 1: //No pointer && array
932 dictStream << " " << stlType.c_str() << " &R__stl = " << stlName.c_str() << "[R__l];" << std::endl;
933 break;
934 case 2: //pointer && No array
935 dictStream << " delete *" << stlName.c_str() << ";" << std::endl
936 << " *" << stlName.c_str() << " = new " << stlType.c_str() << ";" << std::endl
937 << " " << stlType.c_str() << " &R__stl = **" << stlName.c_str() << ";" << std::endl;
938 break;
939 case 3: //pointer && array
940 dictStream << " delete " << stlName.c_str() << "[R__l];" << std::endl
941 << " " << stlName.c_str() << "[R__l] = new " << stlType.c_str() << ";" << std::endl
942 << " " << stlType.c_str() << " &R__stl = *" << stlName.c_str() << "[R__l];" << std::endl;
943 break;
944 }
945
946 dictStream << " R__stl.clear();" << std::endl;
947
948 if (tcl1) {
949 dictStream << " TClass *R__tcl1 = TBuffer::GetClass(typeid(" << fulName1.c_str() << "));" << std::endl
950 << " if (R__tcl1==0) {" << std::endl
951 << " Error(\"" << stlName.c_str() << " streamer\",\"Missing the TClass object for "
952 << fulName1.c_str() << "!\");" << std::endl
953 << " return;" << std::endl
954 << " }" << std::endl;
955 }
956 if (tcl2) {
957 dictStream << " TClass *R__tcl2 = TBuffer::GetClass(typeid(" << fulName2.c_str() << "));" << std::endl
958 << " if (R__tcl2==0) {" << std::endl
959 << " Error(\"" << stlName.c_str() << " streamer\",\"Missing the TClass object for "
960 << fulName2.c_str() << "!\");" << std::endl
961 << " return;" << std::endl
962 << " }" << std::endl;
963 }
964
965 dictStream << " int R__i, R__n;" << std::endl
966 << " R__b >> R__n;" << std::endl;
967
968 if (stltype == kSTLvector) {
969 dictStream << " R__stl.reserve(R__n);" << std::endl;
970 }
971 dictStream << " for (R__i = 0; R__i < R__n; R__i++) {" << std::endl;
972
974 if (stltype == kSTLmap || stltype == kSTLmultimap) { //Second Arg
975 const clang::TemplateArgument &arg1(tmplt_specialization->getTemplateArgs().get(1));
977 }
978
979 /* Need to go from
980 type R__t;
981 R__t.Stream;
982 vec.push_back(R__t);
983 to
984 vec.push_back(type());
985 R__t_p = &(vec.last());
986 *R__t_p->Stream;
987
988 */
989 switch (stltype) {
990
991 case kSTLmap:
992 case kSTLmultimap:
993 case kSTLunorderedmap:
995 std::string keyName(ti.getAsString());
996 dictStream << " typedef " << keyName << " Value_t;" << std::endl
997 << " std::pair<Value_t const, " << tmplt_specialization->getTemplateArgs().get(1).getAsType().getAsString() << " > R__t3(R__t,R__t2);" << std::endl
998 << " R__stl.insert(R__t3);" << std::endl;
999 //fprintf(fp, " R__stl.insert(%s::value_type(R__t,R__t2));\n",stlType.c_str());
1000 break;
1001 }
1002 case kSTLset:
1003 case kSTLunorderedset:
1005 case kSTLmultiset:
1006 dictStream << " R__stl.insert(R__t);" << std::endl;
1007 break;
1008 case kSTLvector:
1009 case kSTLlist:
1010 case kSTLdeque:
1011 dictStream << " R__stl.push_back(R__t);" << std::endl;
1012 break;
1013 case kSTLforwardlist:
1014 dictStream << " R__stl.push_front(R__t);" << std::endl;
1015 break;
1016 default:
1017 assert(0);
1018 }
1019 dictStream << " }" << std::endl
1020 << " }" << std::endl;
1021 if (isArr) dictStream << " }" << std::endl;
1022
1023 } else {
1024
1025 // create write code
1026 if (isArr) {
1027 dictStream << " for (Int_t R__l = 0; R__l < " << len << "; R__l++) {" << std::endl;
1028 }
1029 dictStream << " {" << std::endl;
1030 switch (pa) {
1031 case 0: //No pointer && No array
1032 dictStream << " " << stlType.c_str() << " &R__stl = " << stlName.c_str() << ";" << std::endl;
1033 break;
1034 case 1: //No pointer && array
1035 dictStream << " " << stlType.c_str() << " &R__stl = " << stlName.c_str() << "[R__l];" << std::endl;
1036 break;
1037 case 2: //pointer && No array
1038 dictStream << " " << stlType.c_str() << " &R__stl = **" << stlName.c_str() << ";" << std::endl;
1039 break;
1040 case 3: //pointer && array
1041 dictStream << " " << stlType.c_str() << " &R__stl = *" << stlName.c_str() << "[R__l];" << std::endl;
1042 break;
1043 }
1044
1045 dictStream << " int R__n=int(R__stl.size());" << std::endl
1046 << " R__b << R__n;" << std::endl
1047 << " if(R__n) {" << std::endl;
1048
1049 if (tcl1) {
1050 dictStream << " TClass *R__tcl1 = TBuffer::GetClass(typeid(" << fulName1.c_str() << "));" << std::endl
1051 << " if (R__tcl1==0) {" << std::endl
1052 << " Error(\"" << stlName.c_str() << " streamer\",\"Missing the TClass object for "
1053 << fulName1.c_str() << "!\");" << std::endl
1054 << " return;" << std::endl
1055 << " }" << std::endl;
1056 }
1057 if (tcl2) {
1058 dictStream << " TClass *R__tcl2 = TBuffer::GetClass(typeid(" << fulName2.c_str() << "));" << std::endl
1059 << " if (R__tcl2==0) {" << std::endl
1060 << " Error(\"" << stlName.c_str() << "streamer\",\"Missing the TClass object for " << fulName2.c_str() << "!\");" << std::endl
1061 << " return;" << std::endl
1062 << " }" << std::endl;
1063 }
1064
1065 dictStream << " " << stlType.c_str() << "::iterator R__k;" << std::endl
1066 << " for (R__k = R__stl.begin(); R__k != R__stl.end(); ++R__k) {" << std::endl;
1067 if (stltype == kSTLmap || stltype == kSTLmultimap) {
1068 const clang::TemplateArgument &arg1(tmplt_specialization->getTemplateArgs().get(1));
1069 clang::QualType tmplti = arg1.getAsType();
1072 } else {
1074 }
1075
1076 dictStream << " }" << std::endl
1077 << " }" << std::endl
1078 << " }" << std::endl;
1079 if (isArr) dictStream << " }" << std::endl;
1080 }
1081 return 1;
1082}
1083
1084////////////////////////////////////////////////////////////////////////////////
1085/// Create Streamer code for a standard string object. Returns 1 if data
1086/// member was a standard string and if Streamer code has been created,
1087/// 0 otherwise.
1088
1089int STLStringStreamer(const clang::FieldDecl &m, int rwmode, std::ostream &dictStream)
1090{
1091 std::string mTypenameStr;
1093 // Note: here we could to a direct type comparison!
1095 if (!strcmp(mTypeName, "string")) {
1096
1097 std::string fieldname = m.getName().str();
1098 if (rwmode == 0) {
1099 // create read mode
1100 if (m.getType()->isConstantArrayType()) {
1101 if (m.getType().getTypePtr()->getArrayElementTypeNoTypeQual()->isPointerType()) {
1102 dictStream << "// Array of pointer to std::string are not supported (" << fieldname << "\n";
1103 } else {
1104 std::stringstream fullIdx;
1105 const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(m.getType().getTypePtr());
1106 int dim = 0;
1107 while (arrayType) {
1108 dictStream << " for (int R__i" << dim << "=0; R__i" << dim << "<"
1109 << arrayType->getSize().getLimitedValue() << "; ++R__i" << dim << " )" << std::endl;
1110 fullIdx << "[R__i" << dim << "]";
1111 arrayType = llvm::dyn_cast<clang::ConstantArrayType>(arrayType->getArrayElementTypeNoTypeQual());
1112 ++dim;
1113 }
1114 dictStream << " { TString R__str; R__str.Streamer(R__b); "
1115 << fieldname << fullIdx.str() << " = R__str.Data();}" << std::endl;
1116 }
1117 } else {
1118 dictStream << " { TString R__str; R__str.Streamer(R__b); ";
1119 if (m.getType()->isPointerType())
1120 dictStream << "if (*" << fieldname << ") delete *" << fieldname << "; (*"
1121 << fieldname << " = new string(R__str.Data())); }" << std::endl;
1122 else
1123 dictStream << fieldname << " = R__str.Data(); }" << std::endl;
1124 }
1125 } else {
1126 // create write mode
1127 if (m.getType()->isPointerType())
1128 dictStream << " { TString R__str; if (*" << fieldname << ") R__str = (*"
1129 << fieldname << ")->c_str(); R__str.Streamer(R__b);}" << std::endl;
1130 else if (m.getType()->isConstantArrayType()) {
1131 std::stringstream fullIdx;
1132 const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(m.getType().getTypePtr());
1133 int dim = 0;
1134 while (arrayType) {
1135 dictStream << " for (int R__i" << dim << "=0; R__i" << dim << "<"
1136 << arrayType->getSize().getLimitedValue() << "; ++R__i" << dim << " )" << std::endl;
1137 fullIdx << "[R__i" << dim << "]";
1138 arrayType = llvm::dyn_cast<clang::ConstantArrayType>(arrayType->getArrayElementTypeNoTypeQual());
1139 ++dim;
1140 }
1141 dictStream << " { TString R__str(" << fieldname << fullIdx.str() << ".c_str()); R__str.Streamer(R__b);}" << std::endl;
1142 } else
1143 dictStream << " { TString R__str = " << fieldname << ".c_str(); R__str.Streamer(R__b);}" << std::endl;
1144 }
1145 return 1;
1146 }
1147 return 0;
1148}
1149
1150////////////////////////////////////////////////////////////////////////////////
1151
1152bool isPointerToPointer(const clang::FieldDecl &m)
1153{
1154 if (m.getType()->isPointerType()) {
1155 if (m.getType()->getPointeeType()->isPointerType()) {
1156 return true;
1157 }
1158 }
1159 return false;
1160}
1161
1162////////////////////////////////////////////////////////////////////////////////
1163/// Write "[0]" for all but the 1st dimension.
1164
1165void WriteArrayDimensions(const clang::QualType &type, std::ostream &dictStream)
1166{
1167 const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(type.getTypePtr());
1168 if (arrayType) {
1169 arrayType = llvm::dyn_cast<clang::ConstantArrayType>(arrayType->getArrayElementTypeNoTypeQual());
1170 while (arrayType) {
1171 dictStream << "[0]";
1172 arrayType = llvm::dyn_cast<clang::ConstantArrayType>(arrayType->getArrayElementTypeNoTypeQual());
1173 }
1174 }
1175}
1176
1177////////////////////////////////////////////////////////////////////////////////
1178/// Write the code to set the class name and the initialization object.
1179
1180void WriteClassFunctions(const clang::CXXRecordDecl *cl, std::ostream &dictStream, bool autoLoad = false)
1181{
1183
1184 string fullname;
1185 string clsname;
1186 string nsname;
1187 int enclSpaceNesting = 0;
1188
1191 }
1192
1193 if (autoLoad)
1194 dictStream << "#include \"TInterpreter.h\"\n";
1195
1196 dictStream << "//_______________________________________"
1197 << "_______________________________________" << std::endl;
1198 if (add_template_keyword) dictStream << "template <> ";
1199 dictStream << "atomic_TClass_ptr " << clsname << "::fgIsA(nullptr); // static to hold class pointer" << std::endl
1200 << std::endl
1201
1202 << "//_______________________________________"
1203 << "_______________________________________" << std::endl;
1204 if (add_template_keyword) dictStream << "template <> ";
1205 dictStream << "const char *" << clsname << "::Class_Name()" << std::endl << "{" << std::endl
1206 << " return \"" << fullname << "\";" << std::endl << "}" << std::endl << std::endl;
1207
1208 dictStream << "//_______________________________________"
1209 << "_______________________________________" << std::endl;
1210 if (add_template_keyword) dictStream << "template <> ";
1211 dictStream << "const char *" << clsname << "::ImplFileName()" << std::endl << "{" << std::endl
1212 << " return ::ROOT::GenerateInitInstanceLocal((const ::" << fullname
1213 << "*)nullptr)->GetImplFileName();" << std::endl << "}" << std::endl << std::endl
1214
1215 << "//_______________________________________"
1216 << "_______________________________________" << std::endl;
1217 if (add_template_keyword) dictStream << "template <> ";
1218 dictStream << "int " << clsname << "::ImplFileLine()" << std::endl << "{" << std::endl
1219 << " return ::ROOT::GenerateInitInstanceLocal((const ::" << fullname
1220 << "*)nullptr)->GetImplFileLine();" << std::endl << "}" << std::endl << std::endl
1221
1222 << "//_______________________________________"
1223 << "_______________________________________" << std::endl;
1224 if (add_template_keyword) dictStream << "template <> ";
1225 dictStream << "TClass *" << clsname << "::Dictionary()" << std::endl << "{" << std::endl;
1226
1227 // Trigger autoloading if dictionary is split
1228 if (autoLoad)
1229 dictStream << " gInterpreter->AutoLoad(\"" << fullname << "\");\n";
1230 dictStream << " fgIsA = ::ROOT::GenerateInitInstanceLocal((const ::" << fullname
1231 << "*)nullptr)->GetClass();" << std::endl
1232 << " return fgIsA;\n"
1233 << "}" << std::endl << std::endl
1234
1235 << "//_______________________________________"
1236 << "_______________________________________" << std::endl;
1237 if (add_template_keyword) dictStream << "template <> ";
1238 dictStream << "TClass *" << clsname << "::Class()" << std::endl << "{" << std::endl;
1239 if (autoLoad) {
1240 dictStream << " Dictionary();\n";
1241 } else {
1242 dictStream << " if (!fgIsA.load()) { R__LOCKGUARD(gInterpreterMutex); fgIsA = ::ROOT::GenerateInitInstanceLocal((const ::";
1243 dictStream << fullname << "*)nullptr)->GetClass(); }" << std::endl;
1244 }
1245 dictStream << " return fgIsA;" << std::endl
1246 << "}" << std::endl << std::endl;
1247
1248 while (enclSpaceNesting) {
1249 dictStream << "} // namespace " << nsname << std::endl;
1251 }
1252}
1253
1254////////////////////////////////////////////////////////////////////////////////
1255/// Write the code to initialize the namespace name and the initialization object.
1256
1257void WriteNamespaceInit(const clang::NamespaceDecl *cl,
1258 cling::Interpreter &interp,
1259 std::ostream &dictStream)
1260{
1261 if (cl->isAnonymousNamespace()) {
1262 // Don't write a GenerateInitInstance for the anonymous namespaces.
1263 return;
1264 }
1265
1266 // coverity[fun_call_w_exception] - that's just fine.
1267 string classname = ROOT::TMetaUtils::GetQualifiedName(*cl).c_str();
1268 string mappedname;
1269 TMetaUtils::GetCppName(mappedname, classname.c_str());
1270
1271 int nesting = 0;
1272 // We should probably unwind the namespace to properly nest it.
1273 if (classname != "ROOT") {
1275 }
1276
1277 dictStream << " namespace ROOTDict {" << std::endl;
1278
1279#if !defined(R__AIX)
1280 dictStream << " inline ::ROOT::TGenericClassInfo *GenerateInitInstance();" << std::endl;
1281#endif
1282
1283 if (!Namespace__HasMethod(cl, "Dictionary", interp))
1284 dictStream << " static TClass *" << mappedname.c_str() << "_Dictionary();" << std::endl;
1285 dictStream << std::endl
1286
1287 << " // Function generating the singleton type initializer" << std::endl
1288
1289#if !defined(R__AIX)
1290 << " inline ::ROOT::TGenericClassInfo *GenerateInitInstance()" << std::endl
1291 << " {" << std::endl
1292#else
1293 << " ::ROOT::TGenericClassInfo *GenerateInitInstance()" << std::endl
1294 << " {" << std::endl
1295#endif
1296
1297 << " static ::ROOT::TGenericClassInfo " << std::endl
1298
1299 << " instance(\"" << classname.c_str() << "\", ";
1300
1301 if (Namespace__HasMethod(cl, "Class_Version", interp)) {
1302 dictStream << "::" << classname.c_str() << "::Class_Version(), ";
1303 } else {
1304 dictStream << "0 /*version*/, ";
1305 }
1306
1307 std::string filename = ROOT::TMetaUtils::GetFileName(*cl, interp);
1308 for (unsigned int i = 0; i < filename.length(); i++) {
1309 if (filename[i] == '\\') filename[i] = '/';
1310 }
1311 dictStream << "\"" << filename << "\", " << ROOT::TMetaUtils::GetLineNumber(cl) << "," << std::endl
1312 << " ::ROOT::Internal::DefineBehavior((void*)nullptr,(void*)nullptr)," << std::endl
1313 << " ";
1314
1315 if (Namespace__HasMethod(cl, "Dictionary", interp)) {
1316 dictStream << "&::" << classname.c_str() << "::Dictionary, ";
1317 } else {
1318 dictStream << "&" << mappedname.c_str() << "_Dictionary, ";
1319 }
1320
1321 dictStream << 0 << ");" << std::endl
1322
1323 << " return &instance;" << std::endl
1324 << " }" << std::endl
1325 << " // Insure that the inline function is _not_ optimized away by the compiler\n"
1326 << " ::ROOT::TGenericClassInfo *(*_R__UNIQUE_DICT_(InitFunctionKeeper))() = &GenerateInitInstance; " << std::endl
1327 << " // Static variable to force the class initialization" << std::endl
1328 // must be one long line otherwise R__UseDummy does not work
1329 << " static ::ROOT::TGenericClassInfo *_R__UNIQUE_DICT_(Init) = GenerateInitInstance();"
1330 << " R__UseDummy(_R__UNIQUE_DICT_(Init));" << std::endl;
1331
1332 if (!Namespace__HasMethod(cl, "Dictionary", interp)) {
1333 dictStream << std::endl << " // Dictionary for non-ClassDef classes" << std::endl
1334 << " static TClass *" << mappedname.c_str() << "_Dictionary() {" << std::endl
1335 << " return GenerateInitInstance()->GetClass();" << std::endl
1336 << " }" << std::endl << std::endl;
1337 }
1338
1339 dictStream << " }" << std::endl;
1340 while (nesting--) {
1341 dictStream << "}" << std::endl;
1342 }
1343 dictStream << std::endl;
1344}
1345
1346////////////////////////////////////////////////////////////////////////////////
1347/// GrabIndex returns a static string (so use it or copy it immediately, do not
1348/// call GrabIndex twice in the same expression) containing the size of the
1349/// array data member.
1350/// In case of error, or if the size is not specified, GrabIndex returns 0.
1351
1352llvm::StringRef GrabIndex(const cling::Interpreter& interp, const clang::FieldDecl &member, int printError)
1353{
1354 int error;
1355 llvm::StringRef where;
1356
1358 if (index.size() == 0 && printError) {
1359 const char *errorstring;
1360 switch (error) {
1362 errorstring = "is not an integer";
1363 break;
1365 errorstring = "has not been defined before the array";
1366 break;
1368 errorstring = "is a private member of a parent class";
1369 break;
1371 errorstring = "is not known";
1372 break;
1373 default:
1374 errorstring = "UNKNOWN ERROR!!!!";
1375 }
1376
1377 if (where.size() == 0) {
1378 ROOT::TMetaUtils::Error(nullptr, "*** Datamember %s::%s: no size indication!\n",
1379 member.getParent()->getName().str().c_str(), member.getName().str().c_str());
1380 } else {
1381 ROOT::TMetaUtils::Error(nullptr, "*** Datamember %s::%s: size of array (%s) %s!\n",
1382 member.getParent()->getName().str().c_str(), member.getName().str().c_str(), where.str().c_str(), errorstring);
1383 }
1384 }
1385 return index;
1386}
1387
1388////////////////////////////////////////////////////////////////////////////////
1389
1391 const cling::Interpreter &interp,
1393 std::ostream &dictStream)
1394{
1395 const clang::CXXRecordDecl *clxx = llvm::dyn_cast<clang::CXXRecordDecl>(cl.GetRecordDecl());
1396 if (clxx == nullptr) return;
1397
1399
1400 string fullname;
1401 string clsname;
1402 string nsname;
1403 int enclSpaceNesting = 0;
1404
1407 }
1408
1409 dictStream << "//_______________________________________"
1410 << "_______________________________________" << std::endl;
1411 if (add_template_keyword) dictStream << "template <> ";
1412 dictStream << "void " << clsname << "::Streamer(TBuffer &R__b)" << std::endl << "{" << std::endl
1413 << " // Stream an object of class " << fullname << "." << std::endl << std::endl;
1414
1415 // In case of VersionID<=0 write dummy streamer only calling
1416 // its base class Streamer(s). If no base class(es) let Streamer
1417 // print error message, i.e. this Streamer should never have been called.
1419 if (version <= 0) {
1420 // We also need to look at the base classes.
1421 int basestreamer = 0;
1422 for (clang::CXXRecordDecl::base_class_const_iterator iter = clxx->bases_begin(), end = clxx->bases_end();
1423 iter != end;
1424 ++iter) {
1425 if (ROOT::TMetaUtils::ClassInfo__HasMethod(iter->getType()->getAsCXXRecordDecl(), "Streamer", interp)) {
1426 string base_fullname;
1427 ROOT::TMetaUtils::GetQualifiedName(base_fullname, * iter->getType()->getAsCXXRecordDecl());
1428
1429 if (strstr(base_fullname.c_str(), "::")) {
1430 // there is a namespace involved, trigger MS VC bug workaround
1431 dictStream << " //This works around a msvc bug and should be harmless on other platforms" << std::endl
1432 << " typedef " << base_fullname << " baseClass" << basestreamer << ";" << std::endl
1433 << " baseClass" << basestreamer << "::Streamer(R__b);" << std::endl;
1434 } else {
1435 dictStream << " " << base_fullname << "::Streamer(R__b);" << std::endl;
1436 }
1437 basestreamer++;
1438 }
1439 }
1440 if (!basestreamer) {
1441 dictStream << " ::Error(\"" << fullname << "::Streamer\", \"version id <=0 in ClassDef,"
1442 " dummy Streamer() called\"); if (R__b.IsReading()) { }" << std::endl;
1443 }
1444 dictStream << "}" << std::endl << std::endl;
1445 while (enclSpaceNesting) {
1446 dictStream << "} // namespace " << nsname.c_str() << std::endl;
1448 }
1449 return;
1450 }
1451
1452 // loop twice: first time write reading code, second time writing code
1453 string classname = fullname;
1454 if (strstr(fullname.c_str(), "::")) {
1455 // there is a namespace involved, trigger MS VC bug workaround
1456 dictStream << " //This works around a msvc bug and should be harmless on other platforms" << std::endl
1457 << " typedef ::" << fullname << " thisClass;" << std::endl;
1458 classname = "thisClass";
1459 }
1460 for (int i = 0; i < 2; i++) {
1461
1462 int decli = 0;
1463
1464 if (i == 0) {
1465 dictStream << " UInt_t R__s, R__c;" << std::endl;
1466 dictStream << " if (R__b.IsReading()) {" << std::endl;
1467 dictStream << " Version_t R__v = R__b.ReadVersion(&R__s, &R__c); if (R__v) { }" << std::endl;
1468 } else {
1469 dictStream << " R__b.CheckByteCount(R__s, R__c, " << classname.c_str() << "::IsA());" << std::endl;
1470 dictStream << " } else {" << std::endl;
1471 dictStream << " R__c = R__b.WriteVersion(" << classname.c_str() << "::IsA(), kTRUE);" << std::endl;
1472 }
1473
1474 // Stream base class(es) when they have the Streamer() method
1475 int base = 0;
1476 for (clang::CXXRecordDecl::base_class_const_iterator iter = clxx->bases_begin(), end = clxx->bases_end();
1477 iter != end;
1478 ++iter) {
1479 if (ROOT::TMetaUtils::ClassInfo__HasMethod(iter->getType()->getAsCXXRecordDecl(), "Streamer", interp)) {
1480 string base_fullname;
1481 ROOT::TMetaUtils::GetQualifiedName(base_fullname, * iter->getType()->getAsCXXRecordDecl());
1482
1483 if (strstr(base_fullname.c_str(), "::")) {
1484 // there is a namespace involved, trigger MS VC bug workaround
1485 dictStream << " //This works around a msvc bug and should be harmless on other platforms" << std::endl
1486 << " typedef " << base_fullname << " baseClass" << base << ";" << std::endl
1487 << " baseClass" << base << "::Streamer(R__b);" << std::endl;
1488 ++base;
1489 } else {
1490 dictStream << " " << base_fullname << "::Streamer(R__b);" << std::endl;
1491 }
1492 }
1493 }
1494 // Stream data members
1495 // Loop over the non static data member.
1496 for (clang::RecordDecl::field_iterator field_iter = clxx->field_begin(), end = clxx->field_end();
1497 field_iter != end;
1498 ++field_iter) {
1499 const char *comment = ROOT::TMetaUtils::GetComment(**field_iter).data();
1500
1501 clang::QualType type = field_iter->getType();
1502 std::string type_name = type.getAsString(clxx->getASTContext().getPrintingPolicy());
1503
1505
1506 // we skip:
1507 // - static members
1508 // - members with an ! as first character in the title (comment) field
1509
1510 //special case for Float16_t
1511 int isFloat16 = 0;
1512 if (strstr(type_name.c_str(), "Float16_t")) isFloat16 = 1;
1513
1514 //special case for Double32_t
1515 int isDouble32 = 0;
1516 if (strstr(type_name.c_str(), "Double32_t")) isDouble32 = 1;
1517
1518 // No need to test for static, there are not in this list.
1519 if (strncmp(comment, "!", 1)) {
1520
1521 // fundamental type: short, int, long, etc....
1522 if (underling_type->isFundamentalType() || underling_type->isEnumeralType()) {
1523 if (type.getTypePtr()->isConstantArrayType() &&
1524 type.getTypePtr()->getArrayElementTypeNoTypeQual()->isPointerType()) {
1525 const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(type.getTypePtr());
1527
1528 if (!decli) {
1529 dictStream << " int R__i;" << std::endl;
1530 decli = 1;
1531 }
1532 dictStream << " for (R__i = 0; R__i < " << s << "; R__i++)" << std::endl;
1533 if (i == 0) {
1534 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());
1535 dictStream << " ;//R__b.ReadArray(" << field_iter->getName().str() << ");" << std::endl;
1536 } else {
1537 dictStream << " ;//R__b.WriteArray(" << field_iter->getName().str() << ", __COUNTER__);" << std::endl;
1538 }
1539 } else if (type.getTypePtr()->isPointerType()) {
1540 llvm::StringRef indexvar = GrabIndex(interp, **field_iter, i == 0);
1541 if (indexvar.size() == 0) {
1542 if (i == 0) {
1543 ROOT::TMetaUtils::Error(nullptr, "*** Datamember %s::%s: pointer to fundamental type (need manual intervention)\n", fullname.c_str(), field_iter->getName().str().c_str());
1544 dictStream << " //R__b.ReadArray(" << field_iter->getName().str() << ");" << std::endl;
1545 } else {
1546 dictStream << " //R__b.WriteArray(" << field_iter->getName().str() << ", __COUNTER__);" << std::endl;
1547 }
1548 } else {
1549 if (i == 0) {
1550 dictStream << " delete [] " << field_iter->getName().str() << ";" << std::endl
1551 << " " << GetNonConstMemberName(**field_iter) << " = new "
1552 << ROOT::TMetaUtils::ShortTypeName(**field_iter) << "[" << indexvar.str() << "];" << std::endl;
1553 if (isFloat16) {
1554 dictStream << " R__b.ReadFastArrayFloat16(" << GetNonConstMemberName(**field_iter)
1555 << "," << indexvar.str() << ");" << std::endl;
1556 } else if (isDouble32) {
1557 dictStream << " R__b.ReadFastArrayDouble32(" << GetNonConstMemberName(**field_iter)
1558 << "," << indexvar.str() << ");" << std::endl;
1559 } else {
1560 dictStream << " R__b.ReadFastArray(" << GetNonConstMemberName(**field_iter)
1561 << "," << indexvar.str() << ");" << std::endl;
1562 }
1563 } else {
1564 if (isFloat16) {
1565 dictStream << " R__b.WriteFastArrayFloat16("
1566 << field_iter->getName().str() << "," << indexvar.str() << ");" << std::endl;
1567 } else if (isDouble32) {
1568 dictStream << " R__b.WriteFastArrayDouble32("
1569 << field_iter->getName().str() << "," << indexvar.str() << ");" << std::endl;
1570 } else {
1571 dictStream << " R__b.WriteFastArray("
1572 << field_iter->getName().str() << "," << indexvar.str() << ");" << std::endl;
1573 }
1574 }
1575 }
1576 } else if (type.getTypePtr()->isArrayType()) {
1577 if (i == 0) {
1578 if (type.getTypePtr()->getArrayElementTypeNoTypeQual()->isArrayType()) { // if (m.ArrayDim() > 1) {
1579 if (underling_type->isEnumeralType())
1580 dictStream << " R__b.ReadStaticArray((Int_t*)" << field_iter->getName().str() << ");" << std::endl;
1581 else {
1582 if (isFloat16) {
1583 dictStream << " R__b.ReadStaticArrayFloat16((" << ROOT::TMetaUtils::TrueName(**field_iter)
1584 << "*)" << field_iter->getName().str() << ");" << std::endl;
1585 } else if (isDouble32) {
1586 dictStream << " R__b.ReadStaticArrayDouble32((" << ROOT::TMetaUtils::TrueName(**field_iter)
1587 << "*)" << field_iter->getName().str() << ");" << std::endl;
1588 } else {
1589 dictStream << " R__b.ReadStaticArray((" << ROOT::TMetaUtils::TrueName(**field_iter)
1590 << "*)" << field_iter->getName().str() << ");" << std::endl;
1591 }
1592 }
1593 } else {
1594 if (underling_type->isEnumeralType()) {
1595 dictStream << " R__b.ReadStaticArray((Int_t*)" << field_iter->getName().str() << ");" << std::endl;
1596 } else {
1597 if (isFloat16) {
1598 dictStream << " R__b.ReadStaticArrayFloat16(" << field_iter->getName().str() << ");" << std::endl;
1599 } else if (isDouble32) {
1600 dictStream << " R__b.ReadStaticArrayDouble32(" << field_iter->getName().str() << ");" << std::endl;
1601 } else {
1602 dictStream << " R__b.ReadStaticArray((" << ROOT::TMetaUtils::TrueName(**field_iter)
1603 << "*)" << field_iter->getName().str() << ");" << std::endl;
1604 }
1605 }
1606 }
1607 } else {
1608 const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(type.getTypePtr());
1610
1611 if (type.getTypePtr()->getArrayElementTypeNoTypeQual()->isArrayType()) {// if (m.ArrayDim() > 1) {
1612 if (underling_type->isEnumeralType())
1613 dictStream << " R__b.WriteArray((Int_t*)" << field_iter->getName().str() << ", "
1614 << s << ");" << std::endl;
1615 else if (isFloat16) {
1616 dictStream << " R__b.WriteArrayFloat16((" << ROOT::TMetaUtils::TrueName(**field_iter)
1617 << "*)" << field_iter->getName().str() << ", " << s << ");" << std::endl;
1618 } else if (isDouble32) {
1619 dictStream << " R__b.WriteArrayDouble32((" << ROOT::TMetaUtils::TrueName(**field_iter)
1620 << "*)" << field_iter->getName().str() << ", " << s << ");" << std::endl;
1621 } else {
1622 dictStream << " R__b.WriteArray((" << ROOT::TMetaUtils::TrueName(**field_iter)
1623 << "*)" << field_iter->getName().str() << ", " << s << ");" << std::endl;
1624 }
1625 } else {
1626 if (underling_type->isEnumeralType())
1627 dictStream << " R__b.WriteArray((Int_t*)" << field_iter->getName().str() << ", " << s << ");" << std::endl;
1628 else if (isFloat16) {
1629 dictStream << " R__b.WriteArrayFloat16(" << field_iter->getName().str() << ", " << s << ");" << std::endl;
1630 } else if (isDouble32) {
1631 dictStream << " R__b.WriteArrayDouble32(" << field_iter->getName().str() << ", " << s << ");" << std::endl;
1632 } else {
1633 dictStream << " R__b.WriteArray(" << field_iter->getName().str() << ", " << s << ");" << std::endl;
1634 }
1635 }
1636 }
1637 } else if (underling_type->isEnumeralType()) {
1638 if (i == 0) {
1639 dictStream << " void *ptr_" << field_iter->getName().str() << " = (void*)&" << field_iter->getName().str() << ";\n";
1640 dictStream << " R__b >> *reinterpret_cast<Int_t*>(ptr_" << field_iter->getName().str() << ");" << std::endl;
1641 } else
1642 dictStream << " R__b << (Int_t)" << field_iter->getName().str() << ";" << std::endl;
1643 } else {
1644 if (isFloat16) {
1645 if (i == 0)
1646 dictStream << " {float R_Dummy; R__b >> R_Dummy; " << GetNonConstMemberName(**field_iter)
1647 << "=Float16_t(R_Dummy);}" << std::endl;
1648 else
1649 dictStream << " R__b << float(" << GetNonConstMemberName(**field_iter) << ");" << std::endl;
1650 } else if (isDouble32) {
1651 if (i == 0)
1652 dictStream << " {float R_Dummy; R__b >> R_Dummy; " << GetNonConstMemberName(**field_iter)
1653 << "=Double32_t(R_Dummy);}" << std::endl;
1654 else
1655 dictStream << " R__b << float(" << GetNonConstMemberName(**field_iter) << ");" << std::endl;
1656 } else {
1657 if (i == 0)
1658 dictStream << " R__b >> " << GetNonConstMemberName(**field_iter) << ";" << std::endl;
1659 else
1660 dictStream << " R__b << " << GetNonConstMemberName(**field_iter) << ";" << std::endl;
1661 }
1662 }
1663 } else {
1664 // we have an object...
1665
1666 // check if object is a standard string
1668 continue;
1669
1670 // check if object is an STL container
1672 continue;
1673
1674 // handle any other type of objects
1675 if (type.getTypePtr()->isConstantArrayType() &&
1676 type.getTypePtr()->getArrayElementTypeNoTypeQual()->isPointerType()) {
1677 const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(type.getTypePtr());
1679
1680 if (!decli) {
1681 dictStream << " int R__i;" << std::endl;
1682 decli = 1;
1683 }
1684 dictStream << " for (R__i = 0; R__i < " << s << "; R__i++)" << std::endl;
1685 if (i == 0)
1686 dictStream << " R__b >> " << GetNonConstMemberName(**field_iter);
1687 else {
1689 dictStream << " R__b << (TObject*)" << field_iter->getName().str();
1690 else
1691 dictStream << " R__b << " << GetNonConstMemberName(**field_iter);
1692 }
1694 dictStream << "[R__i];" << std::endl;
1695 } else if (type.getTypePtr()->isPointerType()) {
1696 // This is always good. However, in case of a pointer
1697 // to an object that is guaranteed to be there and not
1698 // being referenced by other objects we could use
1699 // xx->Streamer(b);
1700 // Optimize this with control statement in title.
1702 if (i == 0) {
1703 ROOT::TMetaUtils::Error(nullptr, "*** Datamember %s::%s: pointer to pointer (need manual intervention)\n", fullname.c_str(), field_iter->getName().str().c_str());
1704 dictStream << " //R__b.ReadArray(" << field_iter->getName().str() << ");" << std::endl;
1705 } else {
1706 dictStream << " //R__b.WriteArray(" << field_iter->getName().str() << ", __COUNTER__);";
1707 }
1708 } else {
1710 dictStream << " " << field_iter->getName().str() << "->Streamer(R__b);" << std::endl;
1711 } else {
1712 if (i == 0) {
1713 // The following:
1714 // if (strncmp(m.Title(),"->",2) != 0) fprintf(fp, " delete %s;\n", GetNonConstMemberName(**field_iter).c_str());
1715 // could be used to prevent a memory leak since the next statement could possibly create a new object.
1716 // In the TStreamerInfo based I/O we made the previous statement conditional on TStreamerInfo::CanDelete
1717 // to allow the user to prevent some inadvisable deletions. So we should be offering this flexibility
1718 // here to and should not (technically) rely on TStreamerInfo for it, so for now we leave it as is.
1719 // Note that the leak should happen from here only if the object is stored in an unsplit object
1720 // and either the user request an old branch or the streamer has been customized.
1721 dictStream << " R__b >> " << GetNonConstMemberName(**field_iter) << ";" << std::endl;
1722 } else {
1724 dictStream << " R__b << (TObject*)" << field_iter->getName().str() << ";" << std::endl;
1725 else
1726 dictStream << " R__b << " << GetNonConstMemberName(**field_iter) << ";" << std::endl;
1727 }
1728 }
1729 }
1730 } else if (const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(type.getTypePtr())) {
1732
1733 if (!decli) {
1734 dictStream << " int R__i;" << std::endl;
1735 decli = 1;
1736 }
1737 dictStream << " for (R__i = 0; R__i < " << s << "; R__i++)" << std::endl;
1738 std::string mTypeNameStr;
1740 const char *mTypeName = mTypeNameStr.c_str();
1741 const char *constwd = "const ";
1742 if (strncmp(constwd, mTypeName, strlen(constwd)) == 0) {
1744 dictStream << " const_cast< " << mTypeName << " &>(" << field_iter->getName().str();
1746 dictStream << "[R__i]).Streamer(R__b);" << std::endl;
1747 } else {
1750 dictStream << "[R__i].Streamer(R__b);" << std::endl;
1751 }
1752 } else {
1754 dictStream << " " << GetNonConstMemberName(**field_iter) << ".Streamer(R__b);" << std::endl;
1755 else {
1756 dictStream << " R__b.StreamObject(&(" << field_iter->getName().str() << "),typeid("
1757 << field_iter->getName().str() << "));" << std::endl; //R__t.Streamer(R__b);\n");
1758 //VP if (i == 0)
1759 //VP Error(0, "*** Datamember %s::%s: object has no Streamer() method (need manual intervention)\n",
1760 //VP fullname, field_iter->getName().str());
1761 //VP fprintf(fp, " //%s.Streamer(R__b);\n", m.Name());
1762 }
1763 }
1764 }
1765 }
1766 }
1767 }
1768 dictStream << " R__b.SetByteCount(R__c, kTRUE);" << std::endl
1769 << " }" << std::endl
1770 << "}" << std::endl << std::endl;
1771
1772 while (enclSpaceNesting) {
1773 dictStream << "} // namespace " << nsname.c_str() << std::endl;
1775 }
1776}
1777
1778////////////////////////////////////////////////////////////////////////////////
1779
1781 const cling::Interpreter &interp,
1783 std::ostream &dictStream)
1784{
1785 // Write Streamer() method suitable for automatic schema evolution.
1786
1787 const clang::CXXRecordDecl *clxx = llvm::dyn_cast<clang::CXXRecordDecl>(cl.GetRecordDecl());
1788 if (clxx == nullptr) return;
1789
1791
1792 // We also need to look at the base classes.
1793 for (clang::CXXRecordDecl::base_class_const_iterator iter = clxx->bases_begin(), end = clxx->bases_end();
1794 iter != end;
1795 ++iter) {
1796 int k = ROOT::TMetaUtils::IsSTLContainer(*iter);
1797 if (k != 0) {
1798 Internal::RStl::Instance().GenerateTClassFor(iter->getType(), interp, normCtxt);
1799 }
1800 }
1801
1802 string fullname;
1803 string clsname;
1804 string nsname;
1805 int enclSpaceNesting = 0;
1806
1809 }
1810
1811 dictStream << "//_______________________________________"
1812 << "_______________________________________" << std::endl;
1813 if (add_template_keyword) dictStream << "template <> ";
1814 dictStream << "void " << clsname << "::Streamer(TBuffer &R__b)" << std::endl
1815 << "{" << std::endl
1816 << " // Stream an object of class " << fullname << "." << std::endl << std::endl
1817 << " if (R__b.IsReading()) {" << std::endl
1818 << " R__b.ReadClassBuffer(" << fullname << "::Class(),this);" << std::endl
1819 << " } else {" << std::endl
1820 << " R__b.WriteClassBuffer(" << fullname << "::Class(),this);" << std::endl
1821 << " }" << std::endl
1822 << "}" << std::endl << std::endl;
1823
1824 while (enclSpaceNesting) {
1825 dictStream << "} // namespace " << nsname << std::endl;
1827 }
1828}
1829
1830////////////////////////////////////////////////////////////////////////////////
1831
1833 const cling::Interpreter &interp,
1835 std::ostream &dictStream,
1836 bool isAutoStreamer)
1837{
1838 if (isAutoStreamer) {
1840 } else {
1842 }
1843}
1844
1845////////////////////////////////////////////////////////////////////////////////
1846
1847void GenerateLinkdef(llvm::cl::list<std::string> &InputFiles,
1848 std::string &code_for_parser)
1849{
1850 code_for_parser += "#ifdef __CINT__\n\n";
1851 code_for_parser += "#pragma link off all globals;\n";
1852 code_for_parser += "#pragma link off all classes;\n";
1853 code_for_parser += "#pragma link off all functions;\n\n";
1854
1855 for (std::string& arg : InputFiles) {
1856 char trail[3];
1857 int nostr = 0, noinp = 0, bcnt = 0, l = arg.length() - 1;
1858 for (int j = 0; j < 3; j++) {
1859 if (arg[l] == '-') {
1860 arg[l] = '\0';
1861 nostr = 1;
1862 l--;
1863 }
1864 if (arg[l] == '!') {
1865 arg[l] = '\0';
1866 noinp = 1;
1867 l--;
1868 }
1869 if (arg[l] == '+') {
1870 arg[l] = '\0';
1871 bcnt = 1;
1872 l--;
1873 }
1874 }
1875 if (nostr || noinp) {
1876 trail[0] = 0;
1877 if (nostr) strlcat(trail, "-", 3);
1878 if (noinp) strlcat(trail, "!", 3);
1879 }
1880 if (bcnt) {
1881 strlcpy(trail, "+", 3);
1882 if (nostr)
1883 ROOT::TMetaUtils::Error(nullptr, "option + mutual exclusive with -\n");
1884 }
1885 llvm::SmallString<256> filestem = llvm::sys::path::filename(arg);
1886 llvm::sys::path::replace_extension(filestem, "");
1887
1888 code_for_parser += "#pragma link C++ class ";
1889 code_for_parser += filestem.str().str();
1890 if (nostr || noinp || bcnt)
1892 code_for_parser += ";\n";
1893 }
1894
1895 code_for_parser += "\n#endif\n";
1896}
1897
1898////////////////////////////////////////////////////////////////////////////////
1899/// Find file name in path specified via -I statements to Cling.
1900/// Return false if the file can not be found.
1901/// If the file is found, set pname to the full path name and return true.
1902
1903bool Which(cling::Interpreter &interp, const char *fname, string &pname)
1904{
1905 FILE *fp = nullptr;
1906
1907#ifdef WIN32
1908 static const char *fopenopts = "rb";
1909#else
1910 static const char *fopenopts = "r";
1911#endif
1912
1913 pname = fname;
1914 fp = fopen(pname.c_str(), fopenopts);
1915 if (fp) {
1916 fclose(fp);
1917 return true;
1918 }
1919
1920 llvm::SmallVector<std::string, 10> includePaths;//Why 10? Hell if I know.
1921 //false - no system header, false - with flags.
1922 interp.GetIncludePaths(includePaths, false, false);
1923
1924 const size_t nPaths = includePaths.size();
1925 for (size_t i = 0; i < nPaths; i += 1 /* 2 */) {
1926
1927 pname = includePaths[i].c_str() + gPathSeparator + fname;
1928
1929 fp = fopen(pname.c_str(), fopenopts);
1930 if (fp) {
1931 fclose(fp);
1932 return true;
1933 }
1934 }
1935 pname = "";
1936 return false;
1937}
1938
1939////////////////////////////////////////////////////////////////////////////////
1940/// If the argument starts with MODULE/inc, strip it
1941/// to make it the name we can use in `#includes`.
1942
1943const char *CopyArg(const char *original)
1944{
1945 if (!gBuildingROOT)
1946 return original;
1947
1949 return original;
1950
1951 const char *inc = strstr(original, "\\inc\\");
1952 if (!inc)
1953 inc = strstr(original, "/inc/");
1954 if (inc && strlen(inc) > 5)
1955 return inc + 5;
1956 return original;
1957}
1958
1959////////////////////////////////////////////////////////////////////////////////
1960/// Copy the command line argument, stripping MODULE/inc if
1961/// necessary.
1962
1963void StrcpyArg(string &dest, const char *original)
1964{
1966}
1967
1968////////////////////////////////////////////////////////////////////////////////
1969/// Write the extra header injected into the module:
1970/// umbrella header if (umbrella) else content header.
1971
1972static bool InjectModuleUtilHeader(const char *argv0,
1974 cling::Interpreter &interp,
1975 bool umbrella)
1976{
1977 std::ostringstream out;
1978 if (umbrella) {
1979 // This will duplicate the -D,-U from clingArgs - but as they are surrounded
1980 // by #ifndef there is no problem here.
1981 modGen.WriteUmbrellaHeader(out);
1982 if (interp.declare(out.str()) != cling::Interpreter::kSuccess) {
1983 const std::string &hdrName
1984 = umbrella ? modGen.GetUmbrellaName() : modGen.GetContentName();
1985 ROOT::TMetaUtils::Error(nullptr, "%s: compilation failure (%s)\n", argv0,
1986 hdrName.c_str());
1987 return false;
1988 }
1989 } else {
1990 modGen.WriteContentHeader(out);
1991 }
1992 return true;
1993}
1994
1995////////////////////////////////////////////////////////////////////////////////
1996/// Write the AST of the given CompilerInstance to the given File while
1997/// respecting the given isysroot.
1998/// If module is not a null pointer, we only write the given module to the
1999/// given file and not the whole AST.
2000/// Returns true if the AST was successfully written.
2001static bool WriteAST(llvm::StringRef fileName, clang::CompilerInstance *compilerInstance,
2002 llvm::StringRef iSysRoot,
2003 clang::Module *module = nullptr)
2004{
2005 // From PCHGenerator and friends:
2006 llvm::SmallVector<char, 128> buffer;
2007 llvm::BitstreamWriter stream(buffer);
2008 clang::ASTWriter writer(stream, buffer, compilerInstance->getModuleCache(), /*Extensions=*/{});
2009 std::unique_ptr<llvm::raw_ostream> out =
2010 compilerInstance->createOutputFile(fileName, /*Binary=*/true,
2011 /*RemoveFileOnSignal=*/false,
2012 /*useTemporary=*/false,
2013 /*CreateMissingDirectories*/ false);
2014 if (!out) {
2015 ROOT::TMetaUtils::Error("WriteAST", "Couldn't open output stream to '%s'!\n", fileName.data());
2016 return false;
2017 }
2018
2019 compilerInstance->getFrontendOpts().RelocatablePCH = true;
2020
2021 writer.WriteAST(compilerInstance->getSema(), fileName.str(), module, iSysRoot);
2022
2023 // Write the generated bitstream to "Out".
2024 out->write(&buffer.front(), buffer.size());
2025
2026 // Make sure it hits disk now.
2027 out->flush();
2028
2029 return true;
2030}
2031
2032////////////////////////////////////////////////////////////////////////////////
2033/// Generates a PCH from the given ModuleGenerator and CompilerInstance.
2034/// Returns true iff the PCH was successfully generated.
2035static bool GenerateAllDict(TModuleGenerator &modGen, clang::CompilerInstance *compilerInstance,
2036 const std::string &currentDirectory)
2037{
2038 assert(modGen.IsPCH() && "modGen must be in PCH mode");
2039
2040 std::string iSysRoot("/DUMMY_SYSROOT/include/");
2042 return WriteAST(modGen.GetModuleFileName(), compilerInstance, iSysRoot);
2043}
2044
2045////////////////////////////////////////////////////////////////////////////////
2046/// Includes all given headers in the interpreter. Returns true when we could
2047/// include the headers and otherwise false on an error when including.
2048static bool IncludeHeaders(const std::vector<std::string> &headers, cling::Interpreter &interpreter)
2049{
2050 // If no headers are given, this is a no-op.
2051 if (headers.empty())
2052 return true;
2053
2054 // Turn every header name into an include and parse it in the interpreter.
2055 std::stringstream includes;
2056 for (const std::string &header : headers) {
2057 includes << "#include \"" << header << "\"\n";
2058 }
2059 std::string includeListStr = includes.str();
2060 auto result = interpreter.declare(includeListStr);
2061 return result == cling::Interpreter::CompilationResult::kSuccess;
2062}
2063
2064
2065////////////////////////////////////////////////////////////////////////////////
2066
2067void AddPlatformDefines(std::vector<std::string> &clingArgs)
2068{
2069 char platformDefines[64] = {0};
2070#ifdef __INTEL_COMPILER
2071 snprintf(platformDefines, 64, "-DG__INTEL_COMPILER=%ld", (long)__INTEL_COMPILER);
2072 clingArgs.push_back(platformDefines);
2073#endif
2074#ifdef __xlC__
2075 snprintf(platformDefines, 64, "-DG__xlC=%ld", (long)__xlC__);
2076 clingArgs.push_back(platformDefines);
2077#endif
2078#ifdef __GNUC__
2079 snprintf(platformDefines, 64, "-DG__GNUC=%ld", (long)__GNUC__);
2080 snprintf(platformDefines, 64, "-DG__GNUC_VER=%ld", (long)__GNUC__ * 1000 + __GNUC_MINOR__);
2081 clingArgs.push_back(platformDefines);
2082#endif
2083#ifdef __GNUC_MINOR__
2084 snprintf(platformDefines, 64, "-DG__GNUC_MINOR=%ld", (long)__GNUC_MINOR__);
2085 clingArgs.push_back(platformDefines);
2086#endif
2087#ifdef __HP_aCC
2088 snprintf(platformDefines, 64, "-DG__HP_aCC=%ld", (long)__HP_aCC);
2089 clingArgs.push_back(platformDefines);
2090#endif
2091#ifdef __sun
2092 snprintf(platformDefines, 64, "-DG__sun=%ld", (long)__sun);
2093 clingArgs.push_back(platformDefines);
2094#endif
2095#ifdef __SUNPRO_CC
2096 snprintf(platformDefines, 64, "-DG__SUNPRO_CC=%ld", (long)__SUNPRO_CC);
2097 clingArgs.push_back(platformDefines);
2098#endif
2099#ifdef _STLPORT_VERSION
2100 // stlport version, used on e.g. SUN
2101 snprintf(platformDefines, 64, "-DG__STLPORT_VERSION=%ld", (long)_STLPORT_VERSION);
2102 clingArgs.push_back(platformDefines);
2103#endif
2104#ifdef __ia64__
2105 snprintf(platformDefines, 64, "-DG__ia64=%ld", (long)__ia64__);
2106 clingArgs.push_back(platformDefines);
2107#endif
2108#ifdef __x86_64__
2109 snprintf(platformDefines, 64, "-DG__x86_64=%ld", (long)__x86_64__);
2110 clingArgs.push_back(platformDefines);
2111#endif
2112#ifdef __i386__
2113 snprintf(platformDefines, 64, "-DG__i386=%ld", (long)__i386__);
2114 clingArgs.push_back(platformDefines);
2115#endif
2116#ifdef __arm__
2117 snprintf(platformDefines, 64, "-DG__arm=%ld", (long)__arm__);
2118 clingArgs.push_back(platformDefines);
2119#endif
2120#ifdef _WIN32
2121 snprintf(platformDefines, 64, "-DG__WIN32=%ld", (long)_WIN32);
2122 clingArgs.push_back(platformDefines);
2123#else
2124# ifdef WIN32
2125 snprintf(platformDefines, 64, "-DG__WIN32=%ld", (long)WIN32);
2126 clingArgs.push_back(platformDefines);
2127# endif
2128#endif
2129#ifdef _WIN64
2130 snprintf(platformDefines, 64, "-DG__WIN64=%ld", (long)_WIN64);
2131 clingArgs.push_back(platformDefines);
2132#endif
2133#ifdef _MSC_VER
2134 snprintf(platformDefines, 64, "-DG__MSC_VER=%ld", (long)_MSC_VER);
2135 clingArgs.push_back(platformDefines);
2136 snprintf(platformDefines, 64, "-DG__VISUAL=%ld", (long)_MSC_VER);
2137 clingArgs.push_back(platformDefines);
2138#endif
2139}
2140
2141////////////////////////////////////////////////////////////////////////////////
2142/// Extract the filename from a fullpath
2143
2144std::string ExtractFileName(const std::string &path)
2145{
2146 return llvm::sys::path::filename(path).str();
2147}
2148
2149////////////////////////////////////////////////////////////////////////////////
2150/// Extract the path from a fullpath finding the last \ or /
2151/// according to the content in gPathSeparator
2152
2153void ExtractFilePath(const std::string &path, std::string &dirname)
2154{
2155 const size_t pos = path.find_last_of(gPathSeparator);
2156 if (std::string::npos != pos) {
2157 dirname.assign(path.begin(), path.begin() + pos + 1);
2158 } else {
2159 dirname.assign("");
2160 }
2161}
2162
2163////////////////////////////////////////////////////////////////////////////////
2164/// Check if file has a path
2165
2166bool HasPath(const std::string &name)
2167{
2168 std::string dictLocation;
2170 return !dictLocation.empty();
2171}
2172
2173////////////////////////////////////////////////////////////////////////////////
2174
2176 std::string &rootmapLibName)
2177{
2178 // If the rootmap file name does not exist, create one following the libname
2179 // I.E. put into the directory of the lib the rootmap and within the rootmap the normalised path to the lib
2180 if (rootmapFileName.empty()) {
2181 size_t libExtensionPos = rootmapLibName.find_last_of(gLibraryExtension) - gLibraryExtension.size() + 1;
2182 rootmapFileName = rootmapLibName.substr(0, libExtensionPos) + ".rootmap";
2183 size_t libCleanNamePos = rootmapLibName.find_last_of(gPathSeparator) + 1;
2184 rootmapLibName = rootmapLibName.substr(libCleanNamePos, std::string::npos);
2185 ROOT::TMetaUtils::Info(nullptr, "Rootmap file name %s built from rootmap lib name %s",
2186 rootmapLibName.c_str(),
2187 rootmapFileName.c_str());
2188 }
2189}
2190
2191////////////////////////////////////////////////////////////////////////////////
2192/// Extract the proper autoload key for nested classes
2193/// The routine does not erase the name, just updates it
2194
2195void GetMostExternalEnclosingClassName(const clang::DeclContext &theContext,
2196 std::string &ctxtName,
2197 const cling::Interpreter &interpreter,
2198 bool treatParent = true)
2199{
2200 const clang::DeclContext *outerCtxt = treatParent ? theContext.getParent() : &theContext;
2201 // If the context has no outer context, we are finished
2202 if (!outerCtxt) return;
2203 // If the context is a class, we update the name
2204 if (const clang::RecordDecl *thisRcdDecl = llvm::dyn_cast<clang::RecordDecl>(outerCtxt)) {
2206 }
2207 // We recurse
2209}
2210
2211////////////////////////////////////////////////////////////////////////////////
2212
2214 std::string &ctxtName,
2215 const cling::Interpreter &interpreter)
2216{
2217 const clang::DeclContext *theContext = theDecl.getDeclContext();
2219}
2220
2221////////////////////////////////////////////////////////////////////////////////
2222template<class COLL>
2223int ExtractAutoloadKeys(std::list<std::string> &names,
2224 const COLL &decls,
2225 const cling::Interpreter &interp)
2226{
2227 if (!decls.empty()) {
2228 std::string autoLoadKey;
2229 for (auto & d : decls) {
2230 autoLoadKey = "";
2232 // If there is an outer class, it is already considered
2233 if (autoLoadKey.empty()) {
2234 names.push_back(d->getQualifiedNameAsString());
2235 }
2236 }
2237 }
2238 return 0;
2239}
2240
2241////////////////////////////////////////////////////////////////////////////////
2242/// Generate a rootmap file in the new format, like
2243/// { decls }
2244/// `namespace A { namespace B { template <typename T> class myTemplate; } }`
2245/// [libGpad.so libGraf.so libHist.so libMathCore.so]
2246/// class TAttCanvas
2247/// class TButton
2248/// (header1.h header2.h .. headerN.h)
2249/// class TMyClass
2250
2252 const std::string &rootmapLibName,
2253 const std::list<std::string> &classesDefsList,
2254 const std::list<std::string> &classesNames,
2255 const std::list<std::string> &nsNames,
2256 const std::list<std::string> &tdNames,
2257 const std::list<std::string> &enNames,
2258 const std::list<std::string> &varNames,
2260 const std::unordered_set<std::string> headersToIgnore)
2261{
2262 // Create the rootmap file from the selected classes and namespaces
2263 std::ofstream rootmapFile(rootmapFileName.c_str());
2264 if (!rootmapFile) {
2265 ROOT::TMetaUtils::Error(nullptr, "Opening new rootmap file %s\n", rootmapFileName.c_str());
2266 return 1;
2267 }
2268
2269 // Keep track of the classes keys
2270 // This is done to avoid duplications of keys with typedefs
2271 std::unordered_set<std::string> classesKeys;
2272
2273
2274 // Add the "section"
2275 if (!classesNames.empty() || !nsNames.empty() || !tdNames.empty() ||
2276 !enNames.empty() || !varNames.empty()) {
2277
2278 // Add the template definitions
2279 if (!classesDefsList.empty()) {
2280 rootmapFile << "{ decls }\n";
2281 for (auto & classDef : classesDefsList) {
2282 rootmapFile << classDef << std::endl;
2283 }
2284 rootmapFile << "\n";
2285 }
2286 rootmapFile << "[ " << rootmapLibName << " ]\n";
2287
2288 // Loop on selected classes and insert them in the rootmap
2289 if (!classesNames.empty()) {
2290 rootmapFile << "# List of selected classes\n";
2291 for (auto & className : classesNames) {
2292 rootmapFile << "class " << className << std::endl;
2293 classesKeys.insert(className);
2294 }
2295 // And headers
2296 std::unordered_set<std::string> treatedHeaders;
2297 for (auto & className : classesNames) {
2298 // Don't treat templates
2299 if (className.find("<") != std::string::npos) continue;
2300 if (headersClassesMap.count(className)) {
2301 auto &headers = headersClassesMap.at(className);
2302 if (!headers.empty()){
2303 auto &header = headers.front();
2304 if (treatedHeaders.insert(header).second &&
2305 headersToIgnore.find(header) == headersToIgnore.end() &&
2307 rootmapFile << "header " << header << std::endl;
2308 }
2309 }
2310 }
2311 }
2312 }
2313
2314 // Same for namespaces
2315 if (!nsNames.empty()) {
2316 rootmapFile << "# List of selected namespaces\n";
2317 for (auto & nsName : nsNames) {
2318 rootmapFile << "namespace " << nsName << std::endl;
2319 }
2320 }
2321
2322 // And typedefs. These are used just to trigger the autoload mechanism
2323 if (!tdNames.empty()) {
2324 rootmapFile << "# List of selected typedefs and outer classes\n";
2325 for (const auto & autoloadKey : tdNames)
2326 if (classesKeys.insert(autoloadKey).second)
2327 rootmapFile << "typedef " << autoloadKey << std::endl;
2328 }
2329
2330 // And Enums. There is no incomplete type for an enum but we can nevertheless
2331 // have the key for the cases where the root typesystem is interrogated.
2332 if (!enNames.empty()){
2333 rootmapFile << "# List of selected enums and outer classes\n";
2334 for (const auto & autoloadKey : enNames)
2335 if (classesKeys.insert(autoloadKey).second)
2336 rootmapFile << "enum " << autoloadKey << std::endl;
2337 }
2338
2339 // And variables.
2340 if (!varNames.empty()){
2341 rootmapFile << "# List of selected vars\n";
2342 for (const auto & autoloadKey : varNames)
2343 if (classesKeys.insert(autoloadKey).second)
2344 rootmapFile << "var " << autoloadKey << std::endl;
2345 }
2346
2347 }
2348
2349 return 0;
2350
2351}
2352
2353////////////////////////////////////////////////////////////////////////////////
2354/// Performance is not critical here.
2355
2356std::pair<std::string,std::string> GetExternalNamespaceAndContainedEntities(const std::string line)
2357{
2358 auto nsPattern = '{'; auto nsPatternLength = 1;
2359 auto foundNsPos = line.find_last_of(nsPattern);
2360 if (foundNsPos == std::string::npos) return {"",""};
2362 auto extNs = line.substr(0,foundNsPos);
2363
2364 auto nsEndPattern = '}';
2365 auto foundEndNsPos = line.find(nsEndPattern);
2367
2368 return {extNs, contained};
2369
2370
2371}
2372
2373////////////////////////////////////////////////////////////////////////////////
2374/// If two identical namespaces are there, just declare one only
2375/// Example:
2376/// namespace A { namespace B { fwd1; }}
2377/// namespace A { namespace B { fwd2; }}
2378/// get a namespace A { namespace B { fwd1; fwd2; }} line
2379
2380std::list<std::string> CollapseIdenticalNamespaces(const std::list<std::string>& fwdDeclarationsList)
2381{
2382 // Temp data structure holding the namespaces and the entities therewith
2383 // contained
2384 std::map<std::string, std::string> nsEntitiesMap;
2385 std::list<std::string> optFwdDeclList;
2386 for (auto const & fwdDecl : fwdDeclarationsList){
2387 // Check if the decl(s) are contained in a ns and which one
2389 if (extNsAndEntities.first.empty()) {
2390 // no namespace found. Just put this on top
2391 optFwdDeclList.push_front(fwdDecl);
2392 };
2395 }
2396
2397 // Now fill the new, optimised list
2398 std::string optFwdDecl;
2399 for (auto const & extNsAndEntities : nsEntitiesMap) {
2401 optFwdDecl += extNsAndEntities.second;
2402 for (int i = 0; i < std::count(optFwdDecl.begin(), optFwdDecl.end(), '{'); ++i ){
2403 optFwdDecl += " }";
2404 }
2405 optFwdDeclList.push_front(optFwdDecl);
2406 }
2407
2408 return optFwdDeclList;
2409
2410}
2411
2412////////////////////////////////////////////////////////////////////////////////
2413/// Separate multiline strings
2414
2415bool ProcessAndAppendIfNotThere(const std::string &el,
2416 std::list<std::string> &el_list,
2417 std::unordered_set<std::string> &el_set)
2418{
2419 std::stringstream elStream(el);
2420 std::string tmp;
2421 bool added = false;
2422 while (getline(elStream, tmp, '\n')) {
2423 // Add if not there
2424 if (el_set.insert(tmp).second && !tmp.empty()) {
2425 el_list.push_back(tmp);
2426 added = true;
2427 }
2428 }
2429
2430 return added;
2431}
2432
2433////////////////////////////////////////////////////////////////////////////////
2434
2436 std::list<std::string> &classesList,
2437 std::list<std::string> &classesListForRootmap,
2438 std::list<std::string> &fwdDeclarationsList,
2439 const cling::Interpreter &interpreter)
2440{
2441 // Loop on selected classes. If they don't have the attribute "rootmap"
2442 // set to "false", store them in the list of classes for the rootmap
2443 // Returns 0 in case of success and 1 in case of issues.
2444
2445 // An unordered_set to keep track of the existing classes.
2446 // We want to avoid duplicates there as they may hint to a serious corruption
2447 std::unordered_set<std::string> classesSet;
2448 std::unordered_set<std::string> outerMostClassesSet;
2449
2450 std::string attrName, attrValue;
2451 bool isClassSelected;
2452 std::unordered_set<std::string> availableFwdDecls;
2453 std::string fwdDeclaration;
2454 for (auto const & selVar : scan.fSelectedVariables) {
2455 fwdDeclaration = "";
2458 }
2459
2460 for (auto const & selEnum : scan.fSelectedEnums) {
2461 fwdDeclaration = "";
2464 }
2465
2466 // Loop on selected classes and put them in a list
2467 for (auto const & selClass : scan.fSelectedClasses) {
2468 isClassSelected = true;
2469 const clang::RecordDecl *rDecl = selClass.GetRecordDecl();
2470 std::string normalizedName;
2471 normalizedName = selClass.GetNormalizedName();
2472 if (!normalizedName.empty() &&
2473 !classesSet.insert(normalizedName).second &&
2474 outerMostClassesSet.count(normalizedName) == 0) {
2475 std::cerr << "FATAL: A class with normalized name " << normalizedName
2476 << " was already selected. This means that two different instances of"
2477 << " clang::RecordDecl had the same name, which is not possible."
2478 << " This can be a hint of a serious problem in the class selection."
2479 << " In addition, the generated dictionary would not even compile.\n";
2480 return 1;
2481 }
2482 classesList.push_back(normalizedName);
2483 // Allow to autoload with the name of the class as it was specified in the
2484 // selection xml or linkdef
2485 const char *reqName(selClass.GetRequestedName());
2486
2487 // Get always the containing namespace, put it in the list if not there
2488 fwdDeclaration = "";
2491
2492 // Get template definition and put it in if not there
2493 if (llvm::isa<clang::ClassTemplateSpecializationDecl>(rDecl)) {
2494 fwdDeclaration = "";
2496 if (retCode == 0) {
2497 std::string fwdDeclarationTemplateSpec;
2500 }
2501 if (retCode == 0)
2503 }
2504
2505
2506 // Loop on attributes, if rootmap=false, don't put it in the list!
2507 for (auto ait = rDecl->attr_begin(); ait != rDecl->attr_end(); ++ait) {
2509 attrName == "rootmap" &&
2510 attrValue == "false") {
2511 attrName = attrValue = "";
2512 isClassSelected = false;
2513 break;
2514 }
2515 }
2516 if (isClassSelected) {
2517 // Now, check if this is an internal class. If yes, we check the name of the outermost one
2518 // This is because of ROOT-6517. On the other hand, we exclude from this treatment
2519 // classes which are template instances which are nested in classes. For example:
2520 // class A{
2521 // class B{};
2522 // };
2523 // selection: <class name="A::B" />
2524 // Will result in a rootmap entry like "class A"
2525 // On the other hand, taking
2526 // class A{
2527 // public:
2528 // template <class T> class B{};
2529 // };
2530 // selection: <class name="A::B<int>" />
2531 // Would result in an entry like "class A::B<int>"
2532 std::string outerMostClassName;
2534 if (!outerMostClassName.empty() &&
2535 !llvm::isa<clang::ClassTemplateSpecializationDecl>(rDecl) &&
2536 classesSet.insert(outerMostClassName).second &&
2537 outerMostClassesSet.insert(outerMostClassName).second) {
2539 } else {
2541 if (reqName && reqName[0] && reqName != normalizedName) {
2542 classesListForRootmap.push_back(reqName);
2543 }
2544
2545 // Also register typeinfo::name(), unless we have pseudo-strong typedefs.
2546 // GetDemangledTypeInfo() checks for Double32_t etc already and returns an empty string.
2547 std::string demangledName = selClass.GetDemangledTypeInfo();
2548 if (!demangledName.empty()) {
2549 // See the operations in TCling::AutoLoad(type_info)
2552
2554 // if demangledName != other name
2556 }
2557 }
2558 }
2559 }
2560 }
2561 classesListForRootmap.sort();
2562
2563 // Disable for the moment
2564 // fwdDeclarationsList = CollapseIdenticalNamespaces(fwdDeclarationsList);
2565
2566 return 0;
2567}
2568
2569////////////////////////////////////////////////////////////////////////////////
2570/// Loop on selected classes and put them in a list
2571
2572void ExtractSelectedNamespaces(RScanner &scan, std::list<std::string> &nsList)
2573{
2574 for (RScanner::NamespaceColl_t::const_iterator selNsIter = scan.fSelectedNamespaces.begin();
2575 selNsIter != scan.fSelectedNamespaces.end(); ++selNsIter) {
2576 nsList.push_back(ROOT::TMetaUtils::GetQualifiedName(* selNsIter->GetNamespaceDecl()));
2577 }
2578}
2579
2580////////////////////////////////////////////////////////////////////////////////
2581/// We need annotations even in the PCH: // !, // || etc.
2582
2583void AnnotateAllDeclsForPCH(cling::Interpreter &interp,
2584 RScanner &scan)
2585{
2586 auto const & declSelRulesMap = scan.GetDeclsSelRulesMap();
2587 for (auto const & selClass : scan.fSelectedClasses) {
2588 // Very important: here we decide if we want to attach attributes to the decl.
2589 if (clang::CXXRecordDecl *CXXRD =
2590 llvm::dyn_cast<clang::CXXRecordDecl>(const_cast<clang::RecordDecl *>(selClass.GetRecordDecl()))) {
2592 }
2593 }
2594}
2595
2596////////////////////////////////////////////////////////////////////////////////
2597
2599 RScanner &scan)
2600{
2601 for (auto const & selClass : scan.fSelectedClasses) {
2602 if (!selClass.GetRecordDecl()->isCompleteDefinition() || selClass.RequestOnlyTClass()) {
2603 continue;
2604 }
2605 const clang::CXXRecordDecl *cxxdecl = llvm::dyn_cast<clang::CXXRecordDecl>(selClass.GetRecordDecl());
2607 ROOT::TMetaUtils::Error("CheckClassesForInterpreterOnlyDicts",
2608 "Interactivity only dictionaries are not supported for classes with ClassDef\n");
2609 return 1;
2610 }
2611 }
2612 return 0;
2613}
2614
2615////////////////////////////////////////////////////////////////////////////////
2616/// Make up for skipping RegisterModule, now that dictionary parsing
2617/// is done and these headers cannot be selected anymore.
2618
2619int FinalizeStreamerInfoWriting(cling::Interpreter &interp, bool writeEmptyRootPCM=false)
2620{
2621 if (!gDriverConfig->fCloseStreamerInfoROOTFile)
2622 return 0;
2623
2624 if (interp.parseForModule("#include \"TStreamerInfo.h\"\n"
2625 "#include \"TFile.h\"\n"
2626 "#include \"TObjArray.h\"\n"
2627 "#include \"TVirtualArray.h\"\n"
2628 "#include \"TStreamerElement.h\"\n"
2629 "#include \"TProtoClass.h\"\n"
2630 "#include \"TBaseClass.h\"\n"
2631 "#include \"TListOfDataMembers.h\"\n"
2632 "#include \"TListOfEnums.h\"\n"
2633 "#include \"TListOfEnumsWithLock.h\"\n"
2634 "#include \"TDataMember.h\"\n"
2635 "#include \"TEnum.h\"\n"
2636 "#include \"TEnumConstant.h\"\n"
2637 "#include \"TDictAttributeMap.h\"\n"
2638 "#include \"TMessageHandler.h\"\n"
2639 "#include \"TArray.h\"\n"
2640 "#include \"TRefArray.h\"\n"
2641 "#include \"root_std_complex.h\"\n")
2642 != cling::Interpreter::kSuccess)
2643 return 1;
2644 if (!gDriverConfig->fCloseStreamerInfoROOTFile(writeEmptyRootPCM)) {
2645 return 1;
2646 }
2647 return 0;
2648}
2649
2650////////////////////////////////////////////////////////////////////////////////
2651
2652int GenerateFullDict(std::ostream &dictStream, std::string dictName, cling::Interpreter &interp, RScanner &scan,
2654 bool isSelXML, bool writeEmptyRootPCM)
2655{
2657
2658 bool needsCollectionProxy = false;
2659
2660 //
2661 // We will loop over all the classes several times.
2662 // In order we will call
2663 //
2664 // WriteClassInit (code to create the TGenericClassInfo)
2665 // check for constructor and operator input
2666 // WriteClassFunctions (declared in ClassDef)
2667 // WriteClassCode (Streamer,ShowMembers,Auxiliary functions)
2668 //
2669
2670
2671 //
2672 // Loop over all classes and create Streamer() & Showmembers() methods
2673 //
2674
2675 // SELECTION LOOP
2676 for (auto const & ns : scan.fSelectedNamespaces) {
2679 }
2680 auto nsName = ns.GetNamespaceDecl()->getQualifiedNameAsString();
2681 if (nsName.find("(anonymous)") == std::string::npos)
2682 EmitStreamerInfo(nsName.c_str());
2683 }
2684
2685 for (auto const & selClass : scan.fSelectedClasses) {
2686 if (!selClass.GetRecordDecl()->isCompleteDefinition()) {
2687 ROOT::TMetaUtils::Error(nullptr, "A dictionary has been requested for %s but there is no declaration!\n", ROOT::TMetaUtils::GetQualifiedName(selClass).c_str());
2688 continue;
2689 }
2690 if (selClass.RequestOnlyTClass()) {
2691 // fprintf(stderr,"rootcling: Skipping class %s\n",R__GetQualifiedName(* selClass.GetRecordDecl()).c_str());
2692 // For now delay those for later.
2693 continue;
2694 }
2695
2696 // Very important: here we decide if we want to attach attributes to the decl.
2697
2698 if (clang::CXXRecordDecl *CXXRD =
2699 llvm::dyn_cast<clang::CXXRecordDecl>(const_cast<clang::RecordDecl *>(selClass.GetRecordDecl()))) {
2701 }
2702
2703 const clang::CXXRecordDecl *CRD = llvm::dyn_cast<clang::CXXRecordDecl>(selClass.GetRecordDecl());
2704
2705 if (CRD) {
2706 ROOT::TMetaUtils::Info(nullptr, "Generating code for class %s\n", selClass.GetNormalizedName());
2707 if (TMetaUtils::IsStdClass(*CRD) && 0 != TClassEdit::STLKind(CRD->getName().str() /* unqualified name without template argument */)) {
2708 // Register the collections
2709 // coverity[fun_call_w_exception] - that's just fine.
2710 Internal::RStl::Instance().GenerateTClassFor(selClass.GetNormalizedName(), CRD, interp, normCtxt);
2711 } else if (CRD->getName() == "RVec") {
2712 static const clang::DeclContext *vecOpsDC = nullptr;
2713 if (!vecOpsDC)
2714 vecOpsDC = llvm::dyn_cast<clang::DeclContext>(
2715 interp.getLookupHelper().findScope("ROOT::VecOps", cling::LookupHelper::NoDiagnostics));
2716 if (vecOpsDC && vecOpsDC->Equals(CRD->getDeclContext())) {
2717 // Register the collections
2718 // coverity[fun_call_w_exception] - that's just fine.
2719 Internal::RStl::Instance().GenerateTClassFor(selClass.GetNormalizedName(), CRD, interp, normCtxt);
2720 }
2721 } else {
2725 }
2726 EmitStreamerInfo(selClass.GetNormalizedName());
2727 }
2728 }
2729 }
2730
2731 //
2732 // Write all TBuffer &operator>>(...), Class_Name(), Dictionary(), etc.
2733 // first to allow template specialisation to occur before template
2734 // instantiation (STK)
2735 //
2736 // SELECTION LOOP
2737 for (auto const & selClass : scan.fSelectedClasses) {
2738
2739 if (!selClass.GetRecordDecl()->isCompleteDefinition() || selClass.RequestOnlyTClass()) {
2740 // For now delay those for later.
2741 continue;
2742 }
2743 const clang::CXXRecordDecl *cxxdecl = llvm::dyn_cast<clang::CXXRecordDecl>(selClass.GetRecordDecl());
2746 }
2747 }
2748
2749 // LINKDEF SELECTION LOOP
2750 // Loop to get the shadow class for the class marked 'RequestOnlyTClass' (but not the
2751 // STL class which is done via Internal::RStl::Instance().WriteClassInit(0);
2752 // and the ClassInit
2753
2754 for (auto const & selClass : scan.fSelectedClasses) {
2755 if (!selClass.GetRecordDecl()->isCompleteDefinition() || !selClass.RequestOnlyTClass()) {
2756 continue;
2757 }
2758
2759 const clang::CXXRecordDecl *CRD = llvm::dyn_cast<clang::CXXRecordDecl>(selClass.GetRecordDecl());
2760
2765 }
2766 EmitStreamerInfo(selClass.GetNormalizedName());
2767 }
2768 }
2769 // Loop to write all the ClassCode
2771 for (auto const &selClass : scan.fSelectedClasses) {
2772 // The "isGenreflex" parameter allows the distinction between
2773 // genreflex and rootcling only for the treatment of collections which
2774 // are data members. To preserve the behaviour of the original
2775 // genreflex and rootcling tools, if the selection is performed with
2776 // genreflex, data members with collection type do not trigger the
2777 // selection of the collection type
2779 selClass,
2780 interp,
2781 normCtxt,
2782 dictStream,
2783 ctorTypes,
2784 isGenreflex);
2785 }
2786
2787 // Loop on the registered collections internally
2788 // coverity[fun_call_w_exception] - that's just fine.
2791 }
2792
2793 std::vector<std::string> standaloneTargets;
2797
2798 if (!gDriverConfig->fBuildingROOTStage1) {
2801 // Make up for skipping RegisterModule, now that dictionary parsing
2802 // is done and these headers cannot be selected anymore.
2804 if (finRetCode != 0) return finRetCode;
2805 }
2806
2807 return 0;
2808}
2809
2810////////////////////////////////////////////////////////////////////////////////
2811
2812void CreateDictHeader(std::ostream &dictStream, const std::string &main_dictname)
2813{
2814 dictStream << "// Do NOT change. Changes will be lost next time file is generated\n\n"
2815 << "#define R__DICTIONARY_FILENAME " << main_dictname << std::endl
2816
2817 // We do not want deprecation warnings to fire in dictionaries
2818 << "#define R__NO_DEPRECATION" << std::endl
2819
2820 // Now that CINT is not longer there to write the header file,
2821 // write one and include in there a few things for backward
2822 // compatibility.
2823 << "\n/*******************************************************************/\n"
2824 << "#include <stddef.h>\n"
2825 << "#include <stdio.h>\n"
2826 << "#include <stdlib.h>\n"
2827 << "#include <string.h>\n"
2828 << "#include <assert.h>\n"
2829 << "#define G__DICTIONARY\n"
2830 << "#include \"ROOT/RConfig.hxx\"\n"
2831 << "#include \"TClass.h\"\n"
2832 << "#include \"TDictAttributeMap.h\"\n"
2833 << "#include \"TInterpreter.h\"\n"
2834 << "#include \"TROOT.h\"\n"
2835 << "#include \"TBuffer.h\"\n"
2836 << "#include \"TMemberInspector.h\"\n"
2837 << "#include \"TInterpreter.h\"\n"
2838 << "#include \"TVirtualMutex.h\"\n"
2839 << "#include \"TError.h\"\n\n"
2840 << "#ifndef G__ROOT\n"
2841 << "#define G__ROOT\n"
2842 << "#endif\n\n"
2843 << "#include \"RtypesImp.h\"\n"
2844 << "#include \"TIsAProxy.h\"\n"
2845 << "#include \"TFileMergeInfo.h\"\n"
2846 << "#include <algorithm>\n"
2847 << "#include \"TCollectionProxyInfo.h\"\n"
2848 << "/*******************************************************************/\n\n"
2849 << "#include \"TDataMember.h\"\n\n"; // To set their transiency
2850}
2851
2852////////////////////////////////////////////////////////////////////////////////
2853
2855{
2856 dictStream << "// The generated code does not explicitly qualify STL entities\n"
2857 << "namespace std {} using namespace std;\n\n";
2858}
2859
2860////////////////////////////////////////////////////////////////////////////////
2861
2863 const std::string &includeForSource,
2864 const std::string &extraIncludes)
2865{
2866 dictStream << "// Header files passed as explicit arguments\n"
2867 << includeForSource << std::endl
2868 << "// Header files passed via #pragma extra_include\n"
2869 << extraIncludes << std::endl;
2870}
2871
2872//______________________________________________________________________________
2873
2874// cross-compiling for iOS and iOS simulator (assumes host is Intel Mac OS X)
2875#if defined(R__IOSSIM) || defined(R__IOS)
2876#ifdef __x86_64__
2877#undef __x86_64__
2878#endif
2879#ifdef __i386__
2880#undef __i386__
2881#endif
2882#ifdef R__IOSSIM
2883#define __i386__ 1
2884#endif
2885#ifdef R__IOS
2886#define __arm__ 1
2887#endif
2888#endif
2889
2890////////////////////////////////////////////////////////////////////////////////
2891/// Little helper class to bookkeep the files names which we want to make
2892/// temporary.
2893
2895public:
2896 //______________________________________________
2897 tempFileNamesCatalog(): m_size(0), m_emptyString("") {};
2898
2899 std::string getTmpFileName(const std::string &filename) {
2900 return filename + "_tmp_" + std::to_string(getpid());
2901 }
2902 /////////////////////////////////////////////////////////////////////////////
2903 /// Adds the name and the associated temp name to the catalog.
2904 /// Changes the name into the temp name
2905
2906 void addFileName(std::string &nameStr) {
2907 if (nameStr.empty()) return;
2908
2909 std::string tmpNameStr(getTmpFileName(nameStr));
2910
2911 // For brevity
2912 const char *name(nameStr.c_str());
2913 const char *tmpName(tmpNameStr.c_str());
2914
2915 m_names.push_back(nameStr);
2916 m_tempNames.push_back(tmpNameStr);
2917 ROOT::TMetaUtils::Info(nullptr, "File %s added to the tmp catalog.\n", name);
2918
2919 // This is to allow update of existing files
2920 if (0 == std::rename(name , tmpName)) {
2921 ROOT::TMetaUtils::Info(nullptr, "File %s existing. Preserved as %s.\n", name, tmpName);
2922 }
2923
2924 // To change the name to its tmp version
2926
2927 m_size++;
2928
2929 }
2930
2931 /////////////////////////////////////////////////////////////////////////////
2932
2933 int clean() {
2934 int retval = 0;
2935 // rename the temp files into the normal ones
2936 for (unsigned int i = 0; i < m_size; ++i) {
2937 const char *tmpName = m_tempNames[i].c_str();
2938 // Check if the file exists
2939 std::ifstream ifile(tmpName);
2940 if (!ifile)
2941 ROOT::TMetaUtils::Error(nullptr, "Cannot find %s!\n", tmpName);
2942 // Make sure the file is closed, mostly for Windows FS, also when
2943 // accessing it from a Linux VM via a shared folder
2944 if (ifile.is_open())
2945 ifile.close();
2946 if (0 != std::remove(tmpName)) {
2947 ROOT::TMetaUtils::Error(nullptr, "Removing %s!\n", tmpName);
2948 retval++;
2949 }
2950 }
2951 return retval;
2952 }
2953
2954 /////////////////////////////////////////////////////////////////////////////
2955
2956 int commit() {
2957 int retval = 0;
2958 // rename the temp files into the normal ones
2959 for (unsigned int i = 0; i < m_size; ++i) {
2960 const char *tmpName = m_tempNames[i].c_str();
2961 const char *name = m_names[i].c_str();
2962 // Check if the file exists
2963 std::ifstream ifile(tmpName);
2964 if (!ifile)
2965 ROOT::TMetaUtils::Error(nullptr, "Cannot find %s!\n", tmpName);
2966 // Make sure the file is closed, mostly for Windows FS, also when
2967 // accessing it from a Linux VM via a shared folder
2968 if (ifile.is_open())
2969 ifile.close();
2970#ifdef WIN32
2971 // Sometimes files cannot be renamed on Windows if they don't have
2972 // been released by the system. So just copy them and try to delete
2973 // the old one afterwards.
2974 if (0 != std::rename(tmpName , name)) {
2975 if (llvm::sys::fs::copy_file(tmpName , name)) {
2976 llvm::sys::fs::remove(tmpName);
2977 }
2978 }
2979#else
2980 if (0 != std::rename(tmpName , name)) {
2981 ROOT::TMetaUtils::Error(nullptr, "Renaming %s into %s!\n", tmpName, name);
2982 retval++;
2983 }
2984#endif
2985 }
2986 return retval;
2987 }
2988
2989 /////////////////////////////////////////////////////////////////////////////
2990
2991 const std::string &getFileName(const std::string &tmpFileName) {
2992 size_t i = std::distance(m_tempNames.begin(),
2993 find(m_tempNames.begin(), m_tempNames.end(), tmpFileName));
2994 if (i == m_tempNames.size()) return m_emptyString;
2995 return m_names[i];
2996 }
2997
2998 /////////////////////////////////////////////////////////////////////////////
2999
3000 void dump() {
3001 std::cout << "Restoring files in temporary file catalog:\n";
3002 for (unsigned int i = 0; i < m_size; ++i) {
3003 std::cout << m_tempNames[i] << " --> " << m_names[i] << std::endl;
3004 }
3005 }
3006
3007private:
3008 unsigned int m_size;
3009 const std::string m_emptyString;
3010 std::vector<std::string> m_names;
3011 std::vector<std::string> m_tempNames;
3012};
3013
3014////////////////////////////////////////////////////////////////////////////////
3015/// Transform name of dictionary
3016
3017std::ostream *CreateStreamPtrForSplitDict(const std::string &dictpathname,
3019{
3020 std::string splitDictName(tmpCatalog.getFileName(dictpathname));
3021 const size_t dotPos = splitDictName.find_last_of(".");
3022 splitDictName.insert(dotPos, "_classdef");
3023 tmpCatalog.addFileName(splitDictName);
3024 return new std::ofstream(splitDictName.c_str());
3025}
3026
3027////////////////////////////////////////////////////////////////////////////////
3028/// Transform -W statements in diagnostic pragmas for cling reacting on "-Wno-"
3029/// For example
3030/// -Wno-deprecated-declarations --> `#pragma clang diagnostic ignored "-Wdeprecated-declarations"`
3031
3032static void CheckForMinusW(std::string arg,
3033 std::list<std::string> &diagnosticPragmas)
3034{
3035 static const std::string pattern("-Wno-");
3036
3037 if (arg.find(pattern) != 0)
3038 return;
3039
3040 ROOT::TMetaUtils::ReplaceAll(arg, pattern, "#pragma clang diagnostic ignored \"-W");
3041 arg += "\"";
3042 diagnosticPragmas.push_back(arg);
3043}
3044
3045////////////////////////////////////////////////////////////////////////////////
3046
3048 cling::Interpreter &interp)
3049{
3050 using namespace ROOT::TMetaUtils::AST2SourceTools;
3051 std::string fwdDecl;
3052 std::string initStr("{");
3053 auto &fwdDeclnArgsToSkipColl = normCtxt.GetTemplNargsToKeepMap();
3055 auto &clTemplDecl = *strigNargsToKeepPair.first;
3056 FwdDeclFromTmplDecl(clTemplDecl , interp, fwdDecl);
3057 initStr += "{\"" +
3058 fwdDecl + "\", "
3059 + std::to_string(strigNargsToKeepPair.second)
3060 + "},";
3061 }
3062 if (!fwdDeclnArgsToSkipColl.empty())
3063 initStr.pop_back();
3064 initStr += "}";
3065 return initStr;
3066}
3067
3068////////////////////////////////////////////////////////////////////////////////
3069/// Get the pointee type if possible
3070
3071clang::QualType GetPointeeTypeIfPossible(const clang::QualType &qt)
3072{
3073 if (qt.isNull()) return qt;
3074 clang::QualType thisQt(qt);
3075 while (thisQt->isPointerType() ||
3076 thisQt->isReferenceType()) {
3077 thisQt = thisQt->getPointeeType();
3078 }
3079 return thisQt;
3080
3081}
3082
3083////////////////////////////////////////////////////////////////////////////////
3084/// Extract the list of headers necessary for the Decl
3085
3086std::list<std::string> RecordDecl2Headers(const clang::CXXRecordDecl &rcd,
3087 const cling::Interpreter &interp,
3088 std::set<const clang::CXXRecordDecl *> &visitedDecls)
3089{
3090 std::list<std::string> headers;
3091
3092 // We push a new transaction because we could deserialize decls here
3093 cling::Interpreter::PushTransactionRAII RAII(&interp);
3094
3095 // Avoid infinite recursion
3096 if (!visitedDecls.insert(rcd.getCanonicalDecl()).second)
3097 return headers;
3098
3099 // If this is a template
3100 if (const clang::ClassTemplateSpecializationDecl *tsd = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(&rcd)) {
3101
3102 // Loop on the template args
3103 for (auto & tArg : tsd->getTemplateArgs().asArray()) {
3104 if (clang::TemplateArgument::ArgKind::Type != tArg.getKind()) continue;
3105 auto tArgQualType = GetPointeeTypeIfPossible(tArg.getAsType());
3106 if (tArgQualType.isNull()) continue;
3107 if (const clang::CXXRecordDecl *tArgCxxRcd = tArgQualType->getAsCXXRecordDecl()) {
3109 }
3110 }
3111
3112 if (!ROOT::TMetaUtils::IsStdClass(rcd) && rcd.hasDefinition()) {
3113
3114 // Loop on base classes - with a newer llvm, range based possible
3115 for (auto baseIt = tsd->bases_begin(); baseIt != tsd->bases_end(); baseIt++) {
3116 auto baseQualType = GetPointeeTypeIfPossible(baseIt->getType());
3117 if (baseQualType.isNull()) continue;
3118 if (const clang::CXXRecordDecl *baseRcdPtr = baseQualType->getAsCXXRecordDecl()) {
3120 }
3121 }
3122
3123 // Loop on the data members - with a newer llvm, range based possible
3124 for (auto declIt = tsd->decls_begin(); declIt != tsd->decls_end(); ++declIt) {
3125 if (const clang::FieldDecl *fieldDecl = llvm::dyn_cast<clang::FieldDecl>(*declIt)) {
3127 if (fieldQualType.isNull()) continue ;
3128 if (const clang::CXXRecordDecl *fieldCxxRcd = fieldQualType->getAsCXXRecordDecl()) {
3129 if (fieldCxxRcd->hasDefinition())
3131 }
3132 }
3133 }
3134
3135 // Loop on methods
3136 for (auto methodIt = tsd->method_begin(); methodIt != tsd->method_end(); ++methodIt) {
3137 // Check arguments
3138 for (auto & fPar : methodIt->parameters()) {
3139 auto fParQualType = GetPointeeTypeIfPossible(fPar->getOriginalType());
3140 if (fParQualType.isNull()) continue;
3141 if (const clang::CXXRecordDecl *fParCxxRcd = fParQualType->getAsCXXRecordDecl()) {
3142 if (fParCxxRcd->hasDefinition())
3144 }
3145 }
3146 // Check return value
3147 auto retQualType = GetPointeeTypeIfPossible(methodIt->getReturnType());
3148 if (retQualType.isNull()) continue;
3149 if (const clang::CXXRecordDecl *retCxxRcd = retQualType->getAsCXXRecordDecl()) {
3150 if (retCxxRcd->hasDefinition())
3152 }
3153 }
3154 }
3155
3156 } // End template instance
3157
3158 std::string header = ROOT::TMetaUtils::GetFileName(rcd, interp);
3159 headers.emplace_back(header);
3160 headers.reverse();
3161 return headers;
3162
3163}
3164
3165////////////////////////////////////////////////////////////////////////////////
3166/// Check if the class good for being an autoparse key.
3167/// We exclude from this set stl containers of pods/strings
3168/// TODO: we may use also __gnu_cxx::
3169bool IsGoodForAutoParseMap(const clang::RecordDecl& rcd){
3170
3171 // If it's not an std class, we just pick it up.
3172 if (auto dclCtxt= rcd.getDeclContext()){
3173 if (! dclCtxt->isStdNamespace()){
3174 return true;
3175 }
3176 } else {
3177 return true;
3178 }
3179
3180 // Now, we have a stl class. We now check if it's a template. If not, we
3181 // do not take it: bitset, string and so on.
3182 auto clAsTmplSpecDecl = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(&rcd);
3183 if (!clAsTmplSpecDecl) return false;
3184
3185 // Now we have a template in the stl. Let's see what the arguments are.
3186 // If they are not a POD or something which is good for autoparsing, we keep
3187 // them.
3188 auto& astCtxt = rcd.getASTContext();
3189 auto& templInstArgs = clAsTmplSpecDecl->getTemplateInstantiationArgs();
3190 for (auto&& arg : templInstArgs.asArray()){
3191
3192 auto argKind = arg.getKind();
3193 if (argKind != clang::TemplateArgument::Type){
3194 if (argKind == clang::TemplateArgument::Integral) continue;
3195 else return true;
3196 }
3197
3198 auto argQualType = arg.getAsType();
3199 auto isPOD = argQualType.isPODType(astCtxt);
3200 // This is a POD, we can inspect the next arg
3201 if (isPOD) continue;
3202
3203 auto argType = argQualType.getTypePtr();
3204 if (auto recType = llvm::dyn_cast<clang::RecordType>(argType)){
3206 // The arg is a class but good for the map
3207 if (isArgGoodForAutoParseMap) continue;
3208 } else {
3209 // The class is not a POD nor a class we can skip
3210 return true;
3211 }
3212 }
3213
3214 return false;
3215}
3216
3217////////////////////////////////////////////////////////////////////////////////
3218
3226 const cling::Interpreter &interp)
3227{
3228 std::set<const clang::CXXRecordDecl *> visitedDecls;
3229 std::unordered_set<std::string> buffer;
3230 std::string autoParseKey;
3231
3232 // Add some manip of headers
3233 for (auto & annotatedRcd : annotatedRcds) {
3234 if (const clang::CXXRecordDecl *cxxRcd =
3235 llvm::dyn_cast_or_null<clang::CXXRecordDecl>(annotatedRcd.GetRecordDecl())) {
3236 autoParseKey = "";
3237 visitedDecls.clear();
3238 std::list<std::string> headers(RecordDecl2Headers(*cxxRcd, interp, visitedDecls));
3239 // remove duplicates, also if not subsequent
3240 buffer.clear();
3241 headers.remove_if([&buffer](const std::string & s) {
3242 return !buffer.insert(s).second;
3243 });
3245 if (autoParseKey.empty()) autoParseKey = annotatedRcd.GetNormalizedName();
3248 headersDeclsMap[annotatedRcd.GetRequestedName()] = headers;
3249 } else {
3250 ROOT::TMetaUtils::Info(nullptr, "Class %s is not included in the set of autoparse keys.\n", autoParseKey.c_str());
3251 }
3252
3253 // Propagate to the classes map only if this is not a template.
3254 // The header is then used as autoload key and we want to avoid duplicates.
3255 if (!llvm::isa<clang::ClassTemplateSpecializationDecl>(cxxRcd)){
3257 headersClassesMap[annotatedRcd.GetRequestedName()] = headersDeclsMap[annotatedRcd.GetRequestedName()];
3258 }
3259 }
3260 }
3261
3262 // The same for the typedefs:
3263 for (auto & tDef : tDefDecls) {
3264 if (clang::CXXRecordDecl *cxxRcd = tDef->getUnderlyingType()->getAsCXXRecordDecl()) {
3265 autoParseKey = "";
3266 visitedDecls.clear();
3267 std::list<std::string> headers(RecordDecl2Headers(*cxxRcd, interp, visitedDecls));
3269 // remove duplicates, also if not subsequent
3270 buffer.clear();
3271 headers.remove_if([&buffer](const std::string & s) {
3272 return !buffer.insert(s).second;
3273 });
3275 if (autoParseKey.empty()) autoParseKey = tDef->getQualifiedNameAsString();
3277 }
3278 }
3279
3280 // The same for the functions:
3281 for (auto & func : funcDecls) {
3282 std::list<std::string> headers = {ROOT::TMetaUtils::GetFileName(*func, interp)};
3284 }
3285
3286 // The same for the variables:
3287 for (auto & var : varDecls) {
3288 std::list<std::string> headers = {ROOT::TMetaUtils::GetFileName(*var, interp)};
3290 }
3291
3292 // The same for the enums:
3293 for (auto & en : enumDecls) {
3294 std::list<std::string> headers = {ROOT::TMetaUtils::GetFileName(*en, interp)};
3296 }
3297}
3298
3299////////////////////////////////////////////////////////////////////////////////
3300/// Generate the fwd declarations of the selected entities
3301
3302static std::string GenerateFwdDeclString(const RScanner &scan,
3303 const cling::Interpreter &interp)
3304{
3305 std::string newFwdDeclString;
3306
3307 using namespace ROOT::TMetaUtils::AST2SourceTools;
3308
3309 std::string fwdDeclString;
3310 std::string buffer;
3311 std::unordered_set<std::string> fwdDecls;
3312
3313 // Classes
3314/*
3315 for (auto const & annRcd : scan.fSelectedClasses) {
3316 const auto rcdDeclPtr = annRcd.GetRecordDecl();
3317
3318 int retCode = FwdDeclFromRcdDecl(*rcdDeclPtr, interp, buffer);
3319 if (-1 == retCode) {
3320 ROOT::TMetaUtils::Error("GenerateFwdDeclString",
3321 "Error generating fwd decl for class %s\n",
3322 annRcd.GetNormalizedName());
3323 return emptyString;
3324 }
3325 if (retCode == 0 && fwdDecls.insert(buffer).second)
3326 fwdDeclString += "\"" + buffer + "\"\n";
3327 }
3328*/
3329 // Build the input for a transaction containing all of the selected declarations
3330 // Cling will produce the fwd declaration payload.
3331
3332 std::vector<const clang::Decl *> selectedDecls(scan.fSelectedClasses.size());
3333
3334 // Pick only RecordDecls
3335 std::transform (scan.fSelectedClasses.begin(),
3336 scan.fSelectedClasses.end(),
3338 [](const ROOT::TMetaUtils::AnnotatedRecordDecl& rcd){return rcd.GetRecordDecl();});
3339
3340 for (auto* TD: scan.fSelectedTypedefs)
3341 selectedDecls.push_back(TD);
3342
3343// for (auto* VAR: scan.fSelectedVariables)
3344// selectedDecls.push_back(VAR);
3345
3346 std::string fwdDeclLogs;
3347
3348 // The "R\"DICTFWDDCLS(\n" ")DICTFWDDCLS\"" pieces have been moved to
3349 // TModuleGenerator to be able to make the diagnostics more telling in presence
3350 // of an issue ROOT-6752.
3352
3353 if (genreflex::verbose && !fwdDeclLogs.empty())
3354 std::cout << "Logs from forward decl printer: \n"
3355 << fwdDeclLogs;
3356
3357 // Functions
3358// for (auto const& fcnDeclPtr : scan.fSelectedFunctions){
3359// int retCode = FwdDeclFromFcnDecl(*fcnDeclPtr, interp, buffer);
3360// newFwdDeclString += Decl2FwdDecl(*fcnDeclPtr,interp);
3361// if (-1 == retCode){
3362// ROOT::TMetaUtils::Error("GenerateFwdDeclString",
3363// "Error generating fwd decl for function %s\n",
3364// fcnDeclPtr->getNameAsString().c_str());
3365// return emptyString;
3366// }
3367// if (retCode == 0 && fwdDecls.insert(buffer).second)
3368// fwdDeclString+="\""+buffer+"\"\n";
3369// }
3370
3371 if (fwdDeclString.empty()) fwdDeclString = "";
3372 return fwdDeclString;
3373}
3374
3375////////////////////////////////////////////////////////////////////////////////
3376/// Generate a string for the dictionary from the headers-classes map.
3377
3379 const std::string &detectedUmbrella,
3380 bool payLoadOnly = false)
3381{
3382 std::string headerName;
3383
3385 std::cout << "Class-headers Mapping:\n";
3386 std::string headersClassesMapString = "";
3387 for (auto const & classHeaders : headersClassesMap) {
3389 std::cout << " o " << classHeaders.first << " --> ";
3391 headersClassesMapString += classHeaders.first + "\"";
3392 for (auto const & header : classHeaders.second) {
3393 headerName = (detectedUmbrella == header || payLoadOnly) ? "payloadCode" : "\"" + header + "\"";
3396 std::cout << ", " << headerName;
3397 if (payLoadOnly)
3398 break;
3399 }
3401 std::cout << std::endl;
3402 headersClassesMapString += ", \"@\",\n";
3403 }
3404 headersClassesMapString += "nullptr";
3406}
3407
3408////////////////////////////////////////////////////////////////////////////////
3409
3410bool IsImplementationName(const std::string &filename)
3411{
3413}
3414
3415////////////////////////////////////////////////////////////////////////////////
3416/// Check if the argument is a sane cling argument. Performing the following checks:
3417/// 1) It does not start with "--" and is not the --param option.
3418
3419bool IsCorrectClingArgument(const std::string& argument)
3420{
3421 if (ROOT::TMetaUtils::BeginsWith(argument,"--") && !ROOT::TMetaUtils::BeginsWith(argument,"--param")) return false;
3422 return true;
3423}
3424
3425////////////////////////////////////////////////////////////////////////////////
3426bool NeedsSelection(const char* name)
3427{
3428 static const std::vector<std::string> namePrfxes {
3429 "array<",
3430 "unique_ptr<"};
3431 auto pos = find_if(namePrfxes.begin(),
3432 namePrfxes.end(),
3433 [&](const std::string& str){return ROOT::TMetaUtils::BeginsWith(name,str);});
3434 return namePrfxes.end() == pos;
3435}
3436
3437////////////////////////////////////////////////////////////////////////////////
3438
3440{
3441 static const std::vector<std::string> uclNamePrfxes {
3442 "chrono:",
3443 "ratio<",
3444 "shared_ptr<"};
3445 static const std::set<std::string> unsupportedClassesNormNames{
3446 "regex",
3447 "thread"};
3448 if ( unsupportedClassesNormNames.count(name) == 1) return false;
3449 auto pos = find_if(uclNamePrfxes.begin(),
3451 [&](const std::string& str){return ROOT::TMetaUtils::BeginsWith(name,str);});
3452 return uclNamePrfxes.end() == pos;
3453}
3454
3455////////////////////////////////////////////////////////////////////////////////
3456/// Check if the list of selected classes contains any class which is not
3457/// supported. Return the number of unsupported classes in the selection.
3458
3460{
3461 int nerrors = 0;
3462 for (auto&& aRcd : annotatedRcds){
3463 auto clName = aRcd.GetNormalizedName();
3465 std::cerr << "Error: Class " << clName << " has been selected but "
3466 << "currently the support for its I/O is not yet available. Note that "
3467 << clName << ", even if not selected, will be available for "
3468 << "interpreted code.\n";
3469 nerrors++;
3470 }
3471 if (!NeedsSelection(clName)){
3472 std::cerr << "Error: It is not necessary to explicitly select class "
3473 << clName << ". I/O is supported for it transparently.\n";
3474 nerrors++;
3475 }
3476 }
3477 return nerrors;
3478}
3479
3480////////////////////////////////////////////////////////////////////////////////
3481
3482class TRootClingCallbacks : public cling::InterpreterCallbacks {
3483private:
3484 std::list<std::string>& fFilesIncludedByLinkdef;
3485 bool isLocked = false;
3486public:
3487 TRootClingCallbacks(cling::Interpreter* interp, std::list<std::string>& filesIncludedByLinkdef):
3488 InterpreterCallbacks(interp),
3489 fFilesIncludedByLinkdef(filesIncludedByLinkdef){};
3490
3492
3493 void InclusionDirective(clang::SourceLocation /*HashLoc*/, const clang::Token & /*IncludeTok*/,
3494 llvm::StringRef FileName, bool IsAngled, clang::CharSourceRange /*FilenameRange*/,
3495 clang::OptionalFileEntryRef /*File*/, llvm::StringRef /*SearchPath*/,
3496 llvm::StringRef /*RelativePath*/, const clang::Module * /*Imported*/,
3497 clang::SrcMgr::CharacteristicKind /*FileType*/) override
3498 {
3499 if (isLocked) return;
3500 if (IsAngled) return;
3501 auto& PP = m_Interpreter->getCI()->getPreprocessor();
3502 auto curLexer = PP.getCurrentFileLexer();
3503 if (!curLexer) return;
3504 auto fileEntry = curLexer->getFileEntry();
3505 if (!fileEntry) return;
3506 auto thisFileName = fileEntry->getName();
3507 auto fileNameAsString = FileName.str();
3509 if (isThisLinkdef) {
3512 fFilesIncludedByLinkdef.clear();
3513 isLocked = true;
3514 } else {
3515 fFilesIncludedByLinkdef.emplace_back(fileNameAsString.c_str());
3516 }
3517 }
3518 }
3519
3520 // rootcling pre-includes things such as Rtypes.h. This means that ACLiC can
3521 // call rootcling asking it to create a module for a file with no #includes
3522 // but relying on things from Rtypes.h such as the ClassDef macro.
3523 //
3524 // When rootcling starts building a module, it becomes resilient to the
3525 // outside environment and pre-included files have no effect. This hook
3526 // informs rootcling when a new submodule is being built so that it can
3527 // make Core.Rtypes.h visible.
3528 void EnteredSubmodule(clang::Module* M,
3529 clang::SourceLocation ImportLoc,
3530 bool ForPragma) override {
3531 assert(M);
3532 using namespace clang;
3533 if (llvm::StringRef(M->Name).ends_with("ACLiC_dict")) {
3534 Preprocessor& PP = m_Interpreter->getCI()->getPreprocessor();
3535 HeaderSearch& HS = PP.getHeaderSearchInfo();
3536 // FIXME: Reduce to Core.Rtypes.h.
3537 Module* CoreModule = HS.lookupModule("Core", SourceLocation(),
3538 /*AllowSearch*/false);
3539 assert(M && "Must have module Core");
3540 PP.makeModuleVisible(CoreModule, ImportLoc);
3541 }
3542 }
3543};
3544
3545static llvm::cl::opt<bool> gOptSystemModuleByproducts("mSystemByproducts", llvm::cl::Hidden,
3546 llvm::cl::desc("Allow implicit build of system modules."),
3547 llvm::cl::cat(gRootclingOptions));
3548static llvm::cl::list<std::string>
3549gOptModuleByproducts("mByproduct", llvm::cl::ZeroOrMore,
3550 llvm::cl::Hidden,
3551 llvm::cl::desc("The list of the expected implicit modules build as part of building the current module."),
3552 llvm::cl::cat(gRootclingOptions));
3553// Really llvm::cl::Required, will be changed in RootClingMain below.
3554static llvm::cl::opt<std::string>
3555gOptDictionaryFileName(llvm::cl::Positional,
3556 llvm::cl::desc("<output dictionary file>"),
3557 llvm::cl::cat(gRootclingOptions));
3558
3559////////////////////////////////////////////////////////////////////////////////
3560/// Custom diag client for clang that verifies that each implicitly build module
3561/// is a system module. If not, it will let the current rootcling invocation
3562/// fail with an error. All other diags beside module build remarks will be
3563/// forwarded to the passed child diag client.
3564///
3565/// The reason why we need this is that if we built implicitly a C++ module
3566/// that belongs to a ROOT dictionary, then we will miss information generated
3567/// by rootcling in this file (e.g. the source code comments to annotation
3568/// attributes transformation will be missing in the module file).
3569class CheckModuleBuildClient : public clang::DiagnosticConsumer {
3570 clang::DiagnosticConsumer *fChild;
3572 clang::ModuleMap &fMap;
3573
3574public:
3575 CheckModuleBuildClient(clang::DiagnosticConsumer *Child, bool OwnsChild, clang::ModuleMap &Map)
3576 : fChild(Child), fOwnsChild(OwnsChild), fMap(Map)
3577 {
3578 }
3579
3581 {
3582 if (fOwnsChild)
3583 delete fChild;
3584 }
3585
3586 virtual void HandleDiagnostic(clang::DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &Info) override
3587 {
3588 using namespace clang::diag;
3589
3590 // This method catches the module_build remark from clang and checks if
3591 // the implicitly built module is a system module or not. We only support
3592 // building system modules implicitly.
3593
3594 std::string moduleName;
3595 const clang::Module *module = nullptr;
3596
3597 // Extract the module from the diag argument with index 0.
3598 const auto &ID = Info.getID();
3599 if (ID == remark_module_build || ID == remark_module_build_done) {
3600 moduleName = Info.getArgStdStr(0);
3601 module = fMap.findModule(moduleName);
3602 // We should never be able to build a module without having it in the
3603 // modulemap. Still, let's print a warning that we at least tell the
3604 // user that this could lead to problems.
3605 if (!module) {
3607 "Couldn't find module %s in the available modulemaps. This"
3608 "prevents us from correctly diagnosing wrongly built modules.\n",
3609 moduleName.c_str());
3610 }
3611 }
3612
3613 // A dictionary module could build implicitly a set of implicit modules.
3614 // For example, the Core module builds libc.pcm and std.pcm implicitly.
3615 // Those modules do not require I/O information and it is okay to build
3616 // them as part of another module.
3617 // However, we can build a module which requires I/O implictly which is
3618 // an error because rootcling is not able to generate the corresponding
3619 // dictionary.
3620 // If we build a I/O requiring module implicitly we should display
3621 // an error unless -mSystemByproducts or -mByproduct were specified.
3622 bool isByproductModule = false;
3623 if (module) {
3624 // -mSystemByproducts allows implicit building of any system module.
3625 if (module->IsSystem && gOptSystemModuleByproducts) {
3626 isByproductModule = true;
3627 }
3628 // -mByproduct lists concrete module names that are allowed.
3631 isByproductModule = true;
3632 }
3633 }
3634 if (!isByproductModule)
3635 fChild->HandleDiagnostic(DiagLevel, Info);
3636
3637 if (ID == remark_module_build && !isByproductModule) {
3639 "Building module '%s' implicitly. If '%s' requires a \n"
3640 "dictionary please specify build dependency: '%s' depends on '%s'.\n"
3641 "Otherwise, specify '-mByproduct %s' to disable this diagnostic.\n",
3642 moduleName.c_str(), moduleName.c_str(), gOptDictionaryFileName.c_str(),
3643 moduleName.c_str(), moduleName.c_str());
3644 }
3645 }
3646
3647 // All methods below just forward to the child and the default method.
3648 virtual void clear() override
3649 {
3650 fChild->clear();
3651 DiagnosticConsumer::clear();
3652 }
3653
3654 virtual void BeginSourceFile(const clang::LangOptions &LangOpts, const clang::Preprocessor *PP) override
3655 {
3656 fChild->BeginSourceFile(LangOpts, PP);
3657 DiagnosticConsumer::BeginSourceFile(LangOpts, PP);
3658 }
3659
3660 virtual void EndSourceFile() override
3661 {
3662 fChild->EndSourceFile();
3663 DiagnosticConsumer::EndSourceFile();
3664 }
3665
3666 virtual void finish() override
3667 {
3668 fChild->finish();
3669 DiagnosticConsumer::finish();
3670 }
3671
3672 virtual bool IncludeInDiagnosticCounts() const override { return fChild->IncludeInDiagnosticCounts(); }
3673};
3674
3676#if defined(_WIN32) && defined(_MSC_VER)
3677 // Suppress error dialogs to avoid hangs on build nodes.
3678 // One can use an environment variable (Cling_GuiOnAssert) to enable
3679 // the error dialogs.
3680 const char *EnablePopups = getenv("Cling_GuiOnAssert");
3681 if (EnablePopups == nullptr || EnablePopups[0] == '0') {
3689 }
3690#endif
3691}
3692
3693static llvm::cl::opt<bool> gOptForce("f", llvm::cl::desc("Overwrite <file>s."),
3694 llvm::cl::cat(gRootclingOptions));
3695static llvm::cl::opt<bool> gOptRootBuild("rootbuild", llvm::cl::desc("If we are building ROOT."),
3696 llvm::cl::Hidden,
3697 llvm::cl::cat(gRootclingOptions));
3706static llvm::cl::opt<VerboseLevel>
3707gOptVerboseLevel(llvm::cl::desc("Choose verbosity level:"),
3708 llvm::cl::values(clEnumVal(v, "Show errors."),
3709 clEnumVal(v0, "Show only fatal errors."),
3710 clEnumVal(v1, "Show errors (the same as -v)."),
3711 clEnumVal(v2, "Show warnings (default)."),
3712 clEnumVal(v3, "Show notes."),
3713 clEnumVal(v4, "Show information.")),
3714 llvm::cl::init(v2),
3715 llvm::cl::cat(gRootclingOptions));
3716
3717static llvm::cl::opt<bool>
3718gOptCint("cint", llvm::cl::desc("Deprecated, legacy flag which is ignored."),
3719 llvm::cl::Hidden,
3720 llvm::cl::cat(gRootclingOptions));
3721static llvm::cl::opt<bool>
3722gOptReflex("reflex", llvm::cl::desc("Behave internally like genreflex."),
3723 llvm::cl::cat(gRootclingOptions));
3724static llvm::cl::opt<bool>
3725gOptGccXml("gccxml", llvm::cl::desc("Deprecated, legacy flag which is ignored."),
3726 llvm::cl::Hidden,
3727 llvm::cl::cat(gRootclingOptions));
3728static llvm::cl::opt<std::string>
3729gOptLibListPrefix("lib-list-prefix",
3730 llvm::cl::desc("An ACLiC feature which exports the list of dependent libraries."),
3731 llvm::cl::Hidden,
3732 llvm::cl::cat(gRootclingOptions));
3733static llvm::cl::opt<bool>
3734gOptGeneratePCH("generate-pch",
3735 llvm::cl::desc("Generates a pch file from a predefined set of headers. See makepch.py."),
3736 llvm::cl::Hidden,
3737 llvm::cl::cat(gRootclingOptions));
3738static llvm::cl::opt<bool>
3739gOptC("c", llvm::cl::desc("Deprecated, legacy flag which is ignored."),
3740 llvm::cl::cat(gRootclingOptions));
3741static llvm::cl::opt<bool>
3742gOptP("p", llvm::cl::desc("Deprecated, legacy flag which is ignored."),
3743 llvm::cl::cat(gRootclingOptions));
3744static llvm::cl::list<std::string>
3745gOptRootmapLibNames("rml", llvm::cl::ZeroOrMore,
3746 llvm::cl::desc("Generate rootmap file."),
3747 llvm::cl::cat(gRootclingOptions));
3748static llvm::cl::opt<std::string>
3750 llvm::cl::desc("Generate a rootmap file with the specified name."),
3751 llvm::cl::cat(gRootclingOptions));
3752static llvm::cl::opt<bool>
3753gOptCxxModule("cxxmodule",
3754 llvm::cl::desc("Generate a C++ module."),
3755 llvm::cl::cat(gRootclingOptions));
3756static llvm::cl::list<std::string>
3757gOptModuleMapFiles("moduleMapFile",
3758 llvm::cl::desc("Specify a C++ modulemap file."),
3759 llvm::cl::cat(gRootclingOptions));
3760// FIXME: Figure out how to combine the code of -umbrellaHeader and inlineInputHeader
3761static llvm::cl::opt<bool>
3762gOptUmbrellaInput("umbrellaHeader",
3763 llvm::cl::desc("A single header including all headers instead of specifying them on the command line."),
3764 llvm::cl::cat(gRootclingOptions));
3765static llvm::cl::opt<bool>
3766gOptMultiDict("multiDict",
3767 llvm::cl::desc("If this library has multiple separate LinkDef files."),
3768 llvm::cl::cat(gRootclingOptions));
3769static llvm::cl::opt<bool>
3770gOptNoGlobalUsingStd("noGlobalUsingStd",
3771 llvm::cl::desc("Do not declare {using namespace std} in dictionary global scope."),
3772 llvm::cl::cat(gRootclingOptions));
3773static llvm::cl::opt<bool>
3774gOptInterpreterOnly("interpreteronly",
3775 llvm::cl::desc("Generate minimal dictionary for interactivity (without IO information)."),
3776 llvm::cl::cat(gRootclingOptions));
3777static llvm::cl::opt<bool>
3779 llvm::cl::desc("Split the dictionary into two parts: one containing the IO (ClassDef)\
3780information and another the interactivity support."),
3781 llvm::cl::cat(gRootclingOptions));
3782static llvm::cl::opt<bool>
3783gOptNoDictSelection("noDictSelection",
3784 llvm::cl::Hidden,
3785 llvm::cl::desc("Do not run the selection rules. Useful when in -onepcm mode."),
3786 llvm::cl::cat(gRootclingOptions));
3787static llvm::cl::opt<std::string>
3789 llvm::cl::desc("The path to the library of the built dictionary."),
3790 llvm::cl::cat(gRootclingOptions));
3791static llvm::cl::list<std::string>
3793 llvm::cl::desc("The list of dependent modules of the dictionary."),
3794 llvm::cl::cat(gRootclingOptions));
3795static llvm::cl::list<std::string>
3796gOptExcludePaths("excludePath", llvm::cl::ZeroOrMore,
3797 llvm::cl::desc("Do not store the <path> in the dictionary."),
3798 llvm::cl::cat(gRootclingOptions));
3799// FIXME: This does not seem to work. We have one use of -inlineInputHeader in
3800// ROOT and it does not produce the expected result.
3801static llvm::cl::opt<bool>
3802gOptInlineInput("inlineInputHeader",
3803 llvm::cl::desc("Does not generate #include <header> but expands the header content."),
3804 llvm::cl::cat(gRootclingOptions));
3805// FIXME: This is totally the wrong concept. We should not expose an interface
3806// to be able to tell which component is in the pch and which needs extra
3807// scaffolding for interactive use. Moreover, some of the ROOT components are
3808// partially in the pch and this option makes it impossible to express that.
3809// We should be able to get the list of headers in the pch early and scan
3810// through them.
3811static llvm::cl::opt<bool>
3812gOptWriteEmptyRootPCM("writeEmptyRootPCM",
3813 llvm::cl::Hidden,
3814 llvm::cl::desc("Does not include the header files as it assumes they exist in the pch."),
3815 llvm::cl::cat(gRootclingOptions));
3816static llvm::cl::opt<bool>
3818 llvm::cl::desc("Check the selection syntax only."),
3819 llvm::cl::cat(gRootclingOptions));
3820static llvm::cl::opt<bool>
3821gOptFailOnWarnings("failOnWarnings",
3822 llvm::cl::desc("Fail if there are warnings."),
3823 llvm::cl::cat(gRootclingOptions));
3824static llvm::cl::opt<bool>
3825gOptNoIncludePaths("noIncludePaths",
3826 llvm::cl::desc("Do not store include paths but rely on the env variable ROOT_INCLUDE_PATH."),
3827 llvm::cl::cat(gRootclingOptions));
3828static llvm::cl::opt<std::string>
3829gOptISysRoot("isysroot", llvm::cl::Prefix, llvm::cl::Hidden,
3830 llvm::cl::desc("Specify an isysroot."),
3831 llvm::cl::cat(gRootclingOptions),
3832 llvm::cl::init("-"));
3833static llvm::cl::list<std::string>
3834gOptIncludePaths("I", llvm::cl::Prefix, llvm::cl::ZeroOrMore,
3835 llvm::cl::desc("Specify an include path."),
3836 llvm::cl::cat(gRootclingOptions));
3837static llvm::cl::list<std::string>
3838gOptCompDefaultIncludePaths("compilerI", llvm::cl::Prefix, llvm::cl::ZeroOrMore,
3839 llvm::cl::desc("Specify a compiler default include path, to suppress unneeded `-isystem` arguments."),
3840 llvm::cl::cat(gRootclingOptions));
3841static llvm::cl::list<std::string>
3842gOptSysIncludePaths("isystem", llvm::cl::ZeroOrMore,
3843 llvm::cl::desc("Specify a system include path."),
3844 llvm::cl::cat(gRootclingOptions));
3845static llvm::cl::list<std::string>
3846gOptPPDefines("D", llvm::cl::Prefix, llvm::cl::ZeroOrMore,
3847 llvm::cl::desc("Specify defined macros."),
3848 llvm::cl::cat(gRootclingOptions));
3849static llvm::cl::list<std::string>
3850gOptPPUndefines("U", llvm::cl::Prefix, llvm::cl::ZeroOrMore,
3851 llvm::cl::desc("Specify undefined macros."),
3852 llvm::cl::cat(gRootclingOptions));
3853static llvm::cl::list<std::string>
3854gOptWDiags("W", llvm::cl::Prefix, llvm::cl::ZeroOrMore,
3855 llvm::cl::desc("Specify compiler diagnostics options."),
3856 llvm::cl::cat(gRootclingOptions));
3857// Really OneOrMore, will be changed in RootClingMain below.
3858static llvm::cl::list<std::string>
3859gOptDictionaryHeaderFiles(llvm::cl::Positional, llvm::cl::ZeroOrMore,
3860 llvm::cl::desc("<list of dictionary header files> <LinkDef file | selection xml file>"),
3861 llvm::cl::cat(gRootclingOptions));
3862static llvm::cl::list<std::string>
3863gOptSink(llvm::cl::ZeroOrMore, llvm::cl::Sink,
3864 llvm::cl::desc("Consumes all unrecognized options."),
3865 llvm::cl::cat(gRootclingOptions));
3866
3867static llvm::cl::SubCommand
3868gBareClingSubcommand("bare-cling", "Call directly cling and exit.");
3869
3870static llvm::cl::list<std::string>
3871gOptBareClingSink(llvm::cl::OneOrMore, llvm::cl::Sink,
3872 llvm::cl::desc("Consumes options and sends them to cling."),
3873 llvm::cl::cat(gRootclingOptions), llvm::cl::sub(gBareClingSubcommand));
3874
3875////////////////////////////////////////////////////////////////////////////////
3876/// Returns true iff a given module (and its submodules) contains all headers
3877/// needed by the given ModuleGenerator.
3878/// The names of all header files that are needed by the ModuleGenerator but are
3879/// not in the given module will be inserted into the MissingHeader variable.
3880/// Returns true iff the PCH was successfully generated.
3882 clang::Module *module, std::vector<std::array<std::string, 2>> &missingHeaders)
3883{
3884 // Now we collect all header files from the previously collected modules.
3885 std::vector<clang::Module::Header> moduleHeaders;
3887 [&moduleHeaders](const clang::Module::Header &h) { moduleHeaders.push_back(h); });
3888
3889 bool foundAllHeaders = true;
3890
3891 auto isHeaderInModule = [&moduleHeaders](const std::string &header) {
3892 for (const clang::Module::Header &moduleHeader : moduleHeaders)
3893 if (header == moduleHeader.NameAsWritten)
3894 return true;
3895 return false;
3896 };
3897
3898 // Go through the list of headers that are required by the ModuleGenerator
3899 // and check for each header if it's in one of the modules we loaded.
3900 // If not, make sure we fail at the end and mark the header as missing.
3901 for (const std::string &header : modGen.GetHeaders()) {
3902 if (isHeaderInModule(header))
3903 continue;
3904
3905 clang::ModuleMap::KnownHeader SuggestedModule;
3906 clang::ConstSearchDirIterator *CurDir = nullptr;
3907 if (auto FE = headerSearch.LookupFile(
3908 header, clang::SourceLocation(),
3909 /*isAngled*/ false,
3910 /*FromDir*/ 0, CurDir,
3911 clang::ArrayRef<std::pair<clang::OptionalFileEntryRef, clang::DirectoryEntryRef>>(),
3912 /*SearchPath*/ 0,
3913 /*RelativePath*/ 0,
3914 /*RequestingModule*/ 0, &SuggestedModule,
3915 /*IsMapped*/ 0,
3916 /*IsFrameworkFound*/ nullptr,
3917 /*SkipCache*/ false,
3918 /*BuildSystemModule*/ false,
3919 /*OpenFile*/ false,
3920 /*CacheFail*/ false)) {
3921 if (auto OtherModule = SuggestedModule.getModule()) {
3922 std::string OtherModuleName;
3923 auto TLM = OtherModule->getTopLevelModuleName();
3924 if (!TLM.empty())
3925 OtherModuleName = TLM.str();
3926 else
3928
3929 // Don't complain about headers that are actually in by-products:
3932 continue;
3933
3934 missingHeaders.push_back({header, OtherModuleName});
3935 }
3936 } else {
3937 missingHeaders.push_back({header, {}});
3938 }
3939 foundAllHeaders = false;
3940 }
3941 return foundAllHeaders;
3942}
3943
3944////////////////////////////////////////////////////////////////////////////////
3945/// Check moduleName validity from modulemap. Check if this module is defined or not.
3946static bool CheckModuleValid(TModuleGenerator &modGen, const std::string &resourceDir, cling::Interpreter &interpreter,
3947 llvm::StringRef LinkdefPath, const std::string &moduleName)
3948{
3949 clang::CompilerInstance *CI = interpreter.getCI();
3950 clang::HeaderSearch &headerSearch = CI->getPreprocessor().getHeaderSearchInfo();
3951 headerSearch.loadTopLevelSystemModules();
3952
3953 // Actually lookup the module on the computed module name.
3954 clang::Module *module = headerSearch.lookupModule(llvm::StringRef(moduleName));
3955
3956 // Inform the user and abort if we can't find a module with a given name.
3957 if (!module) {
3958 ROOT::TMetaUtils::Error("CheckModuleValid", "Couldn't find module with name '%s' in modulemap!\n",
3959 moduleName.c_str());
3960 return false;
3961 }
3962
3963 // Check if the loaded module covers all headers that were specified
3964 // by the user on the command line. This is an integrity check to
3965 // ensure that our used module map is not containing extraneous headers.
3966 std::vector<std::array<std::string, 2>> missingHdrMod;
3968 // FIXME: Upgrade this to an error once modules are stable.
3969 std::stringstream msgStream;
3970 msgStream << "after creating module \"" << module->Name << "\" ";
3971 if (!module->PresumedModuleMapFile.empty())
3972 msgStream << "using modulemap \"" << module->PresumedModuleMapFile << "\" ";
3973 msgStream << "the following headers are not part of that module:\n";
3974 for (auto &H : missingHdrMod) {
3975 msgStream << " " << H[0];
3976 if (!H[1].empty())
3977 msgStream << " (already part of module \"" << H[1] << "\")";
3978 msgStream << "\n";
3979 }
3980 std::string warningMessage = msgStream.str();
3981
3982 bool maybeUmbrella = modGen.GetHeaders().size() == 1;
3983 // We may have an umbrella and forgot to add the flag. Downgrade the
3984 // warning into an information message.
3985 // FIXME: We should open the umbrella, extract the set of header files
3986 // and check if they exist in the modulemap.
3987 // FIXME: We should also check if the header files are specified in the
3988 // modulemap file as they appeared in the rootcling invocation, i.e.
3989 // if we passed rootcling ... -I/some/path somedir/some/header, the
3990 // modulemap should contain module M { header "somedir/some/header" }
3991 // This way we will make sure the module is properly activated.
3993 ROOT::TMetaUtils::Info("CheckModuleValid, %s. You can silence this message by adding %s to the invocation.",
3994 warningMessage.c_str(),
3995 gOptUmbrellaInput.ArgStr.data());
3996 return true;
3997 }
3998
3999 ROOT::TMetaUtils::Warning("CheckModuleValid", warningMessage.c_str());
4000 // We include the missing headers to fix the module for the user.
4001 std::vector<std::string> missingHeaders;
4003 [](const std::array<std::string, 2>& HdrMod) { return HdrMod[0];});
4005 ROOT::TMetaUtils::Error("CheckModuleValid", "Couldn't include missing module headers for module '%s'!\n",
4006 module->Name.c_str());
4007 }
4008 }
4009
4010 return true;
4011}
4012
4013static llvm::StringRef GetModuleNameFromRdictName(llvm::StringRef rdictName)
4014{
4015 // Try to get the module name in the modulemap based on the filepath.
4016 llvm::StringRef moduleName = llvm::sys::path::filename(rdictName);
4017 moduleName.consume_front("lib");
4018 moduleName.consume_back(".pcm");
4019 moduleName.consume_back("_rdict");
4020 return moduleName;
4021}
4022
4023////////////////////////////////////////////////////////////////////////////////
4024
4026 char **argv,
4027 bool isGenreflex = false)
4028{
4029 // Set number of required arguments. We cannot do this globally since it
4030 // would interfere with LLVM's option parsing.
4031 gOptDictionaryFileName.setNumOccurrencesFlag(llvm::cl::Required);
4032 gOptDictionaryHeaderFiles.setNumOccurrencesFlag(llvm::cl::OneOrMore);
4033
4034 // Copied from cling driver.
4035 // FIXME: Uncomment once we fix ROOT's teardown order.
4036 //llvm::llvm_shutdown_obj shutdownTrigger;
4037
4038 const char *executableFileName = argv[0];
4039
4040 llvm::sys::PrintStackTraceOnErrorSignal(executableFileName);
4041 llvm::PrettyStackTraceProgram X(argc, argv);
4043
4044#if defined(R__WIN32) && !defined(R__WINGCC)
4045 // FIXME: This is terrible hack allocating and changing the argument set.
4046 // We should remove it and use standard llvm facilities to convert the paths.
4047 // cygwin's make is presenting us some cygwin paths even though
4048 // we are windows native. Convert them as good as we can.
4049 for (int iic = 1 /* ignore binary file name in argv[0] */; iic < argc; ++iic) {
4050 std::string iiarg(argv[iic]);
4052 size_t len = iiarg.length();
4053 // yes, we leak.
4054 char *argviic = new char[len + 1];
4055 strlcpy(argviic, iiarg.c_str(), len + 1);
4056 argv[iic] = argviic;
4057 }
4058 }
4059#endif
4060
4061 // Hide options from llvm which we got from static initialization of libCling.
4062 llvm::cl::HideUnrelatedOptions(/*keep*/gRootclingOptions);
4063
4064 // Define Options aliasses
4065 auto &opts = llvm::cl::getRegisteredOptions();
4066 llvm::cl::Option* optHelp = opts["help"];
4067 llvm::cl::alias optHelpAlias1("h",
4068 llvm::cl::desc("Alias for -help"),
4069 llvm::cl::aliasopt(*optHelp));
4070 llvm::cl::alias optHelpAlias2("?",
4071 llvm::cl::desc("Alias for -help"),
4072 llvm::cl::aliasopt(*optHelp));
4073
4074 llvm::cl::ParseCommandLineOptions(argc, argv, "rootcling");
4075
4076 std::string llvmResourceDir = std::string(gDriverConfig->fTROOT__GetEtcDir()) + "/cling";
4078 std::vector<const char *> clingArgsC;
4079 clingArgsC.push_back(executableFileName);
4080 // Help cling finds its runtime (RuntimeUniverse.h and such).
4081 clingArgsC.push_back("-I");
4082 clingArgsC.push_back(gDriverConfig->fTROOT__GetEtcDir());
4083
4084 //clingArgsC.push_back("-resource-dir");
4085 //clingArgsC.push_back(llvmResourceDir.c_str());
4086
4087 for (const std::string& Opt : gOptBareClingSink)
4088 clingArgsC.push_back(Opt.c_str());
4089
4090 auto interp = std::make_unique<cling::Interpreter>(clingArgsC.size(),
4091 &clingArgsC[0],
4092 llvmResourceDir.c_str());
4093 // FIXME: Diagnose when we have misspelled a flag. Currently we show no
4094 // diagnostic and report exit as success.
4095 return interp->getDiagnostics().hasFatalErrorOccurred();
4096 }
4097
4098 std::string dictname;
4099
4100 if (!gDriverConfig->fBuildingROOTStage1) {
4101 if (gOptRootBuild) {
4102 // running rootcling as part of the ROOT build for ROOT libraries.
4103 gBuildingROOT = true;
4104 }
4105 }
4106
4107 if (!gOptModuleMapFiles.empty() && !gOptCxxModule) {
4108 ROOT::TMetaUtils::Error("", "Option %s can be used only when option %s is specified.\n",
4109 gOptModuleMapFiles.ArgStr.str().c_str(),
4110 gOptCxxModule.ArgStr.str().c_str());
4111 std::cout << "\n";
4112 llvm::cl::PrintHelpMessage();
4113 return 1;
4114 }
4115
4116 // Set the default verbosity
4118 if (gOptVerboseLevel == v4)
4119 genreflex::verbose = true;
4120
4121 if (gOptReflex)
4122 isGenreflex = true;
4123
4124 if (!gOptLibListPrefix.empty()) {
4125 string filein = gOptLibListPrefix + ".in";
4126 FILE *fp;
4127 if ((fp = fopen(filein.c_str(), "r")) == nullptr) {
4128 ROOT::TMetaUtils::Error(nullptr, "%s: The input list file %s does not exist\n", executableFileName, filein.c_str());
4129 return 1;
4130 }
4131 fclose(fp);
4132 }
4133
4135 FILE *fp;
4136 if (!gOptIgnoreExistingDict && (fp = fopen(gOptDictionaryFileName.c_str(), "r")) != nullptr) {
4137 fclose(fp);
4138 if (!gOptForce) {
4139 ROOT::TMetaUtils::Error(nullptr, "%s: output file %s already exists\n", executableFileName, gOptDictionaryFileName.c_str());
4140 return 1;
4141 }
4142 }
4143
4144 // remove possible pathname to get the dictionary name
4145 if (gOptDictionaryFileName.size() > (PATH_MAX - 1)) {
4146 ROOT::TMetaUtils::Error(nullptr, "rootcling: dictionary name too long (more than %d characters): %s\n",
4147 (PATH_MAX - 1), gOptDictionaryFileName.c_str());
4148 return 1;
4149 }
4150
4151 dictname = llvm::sys::path::filename(gOptDictionaryFileName).str();
4152 }
4153
4154 if (gOptForce && dictname.empty()) {
4155 ROOT::TMetaUtils::Error(nullptr, "Inconsistent set of arguments detected: overwrite of dictionary file forced but no filename specified.\n");
4156 llvm::cl::PrintHelpMessage();
4157 return 1;
4158 }
4159
4160 std::vector<std::string> clingArgs;
4161 clingArgs.push_back(executableFileName);
4162 clingArgs.push_back("-iquote.");
4163
4165
4166 // Collect the diagnostic pragmas linked to the usage of -W
4167 // Workaround for ROOT-5656
4168 std::list<std::string> diagnosticPragmas = {"#pragma clang diagnostic ignored \"-Wdeprecated-declarations\""};
4169
4170 if (gOptFailOnWarnings) {
4171 using namespace ROOT::TMetaUtils;
4172 // If warnings are disabled with the current verbosity settings, lower
4173 // it so that the user sees the warning that caused the failure.
4174 if (GetErrorIgnoreLevel() > kWarning)
4175 GetErrorIgnoreLevel() = kWarning;
4176 GetWarningsAreErrors() = true;
4177 }
4178
4179 if (gOptISysRoot != "-") {
4180 if (gOptISysRoot.empty()) {
4181 ROOT::TMetaUtils::Error("", "isysroot specified without a value.\n");
4182 return 1;
4183 }
4184 clingArgs.push_back(gOptISysRoot.ArgStr.str());
4185 clingArgs.push_back(gOptISysRoot.ValueStr.str());
4186 }
4187
4188 // Check if we have a multi dict request but no target library
4189 if (gOptMultiDict && gOptSharedLibFileName.empty()) {
4190 ROOT::TMetaUtils::Error("", "Multidict requested but no target library. Please specify one with the -s argument.\n");
4191 return 1;
4192 }
4193
4194 for (const std::string &PPDefine : gOptPPDefines)
4195 clingArgs.push_back(std::string("-D") + PPDefine);
4196
4197 for (const std::string &PPUndefine : gOptPPUndefines)
4198 clingArgs.push_back(std::string("-U") + PPUndefine);
4199
4200 for (const std::string &IncludePath : gOptIncludePaths)
4201 clingArgs.push_back(std::string("-I") + llvm::sys::path::convert_to_slash(IncludePath));
4202
4203 for (const std::string &IncludePath : gOptSysIncludePaths) {
4204 // Prevent mentioning compiler default include directories as -isystem
4205 // (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70129)
4208 clingArgs.push_back("-isystem");
4209 clingArgs.push_back(llvm::sys::path::convert_to_slash(IncludePath));
4210 }
4211 }
4212
4213 for (const std::string &WDiag : gOptWDiags) {
4214 const std::string FullWDiag = std::string("-W") + WDiag;
4215 // Suppress warning when compiling the dictionary, eg. gcc G__xxx.cxx
4217 // Suppress warning when compiling the input headers by cling.
4218 clingArgs.push_back(FullWDiag);
4219 }
4220
4221 std::string includeDir = llvm::sys::path::convert_to_slash(gDriverConfig->fTROOT__GetIncludeDir());
4222 clingArgs.push_back(std::string("-I") + includeDir);
4223
4224 std::vector<std::string> pcmArgs;
4225 for (size_t parg = 0, n = clingArgs.size(); parg < n; ++parg) {
4226 auto thisArg = clingArgs[parg];
4228 if (thisArg == "-c" ||
4229 (gOptNoIncludePaths && isInclude)) continue;
4230 // We now check if the include directories are not excluded
4231 if (isInclude) {
4232 unsigned int offset = 2; // -I is two characters. Now account for spaces
4233 char c = thisArg[offset];
4234 while (c == ' ') c = thisArg[++offset];
4236 auto excludePathPos = std::find_if(gOptExcludePaths.begin(),
4238 [&](const std::string& path){
4239 return ROOT::TMetaUtils::BeginsWith(&thisArg[offset], path);});
4240 if (excludePathsEnd != excludePathPos) continue;
4241 }
4242 pcmArgs.push_back(thisArg);
4243 }
4244
4245 // cling-only arguments
4246 clingArgs.push_back(std::string("-I") + llvm::sys::path::convert_to_slash(gDriverConfig->fTROOT__GetEtcDir()));
4247 // We do not want __ROOTCLING__ in the pch!
4248 if (!gOptGeneratePCH) {
4249 clingArgs.push_back("-D__ROOTCLING__");
4250 }
4251#ifdef R__MACOSX
4252 clingArgs.push_back("-DSYSTEM_TYPE_macosx");
4253#elif defined(R__WIN32)
4254 clingArgs.push_back("-DSYSTEM_TYPE_winnt");
4255
4256 // Prevent the following #error: The C++ Standard Library forbids macroizing keywords.
4257 clingArgs.push_back("-D_XKEYCHECK_H");
4258 // Tell windows.h not to #define min and max, it clashes with numerical_limits.
4259 clingArgs.push_back("-DNOMINMAX");
4260#else // assume UNIX
4261 clingArgs.push_back("-DSYSTEM_TYPE_unix");
4262#endif
4263
4264 clingArgs.push_back("-fsyntax-only");
4265#ifndef R__WIN32
4266 clingArgs.push_back("-fPIC");
4267#endif
4268 clingArgs.push_back("-Xclang");
4269 clingArgs.push_back("-fmodules-embed-all-files");
4270 clingArgs.push_back("-Xclang");
4271 clingArgs.push_back("-main-file-name");
4272 clingArgs.push_back("-Xclang");
4273 clingArgs.push_back((dictname + ".h").c_str());
4274
4276
4277 // FIXME: This line is from TModuleGenerator, but we can't reuse this code
4278 // at this point because TModuleGenerator needs a CompilerInstance (and we
4279 // currently create the arguments for creating said CompilerInstance).
4280 bool isPCH = (gOptDictionaryFileName.getValue() == "allDict.cxx");
4281 std::string outputFile;
4282 // Data is in 'outputFile', therefore in the same scope.
4283 llvm::StringRef moduleName;
4284 std::string vfsArg;
4285 // Adding -fmodules to the args will break lexing with __CINT__ defined,
4286 // and we actually do lex with __CINT__ and reuse this variable later,
4287 // we have to copy it now.
4289
4290 if (gOptSharedLibFileName.empty()) {
4292 }
4293
4294 if (!isPCH && gOptCxxModule) {
4295 // We just pass -fmodules, the CIFactory will do the rest and configure
4296 // clang correctly once it sees this flag.
4297 clingArgsInterpreter.push_back("-fmodules");
4298 clingArgsInterpreter.push_back("-fno-implicit-module-maps");
4299
4300 for (const std::string &modulemap : gOptModuleMapFiles)
4301 clingArgsInterpreter.push_back("-fmodule-map-file=" + modulemap);
4302
4303 clingArgsInterpreter.push_back("-fmodule-map-file=" +
4304 std::string(gDriverConfig->fTROOT__GetIncludeDir()) +
4305 "/ROOT.modulemap");
4306 std::string ModuleMapCWD = ROOT::FoundationUtils::GetCurrentDir() + "/module.modulemap";
4307 if (llvm::sys::fs::exists(ModuleMapCWD))
4308 clingArgsInterpreter.push_back("-fmodule-map-file=" + ModuleMapCWD);
4309
4310 // Specify the module name that we can lookup the module in the modulemap.
4311 outputFile = llvm::sys::path::stem(gOptSharedLibFileName).str();
4312 // Try to get the module name in the modulemap based on the filepath.
4314
4315#ifdef _MSC_VER
4316 clingArgsInterpreter.push_back("-Xclang");
4317 clingArgsInterpreter.push_back("-fmodule-feature");
4318 clingArgsInterpreter.push_back("-Xclang");
4319 clingArgsInterpreter.push_back("msvc" + std::string(rootclingStringify(_MSC_VER)));
4320#endif
4321 clingArgsInterpreter.push_back("-fmodule-name=" + moduleName.str());
4322
4323 std::string moduleCachePath = llvm::sys::path::parent_path(gOptSharedLibFileName).str();
4324 // FIXME: This is a horrible workaround to fix the incremental builds.
4325 // The enumerated modules are built by clang impicitly based on #include of
4326 // a header which is contained within that module. The build system has
4327 // no way to track dependencies on them and trigger a rebuild.
4328 // A possible solution can be to disable completely the implicit build of
4329 // modules and each module to be built by rootcling. We need to teach
4330 // rootcling how to build modules with no IO support.
4331 if (moduleName == "Core") {
4332 assert(gDriverConfig->fBuildingROOTStage1);
4333 remove((moduleCachePath + llvm::sys::path::get_separator() + "_Builtin_intrinsics.pcm").str().c_str());
4334 remove((moduleCachePath + llvm::sys::path::get_separator() + "_Builtin_stddef_max_align_t.pcm").str().c_str());
4335 remove((moduleCachePath + llvm::sys::path::get_separator() + "Cling_Runtime.pcm").str().c_str());
4336 remove((moduleCachePath + llvm::sys::path::get_separator() + "Cling_Runtime_Extra.pcm").str().c_str());
4337#ifdef R__WIN32
4338 remove((moduleCachePath + llvm::sys::path::get_separator() + "vcruntime.pcm").str().c_str());
4339 remove((moduleCachePath + llvm::sys::path::get_separator() + "services.pcm").str().c_str());
4340#endif
4341
4342#ifdef R__MACOSX
4343 remove((moduleCachePath + llvm::sys::path::get_separator() + "Darwin.pcm").str().c_str());
4344#else
4345 remove((moduleCachePath + llvm::sys::path::get_separator() + "libc.pcm").str().c_str());
4346#endif
4347 remove((moduleCachePath + llvm::sys::path::get_separator() + "std.pcm").str().c_str());
4348 remove((moduleCachePath + llvm::sys::path::get_separator() + "boost.pcm").str().c_str());
4349 remove((moduleCachePath + llvm::sys::path::get_separator() + "tinyxml2.pcm").str().c_str());
4350 remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Config.pcm").str().c_str());
4351 remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Rtypes.pcm").str().c_str());
4352 remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Foundation_C.pcm").str().c_str());
4353 remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Foundation_Stage1_NoRTTI.pcm").str().c_str());
4354 } else if (moduleName == "MathCore") {
4355 remove((moduleCachePath + llvm::sys::path::get_separator() + "Vc.pcm").str().c_str());
4356 }
4357
4358 // Set the C++ modules output directory to the directory where we generate
4359 // the shared library.
4360 clingArgsInterpreter.push_back("-fmodules-cache-path=" + moduleCachePath);
4361 }
4362
4363 if (gOptVerboseLevel == v4)
4364 clingArgsInterpreter.push_back("-v");
4365
4366 // Convert arguments to a C array and check if they are sane
4367 std::vector<const char *> clingArgsC;
4368 for (auto const &clingArg : clingArgsInterpreter) {
4370 std::cerr << "Argument \""<< clingArg << "\" is not a supported cling argument. "
4371 << "This could be mistyped rootcling argument. Please check the commandline.\n";
4372 return 1;
4373 }
4374 clingArgsC.push_back(clingArg.c_str());
4375 }
4376
4377
4378 std::unique_ptr<cling::Interpreter> owningInterpPtr;
4379 cling::Interpreter* interpPtr = nullptr;
4380
4381 std::list<std::string> filesIncludedByLinkdef;
4382 if (gDriverConfig->fBuildingROOTStage1) {
4383#ifdef R__FAST_MATH
4384 // Same setting as in TCling.cxx.
4385 clingArgsC.push_back("-ffast-math");
4386#endif
4387
4388 owningInterpPtr.reset(new cling::Interpreter(clingArgsC.size(), &clingArgsC[0],
4389 llvmResourceDir.c_str()));
4390 interpPtr = owningInterpPtr.get();
4391 } else {
4392 // Pass the interpreter arguments to TCling's interpreter:
4393 clingArgsC.push_back("-resource-dir");
4394 clingArgsC.push_back(llvmResourceDir.c_str());
4395 clingArgsC.push_back(nullptr); // signal end of array
4396 const char ** &extraArgs = *gDriverConfig->fTROOT__GetExtraInterpreterArgs();
4397 extraArgs = &clingArgsC[1]; // skip binary name
4398 interpPtr = gDriverConfig->fTCling__GetInterpreter();
4399 if (!interpPtr->getCI()) // Compiler instance could not be created. See https://its.cern.ch/jira/browse/ROOT-10239
4400 return 1;
4401 if (!isGenreflex && !gOptGeneratePCH) {
4402 std::unique_ptr<TRootClingCallbacks> callBacks (new TRootClingCallbacks(interpPtr, filesIncludedByLinkdef));
4403 interpPtr->setCallbacks(std::move(callBacks));
4404 }
4405 }
4406 cling::Interpreter &interp = *interpPtr;
4407 clang::CompilerInstance *CI = interp.getCI();
4408 // FIXME: Remove this once we switch cling to use the driver. This would handle -fmodules-embed-all-files for us.
4409 CI->getFrontendOpts().ModulesEmbedAllFiles = true;
4410 CI->getSourceManager().setAllFilesAreTransient(true);
4411
4412 clang::Preprocessor &PP = CI->getPreprocessor();
4413 clang::HeaderSearch &headerSearch = PP.getHeaderSearchInfo();
4414 clang::ModuleMap &moduleMap = headerSearch.getModuleMap();
4415 auto &diags = interp.getDiagnostics();
4416
4417 // Manually enable the module build remarks. We don't enable them via the
4418 // normal clang command line arg because otherwise we would get remarks for
4419 // building STL/libc when starting the interpreter in rootcling_stage1.
4420 // We can't prevent these diags in any other way because we can only attach
4421 // our own diag client now after the interpreter has already started.
4422 diags.setSeverity(clang::diag::remark_module_build, clang::diag::Severity::Remark, clang::SourceLocation());
4423
4424 // Attach our own diag client that listens to the module_build remarks from
4425 // clang to check that we don't build dictionary C++ modules implicitly.
4426 auto recordingClient = new CheckModuleBuildClient(diags.getClient(), diags.ownsClient(), moduleMap);
4427 diags.setClient(recordingClient, true);
4428