21 #include "TClingUtils.h"
22 #include "RConfigure.h"
25 #include "cling/Interpreter/CIFactory.h"
26 #include "clang/Basic/SourceManager.h"
27 #include "clang/Frontend/CompilerInstance.h"
28 #include "clang/Lex/HeaderSearch.h"
29 #include "clang/Lex/Preprocessor.h"
30 #include "llvm/Support/Path.h"
41 using namespace clang;
45 TModuleGenerator::TModuleGenerator(CompilerInstance *CI,
46 bool inlineInputHeaders,
47 const std::string &shLibFileName,
48 bool writeEmptyRootPCM):
50 fIsPCH(shLibFileName ==
"allDict.cxx"),
51 fIsInPCH(writeEmptyRootPCM),
52 fInlineInputHeaders(inlineInputHeaders),
53 fDictionaryName(llvm::sys::path::stem(shLibFileName)),
54 fDemangledDictionaryName(llvm::sys::path::stem(shLibFileName)),
55 fModuleDirName(llvm::sys::path::parent_path(shLibFileName)),
61 if (fModuleDirName.empty()) {
62 fModuleDirName =
"./";
64 fModuleDirName +=
"/";
67 fModuleFileName = fModuleDirName
68 + ROOT::TMetaUtils::GetModuleFileName(fDictionaryName.c_str());
71 std::string tmpName = fDictionaryName;
72 fDictionaryName.clear();
73 ROOT::TMetaUtils::GetCppName(fDictionaryName, tmpName.c_str());
76 if (IsPCH()) fModuleFileName[fModuleFileName.length() - 1] =
'h';
79 llvm::SmallString<10> resultPath(
"%%%%%%%%%%");
80 llvm::sys::fs::createUniqueFile(resultPath.str(), resultPath);
81 fUmbrellaName = fModuleDirName + fDictionaryName + resultPath.c_str() +
"_dictUmbrella.h";
82 fContentName = fModuleDirName + fDictionaryName + resultPath.c_str() +
"_dictContent.h";
85 TModuleGenerator::~TModuleGenerator()
87 unlink(fUmbrellaName.c_str());
88 unlink(fContentName.c_str());
95 TModuleGenerator::ESourceFileKind
96 TModuleGenerator::GetSourceFileKind(
const char *filename)
const
98 if (filename[0] ==
'-')
return kSFKNotC;
100 if (ROOT::TMetaUtils::IsLinkdefFile(filename)) {
104 const size_t len = strlen(filename);
105 const char *ext = filename + len - 1;
106 while (ext >= filename && *ext !=
'.') --ext;
107 if (ext < filename || *ext !=
'.') {
110 clang::Preprocessor &PP = fCI->getPreprocessor();
111 clang::HeaderSearch &HdrSearch = PP.getHeaderSearchInfo();
112 const clang::DirectoryLookup *CurDir = 0;
113 const clang::FileEntry *hdrFileEntry
114 = HdrSearch.LookupFile(filename, clang::SourceLocation(),
116 clang::ArrayRef<std::pair<
const clang::FileEntry*,
117 const clang::DirectoryEntry*>>(),
126 const size_t lenExt = filename + len - ext;
128 ESourceFileKind ret = kSFKNotC;
131 const char last = toupper(filename[len - 1]);
132 if (last ==
'H') ret = kSFKHeader;
133 else if (last ==
'C') ret = kSFKSource;
137 if (filename[len - 2] ==
'h' && filename[len - 1] ==
'h')
139 else if (filename[len - 2] ==
'c' && filename[len - 1] ==
'c')
144 const char last = filename[len - 1];
145 if ((last ==
'x' || last ==
'p')
146 && filename[len - 2] == last) {
147 if (filename[len - 3] ==
'h') ret = kSFKHeader;
148 else if (filename[len - 3] ==
'c') ret = kSFKSource;
158 std::pair<std::string, std::string> SplitPPDefine(
const std::string &in)
160 std::string::size_type posEq = in.find(
'=');
162 if (posEq == std::string::npos)
163 return std::make_pair(in,
"1");
166 return std::pair<std::string, std::string>
167 (in.substr(0, posEq), in.substr(posEq + 1, std::string::npos));
173 void TModuleGenerator::ParseArgs(
const std::vector<std::string> &args)
175 for (
size_t iPcmArg = 1 , nPcmArg = args.size();
176 iPcmArg < nPcmArg; ++iPcmArg) {
177 ESourceFileKind sfk = GetSourceFileKind(args[iPcmArg].c_str());
178 if (sfk == kSFKHeader || sfk == kSFKSource) {
179 fHeaders.push_back(args[iPcmArg]);
180 }
else if (sfk == kSFKLinkdef) {
181 fLinkDefFile = args[iPcmArg];
182 }
else if (sfk == kSFKNotC && args[iPcmArg][0] ==
'-') {
183 switch (args[iPcmArg][1]) {
185 if (args[iPcmArg] !=
"-I." && args[iPcmArg] !=
"-Iinclude") {
186 fCompI.push_back(args[iPcmArg].c_str() + 2);
190 if (args[iPcmArg] !=
"-DTRUE=1" && args[iPcmArg] !=
"-DFALSE=0"
191 && args[iPcmArg] !=
"-DG__NOCINTDLL") {
192 fCompD.push_back(SplitPPDefine(args[iPcmArg].c_str() + 2));
196 fCompU.push_back(args[iPcmArg].c_str() + 2);
209 std::ostream &TModuleGenerator::WritePPDefines(std::ostream &out)
const
211 for (
auto const & strPair : fCompD) {
212 std::string cppname(strPair.first);
213 size_t pos = cppname.find(
'(');
214 if (pos != std::string::npos) cppname.erase(pos);
215 out <<
"#ifndef " << cppname <<
"\n"
216 " #define " << strPair.first;
217 out <<
" " << strPair.second;
231 std::ostream &TModuleGenerator::WritePPUndefines(std::ostream &out)
const
233 for (
auto const & undef : fCompU) {
234 out <<
"#ifdef " << undef <<
"\n"
235 " #undef " << undef <<
"\n"
245 int WarnIfPragmaOnceDetected(
const std::string& fullHeaderPath,
246 const std::string& headerFileContent)
248 std::istringstream headerFile(headerFileContent);
250 while(std::getline(headerFile,line)){
251 llvm::StringRef lineRef (line);
252 auto trimmedLineRef = lineRef.trim();
253 if (trimmedLineRef.startswith(
"#pragma") &&
254 (trimmedLineRef.endswith(
" once") || trimmedLineRef.endswith(
"\tonce"))) {
255 std::cerr <<
"Error: #pragma once directive detected in header file "
257 <<
" which was requested to be inlined.\n";
266 int ExtractBufferContent(
const std::string& fullHeaderPath, std::string& bufferContent)
268 std::ifstream buffer(fullHeaderPath);
269 bufferContent = std::string((std::istreambuf_iterator<char>(buffer)),
270 std::istreambuf_iterator<char>());
272 return WarnIfPragmaOnceDetected(fullHeaderPath,bufferContent);
281 std::ostream &TModuleGenerator::WritePPIncludes(std::ostream &out)
const
283 std::string fullHeaderPath;
284 for (
auto const & incl : fHeaders) {
285 if (fInlineInputHeaders){
286 bool headerFound = FindHeader(incl,fullHeaderPath);
288 ROOT::TMetaUtils::Error(0,
"Cannot find header %s: cannot inline it.\n", fullHeaderPath.c_str());
292 std::string bufferContent;
293 fErrorCount += ExtractBufferContent(fullHeaderPath, bufferContent);
295 out << bufferContent << std::endl;
297 out <<
"#include \"" << incl <<
"\"\n";
306 std::ostream &TModuleGenerator::WriteStringVec(
const std::vector<std::string> &vec,
307 std::ostream &out)
const
309 for (
auto const & theStr : vec) {
310 out <<
"\"" << theStr <<
"\",\n";
312 out <<
"0" << std::endl;
318 std::ostream &TModuleGenerator::WriteStringPairVec(
const StringPairVec_t &vec,
319 std::ostream &out)
const
321 for (
auto const & strPair : vec) {
322 out <<
"\"" << strPair.first;
323 if (!strPair.second.empty()) {
326 for (
const char *c = strPair.second.c_str(); *c !=
'\0'; ++c) {
336 out <<
"0" << std::endl;
341 void TModuleGenerator::WriteRegistrationSourceImpl(std::ostream& out,
342 const std::string &dictName,
343 const std::string &demangledDictName,
344 const std::vector<std::string> &headerArray,
345 const std::vector<std::string> &includePathArray,
346 const std::string &fwdDeclStringRAW,
347 const std::string &fwdDeclnArgsToKeepString,
348 const std::string &payloadCodeWrapped,
349 const std::string &headersClassesMapString,
350 const std::string &extraIncludes,
351 bool hasCxxModule)
const
354 out <<
"namespace {\n"
355 " void TriggerDictionaryInitialization_" << dictName <<
"_Impl() {\n"
356 " static const char* headers[] = {\n";
357 WriteStringVec(headerArray, out) <<
" };\n";
358 out <<
" static const char* includePaths[] = {\n";
359 WriteStringVec(includePathArray, out)
362 out <<
" static const char* fwdDeclCode = " << fwdDeclStringRAW <<
";\n"
363 <<
" static const char* payloadCode = " << payloadCodeWrapped <<
";\n";
365 out <<
" static const char* classesHeaders[] = {\n"
366 << headersClassesMapString
368 out <<
" static bool isInitialized = false;\n"
369 " if (!isInitialized) {\n"
370 " TROOT::RegisterModule(\"" << demangledDictName <<
"\",\n"
371 " headers, includePaths, payloadCode, fwdDeclCode,\n"
372 " TriggerDictionaryInitialization_" << dictName <<
"_Impl, "
373 << fwdDeclnArgsToKeepString <<
", classesHeaders, "
374 << (hasCxxModule ?
"/*hasCxxModule*/true" :
"/*hasCxxModule*/false")
376 " isInitialized = true;\n"
379 " static struct DictInit {\n"
381 " TriggerDictionaryInitialization_" << dictName <<
"_Impl();\n"
383 " } __TheDictionaryInitializer;\n"
385 "void TriggerDictionaryInitialization_" << dictName <<
"() {\n"
386 " TriggerDictionaryInitialization_" << dictName <<
"_Impl();\n"
392 void TModuleGenerator::WriteRegistrationSource(std::ostream &out,
const std::string &fwdDeclnArgsToKeepString,
393 const std::string &headersClassesMapString,
394 const std::string &fwdDeclString,
const std::string &extraIncludes,
bool hasCxxModule)
const
397 std::string emptyStr =
"\"\"";
398 WriteRegistrationSourceImpl(out, GetDictionaryName(), GetDemangledDictionaryName(), {}, {},
400 emptyStr, headersClassesMapString,
"0",
405 std::string fwdDeclStringSanitized = fwdDeclString;
409 constexpr
char from[] =
"\n";
410 constexpr
char to[] =
"\n)DICTFWDDCLS\"\nR\"DICTFWDDCLS(";
411 size_t start_pos = 0;
412 while ((start_pos = fwdDeclStringSanitized.find(from, start_pos)) != std::string::npos) {
413 if (fwdDeclStringSanitized.find(from, start_pos + 1) == std::string::npos)
415 if ((fwdDeclStringSanitized.at(start_pos + 1) ==
'}') || (fwdDeclStringSanitized.at(start_pos + 1) ==
'\n'))
418 fwdDeclStringSanitized.replace(start_pos, strlen(from), to);
419 start_pos += strlen(to);
423 std::string fwdDeclStringRAW;
424 if (
"nullptr" == fwdDeclStringSanitized ||
"\"\"" == fwdDeclStringSanitized) {
425 fwdDeclStringRAW = fwdDeclStringSanitized;
427 fwdDeclStringRAW =
"R\"DICTFWDDCLS(\n";
428 fwdDeclStringRAW +=
"#line 1 \"";
429 fwdDeclStringRAW += fDictionaryName +
" dictionary forward declarations' payload\"\n";
430 fwdDeclStringRAW += fwdDeclStringSanitized;
431 fwdDeclStringRAW +=
")DICTFWDDCLS\"";
435 fwdDeclStringRAW =
"nullptr";
437 std::string payloadCode;
441 payloadCode +=
"#line 1 \"";
442 payloadCode += fDictionaryName +
" dictionary payload\"\n";
445 std::ostringstream definesAndUndefines;
455 WritePPUndefines(definesAndUndefines);
456 WritePPDefines(definesAndUndefines);
457 payloadCode += definesAndUndefines.str();
460 std::string hdrFullPath;
461 std::string inlinedHeaders;
463 auto findAndAddToInlineHeaders = [&](
const std::string& hdrName) {
464 bool headerFound = FindHeader(hdrName,hdrFullPath);
466 ROOT::TMetaUtils::Error(0,
"Cannot find header %s: cannot inline it.\n", hdrName.c_str());
468 std::ifstream headerFile(hdrFullPath.c_str());
469 const std::string headerFileAsStr((std::istreambuf_iterator<char>(headerFile)),
470 std::istreambuf_iterator<char>());
471 inlinedHeaders += headerFileAsStr;
475 if (fInlineInputHeaders) {
476 for (
auto const & hdrName : fHeaders) {
477 findAndAddToInlineHeaders(hdrName);
483 for (
auto & hdrName : fHeaders) {
484 inlinedHeaders +=
"#include \"" + hdrName +
"\"\n";
488 if (0 != fLinkDefFile.size() && !fIsPCH) {
489 findAndAddToInlineHeaders(fLinkDefFile);
499 payloadCode +=
"#define _BACKWARD_BACKWARD_WARNING_H\n"
500 "// Inline headers\n"+
501 inlinedHeaders +
"\n"+
502 (extraIncludes.empty() ?
"" :
"// Extra includes\n" + extraIncludes +
"\n") +
503 "#undef _BACKWARD_BACKWARD_WARNING_H\n";
508 std::vector<std::string> headerArray = {
"0"};
509 if (!fInlineInputHeaders)
510 headerArray = fHeaders;
511 const std::vector<std::string>& includePathArray = fCompI;
513 std::string payloadcodeWrapped =
"nullptr";
515 payloadcodeWrapped =
"R\"DICTPAYLOAD(\n" + payloadCode +
")DICTPAYLOAD\"";
517 WriteRegistrationSourceImpl(out, GetDictionaryName(),
518 GetDemangledDictionaryName(),
522 fwdDeclnArgsToKeepString,
524 headersClassesMapString,
536 void TModuleGenerator::WriteContentHeader(std::ostream &out)
const
538 out <<
"namespace ROOT { namespace Dict { namespace _"
539 << GetDictionaryName() <<
"{\n";
541 out <<
"const char* arrIncludes[] = {\n";
542 WriteHeaderArray(out) <<
"};\n";
544 out <<
"const char* arrIncludePaths[] = {\n";
545 WriteIncludePathArray(out) <<
"};\n";
553 out <<
"} } }" << std::endl;
560 bool TModuleGenerator::FindHeader(
const std::string &hdrName, std::string &hdrFullPath)
const
562 hdrFullPath = hdrName;
563 if (llvm::sys::fs::exists(hdrFullPath))
565 for (
auto const &incDir : fCompI) {
566 hdrFullPath = incDir + ROOT::TMetaUtils::GetPathSeparator() + hdrName;
567 if (llvm::sys::fs::exists(hdrFullPath)) {
571 clang::Preprocessor &PP = fCI->getPreprocessor();
572 clang::HeaderSearch &HdrSearch = PP.getHeaderSearchInfo();
573 const clang::DirectoryLookup *CurDir = 0;
574 if (
const clang::FileEntry *hdrFileEntry
575 = HdrSearch.LookupFile(hdrName, clang::SourceLocation(),
577 clang::ArrayRef<std::pair<
const clang::FileEntry*,
578 const clang::DirectoryEntry*>>(),
581 hdrFullPath = hdrFileEntry->getName();
595 void TModuleGenerator::WriteUmbrellaHeader(std::ostream &out)
const
598 WritePPUndefines(out);
599 WritePPIncludes(out);