11 const char *shortHelp =
12 "Usage: rootcling [-v][-v0-4] [-f] [out.cxx] [opts] "
13 "file1.h[+][-][!] file2.h[+][-][!] ...[LinkDef.h]\n";
18 #include "rootclingCommandLineOptionsHelp.h"
20 #include "RConfigure.h"
39 #include <unordered_map>
40 #include <unordered_set>
52 #define PATH_MAX _MAX_PATH
60 #include <mach-o/dyld.h>
63 #if !defined(R__WIN32)
69 #include "cling/Interpreter/Interpreter.h"
70 #include "cling/Interpreter/InterpreterCallbacks.h"
71 #include "cling/Interpreter/LookupHelper.h"
72 #include "cling/Interpreter/Value.h"
73 #include "clang/AST/CXXInheritance.h"
74 #include "clang/AST/Mangle.h"
75 #include "clang/Basic/Diagnostic.h"
76 #include "clang/Basic/MemoryBufferCache.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"
88 #include "llvm/Bitcode/BitstreamWriter.h"
89 #include "llvm/Support/CommandLine.h"
90 #include "llvm/Support/Path.h"
91 #include "llvm/Support/PrettyStackTrace.h"
92 #include "llvm/Support/Signals.h"
97 #include "TClingUtils.h"
109 const std::string gLibraryExtension(
".dll");
111 const std::string gLibraryExtension(
".so");
113 const std::string gPathSeparator(ROOT::TMetaUtils::GetPathSeparator());
116 #include <mach-o/dyld.h>
119 #if defined(R__WIN32)
121 #define strcasecmp _stricmp
122 #define strncasecmp _strnicmp
127 bool gBuildingROOT =
false;
128 const ROOT::Internal::RootCling::DriverConfig* gDriverConfig =
nullptr;
132 using HeadersDeclsMap_t = std::map<std::string, std::list<std::string>>;
134 using namespace ROOT;
135 using namespace TClassEdit;
140 namespace genreflex {
141 bool verbose =
false;
148 ROOT::Internal::RootCling::TROOTSYSSetter::TROOTSYSSetter() {
155 void EmitStreamerInfo(
const char *normName)
157 if (gDriverConfig->fAddStreamerInfoToROOTFile)
158 gDriverConfig->fAddStreamerInfoToROOTFile(normName);
160 static void EmitTypedefs(
const std::vector<const clang::TypedefNameDecl *> &tdvec)
162 if (!gDriverConfig->fAddTypedefToROOTFile)
164 for (
const auto td : tdvec)
165 gDriverConfig->fAddTypedefToROOTFile(td->getQualifiedNameAsString().c_str());
167 static void EmitEnums(
const std::vector<const clang::EnumDecl *> &enumvec)
169 if (!gDriverConfig->fAddEnumToROOTFile)
171 for (
const auto en : enumvec) {
173 if (clang::isa<clang::TranslationUnitDecl>(en->getDeclContext())
174 || clang::isa<clang::LinkageSpecDecl>(en->getDeclContext())
175 || clang::isa<clang::NamespaceDecl>(en->getDeclContext()))
176 gDriverConfig->fAddEnumToROOTFile(en->getQualifiedNameAsString().c_str());
183 const char *GetExePath()
185 static std::string exepath;
188 exepath = _dyld_get_image_name(0);
190 #if defined(__linux) || defined(__linux__)
191 char linkname[PATH_MAX];
197 snprintf(linkname, PATH_MAX,
"/proc/%i/exe", pid);
198 int ret = readlink(linkname, buf, 1024);
199 if (ret > 0 && ret < 1024) {
205 char *buf =
new char[MAX_MODULE_NAME32 + 1];
206 ::GetModuleFileName(NULL, buf, MAX_MODULE_NAME32 + 1);
208 while ((p = strchr(p,
'\\')))
214 return exepath.c_str();
219 bool Namespace__HasMethod(
const clang::NamespaceDecl *cl,
const char *name,
220 const cling::Interpreter &interp)
222 return ROOT::TMetaUtils::ClassInfo__HasMethod(cl, name, interp);
227 static void AnnotateFieldDecl(clang::FieldDecl &decl,
228 const std::list<VariableSelectionRule> &fieldSelRules)
230 using namespace ROOT::TMetaUtils;
236 if (fieldSelRules.empty())
return;
238 clang::ASTContext &C = decl.getASTContext();
239 clang::SourceRange commentRange;
241 const std::string declName(decl.getNameAsString());
243 for (std::list<VariableSelectionRule>::const_iterator it = fieldSelRules.begin();
244 it != fieldSelRules.end(); ++it) {
245 if (! it->GetAttributeValue(propNames::name, varName))
continue;
246 if (declName == varName) {
248 BaseSelectionRule::AttributesMap_t attrMap(it->GetAttributes());
249 BaseSelectionRule::AttributesMap_t::iterator iter;
250 std::string userDefinedProperty;
251 for (iter = attrMap.begin(); iter != attrMap.end(); ++iter) {
252 const std::string &name = iter->first;
253 const std::string &value = iter->second;
255 if (name == propNames::name)
continue;
260 if (name == propNames::iotype &&
261 (decl.getType()->isArrayType() || decl.getType()->isPointerType())) {
262 const char *msg =
"Data member \"%s\" is an array or a pointer. "
263 "It is not possible to assign to it the iotype \"%s\". "
264 "This transformation is possible only with data members "
265 "which are not pointers or arrays.\n";
266 ROOT::TMetaUtils::Error(
"AnnotateFieldDecl",
267 msg, varName.c_str(), value.c_str());
275 if (name == propNames::comment) {
276 decl.addAttr(
new(C) clang::AnnotateAttr(commentRange, C, value, 0));
280 if ((name == propNames::transient && value ==
"true") ||
281 (name == propNames::persistent && value ==
"false")) {
282 userDefinedProperty = propNames::comment + propNames::separator +
"!";
286 decl.addAttr(
new(C) clang::AnnotateAttr(commentRange, C,
"!", 0));
291 userDefinedProperty = name + propNames::separator + value;
293 ROOT::TMetaUtils::Info(0,
"%s %s\n", varName.c_str(), userDefinedProperty.c_str());
294 decl.addAttr(
new(C) clang::AnnotateAttr(commentRange, C, userDefinedProperty, 0));
303 void AnnotateDecl(clang::CXXRecordDecl &CXXRD,
304 const RScanner::DeclsSelRulesMap_t &declSelRulesMap,
305 cling::Interpreter &interpreter,
313 using namespace clang;
314 SourceLocation commentSLoc;
315 llvm::StringRef comment;
317 ASTContext &C = CXXRD.getASTContext();
318 Sema &S = interpreter.getCI()->getSema();
320 SourceRange commentRange;
323 clang::Decl *declBaseClassPtr =
static_cast<clang::Decl *
>(&CXXRD);
324 auto declSelRulePair = declSelRulesMap.find(declBaseClassPtr->getCanonicalDecl());
325 if (declSelRulePair == declSelRulesMap.end()){
326 const std::string thisClassName(CXXRD.getName());
327 ROOT::TMetaUtils::Error(
"AnnotateDecl",
"Cannot find class %s in the list of selected classes.\n",thisClassName.c_str());
330 const BaseSelectionRule *thisClassBaseSelectionRule = declSelRulePair->second;
332 if (thisClassBaseSelectionRule) {
335 BaseSelectionRule::AttributesMap_t::iterator iter;
336 std::string userDefinedProperty;
337 for (
auto const & attr : thisClassBaseSelectionRule->GetAttributes()) {
338 const std::string &name = attr.first;
339 if (name == ROOT::TMetaUtils::propNames::name)
continue;
340 const std::string &value = attr.second;
341 userDefinedProperty = name + ROOT::TMetaUtils::propNames::separator + value;
342 if (genreflex::verbose) std::cout <<
" * " << userDefinedProperty << std::endl;
343 CXXRD.addAttr(
new(C) AnnotateAttr(commentRange, C, userDefinedProperty, 0));
348 const ClassSelectionRule *thisClassSelectionRule =
reinterpret_cast<const ClassSelectionRule *
>(thisClassBaseSelectionRule);
350 for (CXXRecordDecl::decl_iterator I = CXXRD.decls_begin(),
351 E = CXXRD.decls_end(); I != E; ++I) {
355 if (!(*I)->isImplicit()
356 && (isa<CXXMethodDecl>(*I) || isa<FieldDecl>(*I) || isa<VarDecl>(*I))) {
360 SourceLocation maybeMacroLoc = (*I)->getLocation();
361 bool isClassDefMacro = maybeMacroLoc.isMacroID() && S.findMacroSpelling(maybeMacroLoc,
"ClassDef");
362 if (isClassDefMacro) {
363 while (isa<NamedDecl>(*I) && cast<NamedDecl>(*I)->getName() !=
"DeclFileLine") {
368 comment = ROOT::TMetaUtils::GetComment(**I, &commentSLoc);
369 if (comment.size()) {
372 commentRange = SourceRange(commentSLoc, commentSLoc.getLocWithOffset(comment.size()));
374 if (isClassDefMacro) {
375 CXXRD.addAttr(
new(C) AnnotateAttr(commentRange, C, comment.str(), 0));
376 }
else if (!isGenreflex) {
382 (*I)->addAttr(
new(C) AnnotateAttr(commentRange, C, comment.str(), 0));
387 if (isGenreflex && thisClassSelectionRule != 0) {
388 const std::list<VariableSelectionRule> &fieldSelRules = thisClassSelectionRule->GetFieldSelectionRules();
391 if (FieldDecl *fieldDecl = dyn_cast<FieldDecl>(*I)) {
392 AnnotateFieldDecl(*fieldDecl, fieldSelRules);
401 size_t GetFullArrayLength(
const clang::ConstantArrayType *arrayType)
403 llvm::APInt len = arrayType->getSize();
404 while (
const clang::ConstantArrayType *subArrayType = llvm::dyn_cast<clang::ConstantArrayType>(arrayType->getArrayElementTypeNoTypeQual())) {
405 len *= subArrayType->getSize();
406 arrayType = subArrayType;
408 return len.getLimitedValue();
413 bool InheritsFromTObject(
const clang::RecordDecl *cl,
414 const cling::Interpreter &interp)
416 static const clang::CXXRecordDecl *TObject_decl
417 = ROOT::TMetaUtils::ScopeSearch(
"TObject", interp,
true , 0);
419 const clang::CXXRecordDecl *clxx = llvm::dyn_cast<clang::CXXRecordDecl>(cl);
420 return ROOT::TMetaUtils::IsBase(clxx, TObject_decl,
nullptr, interp);
425 bool InheritsFromTSelector(
const clang::RecordDecl *cl,
426 const cling::Interpreter &interp)
428 static const clang::CXXRecordDecl *TObject_decl
429 = ROOT::TMetaUtils::ScopeSearch(
"TSelector", interp,
false , 0);
431 return ROOT::TMetaUtils::IsBase(llvm::dyn_cast<clang::CXXRecordDecl>(cl), TObject_decl,
nullptr, interp);
436 bool IsSelectionXml(
const char *filename)
438 size_t len = strlen(filename);
440 if (strlen(filename) >= xmllen) {
441 return (0 == strcasecmp(filename + (len - xmllen),
".xml"));
449 bool IsLinkdefFile(
const clang::PresumedLoc& PLoc)
451 return ROOT::TMetaUtils::IsLinkdefFile(PLoc.getFilename());
456 bool IsSelectionFile(
const char *filename)
458 return ROOT::TMetaUtils::IsLinkdefFile(filename) || IsSelectionXml(filename);
466 const char *exepath = GetExePath();
467 if (exepath && *exepath) {
469 char *ep =
new char[PATH_MAX];
470 if (!realpath(exepath, ep)) {
471 fprintf(stderr,
"rootcling: error getting realpath of rootcling!");
472 strlcpy(ep, exepath, PATH_MAX);
475 int nche = strlen(exepath) + 1;
476 char *ep =
new char[nche];
477 strlcpy(ep, exepath, nche);
481 if ((s = strrchr(ep,
'/'))) {
483 int removesubdirs = 2;
484 if (!strncmp(s + 1,
"rootcling_stage1.exe", 20)) {
487 gBuildingROOT =
true;
488 }
else if (!strncmp(s + 1,
"rootcling_stage1", 16)) {
491 gBuildingROOT =
true;
493 for (
int i = 1; s && i < removesubdirs; ++i) {
495 s = strrchr(ep,
'/');
506 int ncha = strlen(ep) + 10;
507 char *env =
new char[ncha];
508 snprintf(env, ncha,
"ROOTSYS=%s", ep);
513 const char** pRootDir = gDriverConfig->fPRootDir;
527 bool ParsePragmaLine(
const std::string &line,
528 const char *expectedTokens[],
532 if (line[0] !=
'#')
return false;
534 for (
const char **iToken = expectedTokens; *iToken; ++iToken) {
535 while (isspace(line[pos])) ++pos;
536 size_t lenToken = strlen(*iToken);
537 if (line.compare(pos, lenToken, *iToken)) {
548 map<string, string> gAutoloads;
553 void RecordDeclCallback(
const clang::RecordDecl* recordDecl)
556 if (recordDecl->hasOwningModule()) {
557 clang::Module *M = recordDecl->getOwningModule()->getTopLevelModule();
558 need =
"lib" + M->Name + gLibraryExtension;
560 std::string qual_name;
561 RScanner::GetDeclQualName(recordDecl, qual_name);
563 need = gAutoloads[qual_name];
566 if (need.length() && gLibsNeeded.find(need) == string::npos) {
567 gLibsNeeded +=
" " + need;
573 void CheckClassNameForRootMap(
const std::string &classname, map<string, string> &autoloads)
575 if (classname.find(
':') == std::string::npos)
return;
578 int slen = classname.size();
579 for (
int k = 0; k < slen; ++k) {
580 if (classname[k] ==
':') {
581 if (k + 1 >= slen || classname[k + 1] !=
':') {
586 string base = classname.substr(0, k);
591 autoloads[base] =
"";
595 }
else if (classname[k] ==
'<') {
605 void ParseRootMapFile(ifstream &file, map<string, string> &autoloads)
607 std::string classname;
609 while (file >> line) {
611 if (line.find(
"Library.") != 0)
continue;
613 int pos = line.find(
":", 8);
614 classname = line.substr(8, pos - 8);
616 ROOT::TMetaUtils::ReplaceAll(classname,
"@@",
"::");
617 ROOT::TMetaUtils::ReplaceAll(classname,
"-",
" ");
619 getline(file, line,
'\n');
620 while (line[0] ==
' ') line.replace(0, 1,
"");
622 CheckClassNameForRootMap(classname, autoloads);
624 if (classname ==
"ROOT::TImpProxy") {
628 autoloads[classname] = line;
636 void ParseRootMapFileNewFormat(ifstream &file, map<string, string> &autoloads)
643 const std::unordered_map<char, unsigned int> keyLenMap = {{
'c', 6}, {
'n', 10}, {
't', 8}};
645 while (getline(file, line,
'\n')) {
646 if (line ==
"{ decls }") {
647 while (getline(file, line,
'\n')) {
648 if (line[0] ==
'[')
break;
651 const char firstChar = line[0];
652 if (firstChar ==
'[') {
654 libs = line.substr(1, line.find(
']') - 1);
655 while (libs[0] ==
' ') libs.replace(0, 1,
"");
656 }
else if (0 != keyLenMap.count(firstChar)) {
657 unsigned int keyLen = keyLenMap.at(firstChar);
658 keyname = line.substr(keyLen, line.length() - keyLen);
659 CheckClassNameForRootMap(keyname, autoloads);
660 autoloads[keyname] = libs;
670 void LoadLibraryMap(
const std::string &fileListName, map<string, string> &autoloads)
672 std::ifstream filelist(fileListName.c_str());
674 std::string filename;
677 while (filelist >> filename) {
679 if (llvm::sys::fs::is_directory(filename))
continue;
681 ifstream file(filename.c_str());
685 bool new_format = (line[0] ==
'[' || line[0] ==
'{') ;
687 file.seekg(0, std::ios::beg);
691 ParseRootMapFileNewFormat(file, autoloads);
693 ParseRootMapFile(file, autoloads);
706 bool CheckInputOperator(
const char *what,
708 const string &fullname,
709 const clang::RecordDecl *cl,
710 cling::Interpreter &interp)
713 const clang::FunctionDecl *method
714 = ROOT::TMetaUtils::GetFuncWithProto(llvm::dyn_cast<clang::Decl>(cl->getDeclContext()), what, proto, interp,
718 clang::TranslationUnitDecl *TU =
719 cl->getASTContext().getTranslationUnitDecl();
720 method = ROOT::TMetaUtils::GetFuncWithProto(TU, what, proto, interp,
723 bool has_input_error =
false;
724 if (method != 0 && (method->getAccess() == clang::AS_public || method->getAccess() == clang::AS_none)) {
725 std::string filename = ROOT::TMetaUtils::GetFileName(*method, interp);
726 if (strstr(filename.c_str(),
"TBuffer.h") != 0 ||
727 strstr(filename.c_str(),
"Rtypes.h") != 0) {
729 has_input_error =
true;
732 has_input_error =
true;
734 if (has_input_error) {
736 const char *maybeconst =
"";
737 const char *mayberef =
"&";
738 if (what[strlen(what) - 1] ==
'<') {
739 maybeconst =
"const ";
742 ROOT::TMetaUtils::Error(0,
743 "in this version of ROOT, the option '!' used in a linkdef file\n"
744 " implies the actual existence of customized operators.\n"
745 " The following declaration is now required:\n"
746 " TBuffer &%s(TBuffer &,%s%s *%s);\n", what, maybeconst, fullname.c_str(), mayberef);
748 return has_input_error;
756 bool CheckInputOperator(
const clang::RecordDecl *cl, cling::Interpreter &interp)
759 ROOT::TMetaUtils::GetQualifiedName(fullname, *cl);
760 int ncha = fullname.length() + 13;
761 char *proto =
new char[ncha];
762 snprintf(proto, ncha,
"TBuffer&,%s*&", fullname.c_str());
764 ROOT::TMetaUtils::Info(0,
"Class %s: Do not generate operator>>()\n",
768 bool has_input_error = CheckInputOperator(
"operator>>", proto, fullname, cl, interp);
769 has_input_error = CheckInputOperator(
"operator<<", proto, fullname, cl, interp) || has_input_error;
773 return has_input_error;
779 bool CheckClassDef(
const clang::RecordDecl &cl,
const cling::Interpreter &interp)
783 bool hasClassDef = ROOT::TMetaUtils::ClassInfo__HasMethod(&cl,
"Class_Version", interp);
785 const clang::CXXRecordDecl *clxx = llvm::dyn_cast<clang::CXXRecordDecl>(&cl);
789 bool isAbstract = clxx->isAbstract();
791 if (!isAbstract && InheritsFromTObject(clxx, interp) && !InheritsFromTSelector(clxx, interp) && !hasClassDef) {
792 std::string qualName;
793 ROOT::TMetaUtils::GetQualifiedName(qualName, cl);
794 const char *qualName_c = qualName.c_str();
795 ROOT::TMetaUtils::Warning(qualName_c,
"The data members of %s will not be stored, "
796 "because it inherits from TObject but does not "
797 "have its own ClassDef.\n",
808 string GetNonConstMemberName(
const clang::FieldDecl &m,
const string &prefix =
"")
810 if (m.getType().isConstQualified()) {
811 string ret =
"const_cast< ";
813 ROOT::TMetaUtils::GetQualifiedName(type_name, m.getType(), m);
814 if (type_name.substr(0,6)==
"const ") {
815 ret += type_name.c_str()+6;
821 ret += m.getName().str();
825 return prefix + m.getName().str();
833 int STLContainerStreamer(
const clang::FieldDecl &m,
835 const cling::Interpreter &interp,
836 const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt,
837 std::ostream &dictStream)
839 ROOT::ESTLType stltype = ROOT::TMetaUtils::IsSTLContainer(m);
840 std::string mTypename;
841 ROOT::TMetaUtils::GetQualifiedName(mTypename, m.getType(), m);
843 const clang::CXXRecordDecl *clxx = llvm::dyn_cast_or_null<clang::CXXRecordDecl>(ROOT::TMetaUtils::GetUnderlyingRecordDecl(m.getType()));
845 if (stltype == ROOT::kNotSTL) {
850 clang::QualType utype(ROOT::TMetaUtils::GetUnderlyingType(m.getType()), 0);
851 Internal::RStl::Instance().GenerateTClassFor(utype, interp, normCtxt);
853 if (clxx->getTemplateSpecializationKind() == clang::TSK_Undeclared)
return 0;
855 const clang::ClassTemplateSpecializationDecl *tmplt_specialization = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl> (clxx);
856 if (!tmplt_specialization)
return 0;
859 string stlType(ROOT::TMetaUtils::ShortTypeName(mTypename.c_str()));
861 stlName = ROOT::TMetaUtils::ShortTypeName(m.getName().str().c_str());
863 string fulName1, fulName2;
864 const char *tcl1 = 0, *tcl2 = 0;
865 const clang::TemplateArgument &arg0(tmplt_specialization->getTemplateArgs().get(0));
866 clang::QualType ti = arg0.getAsType();
868 if (ROOT::TMetaUtils::ElementStreamer(dictStream, m, ti, 0, rwmode, interp)) {
870 fulName1 = ti.getAsString();
872 if (stltype == kSTLmap || stltype == kSTLmultimap) {
873 const clang::TemplateArgument &arg1(tmplt_specialization->getTemplateArgs().get(1));
874 clang::QualType tmplti = arg1.getAsType();
875 if (ROOT::TMetaUtils::ElementStreamer(dictStream, m, tmplti, 0, rwmode, interp)) {
877 fulName2 = tmplti.getAsString();
884 const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(m.getType().getTypePtr());
887 len = GetFullArrayLength(arrayType);
890 if (arrayType->getArrayElementTypeNoTypeQual()->isPointerType()) {
894 arrayType = llvm::dyn_cast<clang::ConstantArrayType>(arrayType->getArrayElementTypeNoTypeQual());
896 }
else if (m.getType()->isPointerType()) {
901 dictStream <<
" {" << std::endl;
903 dictStream <<
" for (Int_t R__l = 0; R__l < " << len <<
"; R__l++) {" << std::endl;
908 dictStream <<
" " << stlType.c_str() <<
" &R__stl = " << stlName.c_str() <<
";" << std::endl;
911 dictStream <<
" " << stlType.c_str() <<
" &R__stl = " << stlName.c_str() <<
"[R__l];" << std::endl;
914 dictStream <<
" delete *" << stlName.c_str() <<
";" << std::endl
915 <<
" *" << stlName.c_str() <<
" = new " << stlType.c_str() <<
";" << std::endl
916 <<
" " << stlType.c_str() <<
" &R__stl = **" << stlName.c_str() <<
";" << std::endl;
919 dictStream <<
" delete " << stlName.c_str() <<
"[R__l];" << std::endl
920 <<
" " << stlName.c_str() <<
"[R__l] = new " << stlType.c_str() <<
";" << std::endl
921 <<
" " << stlType.c_str() <<
" &R__stl = *" << stlName.c_str() <<
"[R__l];" << std::endl;
925 dictStream <<
" R__stl.clear();" << std::endl;
928 dictStream <<
" TClass *R__tcl1 = TBuffer::GetClass(typeid(" << fulName1.c_str() <<
"));" << std::endl
929 <<
" if (R__tcl1==0) {" << std::endl
930 <<
" Error(\"" << stlName.c_str() <<
" streamer\",\"Missing the TClass object for "
931 << fulName1.c_str() <<
"!\");" << std::endl
932 <<
" return;" << std::endl
933 <<
" }" << std::endl;
936 dictStream <<
" TClass *R__tcl2 = TBuffer::GetClass(typeid(" << fulName2.c_str() <<
"));" << std::endl
937 <<
" if (R__tcl2==0) {" << std::endl
938 <<
" Error(\"" << stlName.c_str() <<
" streamer\",\"Missing the TClass object for "
939 << fulName2.c_str() <<
"!\");" << std::endl
940 <<
" return;" << std::endl
941 <<
" }" << std::endl;
944 dictStream <<
" int R__i, R__n;" << std::endl
945 <<
" R__b >> R__n;" << std::endl;
947 if (stltype == kSTLvector) {
948 dictStream <<
" R__stl.reserve(R__n);" << std::endl;
950 dictStream <<
" for (R__i = 0; R__i < R__n; R__i++) {" << std::endl;
952 ROOT::TMetaUtils::ElementStreamer(dictStream, m, arg0.getAsType(),
"R__t", rwmode, interp, tcl1);
953 if (stltype == kSTLmap || stltype == kSTLmultimap) {
954 const clang::TemplateArgument &arg1(tmplt_specialization->getTemplateArgs().get(1));
955 ROOT::TMetaUtils::ElementStreamer(dictStream, m, arg1.getAsType(),
"R__t2", rwmode, interp, tcl2);
972 case kSTLunorderedmap:
973 case kSTLunorderedmultimap:{
974 std::string keyName(ti.getAsString());
975 dictStream <<
" typedef " << keyName <<
" Value_t;" << std::endl
976 <<
" std::pair<Value_t const, " << tmplt_specialization->getTemplateArgs().get(1).getAsType().getAsString() <<
" > R__t3(R__t,R__t2);" << std::endl
977 <<
" R__stl.insert(R__t3);" << std::endl;
982 case kSTLunorderedset:
983 case kSTLunorderedmultiset:
985 dictStream <<
" R__stl.insert(R__t);" << std::endl;
990 dictStream <<
" R__stl.push_back(R__t);" << std::endl;
992 case kSTLforwardlist:
993 dictStream <<
" R__stl.push_front(R__t);" << std::endl;
998 dictStream <<
" }" << std::endl
999 <<
" }" << std::endl;
1000 if (isArr) dictStream <<
" }" << std::endl;
1006 dictStream <<
" for (Int_t R__l = 0; R__l < " << len <<
"; R__l++) {" << std::endl;
1008 dictStream <<
" {" << std::endl;
1011 dictStream <<
" " << stlType.c_str() <<
" &R__stl = " << stlName.c_str() <<
";" << std::endl;
1014 dictStream <<
" " << stlType.c_str() <<
" &R__stl = " << stlName.c_str() <<
"[R__l];" << std::endl;
1017 dictStream <<
" " << stlType.c_str() <<
" &R__stl = **" << stlName.c_str() <<
";" << std::endl;
1020 dictStream <<
" " << stlType.c_str() <<
" &R__stl = *" << stlName.c_str() <<
"[R__l];" << std::endl;
1024 dictStream <<
" int R__n=int(R__stl.size());" << std::endl
1025 <<
" R__b << R__n;" << std::endl
1026 <<
" if(R__n) {" << std::endl;
1029 dictStream <<
" TClass *R__tcl1 = TBuffer::GetClass(typeid(" << fulName1.c_str() <<
"));" << std::endl
1030 <<
" if (R__tcl1==0) {" << std::endl
1031 <<
" Error(\"" << stlName.c_str() <<
" streamer\",\"Missing the TClass object for "
1032 << fulName1.c_str() <<
"!\");" << std::endl
1033 <<
" return;" << std::endl
1034 <<
" }" << std::endl;
1037 dictStream <<
" TClass *R__tcl2 = TBuffer::GetClass(typeid(" << fulName2.c_str() <<
"));" << std::endl
1038 <<
" if (R__tcl2==0) {" << std::endl
1039 <<
" Error(\"" << stlName.c_str() <<
"streamer\",\"Missing the TClass object for " << fulName2.c_str() <<
"!\");" << std::endl
1040 <<
" return;" << std::endl
1041 <<
" }" << std::endl;
1044 dictStream <<
" " << stlType.c_str() <<
"::iterator R__k;" << std::endl
1045 <<
" for (R__k = R__stl.begin(); R__k != R__stl.end(); ++R__k) {" << std::endl;
1046 if (stltype == kSTLmap || stltype == kSTLmultimap) {
1047 const clang::TemplateArgument &arg1(tmplt_specialization->getTemplateArgs().get(1));
1048 clang::QualType tmplti = arg1.getAsType();
1049 ROOT::TMetaUtils::ElementStreamer(dictStream, m, ti,
"((*R__k).first )", rwmode, interp, tcl1);
1050 ROOT::TMetaUtils::ElementStreamer(dictStream, m, tmplti,
"((*R__k).second)", rwmode, interp, tcl2);
1052 ROOT::TMetaUtils::ElementStreamer(dictStream, m, ti,
"(*R__k)" , rwmode, interp, tcl1);
1055 dictStream <<
" }" << std::endl
1056 <<
" }" << std::endl
1057 <<
" }" << std::endl;
1058 if (isArr) dictStream <<
" }" << std::endl;
1068 int STLStringStreamer(
const clang::FieldDecl &m,
int rwmode, std::ostream &dictStream)
1070 std::string mTypenameStr;
1071 ROOT::TMetaUtils::GetQualifiedName(mTypenameStr, m.getType(), m);
1073 const char *mTypeName = ROOT::TMetaUtils::ShortTypeName(mTypenameStr.c_str());
1074 if (!strcmp(mTypeName,
"string")) {
1076 std::string fieldname = m.getName().str();
1079 if (m.getType()->isConstantArrayType()) {
1080 if (m.getType().getTypePtr()->getArrayElementTypeNoTypeQual()->isPointerType()) {
1081 dictStream <<
"// Array of pointer to std::string are not supported (" << fieldname <<
"\n";
1083 std::stringstream fullIdx;
1084 const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(m.getType().getTypePtr());
1087 dictStream <<
" for (int R__i" << dim <<
"=0; R__i" << dim <<
"<"
1088 << arrayType->getSize().getLimitedValue() <<
"; ++R__i" << dim <<
" )" << std::endl;
1089 fullIdx <<
"[R__i" << dim <<
"]";
1090 arrayType = llvm::dyn_cast<clang::ConstantArrayType>(arrayType->getArrayElementTypeNoTypeQual());
1093 dictStream <<
" { TString R__str; R__str.Streamer(R__b); "
1094 << fieldname << fullIdx.str() <<
" = R__str.Data();}" << std::endl;
1097 dictStream <<
" { TString R__str; R__str.Streamer(R__b); ";
1098 if (m.getType()->isPointerType())
1099 dictStream <<
"if (*" << fieldname <<
") delete *" << fieldname <<
"; (*"
1100 << fieldname <<
" = new string(R__str.Data())); }" << std::endl;
1102 dictStream << fieldname <<
" = R__str.Data(); }" << std::endl;
1106 if (m.getType()->isPointerType())
1107 dictStream <<
" { TString R__str; if (*" << fieldname <<
") R__str = (*"
1108 << fieldname <<
")->c_str(); R__str.Streamer(R__b);}" << std::endl;
1109 else if (m.getType()->isConstantArrayType()) {
1110 std::stringstream fullIdx;
1111 const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(m.getType().getTypePtr());
1114 dictStream <<
" for (int R__i" << dim <<
"=0; R__i" << dim <<
"<"
1115 << arrayType->getSize().getLimitedValue() <<
"; ++R__i" << dim <<
" )" << std::endl;
1116 fullIdx <<
"[R__i" << dim <<
"]";
1117 arrayType = llvm::dyn_cast<clang::ConstantArrayType>(arrayType->getArrayElementTypeNoTypeQual());
1120 dictStream <<
" { TString R__str(" << fieldname << fullIdx.str() <<
".c_str()); R__str.Streamer(R__b);}" << std::endl;
1122 dictStream <<
" { TString R__str = " << fieldname <<
".c_str(); R__str.Streamer(R__b);}" << std::endl;
1131 bool isPointerToPointer(
const clang::FieldDecl &m)
1133 if (m.getType()->isPointerType()) {
1134 if (m.getType()->getPointeeType()->isPointerType()) {
1144 void WriteArrayDimensions(
const clang::QualType &type, std::ostream &dictStream)
1146 const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(type.getTypePtr());
1148 arrayType = llvm::dyn_cast<clang::ConstantArrayType>(arrayType->getArrayElementTypeNoTypeQual());
1150 dictStream <<
"[0]";
1151 arrayType = llvm::dyn_cast<clang::ConstantArrayType>(arrayType->getArrayElementTypeNoTypeQual());
1159 void WriteClassFunctions(
const clang::CXXRecordDecl *cl, std::ostream &dictStream,
bool autoLoad =
false)
1161 bool add_template_keyword = ROOT::TMetaUtils::NeedTemplateKeyword(cl);
1166 int enclSpaceNesting = 0;
1168 if (ROOT::TMetaUtils::GetNameWithinNamespace(fullname, clsname, nsname, cl)) {
1169 enclSpaceNesting = ROOT::TMetaUtils::WriteNamespaceHeader(dictStream, cl);
1173 dictStream <<
"#include \"TInterpreter.h\"\n";
1175 dictStream <<
"//_______________________________________"
1176 <<
"_______________________________________" << std::endl;
1177 if (add_template_keyword) dictStream <<
"template <> ";
1178 dictStream <<
"atomic_TClass_ptr " << clsname <<
"::fgIsA(0); // static to hold class pointer" << std::endl
1181 <<
"//_______________________________________"
1182 <<
"_______________________________________" << std::endl;
1183 if (add_template_keyword) dictStream <<
"template <> ";
1184 dictStream <<
"const char *" << clsname <<
"::Class_Name()" << std::endl <<
"{" << std::endl
1185 <<
" return \"" << fullname <<
"\";" << std::endl <<
"}" << std::endl << std::endl;
1187 dictStream <<
"//_______________________________________"
1188 <<
"_______________________________________" << std::endl;
1189 if (add_template_keyword) dictStream <<
"template <> ";
1190 dictStream <<
"const char *" << clsname <<
"::ImplFileName()" << std::endl <<
"{" << std::endl
1191 <<
" return ::ROOT::GenerateInitInstanceLocal((const ::" << fullname
1192 <<
"*)0x0)->GetImplFileName();" << std::endl <<
"}" << std::endl << std::endl
1194 <<
"//_______________________________________"
1195 <<
"_______________________________________" << std::endl;
1196 if (add_template_keyword) dictStream <<
"template <> ";
1197 dictStream <<
"int " << clsname <<
"::ImplFileLine()" << std::endl <<
"{" << std::endl
1198 <<
" return ::ROOT::GenerateInitInstanceLocal((const ::" << fullname
1199 <<
"*)0x0)->GetImplFileLine();" << std::endl <<
"}" << std::endl << std::endl
1201 <<
"//_______________________________________"
1202 <<
"_______________________________________" << std::endl;
1203 if (add_template_keyword) dictStream <<
"template <> ";
1204 dictStream <<
"TClass *" << clsname <<
"::Dictionary()" << std::endl <<
"{" << std::endl;
1208 dictStream <<
" gInterpreter->AutoLoad(\"" << fullname <<
"\");\n";
1209 dictStream <<
" fgIsA = ::ROOT::GenerateInitInstanceLocal((const ::" << fullname
1210 <<
"*)0x0)->GetClass();" << std::endl
1211 <<
" return fgIsA;\n"
1212 <<
"}" << std::endl << std::endl
1214 <<
"//_______________________________________"
1215 <<
"_______________________________________" << std::endl;
1216 if (add_template_keyword) dictStream <<
"template <> ";
1217 dictStream <<
"TClass *" << clsname <<
"::Class()" << std::endl <<
"{" << std::endl;
1219 dictStream <<
" Dictionary();\n";
1221 dictStream <<
" if (!fgIsA.load()) { R__LOCKGUARD(gInterpreterMutex); fgIsA = ::ROOT::GenerateInitInstanceLocal((const ::";
1222 dictStream << fullname <<
"*)0x0)->GetClass(); }" << std::endl;
1224 dictStream <<
" return fgIsA;" << std::endl
1225 <<
"}" << std::endl << std::endl;
1227 while (enclSpaceNesting) {
1228 dictStream <<
"} // namespace " << nsname << std::endl;
1236 void WriteNamespaceInit(
const clang::NamespaceDecl *cl,
1237 cling::Interpreter &interp,
1238 std::ostream &dictStream)
1240 if (cl->isAnonymousNamespace()) {
1246 string classname = ROOT::TMetaUtils::GetQualifiedName(*cl).c_str();
1248 TMetaUtils::GetCppName(mappedname, classname.c_str());
1252 if (classname !=
"ROOT") {
1253 nesting = ROOT::TMetaUtils::WriteNamespaceHeader(dictStream,cl);
1256 dictStream <<
" namespace ROOT {" << std::endl;
1258 #if !defined(R__AIX)
1259 dictStream <<
" inline ::ROOT::TGenericClassInfo *GenerateInitInstance();" << std::endl;
1262 if (!Namespace__HasMethod(cl,
"Dictionary", interp))
1263 dictStream <<
" static TClass *" << mappedname.c_str() <<
"_Dictionary();" << std::endl;
1264 dictStream << std::endl
1266 <<
" // Function generating the singleton type initializer" << std::endl
1268 #if !defined(R__AIX)
1269 <<
" inline ::ROOT::TGenericClassInfo *GenerateInitInstance()" << std::endl
1270 <<
" {" << std::endl
1272 <<
" ::ROOT::TGenericClassInfo *GenerateInitInstance()" << std::endl
1273 <<
" {" << std::endl
1276 <<
" static ::ROOT::TGenericClassInfo " << std::endl
1278 <<
" instance(\"" << classname.c_str() <<
"\", ";
1280 if (Namespace__HasMethod(cl,
"Class_Version", interp)) {
1281 dictStream <<
"::" << classname.c_str() <<
"::Class_Version(), ";
1283 dictStream <<
"0 /*version*/, ";
1286 std::string filename = ROOT::TMetaUtils::GetFileName(*cl, interp);
1287 for (
unsigned int i = 0; i < filename.length(); i++) {
1288 if (filename[i] ==
'\\') filename[i] =
'/';
1290 dictStream <<
"\"" << filename <<
"\", " << ROOT::TMetaUtils::GetLineNumber(cl) <<
"," << std::endl
1291 <<
" ::ROOT::Internal::DefineBehavior((void*)0,(void*)0)," << std::endl
1294 if (Namespace__HasMethod(cl,
"Dictionary", interp)) {
1295 dictStream <<
"&::" << classname.c_str() <<
"::Dictionary, ";
1297 dictStream <<
"&" << mappedname.c_str() <<
"_Dictionary, ";
1300 dictStream << 0 <<
");" << std::endl
1302 <<
" return &instance;" << std::endl
1303 <<
" }" << std::endl
1304 <<
" // Insure that the inline function is _not_ optimized away by the compiler\n"
1305 <<
" ::ROOT::TGenericClassInfo *(*_R__UNIQUE_DICT_(InitFunctionKeeper))() = &GenerateInitInstance; " << std::endl
1306 <<
" // Static variable to force the class initialization" << std::endl
1308 <<
" static ::ROOT::TGenericClassInfo *_R__UNIQUE_DICT_(Init) = GenerateInitInstance();"
1309 <<
" R__UseDummy(_R__UNIQUE_DICT_(Init));" << std::endl;
1311 if (!Namespace__HasMethod(cl,
"Dictionary", interp)) {
1312 dictStream << std::endl <<
" // Dictionary for non-ClassDef classes" << std::endl
1313 <<
" static TClass *" << mappedname.c_str() <<
"_Dictionary() {" << std::endl
1314 <<
" return GenerateInitInstance()->GetClass();" << std::endl
1315 <<
" }" << std::endl << std::endl;
1318 dictStream <<
" }" << std::endl;
1320 dictStream <<
"}" << std::endl;
1322 dictStream << std::endl;
1331 llvm::StringRef GrabIndex(
const clang::FieldDecl &member,
int printError)
1334 llvm::StringRef where;
1336 llvm::StringRef index = ROOT::TMetaUtils::DataMemberInfo__ValidArrayIndex(member, &error, &where);
1337 if (index.size() == 0 && printError) {
1338 const char *errorstring;
1340 case TMetaUtils::NOT_INT:
1341 errorstring =
"is not an integer";
1343 case TMetaUtils::NOT_DEF:
1344 errorstring =
"has not been defined before the array";
1346 case TMetaUtils::IS_PRIVATE:
1347 errorstring =
"is a private member of a parent class";
1349 case TMetaUtils::UNKNOWN:
1350 errorstring =
"is not known";
1353 errorstring =
"UNKNOWN ERROR!!!!";
1356 if (where.size() == 0) {
1357 ROOT::TMetaUtils::Error(0,
"*** Datamember %s::%s: no size indication!\n",
1358 member.getParent()->getName().str().c_str(), member.getName().str().c_str());
1360 ROOT::TMetaUtils::Error(0,
"*** Datamember %s::%s: size of array (%s) %s!\n",
1361 member.getParent()->getName().str().c_str(), member.getName().str().c_str(), where.str().c_str(), errorstring);
1369 void WriteStreamer(
const ROOT::TMetaUtils::AnnotatedRecordDecl &cl,
1370 const cling::Interpreter &interp,
1371 const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt,
1372 std::ostream &dictStream)
1374 const clang::CXXRecordDecl *clxx = llvm::dyn_cast<clang::CXXRecordDecl>(cl.GetRecordDecl());
1375 if (clxx == 0)
return;
1377 bool add_template_keyword = ROOT::TMetaUtils::NeedTemplateKeyword(clxx);
1382 int enclSpaceNesting = 0;
1384 if (ROOT::TMetaUtils::GetNameWithinNamespace(fullname, clsname, nsname, clxx)) {
1385 enclSpaceNesting = ROOT::TMetaUtils::WriteNamespaceHeader(dictStream, cl);
1388 dictStream <<
"//_______________________________________"
1389 <<
"_______________________________________" << std::endl;
1390 if (add_template_keyword) dictStream <<
"template <> ";
1391 dictStream <<
"void " << clsname <<
"::Streamer(TBuffer &R__b)" << std::endl <<
"{" << std::endl
1392 <<
" // Stream an object of class " << fullname <<
"." << std::endl << std::endl;
1397 int version = ROOT::TMetaUtils::GetClassVersion(clxx, interp);
1400 int basestreamer = 0;
1401 for (clang::CXXRecordDecl::base_class_const_iterator iter = clxx->bases_begin(), end = clxx->bases_end();
1404 if (ROOT::TMetaUtils::ClassInfo__HasMethod(iter->getType()->getAsCXXRecordDecl(),
"Streamer", interp)) {
1405 string base_fullname;
1406 ROOT::TMetaUtils::GetQualifiedName(base_fullname, * iter->getType()->getAsCXXRecordDecl());
1408 if (strstr(base_fullname.c_str(),
"::")) {
1410 dictStream <<
" //This works around a msvc bug and should be harmless on other platforms" << std::endl
1411 <<
" typedef " << base_fullname <<
" baseClass" << basestreamer <<
";" << std::endl
1412 <<
" baseClass" << basestreamer <<
"::Streamer(R__b);" << std::endl;
1414 dictStream <<
" " << base_fullname <<
"::Streamer(R__b);" << std::endl;
1419 if (!basestreamer) {
1420 dictStream <<
" ::Error(\"" << fullname <<
"::Streamer\", \"version id <=0 in ClassDef,"
1421 " dummy Streamer() called\"); if (R__b.IsReading()) { }" << std::endl;
1423 dictStream <<
"}" << std::endl << std::endl;
1424 while (enclSpaceNesting) {
1425 dictStream <<
"} // namespace " << nsname.c_str() << std::endl;
1432 string classname = fullname;
1433 if (strstr(fullname.c_str(),
"::")) {
1435 dictStream <<
" //This works around a msvc bug and should be harmless on other platforms" << std::endl
1436 <<
" typedef ::" << fullname <<
" thisClass;" << std::endl;
1437 classname =
"thisClass";
1439 for (
int i = 0; i < 2; i++) {
1444 dictStream <<
" UInt_t R__s, R__c;" << std::endl;
1445 dictStream <<
" if (R__b.IsReading()) {" << std::endl;
1446 dictStream <<
" Version_t R__v = R__b.ReadVersion(&R__s, &R__c); if (R__v) { }" << std::endl;
1448 dictStream <<
" R__b.CheckByteCount(R__s, R__c, " << classname.c_str() <<
"::IsA());" << std::endl;
1449 dictStream <<
" } else {" << std::endl;
1450 dictStream <<
" R__c = R__b.WriteVersion(" << classname.c_str() <<
"::IsA(), kTRUE);" << std::endl;
1455 for (clang::CXXRecordDecl::base_class_const_iterator iter = clxx->bases_begin(), end = clxx->bases_end();
1458 if (ROOT::TMetaUtils::ClassInfo__HasMethod(iter->getType()->getAsCXXRecordDecl(),
"Streamer", interp)) {
1459 string base_fullname;
1460 ROOT::TMetaUtils::GetQualifiedName(base_fullname, * iter->getType()->getAsCXXRecordDecl());
1462 if (strstr(base_fullname.c_str(),
"::")) {
1464 dictStream <<
" //This works around a msvc bug and should be harmless on other platforms" << std::endl
1465 <<
" typedef " << base_fullname <<
" baseClass" << base <<
";" << std::endl
1466 <<
" baseClass" << base <<
"::Streamer(R__b);" << std::endl;
1469 dictStream <<
" " << base_fullname <<
"::Streamer(R__b);" << std::endl;
1475 for (clang::RecordDecl::field_iterator field_iter = clxx->field_begin(), end = clxx->field_end();
1478 const char *comment = ROOT::TMetaUtils::GetComment(**field_iter).data();
1480 clang::QualType type = field_iter->getType();
1481 std::string type_name = type.getAsString(clxx->getASTContext().getPrintingPolicy());
1483 const clang::Type *underling_type = ROOT::TMetaUtils::GetUnderlyingType(type);
1491 if (strstr(type_name.c_str(),
"Float16_t")) isFloat16 = 1;
1495 if (strstr(type_name.c_str(),
"Double32_t")) isDouble32 = 1;
1498 if (strncmp(comment,
"!", 1)) {
1501 if (underling_type->isFundamentalType() || underling_type->isEnumeralType()) {
1502 if (type.getTypePtr()->isConstantArrayType() &&
1503 type.getTypePtr()->getArrayElementTypeNoTypeQual()->isPointerType()) {
1504 const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(type.getTypePtr());
1505 int s = GetFullArrayLength(arrayType);
1508 dictStream <<
" int R__i;" << std::endl;
1511 dictStream <<
" for (R__i = 0; R__i < " << s <<
"; R__i++)" << std::endl;
1513 ROOT::TMetaUtils::Error(0,
"*** Datamember %s::%s: array of pointers to fundamental type (need manual intervention)\n", fullname.c_str(), field_iter->getName().str().c_str());
1514 dictStream <<
" ;//R__b.ReadArray(" << field_iter->getName().str() <<
");" << std::endl;
1516 dictStream <<
" ;//R__b.WriteArray(" << field_iter->getName().str() <<
", __COUNTER__);" << std::endl;
1518 }
else if (type.getTypePtr()->isPointerType()) {
1519 llvm::StringRef indexvar = GrabIndex(**field_iter, i == 0);
1520 if (indexvar.size() == 0) {
1522 ROOT::TMetaUtils::Error(0,
"*** Datamember %s::%s: pointer to fundamental type (need manual intervention)\n", fullname.c_str(), field_iter->getName().str().c_str());
1523 dictStream <<
" //R__b.ReadArray(" << field_iter->getName().str() <<
");" << std::endl;
1525 dictStream <<
" //R__b.WriteArray(" << field_iter->getName().str() <<
", __COUNTER__);" << std::endl;
1529 dictStream <<
" delete [] " << field_iter->getName().str() <<
";" << std::endl
1530 <<
" " << GetNonConstMemberName(**field_iter) <<
" = new "
1531 << ROOT::TMetaUtils::ShortTypeName(**field_iter) <<
"[" << indexvar.str() <<
"];" << std::endl;
1533 dictStream <<
" R__b.ReadFastArrayFloat16(" << GetNonConstMemberName(**field_iter)
1534 <<
"," << indexvar.str() <<
");" << std::endl;
1535 }
else if (isDouble32) {
1536 dictStream <<
" R__b.ReadFastArrayDouble32(" << GetNonConstMemberName(**field_iter)
1537 <<
"," << indexvar.str() <<
");" << std::endl;
1539 dictStream <<
" R__b.ReadFastArray(" << GetNonConstMemberName(**field_iter)
1540 <<
"," << indexvar.str() <<
");" << std::endl;
1544 dictStream <<
" R__b.WriteFastArrayFloat16("
1545 << field_iter->getName().str() <<
"," << indexvar.str() <<
");" << std::endl;
1546 }
else if (isDouble32) {
1547 dictStream <<
" R__b.WriteFastArrayDouble32("
1548 << field_iter->getName().str() <<
"," << indexvar.str() <<
");" << std::endl;
1550 dictStream <<
" R__b.WriteFastArray("
1551 << field_iter->getName().str() <<
"," << indexvar.str() <<
");" << std::endl;
1555 }
else if (type.getTypePtr()->isArrayType()) {
1557 if (type.getTypePtr()->getArrayElementTypeNoTypeQual()->isArrayType()) {
1558 if (underling_type->isEnumeralType())
1559 dictStream <<
" R__b.ReadStaticArray((Int_t*)" << field_iter->getName().str() <<
");" << std::endl;
1562 dictStream <<
" R__b.ReadStaticArrayFloat16((" << ROOT::TMetaUtils::TrueName(**field_iter)
1563 <<
"*)" << field_iter->getName().str() <<
");" << std::endl;
1564 }
else if (isDouble32) {
1565 dictStream <<
" R__b.ReadStaticArrayDouble32((" << ROOT::TMetaUtils::TrueName(**field_iter)
1566 <<
"*)" << field_iter->getName().str() <<
");" << std::endl;
1568 dictStream <<
" R__b.ReadStaticArray((" << ROOT::TMetaUtils::TrueName(**field_iter)
1569 <<
"*)" << field_iter->getName().str() <<
");" << std::endl;
1573 if (underling_type->isEnumeralType()) {
1574 dictStream <<
" R__b.ReadStaticArray((Int_t*)" << field_iter->getName().str() <<
");" << std::endl;
1577 dictStream <<
" R__b.ReadStaticArrayFloat16(" << field_iter->getName().str() <<
");" << std::endl;
1578 }
else if (isDouble32) {
1579 dictStream <<
" R__b.ReadStaticArrayDouble32(" << field_iter->getName().str() <<
");" << std::endl;
1581 dictStream <<
" R__b.ReadStaticArray((" << ROOT::TMetaUtils::TrueName(**field_iter)
1582 <<
"*)" << field_iter->getName().str() <<
");" << std::endl;
1587 const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(type.getTypePtr());
1588 int s = GetFullArrayLength(arrayType);
1590 if (type.getTypePtr()->getArrayElementTypeNoTypeQual()->isArrayType()) {
1591 if (underling_type->isEnumeralType())
1592 dictStream <<
" R__b.WriteArray((Int_t*)" << field_iter->getName().str() <<
", "
1593 << s <<
");" << std::endl;
1594 else if (isFloat16) {
1595 dictStream <<
" R__b.WriteArrayFloat16((" << ROOT::TMetaUtils::TrueName(**field_iter)
1596 <<
"*)" << field_iter->getName().str() <<
", " << s <<
");" << std::endl;
1597 }
else if (isDouble32) {
1598 dictStream <<
" R__b.WriteArrayDouble32((" << ROOT::TMetaUtils::TrueName(**field_iter)
1599 <<
"*)" << field_iter->getName().str() <<
", " << s <<
");" << std::endl;
1601 dictStream <<
" R__b.WriteArray((" << ROOT::TMetaUtils::TrueName(**field_iter)
1602 <<
"*)" << field_iter->getName().str() <<
", " << s <<
");" << std::endl;
1605 if (underling_type->isEnumeralType())
1606 dictStream <<
" R__b.WriteArray((Int_t*)" << field_iter->getName().str() <<
", " << s <<
");" << std::endl;
1607 else if (isFloat16) {
1608 dictStream <<
" R__b.WriteArrayFloat16(" << field_iter->getName().str() <<
", " << s <<
");" << std::endl;
1609 }
else if (isDouble32) {
1610 dictStream <<
" R__b.WriteArrayDouble32(" << field_iter->getName().str() <<
", " << s <<
");" << std::endl;
1612 dictStream <<
" R__b.WriteArray(" << field_iter->getName().str() <<
", " << s <<
");" << std::endl;
1616 }
else if (underling_type->isEnumeralType()) {
1618 dictStream <<
" void *ptr_" << field_iter->getName().str() <<
" = (void*)&" << field_iter->getName().str() <<
";\n";
1619 dictStream <<
" R__b >> *reinterpret_cast<Int_t*>(ptr_" << field_iter->getName().str() <<
");" << std::endl;
1621 dictStream <<
" R__b << (Int_t)" << field_iter->getName().str() <<
";" << std::endl;
1625 dictStream <<
" {float R_Dummy; R__b >> R_Dummy; " << GetNonConstMemberName(**field_iter)
1626 <<
"=Float16_t(R_Dummy);}" << std::endl;
1628 dictStream <<
" R__b << float(" << GetNonConstMemberName(**field_iter) <<
");" << std::endl;
1629 }
else if (isDouble32) {
1631 dictStream <<
" {float R_Dummy; R__b >> R_Dummy; " << GetNonConstMemberName(**field_iter)
1632 <<
"=Double32_t(R_Dummy);}" << std::endl;
1634 dictStream <<
" R__b << float(" << GetNonConstMemberName(**field_iter) <<
");" << std::endl;
1637 dictStream <<
" R__b >> " << GetNonConstMemberName(**field_iter) <<
";" << std::endl;
1639 dictStream <<
" R__b << " << GetNonConstMemberName(**field_iter) <<
";" << std::endl;
1646 if (STLStringStreamer(**field_iter, i, dictStream))
1650 if (STLContainerStreamer(**field_iter, i, interp, normCtxt, dictStream))
1654 if (type.getTypePtr()->isConstantArrayType() &&
1655 type.getTypePtr()->getArrayElementTypeNoTypeQual()->isPointerType()) {
1656 const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(type.getTypePtr());
1657 int s = GetFullArrayLength(arrayType);
1660 dictStream <<
" int R__i;" << std::endl;
1663 dictStream <<
" for (R__i = 0; R__i < " << s <<
"; R__i++)" << std::endl;
1665 dictStream <<
" R__b >> " << GetNonConstMemberName(**field_iter);
1667 if (ROOT::TMetaUtils::IsBase(**field_iter,
"TObject", interp) && ROOT::TMetaUtils::IsBase(**field_iter,
"TArray", interp))
1668 dictStream <<
" R__b << (TObject*)" << field_iter->getName().str();
1670 dictStream <<
" R__b << " << GetNonConstMemberName(**field_iter);
1672 WriteArrayDimensions(field_iter->getType(), dictStream);
1673 dictStream <<
"[R__i];" << std::endl;
1674 }
else if (type.getTypePtr()->isPointerType()) {
1680 if (isPointerToPointer(**field_iter)) {
1682 ROOT::TMetaUtils::Error(0,
"*** Datamember %s::%s: pointer to pointer (need manual intervention)\n", fullname.c_str(), field_iter->getName().str().c_str());
1683 dictStream <<
" //R__b.ReadArray(" << field_iter->getName().str() <<
");" << std::endl;
1685 dictStream <<
" //R__b.WriteArray(" << field_iter->getName().str() <<
", __COUNTER__);";
1688 if (ROOT::TMetaUtils::GetQualifiedName(*ROOT::TMetaUtils::GetUnderlyingType(field_iter->getType()), **field_iter) ==
"TClonesArray") {
1689 dictStream <<
" " << field_iter->getName().str() <<
"->Streamer(R__b);" << std::endl;
1700 dictStream <<
" R__b >> " << GetNonConstMemberName(**field_iter) <<
";" << std::endl;
1702 if (ROOT::TMetaUtils::IsBase(**field_iter,
"TObject", interp) && ROOT::TMetaUtils::IsBase(**field_iter,
"TArray", interp))
1703 dictStream <<
" R__b << (TObject*)" << field_iter->getName().str() <<
";" << std::endl;
1705 dictStream <<
" R__b << " << GetNonConstMemberName(**field_iter) <<
";" << std::endl;
1709 }
else if (
const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(type.getTypePtr())) {
1710 int s = GetFullArrayLength(arrayType);
1713 dictStream <<
" int R__i;" << std::endl;
1716 dictStream <<
" for (R__i = 0; R__i < " << s <<
"; R__i++)" << std::endl;
1717 std::string mTypeNameStr;
1718 ROOT::TMetaUtils::GetQualifiedName(mTypeNameStr, field_iter->getType(), **field_iter);
1719 const char *mTypeName = mTypeNameStr.c_str();
1720 const char *constwd =
"const ";
1721 if (strncmp(constwd, mTypeName, strlen(constwd)) == 0) {
1722 mTypeName += strlen(constwd);
1723 dictStream <<
" const_cast< " << mTypeName <<
" &>(" << field_iter->getName().str();
1724 WriteArrayDimensions(field_iter->getType(), dictStream);
1725 dictStream <<
"[R__i]).Streamer(R__b);" << std::endl;
1727 dictStream <<
" " << GetNonConstMemberName(**field_iter);
1728 WriteArrayDimensions(field_iter->getType(), dictStream);
1729 dictStream <<
"[R__i].Streamer(R__b);" << std::endl;
1732 if (ROOT::TMetaUtils::ClassInfo__HasMethod(ROOT::TMetaUtils::GetUnderlyingRecordDecl(field_iter->getType()),
"Streamer", interp))
1733 dictStream <<
" " << GetNonConstMemberName(**field_iter) <<
".Streamer(R__b);" << std::endl;
1735 dictStream <<
" R__b.StreamObject(&(" << field_iter->getName().str() <<
"),typeid("
1736 << field_iter->getName().str() <<
"));" << std::endl;
1747 dictStream <<
" R__b.SetByteCount(R__c, kTRUE);" << std::endl
1748 <<
" }" << std::endl
1749 <<
"}" << std::endl << std::endl;
1751 while (enclSpaceNesting) {
1752 dictStream <<
"} // namespace " << nsname.c_str() << std::endl;
1759 void WriteAutoStreamer(
const ROOT::TMetaUtils::AnnotatedRecordDecl &cl,
1760 const cling::Interpreter &interp,
1761 const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt,
1762 std::ostream &dictStream)
1766 const clang::CXXRecordDecl *clxx = llvm::dyn_cast<clang::CXXRecordDecl>(cl.GetRecordDecl());
1767 if (clxx == 0)
return;
1769 bool add_template_keyword = ROOT::TMetaUtils::NeedTemplateKeyword(clxx);
1772 for (clang::CXXRecordDecl::base_class_const_iterator iter = clxx->bases_begin(), end = clxx->bases_end();
1775 int k = ROOT::TMetaUtils::IsSTLContainer(*iter);
1777 Internal::RStl::Instance().GenerateTClassFor(iter->getType(), interp, normCtxt);
1784 int enclSpaceNesting = 0;
1786 if (ROOT::TMetaUtils::GetNameWithinNamespace(fullname, clsname, nsname, clxx)) {
1787 enclSpaceNesting = ROOT::TMetaUtils::WriteNamespaceHeader(dictStream, cl);
1790 dictStream <<
"//_______________________________________"
1791 <<
"_______________________________________" << std::endl;
1792 if (add_template_keyword) dictStream <<
"template <> ";
1793 dictStream <<
"void " << clsname <<
"::Streamer(TBuffer &R__b)" << std::endl
1795 <<
" // Stream an object of class " << fullname <<
"." << std::endl << std::endl
1796 <<
" if (R__b.IsReading()) {" << std::endl
1797 <<
" R__b.ReadClassBuffer(" << fullname <<
"::Class(),this);" << std::endl
1798 <<
" } else {" << std::endl
1799 <<
" R__b.WriteClassBuffer(" << fullname <<
"::Class(),this);" << std::endl
1800 <<
" }" << std::endl
1801 <<
"}" << std::endl << std::endl;
1803 while (enclSpaceNesting) {
1804 dictStream <<
"} // namespace " << nsname << std::endl;
1811 void CallWriteStreamer(
const ROOT::TMetaUtils::AnnotatedRecordDecl &cl,
1812 const cling::Interpreter &interp,
1813 const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt,
1814 std::ostream &dictStream,
1815 bool isAutoStreamer)
1817 if (isAutoStreamer) {
1818 WriteAutoStreamer(cl, interp, normCtxt, dictStream);
1820 WriteStreamer(cl, interp, normCtxt, dictStream);
1826 void GenerateLinkdef(llvm::cl::list<std::string> &InputFiles,
1827 std::string &code_for_parser)
1829 code_for_parser +=
"#ifdef __CINT__\n\n";
1830 code_for_parser +=
"#pragma link off all globals;\n";
1831 code_for_parser +=
"#pragma link off all classes;\n";
1832 code_for_parser +=
"#pragma link off all functions;\n\n";
1834 for (std::string& arg : InputFiles) {
1836 int nostr = 0, noinp = 0, bcnt = 0, l = arg.length() - 1;
1837 for (
int j = 0; j < 3; j++) {
1838 if (arg[l] ==
'-') {
1843 if (arg[l] ==
'!') {
1848 if (arg[l] ==
'+') {
1854 if (nostr || noinp) {
1856 if (nostr) strlcat(trail,
"-", 3);
1857 if (noinp) strlcat(trail,
"!", 3);
1860 strlcpy(trail,
"+", 3);
1862 ROOT::TMetaUtils::Error(0,
"option + mutual exclusive with -\n");
1864 llvm::SmallString<256> filestem = llvm::sys::path::filename(arg);
1865 llvm::sys::path::replace_extension(filestem,
"");
1867 code_for_parser +=
"#pragma link C++ class ";
1868 code_for_parser += filestem.str().str();
1869 if (nostr || noinp || bcnt)
1870 code_for_parser += trail;
1871 code_for_parser +=
";\n";
1874 code_for_parser +=
"\n#endif\n";
1882 bool Which(cling::Interpreter &interp,
const char *fname,
string &pname)
1887 static const char *fopenopts =
"rb";
1889 static const char *fopenopts =
"r";
1893 fp = fopen(pname.c_str(), fopenopts);
1899 llvm::SmallVector<std::string, 10> includePaths;
1901 interp.GetIncludePaths(includePaths,
false,
false);
1903 const size_t nPaths = includePaths.size();
1904 for (
size_t i = 0; i < nPaths; i += 1 ) {
1906 pname = includePaths[i].c_str() + gPathSeparator + fname;
1908 fp = fopen(pname.c_str(), fopenopts);
1922 const char *CopyArg(
const char *original)
1927 if (IsSelectionFile(original))
1930 const char *inc = strstr(original,
"\\inc\\");
1932 inc = strstr(original,
"/inc/");
1933 if (inc && strlen(inc) > 5)
1942 void StrcpyArg(
string &dest,
const char *original)
1944 dest = CopyArg(original);
1951 static bool InjectModuleUtilHeader(
const char *argv0,
1952 TModuleGenerator &modGen,
1953 cling::Interpreter &interp,
1956 std::ostringstream out;
1960 modGen.WriteUmbrellaHeader(out);
1962 modGen.WriteContentHeader(out);
1964 if (interp.declare(out.str()) != cling::Interpreter::kSuccess) {
1965 const std::string &hdrName
1966 = umbrella ? modGen.GetUmbrellaName() : modGen.GetContentName();
1967 ROOT::TMetaUtils::Error(0,
"%s: compilation failure (%s)\n", argv0,
1980 static bool WriteAST(StringRef fileName, clang::CompilerInstance *compilerInstance, StringRef iSysRoot,
1981 clang::Module *module =
nullptr)
1984 llvm::SmallVector<char, 128> buffer;
1985 llvm::BitstreamWriter stream(buffer);
1986 clang::ASTWriter writer(stream, buffer, compilerInstance->getPCMCache(), {});
1987 std::unique_ptr<llvm::raw_ostream> out =
1988 compilerInstance->createOutputFile(fileName,
true,
1993 ROOT::TMetaUtils::Error(
"WriteAST",
"Couldn't open output stream to '%s'!\n", fileName.data());
1997 compilerInstance->getFrontendOpts().RelocatablePCH =
true;
1999 writer.WriteAST(compilerInstance->getSema(), fileName, module, iSysRoot);
2002 out->write(&buffer.front(), buffer.size());
2013 static bool GenerateAllDict(TModuleGenerator &modGen, clang::CompilerInstance *compilerInstance,
2014 const std::string ¤tDirectory)
2016 assert(modGen.IsPCH() &&
"modGen must be in PCH mode");
2018 std::string iSysRoot(
"/DUMMY_SYSROOT/include/");
2019 if (gBuildingROOT) iSysRoot = (currentDirectory +
"/");
2020 return WriteAST(modGen.GetModuleFileName(), compilerInstance, iSysRoot);
2026 static bool IncludeHeaders(
const std::vector<std::string> &headers, cling::Interpreter &interpreter)
2029 if (headers.empty())
2033 std::stringstream includes;
2034 for (
const std::string &header : headers) {
2035 includes <<
"#include \"" << header <<
"\"\n";
2037 std::string includeListStr = includes.str();
2038 auto result = interpreter.declare(includeListStr);
2039 return result == cling::Interpreter::CompilationResult::kSuccess;
2045 void AddPlatformDefines(std::vector<std::string> &clingArgs)
2047 char platformDefines[64] = {0};
2048 #ifdef __INTEL_COMPILER
2049 snprintf(platformDefines, 64,
"-DG__INTEL_COMPILER=%ld", (
long)__INTEL_COMPILER);
2050 clingArgs.push_back(platformDefines);
2053 snprintf(platformDefines, 64,
"-DG__xlC=%ld", (
long)__xlC__);
2054 clingArgs.push_back(platformDefines);
2057 snprintf(platformDefines, 64,
"-DG__GNUC=%ld", (
long)__GNUC__);
2058 snprintf(platformDefines, 64,
"-DG__GNUC_VER=%ld", (
long)__GNUC__ * 1000 + __GNUC_MINOR__);
2059 clingArgs.push_back(platformDefines);
2061 #ifdef __GNUC_MINOR__
2062 snprintf(platformDefines, 64,
"-DG__GNUC_MINOR=%ld", (
long)__GNUC_MINOR__);
2063 clingArgs.push_back(platformDefines);
2066 snprintf(platformDefines, 64,
"-DG__HP_aCC=%ld", (
long)__HP_aCC);
2067 clingArgs.push_back(platformDefines);
2070 snprintf(platformDefines, 64,
"-DG__sun=%ld", (
long)__sun);
2071 clingArgs.push_back(platformDefines);
2074 snprintf(platformDefines, 64,
"-DG__SUNPRO_CC=%ld", (
long)__SUNPRO_CC);
2075 clingArgs.push_back(platformDefines);
2077 #ifdef _STLPORT_VERSION
2079 snprintf(platformDefines, 64,
"-DG__STLPORT_VERSION=%ld", (
long)_STLPORT_VERSION);
2080 clingArgs.push_back(platformDefines);
2083 snprintf(platformDefines, 64,
"-DG__ia64=%ld", (
long)__ia64__);
2084 clingArgs.push_back(platformDefines);
2087 snprintf(platformDefines, 64,
"-DG__x86_64=%ld", (
long)__x86_64__);
2088 clingArgs.push_back(platformDefines);
2091 snprintf(platformDefines, 64,
"-DG__i386=%ld", (
long)__i386__);
2092 clingArgs.push_back(platformDefines);
2095 snprintf(platformDefines, 64,
"-DG__arm=%ld", (
long)__arm__);
2096 clingArgs.push_back(platformDefines);
2099 snprintf(platformDefines, 64,
"-DG__WIN32=%ld", (
long)_WIN32);
2100 clingArgs.push_back(platformDefines);
2103 snprintf(platformDefines, 64,
"-DG__WIN32=%ld", (
long)WIN32);
2104 clingArgs.push_back(platformDefines);
2108 snprintf(platformDefines, 64,
"-DG__MSC_VER=%ld", (
long)_MSC_VER);
2109 clingArgs.push_back(platformDefines);
2110 snprintf(platformDefines, 64,
"-DG__VISUAL=%ld", (
long)_MSC_VER);
2111 clingArgs.push_back(platformDefines);
2118 std::string ExtractFileName(
const std::string &path)
2120 return llvm::sys::path::filename(path);
2127 void ExtractFilePath(
const std::string &path, std::string &dirname)
2129 const size_t pos = path.find_last_of(gPathSeparator);
2130 if (std::string::npos != pos) {
2131 dirname.assign(path.begin(), path.begin() + pos + 1);
2140 bool HasPath(
const std::string &name)
2142 std::string dictLocation;
2143 ExtractFilePath(name, dictLocation);
2144 return !dictLocation.empty();
2149 void AdjustRootMapNames(std::string &rootmapFileName,
2150 std::string &rootmapLibName)
2154 if (rootmapFileName.empty()) {
2155 size_t libExtensionPos = rootmapLibName.find_last_of(gLibraryExtension) - gLibraryExtension.size() + 1;
2156 rootmapFileName = rootmapLibName.substr(0, libExtensionPos) +
".rootmap";
2157 size_t libCleanNamePos = rootmapLibName.find_last_of(gPathSeparator) + 1;
2158 rootmapLibName = rootmapLibName.substr(libCleanNamePos, std::string::npos);
2159 ROOT::TMetaUtils::Info(0,
"Rootmap file name %s built from rootmap lib name %s",
2160 rootmapLibName.c_str(),
2161 rootmapFileName.c_str());
2169 void GetMostExternalEnclosingClassName(
const clang::DeclContext &theContext,
2170 std::string &ctxtName,
2171 const cling::Interpreter &interpreter,
2172 bool treatParent =
true)
2174 const clang::DeclContext *outerCtxt = treatParent ? theContext.getParent() : &theContext;
2176 if (!outerCtxt)
return;
2178 if (
const clang::RecordDecl *thisRcdDecl = llvm::dyn_cast<clang::RecordDecl>(outerCtxt)) {
2179 ROOT::TMetaUtils::GetNormalizedName(ctxtName, thisRcdDecl, interpreter);
2182 GetMostExternalEnclosingClassName(*outerCtxt, ctxtName, interpreter);
2187 void GetMostExternalEnclosingClassNameFromDecl(
const clang::Decl &theDecl,
2188 std::string &ctxtName,
2189 const cling::Interpreter &interpreter)
2191 const clang::DeclContext *theContext = theDecl.getDeclContext();
2192 GetMostExternalEnclosingClassName(*theContext, ctxtName, interpreter,
false);
2196 template<
class COLL>
2197 int ExtractAutoloadKeys(std::list<std::string> &names,
2199 const cling::Interpreter &interp)
2201 if (!decls.empty()) {
2202 std::string autoLoadKey;
2203 for (
auto & d : decls) {
2205 GetMostExternalEnclosingClassNameFromDecl(*d, autoLoadKey, interp);
2207 if (autoLoadKey.empty()) {
2208 names.push_back(d->getQualifiedNameAsString());
2225 int CreateNewRootMapFile(
const std::string &rootmapFileName,
2226 const std::string &rootmapLibName,
2227 const std::list<std::string> &classesDefsList,
2228 const std::list<std::string> &classesNames,
2229 const std::list<std::string> &nsNames,
2230 const std::list<std::string> &tdNames,
2231 const std::list<std::string> &enNames,
2232 const std::list<std::string> &varNames,
2233 const HeadersDeclsMap_t &headersClassesMap,
2234 const std::unordered_set<std::string> headersToIgnore)
2237 std::ofstream rootmapFile(rootmapFileName.c_str());
2239 ROOT::TMetaUtils::Error(0,
"Opening new rootmap file %s\n", rootmapFileName.c_str());
2245 std::unordered_set<std::string> classesKeys;
2249 if (!classesNames.empty() || !nsNames.empty() || !tdNames.empty() ||
2250 !enNames.empty() || !varNames.empty()) {
2253 if (!classesDefsList.empty()) {
2254 rootmapFile <<
"{ decls }\n";
2255 for (
auto & classDef : classesDefsList) {
2256 rootmapFile << classDef << std::endl;
2258 rootmapFile <<
"\n";
2260 rootmapFile <<
"[ " << rootmapLibName <<
" ]\n";
2263 if (!classesNames.empty()) {
2264 rootmapFile <<
"# List of selected classes\n";
2265 for (
auto & className : classesNames) {
2266 rootmapFile <<
"class " << className << std::endl;
2267 classesKeys.insert(className);
2270 std::unordered_set<std::string> treatedHeaders;
2271 for (
auto & className : classesNames) {
2273 if (className.find(
"<") != std::string::npos)
continue;
2274 if (headersClassesMap.count(className)) {
2275 auto &headers = headersClassesMap.at(className);
2276 if (!headers.empty()){
2277 auto &header = headers.front();
2278 if (treatedHeaders.insert(header).second &&
2279 headersToIgnore.find(header) == headersToIgnore.end() &&
2280 ROOT::TMetaUtils::IsHeaderName(header)){
2281 rootmapFile <<
"header " << header << std::endl;
2289 if (!nsNames.empty()) {
2290 rootmapFile <<
"# List of selected namespaces\n";
2291 for (
auto & nsName : nsNames) {
2292 rootmapFile <<
"namespace " << nsName << std::endl;
2297 if (!tdNames.empty()) {
2298 rootmapFile <<
"# List of selected typedefs and outer classes\n";
2299 for (
const auto & autoloadKey : tdNames)
2300 if (classesKeys.insert(autoloadKey).second)
2301 rootmapFile <<
"typedef " << autoloadKey << std::endl;
2306 if (!enNames.empty()){
2307 rootmapFile <<
"# List of selected enums and outer classes\n";
2308 for (
const auto & autoloadKey : enNames)
2309 if (classesKeys.insert(autoloadKey).second)
2310 rootmapFile <<
"enum " << autoloadKey << std::endl;
2314 if (!varNames.empty()){
2315 rootmapFile <<
"# List of selected vars\n";
2316 for (
const auto & autoloadKey : varNames)
2317 if (classesKeys.insert(autoloadKey).second)
2318 rootmapFile <<
"var " << autoloadKey << std::endl;
2330 std::pair<std::string,std::string> GetExternalNamespaceAndContainedEntities(
const std::string line)
2332 auto nsPattern =
'{';
auto nsPatternLength = 1;
2333 auto foundNsPos = line.find_last_of(nsPattern);
2334 if (foundNsPos == std::string::npos)
return {
"",
""};
2335 foundNsPos+=nsPatternLength;
2336 auto extNs = line.substr(0,foundNsPos);
2338 auto nsEndPattern =
'}';
2339 auto foundEndNsPos = line.find(nsEndPattern);
2340 auto contained = line.substr(foundNsPos, foundEndNsPos-foundNsPos);
2342 return {extNs, contained};
2354 std::list<std::string> CollapseIdenticalNamespaces(
const std::list<std::string>& fwdDeclarationsList)
2358 std::map<std::string, std::string> nsEntitiesMap;
2359 std::list<std::string> optFwdDeclList;
2360 for (
auto const & fwdDecl : fwdDeclarationsList){
2362 auto extNsAndEntities = GetExternalNamespaceAndContainedEntities(fwdDecl);
2363 if (extNsAndEntities.first.empty()) {
2365 optFwdDeclList.push_front(fwdDecl);
2367 auto currentVal = nsEntitiesMap[extNsAndEntities.first];
2368 nsEntitiesMap[extNsAndEntities.first] = currentVal +=extNsAndEntities.second;
2372 std::string optFwdDecl;
2373 for (
auto const & extNsAndEntities : nsEntitiesMap) {
2374 optFwdDecl = extNsAndEntities.first;
2375 optFwdDecl += extNsAndEntities.second;
2376 for (
int i = 0; i < std::count(optFwdDecl.begin(), optFwdDecl.end(),
'{'); ++i ){
2379 optFwdDeclList.push_front(optFwdDecl);
2382 return optFwdDeclList;
2389 bool ProcessAndAppendIfNotThere(
const std::string &el,
2390 std::list<std::string> &el_list,
2391 std::unordered_set<std::string> &el_set)
2393 std::stringstream elStream(el);
2396 while (getline(elStream, tmp,
'\n')) {
2398 if (el_set.insert(tmp).second && !tmp.empty()) {
2399 el_list.push_back(tmp);
2409 int ExtractClassesListAndDeclLines(RScanner &scan,
2410 std::list<std::string> &classesList,
2411 std::list<std::string> &classesListForRootmap,
2412 std::list<std::string> &fwdDeclarationsList,
2413 const cling::Interpreter &interpreter)
2421 std::unordered_set<std::string> classesSet;
2422 std::unordered_set<std::string> outerMostClassesSet;
2424 std::string attrName, attrValue;
2425 bool isClassSelected;
2426 std::unordered_set<std::string> availableFwdDecls;
2427 std::string fwdDeclaration;
2428 for (
auto const & selVar : scan.fSelectedVariables) {
2429 fwdDeclaration =
"";
2430 int retCode = ROOT::TMetaUtils::AST2SourceTools::EncloseInNamespaces(*selVar, fwdDeclaration);
2431 if (retCode == 0) ProcessAndAppendIfNotThere(fwdDeclaration, fwdDeclarationsList, availableFwdDecls);
2434 for (
auto const & selEnum : scan.fSelectedEnums) {
2435 fwdDeclaration =
"";
2436 int retCode = ROOT::TMetaUtils::AST2SourceTools::EncloseInNamespaces(*selEnum, fwdDeclaration);
2437 if (retCode == 0) ProcessAndAppendIfNotThere(fwdDeclaration, fwdDeclarationsList, availableFwdDecls);
2441 for (
auto const & selClass : scan.fSelectedClasses) {
2442 isClassSelected =
true;
2443 const clang::RecordDecl *rDecl = selClass.GetRecordDecl();
2444 std::string normalizedName;
2445 normalizedName = selClass.GetNormalizedName();
2446 if (!normalizedName.empty() &&
2447 !classesSet.insert(normalizedName).second &&
2448 outerMostClassesSet.count(normalizedName) == 0) {
2449 std::cerr <<
"FATAL: A class with normalized name " << normalizedName
2450 <<
" was already selected. This means that two different instances of"
2451 <<
" clang::RecordDecl had the same name, which is not possible."
2452 <<
" This can be a hint of a serious problem in the class selection."
2453 <<
" In addition, the generated dictionary would not even compile.\n";
2456 classesList.push_back(normalizedName);
2459 const char *reqName(selClass.GetRequestedName());
2462 fwdDeclaration =
"";
2463 int retCode = ROOT::TMetaUtils::AST2SourceTools::EncloseInNamespaces(*rDecl, fwdDeclaration);
2464 if (retCode == 0) ProcessAndAppendIfNotThere(fwdDeclaration, fwdDeclarationsList, availableFwdDecls);
2467 if (llvm::isa<clang::ClassTemplateSpecializationDecl>(rDecl)) {
2468 fwdDeclaration =
"";
2469 retCode = ROOT::TMetaUtils::AST2SourceTools::FwdDeclFromRcdDecl(*rDecl, interpreter, fwdDeclaration);
2470 if (retCode == 0) ProcessAndAppendIfNotThere(fwdDeclaration, fwdDeclarationsList, availableFwdDecls);
2475 for (
auto ait = rDecl->attr_begin(); ait != rDecl->attr_end(); ++ait) {
2476 if (0 == ROOT::TMetaUtils::extractPropertyNameVal(*ait, attrName, attrValue) &&
2477 attrName ==
"rootmap" &&
2478 attrValue ==
"false") {
2479 attrName = attrValue =
"";
2480 isClassSelected =
false;
2484 if (isClassSelected) {
2500 std::string outerMostClassName;
2501 GetMostExternalEnclosingClassName(*rDecl, outerMostClassName, interpreter);
2502 if (!outerMostClassName.empty() &&
2503 !llvm::isa<clang::ClassTemplateSpecializationDecl>(rDecl) &&
2504 classesSet.insert(outerMostClassName).second &&
2505 outerMostClassesSet.insert(outerMostClassName).second) {
2506 classesListForRootmap.push_back(outerMostClassName);
2508 classesListForRootmap.push_back(normalizedName);
2509 if (reqName !=
nullptr && 0 != strcmp(reqName,
"") && reqName != normalizedName) {
2510 classesListForRootmap.push_back(reqName);
2514 if (normalizedName.find(
"Double32_t") == std::string::npos
2515 && normalizedName.find(
"Float16_t") == std::string::npos) {
2516 std::unique_ptr<clang::MangleContext> mangleCtx(rDecl->getASTContext().createMangleContext());
2517 std::string mangledName;
2519 llvm::raw_string_ostream sstr(mangledName);
2520 if (
const clang::TypeDecl* TD = llvm::dyn_cast<clang::TypeDecl>(rDecl)) {
2521 mangleCtx->mangleCXXRTTI(clang::QualType(TD->getTypeForDecl(), 0), sstr);
2524 if (!mangledName.empty()) {
2525 int errDemangle = 0;
2527 if (mangledName[0] ==
'\01')
2528 mangledName.erase(0, 1);
2529 char *demangledTIName = TClassEdit::DemangleName(mangledName.c_str(), errDemangle);
2530 if (!errDemangle && demangledTIName) {
2531 static const char typeinfoNameFor[] =
" `RTTI Type Descriptor'";
2532 if (strstr(demangledTIName, typeinfoNameFor)) {
2533 std::string demangledName = demangledTIName;
2534 demangledName.erase(demangledName.end() - strlen(typeinfoNameFor), demangledName.end());
2535 if (demangledName.compare(0, 6,
"class ") == 0)
2536 demangledName.erase(0, 6);
2537 else if (demangledName.compare(0, 7,
"struct ") == 0)
2538 demangledName.erase(0, 7);
2540 char* demangledTIName = TClassEdit::DemangleName(mangledName.c_str(), errDemangle);
2541 if (!errDemangle && demangledTIName) {
2542 static const char typeinfoNameFor[] =
"typeinfo for ";
2543 if (!strncmp(demangledTIName, typeinfoNameFor, strlen(typeinfoNameFor))) {
2544 std::string demangledName = demangledTIName + strlen(typeinfoNameFor);
2547 TClassEdit::TSplitType splitname( demangledName.c_str(), (TClassEdit::EModType)(TClassEdit::kLong64 | TClassEdit::kDropStd) );
2548 splitname.ShortType(demangledName, TClassEdit::kDropStlDefault | TClassEdit::kDropStd);
2550 if (demangledName != normalizedName && (!reqName || demangledName != reqName)) {
2551 classesListForRootmap.push_back(demangledName);
2555 ROOT::TMetaUtils::Error(
"ExtractClassesListAndDeclLines",
2556 "Demangled typeinfo name '%s' does not contain `RTTI Type Descriptor'\n",
2559 ROOT::TMetaUtils::Error(
"ExtractClassesListAndDeclLines",
2560 "Demangled typeinfo name '%s' does not start with 'typeinfo for'\n",
2565 free(demangledTIName);
2571 classesListForRootmap.sort();
2582 void ExtractSelectedNamespaces(RScanner &scan, std::list<std::string> &nsList)
2584 for (RScanner::NamespaceColl_t::const_iterator selNsIter = scan.fSelectedNamespaces.begin();
2585 selNsIter != scan.fSelectedNamespaces.end(); ++selNsIter) {
2586 nsList.push_back(ROOT::TMetaUtils::GetQualifiedName(* selNsIter->GetNamespaceDecl()));
2593 void AnnotateAllDeclsForPCH(cling::Interpreter &interp,
2596 auto const & declSelRulesMap = scan.GetDeclsSelRulesMap();
2597 for (
auto const & selClass : scan.fSelectedClasses) {
2599 if (clang::CXXRecordDecl *CXXRD =
2600 llvm::dyn_cast<clang::CXXRecordDecl>(const_cast<clang::RecordDecl *>(selClass.GetRecordDecl()))) {
2601 AnnotateDecl(*CXXRD, declSelRulesMap, interp,
false);
2608 int CheckClassesForInterpreterOnlyDicts(cling::Interpreter &interp,
2611 for (
auto const & selClass : scan.fSelectedClasses) {
2612 if (!selClass.GetRecordDecl()->isCompleteDefinition() || selClass.RequestOnlyTClass()) {
2615 const clang::CXXRecordDecl *cxxdecl = llvm::dyn_cast<clang::CXXRecordDecl>(selClass.GetRecordDecl());
2616 if (cxxdecl && ROOT::TMetaUtils::ClassInfo__HasMethod(selClass,
"Class_Name", interp)) {
2617 ROOT::TMetaUtils::Error(
"CheckClassesForInterpreterOnlyDicts",
2618 "Interactivity only dictionaries are not supported for classes with ClassDef\n");
2629 int FinalizeStreamerInfoWriting(cling::Interpreter &interp,
bool writeEmptyRootPCM=
false)
2631 if (!gDriverConfig->fCloseStreamerInfoROOTFile)
2634 if (interp.parseForModule(
"#include \"TStreamerInfo.h\"\n"
2635 "#include \"TFile.h\"\n"
2636 "#include \"TObjArray.h\"\n"
2637 "#include \"TVirtualArray.h\"\n"
2638 "#include \"TStreamerElement.h\"\n"
2639 "#include \"TProtoClass.h\"\n"
2640 "#include \"TBaseClass.h\"\n"
2641 "#include \"TListOfDataMembers.h\"\n"
2642 "#include \"TListOfEnums.h\"\n"
2643 "#include \"TListOfEnumsWithLock.h\"\n"
2644 "#include \"TDataMember.h\"\n"
2645 "#include \"TEnum.h\"\n"
2646 "#include \"TEnumConstant.h\"\n"
2647 "#include \"TDictAttributeMap.h\"\n"
2648 "#include \"TMessageHandler.h\"\n"
2649 "#include \"TArray.h\"\n"
2650 "#include \"TRefArray.h\"\n"
2651 "#include \"root_std_complex.h\"\n")
2652 != cling::Interpreter::kSuccess)
2654 if (!gDriverConfig->fCloseStreamerInfoROOTFile(writeEmptyRootPCM)) {
2662 int GenerateFullDict(std::ostream &dictStream,
2663 cling::Interpreter &interp,
2665 const ROOT::TMetaUtils::RConstructorTypes &ctorTypes,
2668 bool writeEmptyRootPCM)
2670 ROOT::TMetaUtils::TNormalizedCtxt normCtxt(interp.getLookupHelper());
2672 bool needsCollectionProxy =
false;
2690 for (
auto const & ns : scan.fSelectedNamespaces) {
2691 WriteNamespaceInit(ns, interp, dictStream);
2692 auto nsName = ns.GetNamespaceDecl()->getQualifiedNameAsString();
2693 if (nsName.find(
"(anonymous)") == std::string::npos)
2694 EmitStreamerInfo(nsName.c_str());
2697 for (
auto const & selClass : scan.fSelectedClasses) {
2698 if (!selClass.GetRecordDecl()->isCompleteDefinition()) {
2699 ROOT::TMetaUtils::Error(0,
"A dictionary has been requested for %s but there is no declaration!\n", ROOT::TMetaUtils::GetQualifiedName(selClass).c_str());
2702 if (selClass.RequestOnlyTClass()) {
2710 if (clang::CXXRecordDecl *CXXRD =
2711 llvm::dyn_cast<clang::CXXRecordDecl>(const_cast<clang::RecordDecl *>(selClass.GetRecordDecl()))) {
2712 AnnotateDecl(*CXXRD, scan.GetDeclsSelRulesMap() , interp, isGenreflex);
2715 const clang::CXXRecordDecl *CRD = llvm::dyn_cast<clang::CXXRecordDecl>(selClass.GetRecordDecl());
2718 ROOT::TMetaUtils::Info(0,
"Generating code for class %s\n", selClass.GetNormalizedName());
2719 if (TMetaUtils::IsStdClass(*CRD) && 0 != TClassEdit::STLKind(CRD->getName().str() )) {
2722 Internal::RStl::Instance().GenerateTClassFor(selClass.GetNormalizedName(), CRD, interp, normCtxt);
2724 ROOT::TMetaUtils::WriteClassInit(dictStream, selClass, CRD, interp, normCtxt, ctorTypes, needsCollectionProxy);
2725 EmitStreamerInfo(selClass.GetNormalizedName());
2736 for (
auto const & selClass : scan.fSelectedClasses) {
2738 if (!selClass.GetRecordDecl()->isCompleteDefinition() || selClass.RequestOnlyTClass()) {
2742 const clang::CXXRecordDecl *cxxdecl = llvm::dyn_cast<clang::CXXRecordDecl>(selClass.GetRecordDecl());
2743 if (cxxdecl && ROOT::TMetaUtils::ClassInfo__HasMethod(selClass,
"Class_Name", interp)) {
2744 WriteClassFunctions(cxxdecl, dictStream, isSplit);
2753 for (
auto const & selClass : scan.fSelectedClasses) {
2754 if (!selClass.GetRecordDecl()->isCompleteDefinition() || !selClass.RequestOnlyTClass()) {
2758 const clang::CXXRecordDecl *CRD = llvm::dyn_cast<clang::CXXRecordDecl>(selClass.GetRecordDecl());
2760 if (!ROOT::TMetaUtils::IsSTLContainer(selClass)) {
2761 ROOT::TMetaUtils::WriteClassInit(dictStream, selClass, CRD, interp, normCtxt, ctorTypes, needsCollectionProxy);
2762 EmitStreamerInfo(selClass.GetNormalizedName());
2766 for (
auto const & selClass : scan.fSelectedClasses) {
2767 ROOT::TMetaUtils::WriteClassCode(&CallWriteStreamer,
2778 ROOT::Internal::RStl::Instance().WriteClassInit(dictStream, interp, normCtxt, ctorTypes, needsCollectionProxy, EmitStreamerInfo);
2780 if (!gDriverConfig->fBuildingROOTStage1) {
2781 EmitTypedefs(scan.fSelectedTypedefs);
2782 EmitEnums(scan.fSelectedEnums);
2785 int finRetCode = FinalizeStreamerInfoWriting(interp, writeEmptyRootPCM);
2786 if (finRetCode != 0)
return finRetCode;
2794 void CreateDictHeader(std::ostream &dictStream,
const std::string &main_dictname)
2796 dictStream <<
"// Do NOT change. Changes will be lost next time file is generated\n\n"
2797 <<
"#define R__DICTIONARY_FILENAME " << main_dictname << std::endl
2800 <<
"#define R__NO_DEPRECATION" << std::endl
2805 <<
"\n/*******************************************************************/\n"
2806 <<
"#include <stddef.h>\n"
2807 <<
"#include <stdio.h>\n"
2808 <<
"#include <stdlib.h>\n"
2809 <<
"#include <string.h>\n"
2810 <<
"#include <assert.h>\n"
2811 <<
"#define G__DICTIONARY\n"
2812 <<
"#include \"RConfig.h\"\n"
2813 <<
"#include \"TClass.h\"\n"
2814 <<
"#include \"TDictAttributeMap.h\"\n"
2815 <<
"#include \"TInterpreter.h\"\n"
2816 <<
"#include \"TROOT.h\"\n"
2817 <<
"#include \"TBuffer.h\"\n"
2818 <<
"#include \"TMemberInspector.h\"\n"
2819 <<
"#include \"TInterpreter.h\"\n"
2820 <<
"#include \"TVirtualMutex.h\"\n"
2821 <<
"#include \"TError.h\"\n\n"
2822 <<
"#ifndef G__ROOT\n"
2823 <<
"#define G__ROOT\n"
2825 <<
"#include \"RtypesImp.h\"\n"
2826 <<
"#include \"TIsAProxy.h\"\n"
2827 <<
"#include \"TFileMergeInfo.h\"\n"
2828 <<
"#include <algorithm>\n"
2829 <<
"#include \"TCollectionProxyInfo.h\"\n"
2830 <<
"/*******************************************************************/\n\n"
2831 <<
"#include \"TDataMember.h\"\n\n";
2833 dictStream <<
"// The generated code does not explicitly qualifies STL entities\n"
2834 <<
"namespace std {} using namespace std;\n\n";
2840 void GenerateNecessaryIncludes(std::ostream &dictStream,
2841 const std::string &includeForSource,
2842 const std::string &extraIncludes)
2844 dictStream <<
"// Header files passed as explicit arguments\n"
2845 << includeForSource << std::endl
2846 <<
"// Header files passed via #pragma extra_include\n"
2847 << extraIncludes << std::endl;
2853 #if defined(R__IOSSIM) || defined(R__IOS)
2872 class tempFileNamesCatalog {
2875 tempFileNamesCatalog(): m_size(0), m_emptyString(
"") {};
2877 std::string getTmpFileName(
const std::string &filename) {
2878 return filename +
"_tmp_" + std::to_string(getpid());
2884 void addFileName(std::string &nameStr) {
2885 if (nameStr.empty())
return;
2887 std::string tmpNameStr(getTmpFileName(nameStr));
2890 const char *name(nameStr.c_str());
2891 const char *tmpName(tmpNameStr.c_str());
2893 m_names.push_back(nameStr);
2894 m_tempNames.push_back(tmpNameStr);
2895 ROOT::TMetaUtils::Info(0,
"File %s added to the tmp catalog.\n", name);
2898 if (0 == std::rename(name , tmpName)) {
2899 ROOT::TMetaUtils::Info(0,
"File %s existing. Preserved as %s.\n", name, tmpName);
2903 nameStr = tmpNameStr;
2914 for (
unsigned int i = 0; i < m_size; ++i) {
2915 const char *tmpName = m_tempNames[i].c_str();
2917 std::ifstream ifile(tmpName);
2919 ROOT::TMetaUtils::Error(0,
"Cannot find %s!\n", tmpName);
2921 if (0 != std::remove(tmpName)) {
2922 ROOT::TMetaUtils::Error(0,
"Removing %s!\n", tmpName);
2934 for (
unsigned int i = 0; i < m_size; ++i) {
2935 const char *tmpName = m_tempNames[i].c_str();
2936 const char *name = m_names[i].c_str();
2938 std::ifstream ifile(tmpName);
2940 ROOT::TMetaUtils::Error(0,
"Cannot find %s!\n", tmpName);
2945 if (ifile.is_open())
2947 if (0 != std::rename(tmpName , name)) {
2948 if (llvm::sys::fs::copy_file(tmpName , name)) {
2949 llvm::sys::fs::remove(tmpName);
2953 if (0 != std::rename(tmpName , name)) {
2954 ROOT::TMetaUtils::Error(0,
"Renaming %s into %s!\n", tmpName, name);
2964 const std::string &getFileName(
const std::string &tmpFileName) {
2965 size_t i = std::distance(m_tempNames.begin(),
2966 find(m_tempNames.begin(), m_tempNames.end(), tmpFileName));
2967 if (i == m_tempNames.size())
return m_emptyString;
2974 std::cout <<
"Restoring files in temporary file catalog:\n";
2975 for (
unsigned int i = 0; i < m_size; ++i) {
2976 std::cout << m_tempNames[i] <<
" --> " << m_names[i] << std::endl;
2981 unsigned int m_size;
2982 const std::string m_emptyString;
2983 std::vector<std::string> m_names;
2984 std::vector<std::string> m_tempNames;
2990 std::ostream *CreateStreamPtrForSplitDict(
const std::string &dictpathname,
2991 tempFileNamesCatalog &tmpCatalog)
2993 std::string splitDictName(tmpCatalog.getFileName(dictpathname));
2994 const size_t dotPos = splitDictName.find_last_of(
".");
2995 splitDictName.insert(dotPos,
"_classdef");
2996 tmpCatalog.addFileName(splitDictName);
2997 return new std::ofstream(splitDictName.c_str());
3005 static void CheckForMinusW(std::string arg,
3006 std::list<std::string> &diagnosticPragmas)
3008 static const std::string pattern(
"-Wno-");
3010 if (arg.find(pattern) != 0)
3012 if (arg ==
"-Wno-noexcept-type") {
3017 ROOT::TMetaUtils::ReplaceAll(arg, pattern,
"#pragma clang diagnostic ignored \"-W");
3019 diagnosticPragmas.push_back(arg);
3024 std::string GetFwdDeclnArgsToKeepString(
const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt,
3025 cling::Interpreter &interp)
3027 using namespace ROOT::TMetaUtils::AST2SourceTools;
3028 std::string fwdDecl;
3029 std::string initStr(
"{");
3030 auto &fwdDeclnArgsToSkipColl = normCtxt.GetTemplNargsToKeepMap();
3031 for (
auto & strigNargsToKeepPair : fwdDeclnArgsToSkipColl) {
3032 auto &clTemplDecl = *strigNargsToKeepPair.first;
3033 FwdDeclFromTmplDecl(clTemplDecl , interp, fwdDecl);
3036 + std::to_string(strigNargsToKeepPair.second)
3039 if (!fwdDeclnArgsToSkipColl.empty())
3048 clang::QualType GetPointeeTypeIfPossible(
const clang::QualType &qt)
3050 if (qt.isNull())
return qt;
3051 clang::QualType thisQt(qt);
3052 while (thisQt->isPointerType() ||
3053 thisQt->isReferenceType()) {
3054 thisQt = thisQt->getPointeeType();
3063 std::list<std::string> RecordDecl2Headers(
const clang::CXXRecordDecl &rcd,
3064 const cling::Interpreter &interp,
3065 std::set<const clang::CXXRecordDecl *> &visitedDecls)
3067 std::list<std::string> headers;
3070 cling::Interpreter::PushTransactionRAII RAII(&interp);
3073 if (!visitedDecls.insert(rcd.getCanonicalDecl()).second)
3077 if (
const clang::ClassTemplateSpecializationDecl *tsd = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(&rcd)) {
3080 for (
auto & tArg : tsd->getTemplateArgs().asArray()) {
3081 if (clang::TemplateArgument::ArgKind::Type != tArg.getKind())
continue;
3082 auto tArgQualType = GetPointeeTypeIfPossible(tArg.getAsType());
3083 if (tArgQualType.isNull())
continue;
3084 if (
const clang::CXXRecordDecl *tArgCxxRcd = tArgQualType->getAsCXXRecordDecl()) {
3085 headers.splice(headers.end(), RecordDecl2Headers(*tArgCxxRcd, interp, visitedDecls));
3089 if (!ROOT::TMetaUtils::IsStdClass(rcd) && rcd.hasDefinition()) {
3092 for (
auto baseIt = tsd->bases_begin(); baseIt != tsd->bases_end(); baseIt++) {
3093 auto baseQualType = GetPointeeTypeIfPossible(baseIt->getType());
3094 if (baseQualType.isNull())
continue;
3095 if (
const clang::CXXRecordDecl *baseRcdPtr = baseQualType->getAsCXXRecordDecl()) {
3096 headers.splice(headers.end(), RecordDecl2Headers(*baseRcdPtr, interp, visitedDecls));
3101 for (
auto declIt = tsd->decls_begin(); declIt != tsd->decls_end(); ++declIt) {
3102 if (
const clang::FieldDecl *fieldDecl = llvm::dyn_cast<clang::FieldDecl>(*declIt)) {
3103 auto fieldQualType = GetPointeeTypeIfPossible(fieldDecl->getType());
3104 if (fieldQualType.isNull())
continue ;
3105 if (
const clang::CXXRecordDecl *fieldCxxRcd = fieldQualType->getAsCXXRecordDecl()) {
3106 if (fieldCxxRcd->hasDefinition())
3107 headers.splice(headers.end(), RecordDecl2Headers(*fieldCxxRcd, interp, visitedDecls));
3113 for (
auto methodIt = tsd->method_begin(); methodIt != tsd->method_end(); ++methodIt) {
3115 for (
auto & fPar : methodIt->parameters()) {
3116 auto fParQualType = GetPointeeTypeIfPossible(fPar->getOriginalType());
3117 if (fParQualType.isNull())
continue;
3118 if (
const clang::CXXRecordDecl *fParCxxRcd = fParQualType->getAsCXXRecordDecl()) {
3119 if (fParCxxRcd->hasDefinition())
3120 headers.splice(headers.end(), RecordDecl2Headers(*fParCxxRcd, interp, visitedDecls));
3124 auto retQualType = GetPointeeTypeIfPossible(methodIt->getReturnType());
3125 if (retQualType.isNull())
continue;
3126 if (
const clang::CXXRecordDecl *retCxxRcd = retQualType->getAsCXXRecordDecl()) {
3127 if (retCxxRcd->hasDefinition())
3128 headers.splice(headers.end(), RecordDecl2Headers(*retCxxRcd, interp, visitedDecls));
3135 std::string header = ROOT::TMetaUtils::GetFileName(rcd, interp);
3136 headers.emplace_back(header);
3146 bool IsGoodForAutoParseMap(
const clang::RecordDecl& rcd){
3149 if (
auto dclCtxt= rcd.getDeclContext()){
3150 if (! dclCtxt->isStdNamespace()){
3159 auto clAsTmplSpecDecl = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(&rcd);
3160 if (!clAsTmplSpecDecl)
return false;
3165 auto& astCtxt = rcd.getASTContext();
3166 auto& templInstArgs = clAsTmplSpecDecl->getTemplateInstantiationArgs();
3167 for (
auto&& arg : templInstArgs.asArray()){
3169 auto argKind = arg.getKind();
3170 if (argKind != clang::TemplateArgument::Type){
3171 if (argKind == clang::TemplateArgument::Integral)
continue;
3175 auto argQualType = arg.getAsType();
3176 auto isPOD = argQualType.isPODType(astCtxt);
3178 if (isPOD)
continue;
3180 auto argType = argQualType.getTypePtr();
3181 if (
auto recType = llvm::dyn_cast<clang::RecordType>(argType)){
3182 auto isArgGoodForAutoParseMap = IsGoodForAutoParseMap(*recType->getDecl());
3184 if (isArgGoodForAutoParseMap)
continue;
3196 void ExtractHeadersForDecls(
const RScanner::ClassColl_t &annotatedRcds,
3197 const RScanner::TypedefColl_t tDefDecls,
3198 const RScanner::FunctionColl_t funcDecls,
3199 const RScanner::VariableColl_t varDecls,
3200 const RScanner::EnumColl_t enumDecls,
3201 HeadersDeclsMap_t &headersClassesMap,
3202 HeadersDeclsMap_t &headersDeclsMap,
3203 const cling::Interpreter &interp)
3205 std::set<const clang::CXXRecordDecl *> visitedDecls;
3206 std::unordered_set<std::string> buffer;
3207 std::string autoParseKey;
3210 for (
auto & annotatedRcd : annotatedRcds) {
3211 if (
const clang::CXXRecordDecl *cxxRcd =
3212 llvm::dyn_cast_or_null<clang::CXXRecordDecl>(annotatedRcd.GetRecordDecl())) {
3214 visitedDecls.clear();
3215 std::list<std::string> headers(RecordDecl2Headers(*cxxRcd, interp, visitedDecls));
3218 headers.remove_if([&buffer](
const std::string & s) {
3219 return !buffer.insert(s).second;
3221 GetMostExternalEnclosingClassName(*cxxRcd, autoParseKey, interp);
3222 if (autoParseKey.empty()) autoParseKey = annotatedRcd.GetNormalizedName();
3223 if (IsGoodForAutoParseMap(*cxxRcd)){
3224 headersDeclsMap[autoParseKey] = headers;
3225 headersDeclsMap[annotatedRcd.GetRequestedName()] = headers;
3227 ROOT::TMetaUtils::Info(0,
"Class %s is not included in the set of autoparse keys.\n", autoParseKey.c_str());
3232 if (!llvm::isa<clang::ClassTemplateSpecializationDecl>(cxxRcd)){
3233 headersClassesMap[autoParseKey] = headersDeclsMap[autoParseKey];
3234 headersClassesMap[annotatedRcd.GetRequestedName()] = headersDeclsMap[annotatedRcd.GetRequestedName()];
3240 for (
auto & tDef : tDefDecls) {
3241 if (clang::CXXRecordDecl *cxxRcd = tDef->getUnderlyingType()->getAsCXXRecordDecl()) {
3243 visitedDecls.clear();
3244 std::list<std::string> headers(RecordDecl2Headers(*cxxRcd, interp, visitedDecls));
3245 headers.push_back(ROOT::TMetaUtils::GetFileName(*tDef, interp));
3248 headers.remove_if([&buffer](
const std::string & s) {
3249 return !buffer.insert(s).second;
3251 GetMostExternalEnclosingClassNameFromDecl(*tDef, autoParseKey, interp);
3252 if (autoParseKey.empty()) autoParseKey = tDef->getQualifiedNameAsString();
3253 headersDeclsMap[autoParseKey] = headers;
3258 for (
auto & func : funcDecls) {
3259 std::list<std::string> headers = {ROOT::TMetaUtils::GetFileName(*func, interp)};
3260 headersDeclsMap[ROOT::TMetaUtils::GetQualifiedName(*func)] = headers;
3264 for (
auto & var : varDecls) {
3265 std::list<std::string> headers = {ROOT::TMetaUtils::GetFileName(*var, interp)};
3266 headersDeclsMap[ROOT::TMetaUtils::GetQualifiedName(*var)] = headers;
3270 for (
auto & en : enumDecls) {
3271 std::list<std::string> headers = {ROOT::TMetaUtils::GetFileName(*en, interp)};
3272 headersDeclsMap[ROOT::TMetaUtils::GetQualifiedName(*en)] = headers;
3279 static std::string GenerateFwdDeclString(
const RScanner &scan,
3280 const cling::Interpreter &interp)
3282 std::string newFwdDeclString;
3284 using namespace ROOT::TMetaUtils::AST2SourceTools;
3286 std::string fwdDeclString;
3288 std::unordered_set<std::string> fwdDecls;
3309 std::vector<const clang::Decl *> selectedDecls(scan.fSelectedClasses.size());
3312 std::transform (scan.fSelectedClasses.begin(),
3313 scan.fSelectedClasses.end(),
3314 selectedDecls.begin(),
3315 [](
const ROOT::TMetaUtils::AnnotatedRecordDecl& rcd){
return rcd.GetRecordDecl();});
3317 for (
auto* TD: scan.fSelectedTypedefs)
3318 selectedDecls.push_back(TD);
3326 fwdDeclString += Decls2FwdDecls(selectedDecls,IsLinkdefFile,interp);
3342 if (fwdDeclString.empty()) fwdDeclString =
"";
3343 return fwdDeclString;
3349 const std::string GenerateStringFromHeadersForClasses(
const HeadersDeclsMap_t &headersClassesMap,
3350 const std::string &detectedUmbrella,
3351 bool payLoadOnly =
false)
3353 std::string headerName;
3355 if (genreflex::verbose)
3356 std::cout <<
"Class-headers Mapping:\n";
3357 std::string headersClassesMapString =
"";
3358 for (
auto const & classHeaders : headersClassesMap) {
3359 if (genreflex::verbose)
3360 std::cout <<
" o " << classHeaders.first <<
" --> ";
3361 headersClassesMapString +=
"\"";
3362 headersClassesMapString += classHeaders.first +
"\"";
3363 for (
auto const & header : classHeaders.second) {
3364 headerName = (detectedUmbrella == header || payLoadOnly) ?
"payloadCode" :
"\"" + header +
"\"";
3365 headersClassesMapString +=
", " + headerName;
3366 if (genreflex::verbose)
3367 std::cout <<
", " << headerName;
3371 if (genreflex::verbose)
3372 std::cout << std::endl;
3373 headersClassesMapString +=
", \"@\",\n";
3375 headersClassesMapString +=
"nullptr";
3376 return headersClassesMapString;
3381 bool IsImplementationName(
const std::string &filename)
3383 return !ROOT::TMetaUtils::IsHeaderName(filename);
3390 bool IsCorrectClingArgument(
const std::string& argument)
3392 if (ROOT::TMetaUtils::BeginsWith(argument,
"--") && !ROOT::TMetaUtils::BeginsWith(argument,
"--param"))
return false;
3397 bool NeedsSelection(
const char* name)
3399 static const std::vector<std::string> namePrfxes {
3402 auto pos = find_if(namePrfxes.begin(),
3404 [&](
const std::string& str){
return ROOT::TMetaUtils::BeginsWith(name,str);});
3405 return namePrfxes.end() == pos;
3410 bool IsSupportedClassName(
const char* name)
3412 static const std::vector<std::string> uclNamePrfxes {
3416 static const std::set<std::string> unsupportedClassesNormNames{
3419 if ( unsupportedClassesNormNames.count(name) == 1)
return false;
3420 auto pos = find_if(uclNamePrfxes.begin(),
3421 uclNamePrfxes.end(),
3422 [&](
const std::string& str){
return ROOT::TMetaUtils::BeginsWith(name,str);});
3423 return uclNamePrfxes.end() == pos;
3430 int CheckForUnsupportedClasses(
const RScanner::ClassColl_t &annotatedRcds)
3433 for (
auto&& aRcd : annotatedRcds){
3434 auto clName = aRcd.GetNormalizedName();
3435 if (!IsSupportedClassName(clName)){
3436 std::cerr <<
"Error: Class " << clName <<
" has been selected but "
3437 <<
"currently the support for its I/O is not yet available. Note that "
3438 << clName <<
", even if not selected, will be available for "
3439 <<
"interpreted code.\n";
3442 if (!NeedsSelection(clName)){
3443 std::cerr <<
"Error: It is not necessary to explicitly select class "
3444 << clName <<
". I/O is supported for it transparently.\n";
3453 class TRootClingCallbacks :
public cling::InterpreterCallbacks {
3455 std::list<std::string>& fFilesIncludedByLinkdef;
3456 bool isLocked =
false;
3458 TRootClingCallbacks(cling::Interpreter* interp, std::list<std::string>& filesIncludedByLinkdef):
3459 InterpreterCallbacks(interp),
3460 fFilesIncludedByLinkdef(filesIncludedByLinkdef){};
3462 ~TRootClingCallbacks(){};
3464 virtual void InclusionDirective(clang::SourceLocation ,
const clang::Token & ,
3465 llvm::StringRef FileName,
bool IsAngled, clang::CharSourceRange ,
3466 const clang::FileEntry * , llvm::StringRef ,
3467 llvm::StringRef ,
const clang::Module * )
3469 if (isLocked)
return;
3470 if (IsAngled)
return;
3471 auto& PP = m_Interpreter->getCI()->getPreprocessor();
3472 auto curLexer = PP.getCurrentFileLexer();
3473 if (!curLexer)
return;
3474 auto fileEntry = curLexer->getFileEntry();
3475 if (!fileEntry)
return;
3476 auto thisFileName = fileEntry->getName();
3477 auto fileNameAsString = FileName.str();
3478 auto isThisLinkdef = ROOT::TMetaUtils::IsLinkdefFile(thisFileName.data());
3479 if (isThisLinkdef) {
3480 auto isTheIncludedLinkdef = ROOT::TMetaUtils::IsLinkdefFile(fileNameAsString.c_str());
3481 if (isTheIncludedLinkdef) {
3482 fFilesIncludedByLinkdef.clear();
3485 fFilesIncludedByLinkdef.emplace_back(fileNameAsString.c_str());
3498 virtual void EnteredSubmodule(clang::Module* M,
3499 clang::SourceLocation ImportLoc,
3502 using namespace clang;
3503 if (llvm::StringRef(M->Name).endswith(
"ACLiC_dict")) {
3504 Preprocessor& PP = m_Interpreter->getCI()->getPreprocessor();
3505 HeaderSearch& HS = PP.getHeaderSearchInfo();
3507 Module* CoreModule = HS.lookupModule(
"Core",
false);
3508 assert(M &&
"Must have module Core");
3509 PP.makeModuleVisible(CoreModule, ImportLoc);
3524 class CheckModuleBuildClient :
public clang::DiagnosticConsumer {
3525 clang::DiagnosticConsumer *fChild;
3527 clang::ModuleMap &fMap;
3530 CheckModuleBuildClient(clang::DiagnosticConsumer *Child,
bool OwnsChild, clang::ModuleMap &Map)
3531 : fChild(Child), fOwnsChild(OwnsChild), fMap(Map)
3535 ~CheckModuleBuildClient()
3541 virtual void HandleDiagnostic(clang::DiagnosticsEngine::Level DiagLevel,
const clang::Diagnostic &Info)
override
3543 using namespace clang::diag;
3549 std::string moduleName;
3550 const clang::Module *module =
nullptr;
3553 const auto &ID = Info.getID();
3554 if (ID == remark_module_build || ID == remark_module_build_done) {
3555 moduleName = Info.getArgStdStr(0);
3556 module = fMap.findModule(moduleName);
3561 ROOT::TMetaUtils::Warning(0,
3562 "Couldn't find module %s in the available modulemaps. This"
3563 "prevents us from correctly diagnosing wrongly built modules.\n",
3564 moduleName.c_str());
3571 bool isROOTSystemModuleDiag = module && llvm::StringRef(moduleName).startswith(
"ROOT_");
3572 bool isSystemModuleDiag = module && module->IsSystem;
3573 if (!isROOTSystemModuleDiag && !isSystemModuleDiag)
3574 fChild->HandleDiagnostic(DiagLevel, Info);
3576 if (ID == remark_module_build && !isROOTSystemModuleDiag && !isSystemModuleDiag) {
3577 ROOT::TMetaUtils::Error(0,
3578 "Had to build non-system module %s implicitly. You first need to\n"
3579 "generate the dictionary for %s or mark the C++ module as a system\n"
3580 "module if you provided your own system modulemap file:\n"
3581 "%s [system] { ... }\n",
3582 moduleName.c_str(), moduleName.c_str(), moduleName.c_str());
3587 virtual void clear()
override
3590 DiagnosticConsumer::clear();
3593 virtual void BeginSourceFile(
const clang::LangOptions &LangOpts,
const clang::Preprocessor *PP)
override
3595 fChild->BeginSourceFile(LangOpts, PP);
3596 DiagnosticConsumer::BeginSourceFile(LangOpts, PP);
3599 virtual void EndSourceFile()
override
3601 fChild->EndSourceFile();
3602 DiagnosticConsumer::EndSourceFile();
3605 virtual void finish()
override
3608 DiagnosticConsumer::finish();
3611 virtual bool IncludeInDiagnosticCounts()
const override {
return fChild->IncludeInDiagnosticCounts(); }
3614 static void MaybeSuppressWin32CrashDialogs() {
3615 #if defined(_WIN32) && defined(_MSC_VER)
3619 const char *EnablePopups = getenv(
"Cling_GuiOnAssert");
3620 if (EnablePopups ==
nullptr || EnablePopups[0] ==
'0') {
3621 ::_set_error_mode(_OUT_TO_STDERR);
3622 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
3623 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
3624 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
3625 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
3626 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
3627 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
3632 static llvm::cl::OptionCategory gRootclingOptions(
"rootcling common options");
3633 static llvm::cl::opt<bool> gOptForce(
"f", llvm::cl::desc(
"Overwrite <file>s."),
3634 llvm::cl::cat(gRootclingOptions));
3635 static llvm::cl::opt<bool> gOptRootBuild(
"rootbuild", llvm::cl::desc(
"If we are building ROOT."),
3637 llvm::cl::cat(gRootclingOptions));
3639 v = ROOT::TMetaUtils::kError,
3640 v0 = ROOT::TMetaUtils::kFatal,
3642 v2 = ROOT::TMetaUtils::kWarning,
3643 v3 = ROOT::TMetaUtils::kNote,
3644 v4 = ROOT::TMetaUtils::kInfo
3646 static llvm::cl::opt<VerboseLevel>
3647 gOptVerboseLevel(llvm::cl::desc(
"Choose verbosity level:"),
3648 llvm::cl::values(clEnumVal(v,
"Show errors."),
3649 clEnumVal(v0,
"Show only fatal errors."),
3650 clEnumVal(v1,
"Show errors (the same as -v)."),
3651 clEnumVal(v2,
"Show warnings (default)."),
3652 clEnumVal(v3,
"Show notes."),
3653 clEnumVal(v4,
"Show information.")),
3655 llvm::cl::cat(gRootclingOptions));
3657 static llvm::cl::opt<bool>
3658 gOptCint(
"cint", llvm::cl::desc(
"Deprecated, legacy flag which is ignored."),
3660 llvm::cl::cat(gRootclingOptions));
3661 static llvm::cl::opt<bool>
3662 gOptReflex(
"reflex", llvm::cl::desc(
"Deprecated, legacy flag which is ignored."),
3664 llvm::cl::cat(gRootclingOptions));
3665 static llvm::cl::opt<bool>
3666 gOptGccXml(
"gccxml", llvm::cl::desc(
"Deprecated, legacy flag which is ignored."),
3668 llvm::cl::cat(gRootclingOptions));
3669 static llvm::cl::opt<std::string>
3670 gOptLibListPrefix(
"lib-list-prefix",
3671 llvm::cl::desc(
"An ACLiC feature which exports the list of dependent libraries."),
3673 llvm::cl::cat(gRootclingOptions));
3674 static llvm::cl::opt<bool>
3675 gOptGeneratePCH(
"generate-pch",
3676 llvm::cl::desc(
"Generates a pch file from a predefined set of headers. See makepch.py."),
3678 llvm::cl::cat(gRootclingOptions));
3680 static llvm::cl::opt<bool>
3681 gOptIgnoreExistingDict(
"r",
3682 llvm::cl::desc(
"Deprecated, legacy flag which is ignored."),
3684 llvm::cl::cat(gRootclingOptions));
3685 static llvm::cl::opt<std::string>
3686 gOptDictionaryFileName(llvm::cl::Positional, llvm::cl::Required,
3687 llvm::cl::desc(
"<output dictionary file>"),
3688 llvm::cl::cat(gRootclingOptions));
3689 static llvm::cl::opt<bool>
3690 gOptC(
"c", llvm::cl::desc(
"Deprecated, legacy flag which is ignored."),
3691 llvm::cl::cat(gRootclingOptions));
3692 static llvm::cl::opt<bool>
3693 gOptP(
"p", llvm::cl::desc(
"Deprecated, legacy flag which is ignored."),
3694 llvm::cl::cat(gRootclingOptions));
3695 static llvm::cl::list<std::string>
3696 gOptRootmapLibNames(
"rml", llvm::cl::ZeroOrMore,
3697 llvm::cl::desc(
"Generate rootmap file."),
3698 llvm::cl::cat(gRootclingOptions));
3699 static llvm::cl::opt<std::string>
3700 gOptRootMapFileName(
"rmf",
3701 llvm::cl::desc(
"Generate a rootmap file with the specified name."),
3702 llvm::cl::cat(gRootclingOptions));
3703 static llvm::cl::opt<bool>
3704 gOptCxxModule(
"cxxmodule",
3705 llvm::cl::desc(
"Generate a C++ module."),
3706 llvm::cl::cat(gRootclingOptions));
3707 static llvm::cl::list<std::string>
3708 gOptModuleMapFiles(
"moduleMapFile",
3709 llvm::cl::desc(
"Specify a C++ modulemap file."),
3710 llvm::cl::cat(gRootclingOptions));
3712 static llvm::cl::opt<bool>
3713 gOptUmbrellaInput(
"umbrellaHeader",
3714 llvm::cl::desc(
"A single header including all headers instead of specifying them on the command line."),
3715 llvm::cl::cat(gRootclingOptions));
3716 static llvm::cl::opt<bool>
3717 gOptMultiDict(
"multiDict",
3718 llvm::cl::desc(
"If this library has multiple separate LinkDef files."),
3719 llvm::cl::cat(gRootclingOptions));
3720 static llvm::cl::opt<bool>
3721 gOptInterpreterOnly(
"interpreteronly",
3722 llvm::cl::desc(
"Generate minimal dictionary for interactivity (without IO information)."),
3723 llvm::cl::cat(gRootclingOptions));
3724 static llvm::cl::opt<bool>
3726 llvm::cl::desc(
"Split the dictionary into two parts: one containing the IO (ClassDef)\
3727 information and another the interactivity support."),
3728 llvm::cl::cat(gRootclingOptions));
3729 static llvm::cl::opt<bool>
3730 gOptNoDictSelection(
"noDictSelection",
3732 llvm::cl::desc(
"Do not run the selection rules. Useful when in -onepcm mode."),
3733 llvm::cl::cat(gRootclingOptions));
3734 static llvm::cl::opt<std::string>
3735 gOptSharedLibFileName(
"s",
3736 llvm::cl::desc(
"The path to the library of the built dictionary."),
3737 llvm::cl::cat(gRootclingOptions));
3738 static llvm::cl::list<std::string>
3739 gOptModuleDependencies(
"m",
3740 llvm::cl::desc(
"The list of dependent modules of the dictionary."),
3741 llvm::cl::cat(gRootclingOptions));
3742 static llvm::cl::list<std::string>
3743 gOptExcludePaths(
"excludePath", llvm::cl::ZeroOrMore,
3744 llvm::cl::desc(
"Do not store the <path> in the dictionary."),
3745 llvm::cl::cat(gRootclingOptions));
3748 static llvm::cl::opt<bool>
3749 gOptInlineInput(
"inlineInputHeader",
3750 llvm::cl::desc(
"Does not generate #include <header> but expands the header content."),
3751 llvm::cl::cat(gRootclingOptions));
3758 static llvm::cl::opt<bool>
3759 gOptWriteEmptyRootPCM(
"writeEmptyRootPCM",
3761 llvm::cl::desc(
"Does not include the header files as it assumes they exist in the pch."),
3762 llvm::cl::cat(gRootclingOptions));
3763 static llvm::cl::opt<bool>
3764 gOptCheckSelectionSyntax(
"selSyntaxOnly",
3765 llvm::cl::desc(
"Check the selection syntax only."),
3766 llvm::cl::cat(gRootclingOptions));
3767 static llvm::cl::opt<bool>
3768 gOptFailOnWarnings(
"failOnWarnings",
3769 llvm::cl::desc(
"Fail if there are warnings."),
3770 llvm::cl::cat(gRootclingOptions));
3771 static llvm::cl::opt<bool>
3772 gOptNoIncludePaths(
"noIncludePaths",
3773 llvm::cl::desc(
"Do not store include paths but rely on the env variable ROOT_INCLUDE_PATH."),
3774 llvm::cl::cat(gRootclingOptions));
3775 static llvm::cl::opt<std::string>
3776 gOptISysRoot(
"isysroot", llvm::cl::Prefix, llvm::cl::Hidden,
3777 llvm::cl::desc(
"Specify an isysroot."),
3778 llvm::cl::cat(gRootclingOptions),
3779 llvm::cl::init(
"-"));
3780 static llvm::cl::list<std::string>
3781 gOptIncludePaths(
"I", llvm::cl::Prefix, llvm::cl::ZeroOrMore,
3782 llvm::cl::desc(
"Specify an include path."),
3783 llvm::cl::cat(gRootclingOptions));
3784 static llvm::cl::list<std::string>
3785 gOptPPDefines(
"D", llvm::cl::Prefix, llvm::cl::ZeroOrMore,
3786 llvm::cl::desc(
"Specify defined macros."),
3787 llvm::cl::cat(gRootclingOptions));
3788 static llvm::cl::list<std::string>
3789 gOptPPUndefines(
"U", llvm::cl::Prefix, llvm::cl::ZeroOrMore,
3790 llvm::cl::desc(
"Specify undefined macros."),
3791 llvm::cl::cat(gRootclingOptions));
3792 static llvm::cl::list<std::string>
3793 gOptWDiags(
"W", llvm::cl::Prefix, llvm::cl::ZeroOrMore,
3794 llvm::cl::desc(
"Specify compiler diagnostics options."),
3795 llvm::cl::cat(gRootclingOptions));
3796 static llvm::cl::list<std::string>
3797 gOptDictionaryHeaderFiles(llvm::cl::Positional, llvm::cl::OneOrMore,
3798 llvm::cl::desc(
"<list of dictionary header files> <LinkDef file>"),
3799 llvm::cl::cat(gRootclingOptions));
3800 static llvm::cl::list<std::string>
3801 gOptSink(llvm::cl::ZeroOrMore, llvm::cl::Sink,
3802 llvm::cl::desc(
"Consumes all unrecognized options."),
3803 llvm::cl::cat(gRootclingOptions));
3805 static llvm::cl::SubCommand
3806 gBareClingSubcommand(
"bare-cling",
"Call directly cling and exit.");
3808 static llvm::cl::list<std::string>
3809 gOptBareClingSink(llvm::cl::OneOrMore, llvm::cl::Sink,
3810 llvm::cl::desc(
"Consumes options and sends them to cling."),
3811 llvm::cl::cat(gRootclingOptions), llvm::cl::sub(gBareClingSubcommand));
3819 static bool ModuleContainsHeaders(TModuleGenerator &modGen, clang::Module *module,
3820 std::vector<std::string> &missingHeaders)
3823 std::vector<clang::Module::Header> moduleHeaders;
3824 ROOT::TMetaUtils::foreachHeaderInModule(*module,
3825 [&moduleHeaders](
const clang::Module::Header &h) { moduleHeaders.push_back(h); });
3827 bool foundAllHeaders =
true;
3832 for (
const std::string &header : modGen.GetHeaders()) {
3833 bool headerFound =
false;
3834 for (
const clang::Module::Header &moduleHeader : moduleHeaders) {
3835 if (header == moduleHeader.NameAsWritten) {
3841 missingHeaders.push_back(header);
3842 foundAllHeaders =
false;
3845 return foundAllHeaders;
3850 static bool CheckModuleValid(TModuleGenerator &modGen,
const std::string &resourceDir, cling::Interpreter &interpreter,
3851 StringRef LinkdefPath,
const std::string &moduleName)
3855 if (moduleName ==
"Krb5Auth" || moduleName ==
"GCocoa" || moduleName ==
"GQuartz")
3859 clang::CompilerInstance *CI = interpreter.getCI();
3860 clang::HeaderSearch &headerSearch = CI->getPreprocessor().getHeaderSearchInfo();
3861 headerSearch.loadTopLevelSystemModules();
3864 clang::Module *module = headerSearch.lookupModule(StringRef(moduleName));
3868 ROOT::TMetaUtils::Error(
"CheckModuleValid",
"Couldn't find module with name '%s' in modulemap!\n",
3869 moduleName.c_str());
3876 std::vector<std::string> missingHeaders;
3877 if (!ModuleContainsHeaders(modGen, module, missingHeaders)) {
3879 std::stringstream msgStream;
3880 msgStream <<
"warning: Couldn't find in "
3881 << module->PresumedModuleMapFile
3882 <<
" the following specified headers in "
3883 <<
"the module " << module->Name <<
":\n";
3884 for (
auto &H : missingHeaders) {
3885 msgStream <<
" " << H <<
"\n";
3887 std::string warningMessage = msgStream.str();
3889 bool maybeUmbrella = modGen.GetHeaders().size() == 1;
3899 if (!gOptUmbrellaInput && maybeUmbrella) {
3900 ROOT::TMetaUtils::Info(
"CheckModuleValid, %s. You can silence this message by adding %s to the invocation.",
3901 warningMessage.c_str(),
3902 gOptUmbrellaInput.ArgStr.data());
3906 ROOT::TMetaUtils::Warning(
"CheckModuleValid", warningMessage.c_str());
3908 if (!IncludeHeaders(missingHeaders, interpreter)) {
3909 ROOT::TMetaUtils::Error(
"CheckModuleValid",
"Couldn't include missing module headers for module '%s'!\n",
3910 module->Name.c_str());
3920 int RootClingMain(
int argc,
3922 bool isGenreflex =
false)
3925 auto &opts = llvm::cl::getRegisteredOptions();
3926 auto &optHelp = *opts[
"help"];
3927 llvm::cl::alias optHelpAlias1(
"h",
3928 llvm::cl::desc(
"Alias for -help"),
3929 llvm::cl::aliasopt(optHelp));
3930 llvm::cl::alias optHelpAlias2(
"?",
3931 llvm::cl::desc(
"Alias for -help"),
3932 llvm::cl::aliasopt(optHelp));
3938 const char *executableFileName = argv[0];
3940 llvm::sys::PrintStackTraceOnErrorSignal(executableFileName);
3941 llvm::PrettyStackTraceProgram X(argc, argv);
3942 MaybeSuppressWin32CrashDialogs();
3944 #if defined(R__WIN32) && !defined(R__WINGCC)
3949 for (
int iic = 1 ; iic < argc; ++iic) {
3950 std::string iiarg(argv[iic]);
3951 if (FromCygToNativePath(iiarg)) {
3952 size_t len = iiarg.length();
3954 char *argviic =
new char[len + 1];
3955 strlcpy(argviic, iiarg.c_str(), len + 1);
3956 argv[iic] = argviic;
3962 llvm::cl::HideUnrelatedOptions(gRootclingOptions);
3964 llvm::cl::ParseCommandLineOptions(argc, argv,
"rootcling");
3966 std::string llvmResourceDir = std::string(gDriverConfig->fTROOT__GetEtcDir()) +
"/cling";
3967 if (gBareClingSubcommand) {
3968 std::vector<const char *> clingArgsC;
3969 clingArgsC.push_back(executableFileName);
3971 clingArgsC.push_back(
"-I");
3972 clingArgsC.push_back(gDriverConfig->fTROOT__GetEtcDir());
3977 for (
const std::string& Opt : gOptBareClingSink)
3978 clingArgsC.push_back(Opt.c_str());
3980 auto interp = llvm::make_unique<cling::Interpreter>(clingArgsC.size(),
3982 llvmResourceDir.c_str());
3985 return interp->getDiagnostics().hasFatalErrorOccurred();
3988 std::string dictname;
3989 std::string dictpathname;
3991 if (!gDriverConfig->fBuildingROOTStage1) {
3992 if (gOptRootBuild) {
3994 gBuildingROOT =
true;
3998 if (!gOptModuleMapFiles.empty() && !gOptCxxModule) {
3999 ROOT::TMetaUtils::Error(
"",
"Option %s can be used only when option %s is specified.\n",
4000 gOptModuleMapFiles.ArgStr.str().c_str(),
4001 gOptCxxModule.ArgStr.str().c_str());
4003 llvm::cl::PrintHelpMessage();
4008 ROOT::TMetaUtils::GetErrorIgnoreLevel() = gOptVerboseLevel;
4009 if (gOptVerboseLevel == v4)
4010 genreflex::verbose =
true;
4015 #if ROOT_VERSION_CODE < ROOT_VERSION(6,21,00)
4017 fprintf(stderr,
"warning: Please remove the deprecated flag -cint.\n");
4019 fprintf(stderr,
"warning: Please remove the deprecated flag -gccxml.\n");
4021 fprintf(stderr,
"warning: Please remove the deprecated flag -c.\n");
4023 fprintf(stderr,
"warning: Please remove the deprecated flag -p.\n");
4024 if (gOptIgnoreExistingDict)
4025 fprintf(stderr,
"warning: Please remove the deprecated flag -r.\n");
4027 for (
auto I = gOptDictionaryHeaderFiles.begin(), E = gOptDictionaryHeaderFiles.end(); I != E; ++I) {
4028 if ((*I)[0] ==
'+') {
4030 fprintf(stderr,
"warning: Please remove the deprecated flag %s\n", I->c_str());
4032 gOptDictionaryHeaderFiles.erase(I);
4036 for (
const std::string& Opt : gOptSink)
4037 fprintf(stderr,
"warning: Please remove the deprecated flag %s\n", Opt.c_str());
4039 # error "Remove this deprecated code"
4042 if (!gOptLibListPrefix.empty()) {
4043 string filein = gOptLibListPrefix +
".in";
4045 if ((fp = fopen(filein.c_str(),
"r")) == 0) {
4046 ROOT::TMetaUtils::Error(0,
"%s: The input list file %s does not exist\n", executableFileName, filein.c_str());
4052 if (IsImplementationName(gOptDictionaryFileName)) {
4054 if (!gOptIgnoreExistingDict && (fp = fopen(gOptDictionaryFileName.c_str(),
"r")) != 0) {
4057 ROOT::TMetaUtils::Error(0,
"%s: output file %s already exists\n", executableFileName, gOptDictionaryFileName.c_str());
4063 if (gOptDictionaryFileName.size() > (PATH_MAX - 1)) {
4064 ROOT::TMetaUtils::Error(0,
"rootcling: dictionary name too long (more than %d characters): %s\n",
4065 (PATH_MAX - 1), gOptDictionaryFileName.c_str());
4069 dictpathname = gOptDictionaryFileName;
4070 dictname = llvm::sys::path::filename(gOptDictionaryFileName);
4073 if (gOptForce && dictname.empty()) {
4074 ROOT::TMetaUtils::Error(0,
"Inconsistent set of arguments detected: overwrite of dictionary file forced but no filename specified.\n");
4075 fprintf(stderr,
"%s\n", shortHelp);
4079 std::vector<std::string> clingArgs;
4080 clingArgs.push_back(executableFileName);
4081 clingArgs.push_back(
"-iquote.");
4083 bool dictSelection = !gOptNoDictSelection;
4087 std::list<std::string> diagnosticPragmas = {
"#pragma clang diagnostic ignored \"-Wdeprecated-declarations\""};
4089 if (gOptFailOnWarnings) {
4090 using namespace ROOT::TMetaUtils;
4093 if (GetErrorIgnoreLevel() > kWarning)
4094 GetErrorIgnoreLevel() = kWarning;
4095 GetWarningsAreErrors() =
true;
4098 if (gOptISysRoot !=
"-") {
4099 if (gOptISysRoot.empty()) {
4100 ROOT::TMetaUtils::Error(
"",
"isysroot specified without a value.\n");
4103 clingArgs.push_back(gOptISysRoot.ArgStr);
4104 clingArgs.push_back(gOptISysRoot.ValueStr);
4108 if (gOptMultiDict && gOptSharedLibFileName.empty()) {
4109 ROOT::TMetaUtils::Error(
"",
"Multidict requested but no target library. Please specify one with the -s argument.\n");
4113 for (
const std::string &PPDefine : gOptPPDefines)
4114 clingArgs.push_back(std::string(
"-D") + PPDefine);
4116 for (
const std::string &PPUndefine : gOptPPUndefines)
4117 clingArgs.push_back(std::string(
"-U") + PPUndefine);
4119 for (
const std::string &IncludePath : gOptIncludePaths)
4120 clingArgs.push_back(std::string(
"-I") + llvm::sys::path::convert_to_slash(IncludePath));
4122 for (
const std::string &WDiag : gOptWDiags) {
4123 const std::string FullWDiag = std::string(
"-W") + WDiag;
4125 CheckForMinusW(FullWDiag, diagnosticPragmas);
4127 clingArgs.push_back(FullWDiag);
4130 std::string includeDir = llvm::sys::path::convert_to_slash(gDriverConfig->fTROOT__GetIncludeDir());
4131 clingArgs.push_back(std::string(
"-I") + includeDir);
4133 std::vector<std::string> pcmArgs;
4134 for (
size_t parg = 0, n = clingArgs.size(); parg < n; ++parg) {
4135 auto thisArg = clingArgs[parg];
4136 auto isInclude = ROOT::TMetaUtils::BeginsWith(thisArg,
"-I");
4137 if (thisArg ==
"-c" ||
4138 (gOptNoIncludePaths && isInclude))
continue;
4141 unsigned int offset = 2;
4142 char c = thisArg[offset];
4143 while (c ==
' ') c = thisArg[++offset];
4144 auto excludePathsEnd = gOptExcludePaths.end();
4145 auto excludePathPos = std::find_if(gOptExcludePaths.begin(),
4147 [&](
const std::string& path){
4148 return ROOT::TMetaUtils::BeginsWith(&thisArg[offset], path);});
4149 if (excludePathsEnd != excludePathPos)
continue;
4151 pcmArgs.push_back(thisArg);
4155 clingArgs.push_back(std::string(
"-I") + llvm::sys::path::convert_to_slash(gDriverConfig->fTROOT__GetEtcDir()));
4157 if (!gOptGeneratePCH) {
4158 clingArgs.push_back(
"-D__ROOTCLING__");
4161 clingArgs.push_back(
"-DSYSTEM_TYPE_macosx");
4162 #elif defined(R__WIN32)
4163 clingArgs.push_back(
"-DSYSTEM_TYPE_winnt");
4166 clingArgs.push_back(
"-D_XKEYCHECK_H");
4168 clingArgs.push_back(
"-DNOMINMAX");
4169 #else // assume UNIX
4170 clingArgs.push_back(
"-DSYSTEM_TYPE_unix");
4173 clingArgs.push_back(
"-fsyntax-only");
4175 clingArgs.push_back(
"-fPIC");
4177 clingArgs.push_back(
"-Xclang");
4178 clingArgs.push_back(
"-fmodules-embed-all-files");
4179 clingArgs.push_back(
"-Xclang");
4180 clingArgs.push_back(
"-main-file-name");
4181 clingArgs.push_back(
"-Xclang");
4182 clingArgs.push_back((dictname +
".h").c_str());
4184 ROOT::TMetaUtils::SetPathsForRelocatability(clingArgs);
4189 bool isPCH = (dictpathname ==
"allDict.cxx");
4190 std::string outputFile;
4192 StringRef moduleName;
4197 auto clingArgsInterpreter = clingArgs;
4199 if (gOptSharedLibFileName.empty()) {
4200 gOptSharedLibFileName = dictpathname;
4203 if (!isPCH && gOptCxxModule) {
4206 clingArgsInterpreter.push_back(
"-fmodules");
4207 clingArgsInterpreter.push_back(
"-fno-implicit-module-maps");
4209 for (
const std::string &modulemap : gOptModuleMapFiles)
4210 clingArgsInterpreter.push_back(
"-fmodule-map-file=" + modulemap);
4212 clingArgsInterpreter.push_back(
"-fmodule-map-file=" +
4213 std::string(gDriverConfig->fTROOT__GetIncludeDir()) +
4214 "/module.modulemap");
4215 std::string ModuleMapCWD = ROOT::FoundationUtils::GetCurrentDir() +
"/module.modulemap";
4216 if (llvm::sys::fs::exists(ModuleMapCWD))
4217 clingArgsInterpreter.push_back(
"-fmodule-map-file=" + ModuleMapCWD);
4220 outputFile = llvm::sys::path::stem(gOptSharedLibFileName).str();
4222 moduleName = llvm::sys::path::filename(outputFile);
4223 moduleName.consume_front(
"lib");
4224 moduleName.consume_back(
"_rdict.pcm");
4226 clingArgsInterpreter.push_back(
"-fmodule-name");
4227 clingArgsInterpreter.push_back(moduleName.str());
4229 std::string moduleCachePath = llvm::sys::path::parent_path(gOptSharedLibFileName).str();
4237 if (moduleName ==
"Core") {
4238 assert(gDriverConfig->fBuildingROOTStage1);
4239 remove((moduleCachePath + llvm::sys::path::get_separator() +
"_Builtin_intrinsics.pcm").str().c_str());
4240 remove((moduleCachePath + llvm::sys::path::get_separator() +
"_Builtin_stddef_max_align_t.pcm").str().c_str());
4241 remove((moduleCachePath + llvm::sys::path::get_separator() +
"Cling_Runtime.pcm").str().c_str());
4242 remove((moduleCachePath + llvm::sys::path::get_separator() +
"Cling_Runtime_Extra.pcm").str().c_str());
4244 remove((moduleCachePath + llvm::sys::path::get_separator() +
"Darwin.pcm").str().c_str());
4246 remove((moduleCachePath + llvm::sys::path::get_separator() +
"libc.pcm").str().c_str());
4248 remove((moduleCachePath + llvm::sys::path::get_separator() +
"std.pcm").str().c_str());
4249 remove((moduleCachePath + llvm::sys::path::get_separator() +
"cuda.pcm").str().c_str());
4250 remove((moduleCachePath + llvm::sys::path::get_separator() +
"ROOT_Config.pcm").str().c_str());
4251 remove((moduleCachePath + llvm::sys::path::get_separator() +
"ROOT_Rtypes.pcm").str().c_str());
4252 remove((moduleCachePath + llvm::sys::path::get_separator() +
"ROOT_Foundation_C.pcm").str().c_str());
4253 remove((moduleCachePath + llvm::sys::path::get_separator() +
"ROOT_Foundation_Stage1_NoRTTI.pcm").str().c_str());
4258 clingArgsInterpreter.push_back(
"-fmodules-cache-path=" + moduleCachePath);
4261 if (gOptVerboseLevel == v4)
4262 clingArgsInterpreter.push_back(
"-v");
4265 std::vector<const char *> clingArgsC;
4266 for (
auto const &clingArg : clingArgsInterpreter) {
4267 if (!IsCorrectClingArgument(clingArg)){
4268 std::cerr <<
"Argument \""<< clingArg <<
"\" is not a supported cling argument. "
4269 <<
"This could be mistyped rootcling argument. Please check the commandline.\n";
4272 clingArgsC.push_back(clingArg.c_str());
4276 std::unique_ptr<cling::Interpreter> owningInterpPtr;
4277 cling::Interpreter* interpPtr =
nullptr;
4279 std::list<std::string> filesIncludedByLinkdef;
4280 if (!gDriverConfig->fBuildingROOTStage1) {
4282 clingArgsC.push_back(
"-resource-dir");
4283 clingArgsC.push_back(llvmResourceDir.c_str());
4284 clingArgsC.push_back(0);
4285 const char ** &extraArgs = *gDriverConfig->fTROOT__GetExtraInterpreterArgs();
4286 extraArgs = &clingArgsC[1];
4287 interpPtr = gDriverConfig->fTCling__GetInterpreter();
4288 if (!isGenreflex && !gOptGeneratePCH) {
4289 std::unique_ptr<TRootClingCallbacks> callBacks (
new TRootClingCallbacks(interpPtr, filesIncludedByLinkdef));
4290 interpPtr->setCallbacks(std::move(callBacks));
4295 clingArgsC.push_back(
"-ffast-math");
4298 owningInterpPtr.reset(
new cling::Interpreter(clingArgsC.size(), &clingArgsC[0],
4299 llvmResourceDir.c_str()));
4300 interpPtr = owningInterpPtr.get();
4307 interpPtr->loadModule(
"_Builtin_intrinsics",
true);
4309 cling::Interpreter &interp = *interpPtr;
4310 clang::CompilerInstance *CI = interp.getCI();
4312 CI->getFrontendOpts().ModulesEmbedAllFiles =
true;
4313 CI->getSourceManager().setAllFilesAreTransient(
true);
4315 clang::Preprocessor &PP = CI->getPreprocessor();
4316 clang::HeaderSearch &headerSearch = PP.getHeaderSearchInfo();
4317 clang::ModuleMap &moduleMap = headerSearch.getModuleMap();
4318 auto &diags = interp.getDiagnostics();
4325 diags.setSeverity(clang::diag::remark_module_build, clang::diag::Severity::Remark, clang::SourceLocation());
4329 auto recordingClient =
new CheckModuleBuildClient(diags.getClient(), diags.ownsClient(), moduleMap);
4330 diags.setClient(recordingClient,
true);
4332 if (ROOT::TMetaUtils::GetErrorIgnoreLevel() == ROOT::TMetaUtils::kInfo) {
4333 ROOT::TMetaUtils::Info(0,
"\n");
4334 ROOT::TMetaUtils::Info(0,
"==== INTERPRETER CONFIGURATION ====\n");
4335 ROOT::TMetaUtils::Info(0,
"== Include paths\n");
4336 interp.DumpIncludePath();
4340 ROOT::TMetaUtils::Info(0,
"== Included files\n");
4341 interp.printIncludedFiles(llvm::outs());
4342 llvm::outs() <<
"\n\n";
4343 llvm::outs().flush();
4345 ROOT::TMetaUtils::Info(0,
"== Language Options\n");
4346 const clang::LangOptions& LangOpts
4347 = interp.getCI()->getASTContext().getLangOpts();
4348 #define LANGOPT(Name, Bits, Default, Description) \
4349 ROOT::TMetaUtils::Info(0, "%s = %d // %s\n", #Name, (int)LangOpts.Name, Description);
4350 #define ENUM_LANGOPT(Name, Type, Bits, Default, Description)
4351 #include "clang/Basic/LangOptions.def"
4352 ROOT::TMetaUtils::Info(0,
"==== END interpreter configuration ====\n\n");
4355 interp.getOptions().ErrorOut =
true;
4356 interp.enableRawInput(
true);
4358 if (interp.declare(
"namespace std {} using namespace std;") != cling::Interpreter::kSuccess) {
4360 ROOT::TMetaUtils::Error(0,
"Error loading the default header files.\n");
4365 if (interp.declare(
"namespace std {} using namespace std;") != cling::Interpreter::kSuccess
4367 || interp.declare(
"#include <assert.h>\n"
4368 "#include <stdlib.h>\n"
4369 "#include <stddef.h>\n"
4370 "#include <string.h>\n"
4371 ) != cling::Interpreter::kSuccess
4372 || interp.declare(
"#include \"Rtypes.h\"\n"
4373 "#include \"TClingRuntime.h\"\n"
4374 "#include \"TObject.h\""
4375 ) != cling::Interpreter::kSuccess
4378 ROOT::TMetaUtils::Error(0,
"Error loading the default header files.\n");
4384 interp.declare(
"#include <string>");
4387 ROOT::TMetaUtils::TNormalizedCtxt normCtxt(interp.getLookupHelper());
4388 ROOT::TMetaUtils::TClingLookupHelper helper(interp, normCtxt, 0, 0,
nullptr);
4389 TClassEdit::Init(&helper);
4392 clingArgs.push_back(
"-D__CINT__");
4393 clingArgs.push_back(
"-D__MAKECINT__");
4395 AddPlatformDefines(clingArgs);
4397 std::string currentDirectory = ROOT::FoundationUtils::GetCurrentDir();
4399 std::string interpPragmaSource;
4400 std::string includeForSource;
4401 std::string interpreterDeclarations;
4402 std::string linkdef;
4404 for (
size_t i = 0, e = gOptDictionaryHeaderFiles.size(); i < e; ++i) {
4405 const std::string& optHeaderFileName = gOptDictionaryHeaderFiles[i];
4406 bool isSelectionFile = IsSelectionFile(optHeaderFileName.c_str());
4408 if (isSelectionFile) {
4410 linkdef = optHeaderFileName;
4412 ROOT::TMetaUtils::Error(0,
"%s: %s must be last file on command line\n",
4413 executableFileName, optHeaderFileName.c_str());
4419 std::string fullheader(optHeaderFileName);
4422 if (fullheader[fullheader.length() - 1] ==
'+') {
4423 fullheader.erase(fullheader.length() - 1);
4426 isSelectionFile ? fullheader : ROOT::FoundationUtils::MakePathRelative(fullheader, currentDirectory, gBuildingROOT));
4428 interpPragmaSource += std::string(
"#include \"") + header +
"\"\n";
4429 if (!isSelectionFile) {
4437 includeForSource += std::string(
"#include \"") + fullheader +
"\"\n";
4438 pcmArgs.push_back(header);
4439 }
else if (!IsSelectionXml(optHeaderFileName.c_str())) {
4440 interpreterDeclarations += std::string(
"#include \"") + header +
"\"\n";
4444 if (gOptUmbrellaInput) {
4445 bool hasSelectionFile = !linkdef.empty();
4446 unsigned expectedHeaderFilesSize = 1 + hasSelectionFile;
4447 if (gOptDictionaryHeaderFiles.size() > expectedHeaderFilesSize)
4448 ROOT::TMetaUtils::Error(0,
"Option %s used but more than one header file specified.\n",
4449 gOptUmbrellaInput.ArgStr.data());
4453 if (gDriverConfig->fAddAncestorPCMROOTFile) {
4454 for (
const auto & baseModule : gOptModuleDependencies)
4455 gDriverConfig->fAddAncestorPCMROOTFile(baseModule.c_str());
4460 if (gOptMultiDict) {
4462 std::string newName = llvm::sys::path::parent_path(gOptSharedLibFileName).str();
4463 if (!newName.empty())
4464 newName += gPathSeparator;
4465 newName += llvm::sys::path::stem(gOptSharedLibFileName);
4467 newName += llvm::sys::path::stem(dictpathname);
4468 newName += llvm::sys::path::extension(gOptSharedLibFileName);
4469 gOptSharedLibFileName = newName;
4475 if (!gBuildingROOT && !gOptNoIncludePaths){
4476 string incCurDir =
"-I";
4477 incCurDir += currentDirectory;
4478 pcmArgs.push_back(incCurDir);
4483 std::stringstream res;
4484 const char* delim=
"\n";
4485 std::copy(diagnosticPragmas.begin(),
4486 diagnosticPragmas.end(),
4487 std::ostream_iterator<std::string>(res, delim));
4488 interp.declare(res.str());
4491 class IgnoringPragmaHandler:
public clang::PragmaNamespace {
4493 IgnoringPragmaHandler(
const char* pragma):
4494 clang::PragmaNamespace(pragma) {}
4495 void HandlePragma(clang::Preprocessor &PP,
4496 clang::PragmaIntroducerKind Introducer,
4497 clang::Token &tok) {
4498 PP.DiscardUntilEndOfDirective();
4504 PP.AddPragmaHandler(
new IgnoringPragmaHandler(
"link"));
4505 PP.AddPragmaHandler(
new IgnoringPragmaHandler(
"extra_include"));
4506 PP.AddPragmaHandler(
new IgnoringPragmaHandler(
"read"));
4507 PP.AddPragmaHandler(
new IgnoringPragmaHandler(
"create"));
4509 if (!interpreterDeclarations.empty() &&
4510 interp.declare(interpreterDeclarations) != cling::Interpreter::kSuccess) {
4511 ROOT::TMetaUtils::Error(0,
"%s: Linkdef compilation failure\n", executableFileName);
4516 TModuleGenerator modGen(interp.getCI(),
4518 gOptSharedLibFileName,
4519 gOptWriteEmptyRootPCM);
4521 if (!gDriverConfig->fBuildingROOTStage1 && !filesIncludedByLinkdef.empty()) {
4522 pcmArgs.push_back(linkdef);
4525 modGen.ParseArgs(pcmArgs);
4527 if (!gDriverConfig->fBuildingROOTStage1) {
4529 for (
const std::string & inclPath : modGen.GetIncludePaths()) {
4530 interp.AddIncludePath(inclPath);
4532 std::stringstream definesUndefinesStr;
4533 modGen.WritePPDefines(definesUndefinesStr);
4534 modGen.WritePPUndefines(definesUndefinesStr);
4535 if (!definesUndefinesStr.str().empty())
4536 interp.declare(definesUndefinesStr.str());
4539 if (!InjectModuleUtilHeader(executableFileName, modGen, interp,
true)
4540 || !InjectModuleUtilHeader(executableFileName, modGen, interp,
false)) {
4544 if (linkdef.empty()) {
4546 GenerateLinkdef(gOptDictionaryHeaderFiles, interpPragmaSource);
4550 std::ofstream fileout;
4551 string main_dictname(dictpathname);
4552 std::ostream *dictStreamPtr = NULL;
4554 tempFileNamesCatalog tmpCatalog;
4555 if (!gOptIgnoreExistingDict) {
4556 if (!dictpathname.empty()) {
4557 tmpCatalog.addFileName(dictpathname);
4558 fileout.open(dictpathname.c_str());
4559 dictStreamPtr = &fileout;
4560 if (!(*dictStreamPtr)) {
4561 ROOT::TMetaUtils::Error(0,
"rootcling: failed to open %s in main\n",
4562 dictpathname.c_str());
4566 dictStreamPtr = &std::cout;
4569 fileout.open(
"/dev/null");
4570 dictStreamPtr = &fileout;
4574 std::ostream *splitDictStreamPtr = gOptSplit ? CreateStreamPtrForSplitDict(dictpathname, tmpCatalog) : dictStreamPtr;
4575 std::ostream &dictStream = *dictStreamPtr;
4576 std::ostream &splitDictStream = *splitDictStreamPtr;
4578 size_t dh = main_dictname.rfind(
'.');
4579 if (dh != std::string::npos) {
4580 main_dictname.erase(dh);
4583 std::string main_dictname_copy(main_dictname);
4584 TMetaUtils::GetCppName(main_dictname, main_dictname_copy.c_str());
4586 CreateDictHeader(dictStream, main_dictname);
4588 CreateDictHeader(splitDictStream, main_dictname);
4594 string linkdefFilename;
4595 if (linkdef.empty()) {
4596 linkdefFilename =
"in memory";
4598 bool found = Which(interp, linkdef.c_str(), linkdefFilename);
4600 ROOT::TMetaUtils::Error(0,
"%s: cannot open linkdef file %s\n", executableFileName, linkdef.c_str());
4606 std::vector<std::pair<std::string, std::string>> namesForExclusion;
4607 if (!gBuildingROOT) {
4608 namesForExclusion.push_back(std::make_pair(ROOT::TMetaUtils::propNames::name,
"std::string"));
4609 namesForExclusion.push_back(std::make_pair(ROOT::TMetaUtils::propNames::pattern,
"ROOT::Meta::Selection*"));
4612 SelectionRules selectionRules(interp, normCtxt, namesForExclusion);
4614 std::string extraIncludes;
4616 ROOT::TMetaUtils::RConstructorTypes constructorTypes;
4619 const unsigned int selRulesInitialSize = selectionRules.Size();
4620 if (dictSelection && !gOptGeneratePCH)
4621 ROOT::Internal::DictSelectionReader dictSelReader(interp, selectionRules, CI->getASTContext(), normCtxt);
4623 bool dictSelRulesPresent = selectionRules.Size() > selRulesInitialSize;
4625 bool isSelXML = IsSelectionXml(linkdefFilename.c_str());
4627 int rootclingRetCode(0);
4629 if (linkdef.empty()) {
4633 LinkdefReader ldefr(interp, constructorTypes);
4634 clingArgs.push_back(
"-Ietc/cling/cint");
4636 if (!ldefr.Parse(selectionRules, interpPragmaSource, clingArgs,
4637 llvmResourceDir.c_str())) {
4638 ROOT::TMetaUtils::Error(0,
"Parsing #pragma failed %s\n", linkdefFilename.c_str());
4639 rootclingRetCode += 1;
4641 ROOT::TMetaUtils::Info(0,
"#pragma successfully parsed.\n");
4644 if (!ldefr.LoadIncludes(extraIncludes)) {
4645 ROOT::TMetaUtils::Error(0,
"Error loading the #pragma extra_include.\n");
4649 }
else if (isSelXML) {
4651 selectionRules.SetSelectionFileType(SelectionRules::kSelectionXMLFile);
4653 std::ifstream file(linkdefFilename.c_str());
4654 if (file.is_open()) {
4655 ROOT::TMetaUtils::Info(0,
"Selection XML file\n");
4657 XMLReader xmlr(interp);
4658 if (!xmlr.Parse(linkdefFilename.c_str(), selectionRules)) {
4659 ROOT::TMetaUtils::Error(0,
"Parsing XML file %s\n", linkdefFilename.c_str());
4662 ROOT::TMetaUtils::Info(0,
"XML file successfully parsed\n");
4666 ROOT::TMetaUtils::Error(0,
"XML file %s couldn't be opened!\n", linkdefFilename.c_str());
4669 }
else if (ROOT::TMetaUtils::IsLinkdefFile(linkdefFilename.c_str())) {
4671 std::ifstream file(linkdefFilename.c_str());
4672 if (file.is_open()) {
4673 ROOT::TMetaUtils::Info(0,
"Using linkdef file: %s\n", linkdefFilename.c_str());
4676 ROOT::TMetaUtils::Error(0,
"Linkdef file %s couldn't be opened!\n", linkdefFilename.c_str());
4679 selectionRules.SetSelectionFileType(SelectionRules::kLinkdefFile);
4681 LinkdefReader ldefr(interp, constructorTypes);
4682 clingArgs.push_back(
"-Ietc/cling/cint");
4684 if (!ldefr.Parse(selectionRules, interpPragmaSource, clingArgs,
4685 llvmResourceDir.c_str())) {
4686 ROOT::TMetaUtils::Error(0,
"Parsing Linkdef file %s\n", linkdefFilename.c_str());
4687 rootclingRetCode += 1;
4689 ROOT::TMetaUtils::Info(0,
"Linkdef file successfully parsed.\n");
4692 if (! ldefr.LoadIncludes(extraIncludes)) {
4693 ROOT::TMetaUtils::Error(0,
"Error loading the #pragma extra_include.\n");
4699 ROOT::TMetaUtils::Error(0,
"Unrecognized selection file: %s\n", linkdefFilename.c_str());
4704 selectionRules.FillCache();
4705 selectionRules.Optimize();
4708 if (0 != selectionRules.CheckDuplicates()){
4714 if (gOptCheckSelectionSyntax)
4721 if (!ROOT::gReadRules.empty() || !ROOT::gReadRawRules.empty()) {
4722 dictStream <<
"#include \"TBuffer.h\"\n"
4723 <<
"#include \"TVirtualObject.h\"\n"
4724 <<
"#include <vector>\n"
4725 <<
"#include \"TSchemaHelper.h\"\n\n";
4727 std::list<std::string> includes;
4728 GetRuleIncludes(includes);
4729 for (
auto & incFile : includes) {
4730 dictStream <<
"#include <" << incFile <<
">" << std::endl;
4732 dictStream << std::endl;
4735 selectionRules.SearchNames(interp);
4737 int scannerVerbLevel = 0;
4739 using namespace ROOT::TMetaUtils;
4740 scannerVerbLevel = GetErrorIgnoreLevel() == kInfo;
4742 scannerVerbLevel = GetErrorIgnoreLevel() < kWarning;
4747 auto scanType = RScanner::EScanType::kNormal;
4748 if (gOptGeneratePCH)
4749 scanType = RScanner::EScanType::kOnePCM;
4751 scanType = RScanner::EScanType::kTwoPasses;
4753 RScanner scan(selectionRules,
4760 if (!gOptLibListPrefix.empty()) {
4761 LoadLibraryMap(gOptLibListPrefix +
".in", gAutoloads);
4762 scan.SetRecordDeclCallback(RecordDeclCallback);
4765 scan.Scan(CI->getASTContext());
4767 bool has_input_error =
false;
4769 if (genreflex::verbose)
4770 selectionRules.PrintSelectionRules();
4772 if (ROOT::TMetaUtils::GetErrorIgnoreLevel() != ROOT::TMetaUtils::kFatal &&
4774 !dictSelRulesPresent &&
4775 !selectionRules.AreAllSelectionRulesUsed()) {
4776 ROOT::TMetaUtils::Warning(0,
"Not all selection rules are used!\n");
4779 if (!gOptGeneratePCH){
4780 rootclingRetCode += CheckForUnsupportedClasses(scan.fSelectedClasses);
4781 if (rootclingRetCode)
return rootclingRetCode;
4786 for (
auto const & annRcd : scan.fSelectedClasses) {
4787 if (ROOT::TMetaUtils::ClassInfo__HasMethod(annRcd,
"Streamer", interp)) {
4788 if (annRcd.RequestNoInputOperator()) {
4789 int version = ROOT::TMetaUtils::GetClassVersion(annRcd, interp);
4793 has_input_error |= CheckInputOperator(annRcd, interp);
4797 has_input_error |= !CheckClassDef(*annRcd, interp);
4800 if (has_input_error) {
4809 if (!gDriverConfig->fBuildingROOTStage1) {
4810 for (
auto &&includedFromLinkdef : filesIncludedByLinkdef) {
4811 includeForSource +=
"#include \"" + includedFromLinkdef +
"\"\n";
4815 if (!gOptGeneratePCH) {
4816 GenerateNecessaryIncludes(dictStream, includeForSource, extraIncludes);
4818 GenerateNecessaryIncludes(splitDictStream, includeForSource, extraIncludes);
4820 if (gDriverConfig->fInitializeStreamerInfoROOTFile) {
4821 gDriverConfig->fInitializeStreamerInfoROOTFile(modGen.GetModuleFileName().c_str());
4827 if (!gOptInterpreterOnly) {
4828 constructorTypes.push_back(ROOT::TMetaUtils::RConstructorType(
"TRootIOCtor", interp));
4829 constructorTypes.push_back(ROOT::TMetaUtils::RConstructorType(
"__void__", interp));
4830 constructorTypes.push_back(ROOT::TMetaUtils::RConstructorType(
"", interp));
4834 if (gOptGeneratePCH) {
4835 AnnotateAllDeclsForPCH(interp, scan);
4836 }
else if (gOptInterpreterOnly) {
4837 rootclingRetCode += CheckClassesForInterpreterOnlyDicts(interp, scan);
4840 if (!gDriverConfig->fBuildingROOTStage1) {
4841 rootclingRetCode += FinalizeStreamerInfoWriting(interp);
4844 rootclingRetCode += GenerateFullDict(splitDictStream,
4850 gOptWriteEmptyRootPCM);
4853 if (rootclingRetCode != 0) {
4854 return rootclingRetCode;
4857 if (gOptSplit && splitDictStreamPtr)
delete splitDictStreamPtr;
4861 HeadersDeclsMap_t headersClassesMap;
4862 HeadersDeclsMap_t headersDeclsMap;
4863 if (!gOptIgnoreExistingDict) {
4864 const std::string fwdDeclnArgsToKeepString(GetFwdDeclnArgsToKeepString(normCtxt, interp));
4866 ExtractHeadersForDecls(scan.fSelectedClasses,
4867 scan.fSelectedTypedefs,
4868 scan.fSelectedFunctions,
4869 scan.fSelectedVariables,
4870 scan.fSelectedEnums,
4875 std::string detectedUmbrella;
4876 for (
auto & arg : pcmArgs) {
4877 if (gOptInlineInput && !ROOT::TMetaUtils::IsLinkdefFile(arg.c_str()) && ROOT::TMetaUtils::IsHeaderName(arg)) {
4878 detectedUmbrella = arg;
4883 if (gOptWriteEmptyRootPCM){
4884 headersDeclsMap.clear();
4888 std::string headersClassesMapString =
"\"\"";
4889 std::string fwdDeclsString =
"\"\"";
4890 if (!gOptCxxModule) {
4891 headersClassesMapString = GenerateStringFromHeadersForClasses(headersDeclsMap,
4894 if (!gDriverConfig->fBuildingROOTStage1) {
4895 if (!gOptWriteEmptyRootPCM)
4896 fwdDeclsString = GenerateFwdDeclString(scan, interp);
4899 modGen.WriteRegistrationSource(dictStream, fwdDeclnArgsToKeepString, headersClassesMapString, fwdDeclsString,
4900 extraIncludes, gOptCxxModule);
4903 if (!gOptInlineInput) {
4905 if (modGen.IsPCH()) {
4906 if (!GenerateAllDict(modGen, CI, currentDirectory))
return 1;
4907 }
else if (gOptCxxModule) {
4908 if (!CheckModuleValid(modGen, llvmResourceDir, interp, linkdefFilename, moduleName.str()))
4915 if (!gOptLibListPrefix.empty()) {
4916 string liblist_filename = gOptLibListPrefix +
".out";
4918 ofstream outputfile(liblist_filename.c_str(), ios::out);
4920 ROOT::TMetaUtils::Error(0,
"%s: Unable to open output lib file %s\n",
4921 executableFileName, liblist_filename.c_str());
4923 const size_t endStr = gLibsNeeded.find_last_not_of(
" \t");
4924 outputfile << gLibsNeeded.substr(0, endStr + 1) << endl;
4926 outputfile <<
"# Now the list of classes\n";
4928 for (
auto const & annRcd : scan.fSelectedClasses) {
4931 outputfile << annRcd.GetNormalizedName() << endl;
4937 rootclingRetCode += modGen.GetErrorCount();
4938 if (0 != rootclingRetCode)
return rootclingRetCode;
4941 std::string rootmapLibName = std::accumulate(gOptRootmapLibNames.begin(),
4942 gOptRootmapLibNames.end(),
4944 [](
const std::string & a,
const std::string & b) -> std::string {
4945 if (a.empty())
return b;
4946 else return a +
" " + b;
4949 bool rootMapNeeded = !gOptRootMapFileName.empty() || !rootmapLibName.empty();
4951 std::list<std::string> classesNames;
4952 std::list<std::string> classesNamesForRootmap;
4953 std::list<std::string> classesDefsList;
4955 rootclingRetCode = ExtractClassesListAndDeclLines(scan,
4957 classesNamesForRootmap,
4961 std::list<std::string> enumNames;
4962 rootclingRetCode += ExtractAutoloadKeys(enumNames,
4963 scan.fSelectedEnums,
4966 std::list<std::string> varNames;
4967 rootclingRetCode += ExtractAutoloadKeys(varNames,
4968 scan.fSelectedVariables,
4971 if (0 != rootclingRetCode)
return rootclingRetCode;
4974 if (rootMapNeeded) {
4976 std::list<std::string> nsNames;
4978 ExtractSelectedNamespaces(scan, nsNames);
4980 AdjustRootMapNames(gOptRootMapFileName,
4983 ROOT::TMetaUtils::Info(0,
"Rootmap file name %s and lib name(s) \"%s\"\n",
4984 gOptRootMapFileName.c_str(),
4985 rootmapLibName.c_str());
4987 tmpCatalog.addFileName(gOptRootMapFileName);
4988 std::unordered_set<std::string> headersToIgnore;
4989 if (gOptInlineInput)
4990 for (
const std::string& optHeaderFileName : gOptDictionaryHeaderFiles)
4991 headersToIgnore.insert(optHeaderFileName.c_str());
4993 std::list<std::string> typedefsRootmapLines;
4994 rootclingRetCode += ExtractAutoloadKeys(typedefsRootmapLines,
4995 scan.fSelectedTypedefs,
4998 rootclingRetCode = CreateNewRootMapFile(gOptRootMapFileName,
5001 classesNamesForRootmap,
5003 typedefsRootmapLines,
5009 if (0 != rootclingRetCode)
return 1;
5012 if (genreflex::verbose)
5019 cling::Interpreter::PushTransactionRAII RAII(&interp);
5020 CI->getSema().getASTConsumer().HandleTranslationUnit(CI->getSema().getASTContext());
5024 rootclingRetCode += ROOT::TMetaUtils::GetNumberOfErrors();
5031 if(rootclingRetCode == 0) {
5032 rootclingRetCode += tmpCatalog.commit();
5037 return rootclingRetCode;
5041 namespace genreflex {
5046 unsigned int checkHeadersNames(std::vector<std::string> &headersNames)
5048 unsigned int numberOfHeaders = 0;
5049 for (std::vector<std::string>::iterator it = headersNames.begin();
5050 it != headersNames.end(); ++it) {
5051 const std::string headername(*it);
5052 if (ROOT::TMetaUtils::IsHeaderName(headername)) {
5055 ROOT::TMetaUtils::Warning(0,
5056 "*** genreflex: %s is not a valid header name (.h and .hpp extensions expected)!\n",
5057 headername.c_str());
5060 return numberOfHeaders;
5066 unsigned int extractArgs(
int argc,
char **argv, std::vector<std::string> &args)
5069 unsigned int argvCounter = 0;
5070 for (
int i = 1; i < argc; ++i) {
5071 if (!ROOT::TMetaUtils::BeginsWith(argv[i - 1],
"-") &&
5072 !ROOT::TMetaUtils::BeginsWith(argv[i],
"-")) {
5073 args.push_back(argv[i]);
5075 }
else if (argvCounter) {
5076 argv[i - argvCounter] = argv[i];
5081 if (genreflex::verbose) {
5083 std::cout <<
"Args: \n";
5084 for (std::vector<std::string>::iterator it = args.begin();
5085 it < args.end(); ++it) {
5086 std::cout << i <<
") " << *it << std::endl;
5097 void changeExtension(std::string &filename,
const std::string &newExtension)
5099 size_t result = filename.find_last_of(
'.');
5100 if (std::string::npos != result) {
5101 filename.erase(result);
5102 filename.append(newExtension);
5110 char *string2charptr(
const std::string &str)
5112 const unsigned int size(str.size());
5113 char *a =
new char[size + 1];
5115 memcpy(a, str.c_str(), size);
5122 void header2outputName(std::string &fileName)
5124 changeExtension(fileName,
"_rflx.cpp");
5130 void headers2outputsNames(
const std::vector<std::string> &headersNames,
5131 std::vector<std::string> &ofilesnames)
5133 ofilesnames.reserve(headersNames.size());
5135 for (std::vector<std::string>::const_iterator it = headersNames.begin();
5136 it != headersNames.end(); ++it) {
5137 std::string ofilename(*it);
5138 header2outputName(ofilename);
5139 ofilesnames.push_back(ofilename);
5145 void AddToArgVector(std::vector<char *> &argvVector,
5146 const std::vector<std::string> &argsToBeAdded,
5147 const std::string &optName =
"")
5149 for (std::vector<std::string>::const_iterator it = argsToBeAdded.begin();
5150 it != argsToBeAdded.end(); ++it) {
5151 argvVector.push_back(string2charptr(optName + *it));
5157 void AddToArgVectorSplit(std::vector<char *> &argvVector,
5158 const std::vector<std::string> &argsToBeAdded,
5159 const std::string &optName =
"")
5161 for (std::vector<std::string>::const_iterator it = argsToBeAdded.begin();
5162 it != argsToBeAdded.end(); ++it) {
5163 if (optName.length()) {
5164 argvVector.push_back(string2charptr(optName));
5166 argvVector.push_back(string2charptr(*it));
5172 int invokeRootCling(
const std::string &verbosity,
5173 const std::string &selectionFileName,
5174 const std::string &targetLibName,
5176 const std::vector<std::string> &pcmsNames,
5177 const std::vector<std::string> &includes,
5178 const std::vector<std::string> &preprocDefines,
5179 const std::vector<std::string> &preprocUndefines,
5180 const std::vector<std::string> &warnings,
5181 const std::string &rootmapFileName,
5182 const std::string &rootmapLibName,
5183 bool interpreteronly,
5186 bool writeEmptyRootPCM,
5188 bool noIncludePaths,
5189 const std::vector<std::string> &headersNames,
5190 bool failOnWarnings,
5191 const std::string &ofilename)
5195 std::vector<char *> argvVector;
5197 argvVector.push_back(string2charptr(
"rootcling"));
5198 argvVector.push_back(string2charptr(verbosity));
5199 argvVector.push_back(string2charptr(
"-f"));
5200 argvVector.push_back(string2charptr(ofilename));
5203 argvVector.push_back(string2charptr(
"-cxxmodule"));
5206 std::string dictLocation;
5207 ExtractFilePath(ofilename, dictLocation);
5212 std::string newRootmapLibName(rootmapLibName);
5213 if (!rootmapFileName.empty() && newRootmapLibName.empty()) {
5214 if (headersNames.size() != 1) {
5215 ROOT::TMetaUtils::Warning(0,
5216 "*** genreflex: No rootmap lib and several header specified!\n");
5218 std::string cleanHeaderName = ExtractFileName(headersNames[0]);
5219 newRootmapLibName =
"lib";
5220 newRootmapLibName += cleanHeaderName;
5221 changeExtension(newRootmapLibName, gLibraryExtension);
5226 std::string newRootmapFileName(rootmapFileName);
5227 if (!newRootmapFileName.empty() && !HasPath(newRootmapFileName)) {
5228 newRootmapFileName = dictLocation + newRootmapFileName;
5233 if (!newRootmapFileName.empty()) {
5234 argvVector.push_back(string2charptr(
"-rmf"));
5235 argvVector.push_back(string2charptr(newRootmapFileName));
5239 if (!newRootmapLibName.empty()) {
5240 argvVector.push_back(string2charptr(
"-rml"));
5241 argvVector.push_back(string2charptr(newRootmapLibName));
5245 if (interpreteronly)
5246 argvVector.push_back(string2charptr(
"-interpreteronly"));
5250 argvVector.push_back(string2charptr(
"-split"));
5253 if (!targetLibName.empty()) {
5254 argvVector.push_back(string2charptr(
"-s"));
5255 argvVector.push_back(string2charptr(targetLibName));
5260 argvVector.push_back(string2charptr(
"-multiDict"));
5263 AddToArgVectorSplit(argvVector, pcmsNames,
"-m");
5266 argvVector.push_back(string2charptr(
"-inlineInputHeader"));
5269 if (writeEmptyRootPCM)
5270 argvVector.push_back(string2charptr(
"-writeEmptyRootPCM"));
5274 argvVector.push_back(string2charptr(
"-selSyntaxOnly"));
5278 argvVector.push_back(string2charptr(
"-noIncludePaths"));
5282 argvVector.push_back(string2charptr(
"-failOnWarnings"));
5285 AddToArgVector(argvVector, includes,
"-I");
5286 AddToArgVector(argvVector, preprocDefines,
"-D");
5287 AddToArgVector(argvVector, preprocUndefines,
"-U");
5288 AddToArgVector(argvVector, warnings,
"-W");
5290 AddToArgVector(argvVector, headersNames);
5292 if (!selectionFileName.empty()) {
5293 argvVector.push_back(string2charptr(selectionFileName));
5296 const int argc = argvVector.size();
5299 if (genreflex::verbose) {
5300 std::cout <<
"Rootcling commandline:\n";
5301 for (
int i = 0; i < argc; i++)
5302 std::cout << i <<
") " << argvVector[i] << std::endl;
5305 char **argv = & (argvVector[0]);
5306 int rootclingReturnCode = RootClingMain(argc,
5310 for (
int i = 0; i < argc; i++)
5311 delete [] argvVector[i];
5313 return rootclingReturnCode;
5321 int invokeManyRootCling(
const std::string &verbosity,
5322 const std::string &selectionFileName,
5323 const std::string &targetLibName,
5325 const std::vector<std::string> &pcmsNames,
5326 const std::vector<std::string> &includes,
5327 const std::vector<std::string> &preprocDefines,
5328 const std::vector<std::string> &preprocUndefines,
5329 const std::vector<std::string> &warnings,
5330 const std::string &rootmapFileName,
5331 const std::string &rootmapLibName,
5332 bool interpreteronly,
5335 bool writeEmptyRootPCM,
5337 bool noIncludePaths,
5338 const std::vector<std::string> &headersNames,
5339 bool failOnWarnings,
5340 const std::string &outputDirName_const =
"")
5342 std::string outputDirName(outputDirName_const);
5344 std::vector<std::string> ofilesNames;
5345 headers2outputsNames(headersNames, ofilesNames);
5347 if (!outputDirName.empty() && !ROOT::TMetaUtils::EndsWith(outputDirName, gPathSeparator)) {
5348 outputDirName += gPathSeparator;
5351 std::vector<std::string> namesSingleton(1);
5352 for (
unsigned int i = 0; i < headersNames.size(); ++i) {
5353 namesSingleton[0] = headersNames[i];
5354 std::string ofilenameFullPath(ofilesNames[i]);
5355 if (llvm::sys::path::parent_path(ofilenameFullPath) ==
"")
5356 ofilenameFullPath = outputDirName + ofilenameFullPath;
5357 int returnCode = invokeRootCling(verbosity,
5377 if (returnCode != 0)
5390 int extractMultipleOptions(std::vector<ROOT::option::Option> &options,
5392 std::vector<std::string> &values)
5395 if (options[oIndex]) {
5396 const int nVals = options[oIndex].count();
5397 values.reserve(nVals);
5398 int optionIndex = 0;
5399 for (ROOT::option::Option *opt = options[oIndex]; opt; opt = opt->next()) {
5400 if (genreflex::verbose) std::cout <<
"Extracting multiple args: "
5401 << optionIndex <<
"/" << nVals <<
" "
5402 << opt->arg << std::endl;
5404 values.push_back(opt->arg);
5413 void RiseWarningIfPresent(std::vector<ROOT::option::Option> &options,
5415 const char *descriptor)
5417 if (options[optionIndex]) {
5418 ROOT::TMetaUtils::Warning(0,
5419 "*** genereflex: %s is not supported anymore.\n",
5426 bool IsGoodLibraryName(
const std::string &name)
5430 auto isGood = ROOT::TMetaUtils::EndsWith(name, gLibraryExtension);
5432 isGood |= ROOT::TMetaUtils::EndsWith(name,
".dylib");
5471 int GenReflexMain(
int argc,
char **argv)
5473 using namespace genreflex;
5476 enum optionIndex { UNKNOWN,
5506 enum optionTypes { NOTYPE, STRING } ;
5509 const char *genreflexUsage =
5510 "Generates dictionary sources and related ROOT pcm starting from an header.\n"
5511 "Usage: genreflex headerfile.h [opts] [preproc. opts]\n\n"
5514 const char *selectionFilenameUsage =
5515 "-s, --selection_file\tSelection filename\n"
5516 " Class selection file to specify for which classes the dictionary\n"
5517 " will be generated. The final set can be crafted with exclusion and\n"
5518 " exclusion rules.\n"
5519 " Properties can be specified. Some have special meaning:\n"
5520 " - name [string] name of the entity to select with an exact matching\n"
5521 " - pattern [string] name with wildcards (*) to select entities\n"
5522 " - file_name/file_pattern [string]: as name/pattern but referring to\n"
5523 " file where the C++ entities reside and not to C++ entities themselves.\n"
5524 " - transient/persistent [string: true/false] The fields to which they are\n"
5525 " applied will not be persistified if requested.\n"
5526 " - comment [string]: what you could write in code after an inline comment\n"
5527 " without \"//\". For example comment=\"!\" or \"||\".\n"
5528 " - noStreamer [true/false]: turns off streamer generation if set to 'true.'\n"
5529 " Default value is 'false'\n"
5530 " - noInputOperator [true/false]: turns off input operator generation if set\n"
5531 " to 'true'. Default value is 'false'\n"
5535 " <class [name=\"classname\"] [pattern=\"wildname\"]\n"
5536 " [file_name=\"filename\"] [file_pattern=\"wildname\"]\n"
5537 " [id=\"xxxx\"] [noStreamer=\"true/false\"]\n"
5538 " [noInputOperator=\"true/false\"] />\n"
5539 " <class name=\"classname\" >\n"
5540 " <field name=\"m_transient\" transient=\"true\"/>\n"
5541 " <field name=\"m_anothertransient\" persistent=\"false\"/>\n"
5542 " <field name=\"m_anothertransient\" comment=\"||\"/>\n"
5543 " <properties prop1=\"value1\" [prop2=\"value2\"]/>\n"
5545 " <function [name=\"funcname\"] [pattern=\"wildname\"] />\n"
5546 " <enum [name=\"enumname\"] [pattern=\"wildname\"] />\n"
5547 " <variable [name=\"varname\"] [pattern=\"wildname\"] />\n"
5550 " <class [name=\"classname\"] [pattern=\"wildname\"] />\n"
5551 " <method name=\"unwanted\" />\n"
5556 " If no selection file is specified, the class with the filename without\n"
5557 " extension will be selected, i.e. myClass.h as argument without any\n"
5558 " selection xml comes with an implicit selection rule for class \"myClass\".\n";
5560 const char *outputFilenameUsage =
5561 "-o, --output\tOutput filename\n"
5562 " Output file name. If an existing directory is specified instead of a file,\n"
5563 " then a filename will be build using the name of the input file and will\n"
5564 " be placed in the given directory. <headerfile>_rflx.cpp.\n"
5565 " NOTA BENE: the dictionaries that will be used within the same project must\n"
5566 " have unique names.\n";
5569 const char *targetLib =
5570 "-l, --library\tTarget library\n"
5571 " The flag -l must be followed by the name of the library that will\n"
5572 " contain the object file corresponding to the dictionary produced by\n"
5573 " this invocation of genreflex.\n"
5574 " The name takes priority over the one specified for the rootmapfile.\n"
5575 " The name influences the name of the created pcm:\n"
5576 " 1) If it is not specified, the pcm is called libINPUTHEADER_rdict.pcm\n"
5577 " 2) If it is specified, the pcm is called libTARGETLIBRARY_rdict.pcm\n"
5578 " Any \"liblib\" occurence is transformed in the expected \"lib\".\n"
5579 " 3) If this is specified in conjunction with --multiDict, the output is\n"
5580 " libTARGETLIBRARY_DICTIONARY_rdict.pcm\n";
5582 const char *rootmapUsage =
5583 "--rootmap\tGenerate the rootmap file to be used by ROOT.\n"
5584 " This file lists the autoload keys. For example classes for which the\n"
5585 " reflection information is provided.\n"
5586 " The format of the rootmap is the following:\n"
5587 " - Forward declarations section\n"
5588 " - Libraries sections\n"
5589 " Rootmaps can be concatenated together, for example with the cat util.\n"
5590 " In order for ROOT to pick up the information in the rootmaps, they\n"
5591 " have to be located in the library path and have the .rootmap extension.\n"
5592 " An example rootmap file could be:\n"
5594 " template <class T> class A;\n"
5595 " [ libMyLib.so ]\n"
5596 " class A<double>\n"
5601 const char *rootmapLibUsage =
5602 "--rootmap-lib\tLibrary name for the rootmap file.\n";
5605 const ROOT::option::Descriptor genreflexUsageDescriptor[] = {
5610 ROOT::option::Arg::None,
5618 ROOT::option::FullArg::Required,
5626 ROOT::option::FullArg::Required,
5634 ROOT::option::FullArg::None,
5635 "--multiDict\tSupport for many dictionaries in one library\n"
5636 " Form correct pcm names if multiple dictionaries will be in the same\n"
5637 " library (needs target library switch. See its documentation).\n"
5643 "s" ,
"selection_file" ,
5644 ROOT::option::FullArg::Required,
5645 selectionFilenameUsage
5652 ROOT::option::FullArg::Required,
5659 "" ,
"rootmap-lib" ,
5660 ROOT::option::FullArg::Required,
5667 "" ,
"interpreteronly",
5668 ROOT::option::Arg::None,
5669 "--interpreteronly\tDo not generate I/O related information.\n"
5670 " Generate minimal dictionary required for interactivity.\n"
5677 ROOT::option::Arg::None,
5678 "--split\tSplit the dictionary\n"
5679 " Split in two the dictionary, isolating the part with\n"
5680 " ClassDef related functions in a separate file.\n"
5687 ROOT::option::FullArg::Required,
5688 "-m \tPcm file loaded before any header (option can be repeated).\n"
5695 ROOT::option::Arg::None,
5704 ROOT::option::Arg::None,
5705 "-v, --verbose\tPrint some debug information.\n"
5712 ROOT::option::Arg::None,
5713 "--debug\tPrint all debug information.\n"
5720 ROOT::option::Arg::None,
5721 "--quiet\tPrint only warnings and errors (default).\n"
5728 ROOT::option::Arg::None,
5729 "--silent\tPrint no information at all.\n"
5735 "" ,
"writeEmptyPCM",
5736 ROOT::option::Arg::None,
5737 "--writeEmptyPCM\tWrite an empty ROOT pcm.\n"
5744 ROOT::option::Arg::None,
5745 "--cxxmodule\tGenerates a PCM for C++ Modules.\n"
5753 ROOT::option::Arg::None,
5754 "--help\tPrint usage and exit.\n"
5760 "",
"fail_on_warnings",
5761 ROOT::option::Arg::None,
5762 "--fail_on_warnings\tFail on warnings and errors.\n"
5768 "",
"selSyntaxOnly",
5769 ROOT::option::Arg::None,
5770 "--selSyntaxOnly\tValidate selection file w/o generating the dictionary.\n"
5776 "" ,
"noIncludePaths",
5777 ROOT::option::Arg::None,
5778 "--noIncludePaths\tDo not store the headers' directories in the dictionary. Instead, rely on the environment variable $ROOT_INCLUDE_PATH at runtime.\n"
5786 ROOT::option::FullArg::Required,
5794 ROOT::option::FullArg::Required,
5802 ROOT::option::FullArg::Required,
5810 ROOT::option::FullArg::Required,
5817 "" ,
"no_membertypedefs" ,
5818 ROOT::option::FullArg::None,
5825 "" ,
"no_templatetypedefs" ,
5826 ROOT::option::FullArg::None,
5833 std::vector<std::string> headersNames;
5834 const int originalArgc = argc;
5836 const int extractedArgs = extractArgs(argc, argv, headersNames);
5838 const int offset = 1;
5839 argc -= offset + extractedArgs;
5843 ROOT::option::Stats stats(genreflexUsageDescriptor, argc, argv);
5844 std::vector<ROOT::option::Option> options(stats.options_max);
5845 std::vector<ROOT::option::Option> buffer(stats.buffer_max);
5849 ROOT::option::Parser parse(genreflexUsageDescriptor, argc, argv, &options[0], &buffer[0], 5);
5851 if (parse.error()) {
5852 ROOT::TMetaUtils::Error(0,
"Argument parsing error!\n");
5857 if (options[HELP] || originalArgc == 1) {
5858 ROOT::option::printUsage(std::cout, genreflexUsageDescriptor);
5862 int numberOfHeaders = checkHeadersNames(headersNames);
5863 if (0 == numberOfHeaders) {
5864 ROOT::TMetaUtils::Error(0,
"No valid header was provided!\n");
5868 ROOT::TMetaUtils::GetErrorIgnoreLevel() = ROOT::TMetaUtils::kNote;
5871 ROOT::TMetaUtils::Warning(0,
"--deep has no effect. Please remove the deprecated flag!\n");
5874 std::string verbosityOption(
"-v2");
5875 if (options[SILENT]) verbosityOption =
"-v0";
5876 if (options[VERBOSE] || getenv (
"VERBOSE")) verbosityOption =
"-v3";
5877 if (options[DEBUG]) verbosityOption =
"-v4";
5879 genreflex::verbose = verbosityOption ==
"-v4";
5882 std::string selectionFileName;
5883 if (options[SELECTIONFILENAME]) {
5884 selectionFileName = options[SELECTIONFILENAME].arg;
5885 if (!ROOT::TMetaUtils::EndsWith(selectionFileName,
".xml")) {
5886 ROOT::TMetaUtils::Error(0,
5887 "Invalid selection file extension: filename is %s and extension .xml is expected!\n",
5888 selectionFileName.c_str());
5903 std::string rootmapFileName(options[ROOTMAP].arg ? options[ROOTMAP].arg :
"");
5904 std::string rootmapLibName(options[ROOTMAPLIB].arg ? options[ROOTMAPLIB].arg :
"");
5907 std::string targetLibName;
5908 if (options[TARGETLIB]) {
5909 targetLibName = options[TARGETLIB].arg;
5910 if (!IsGoodLibraryName(targetLibName)) {
5911 ROOT::TMetaUtils::Error(
"",
5912 "Invalid target library extension: filename is %s and extension %s is expected!\n",
5913 targetLibName.c_str(),
5914 gLibraryExtension.c_str());
5917 if (options[ROOTMAP]) {
5918 rootmapLibName = ExtractFileName(options[TARGETLIB].arg);
5922 bool isCxxmodule = options[CXXMODULE];
5924 bool multidict =
false;
5925 if (options[MULTIDICT]) multidict =
true;
5927 if (multidict && targetLibName.empty()) {
5928 ROOT::TMetaUtils::Error(
"",
5929 "Multilib support is requested but no target lib is specified. A sane pcm name cannot be formed.\n");
5933 bool interpreteronly =
false;
5934 if (options[INTERPRETERONLY])
5935 interpreteronly =
true;
5937 bool doSplit =
false;
5941 bool writeEmptyRootPCM =
false;
5942 if (options[WRITEEMPTYROOTPCM])
5943 writeEmptyRootPCM =
true;
5945 bool selSyntaxOnly =
false;
5946 if (options[SELSYNTAXONLY]) {
5947 selSyntaxOnly =
true;
5950 bool noIncludePaths =
false;
5951 if (options[NOINCLUDEPATHS]) {
5952 noIncludePaths =
true;
5955 bool failOnWarnings =
false;
5956 if (options[FAILONWARNINGS]) {
5957 failOnWarnings =
true;
5961 if (!rootmapLibName.empty() && !IsGoodLibraryName(rootmapLibName)) {
5962 rootmapLibName += gLibraryExtension;
5966 std::vector<std::string> pcmsNames;
5967 extractMultipleOptions(options, PCMFILENAME, pcmsNames);
5970 std::vector<std::string> preprocDefines;
5971 extractMultipleOptions(options, PREPROCDEFINE, preprocDefines);
5974 std::vector<std::string> preprocUndefines;
5975 extractMultipleOptions(options, PREPROCUNDEFINE, preprocUndefines);
5978 std::vector<std::string> includes;
5979 extractMultipleOptions(options, INCLUDE, includes);
5982 std::vector<std::string> warnings;
5983 extractMultipleOptions(options, WARNING, warnings);
5993 int returnValue = 0;
5994 std::string ofileName(options[OFILENAME] ? options[OFILENAME].arg :
"");
5998 if (!ofileName.empty() && !llvm::sys::fs::is_directory(ofileName)) {
5999 returnValue = invokeRootCling(verbosityOption,
6021 returnValue = invokeManyRootCling(verbosityOption,
6050 int ROOT_rootcling_Driver(
int argc,
char **argv,
const ROOT::Internal::RootCling::DriverConfig& config)
6053 assert(!gDriverConfig &&
"Driver configuration already set!");
6054 gDriverConfig = &config;
6056 gBuildingROOT = config.fBuildingROOTStage1;
6058 std::string exeName = ExtractFileName(GetExePath());
6067 if (std::string::npos != exeName.find(
"genreflex"))
6068 retVal = GenReflexMain(argc, argv);
6070 retVal = RootClingMain(argc, argv);
6072 gDriverConfig =
nullptr;
6074 if (ROOT::TMetaUtils::GetNumberOfErrors()){
6075 ROOT::TMetaUtils::Info(0,
"Problems have been detected during the generation of the dictionary.\n");