Support inclusion of precompiled header from header search paths.

This commit is contained in:
Frederich Munch 2016-09-08 17:15:38 -04:00 committed by sftnight
parent a757a424a3
commit e10447fe92
4 changed files with 120 additions and 32 deletions

View File

@ -13,6 +13,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include <string>
#include <vector>
namespace llvm {
class raw_ostream;
@ -20,6 +21,7 @@ namespace llvm {
namespace clang {
class HeaderSearchOptions;
class FileManager;
}
namespace cling {
@ -66,6 +68,23 @@ namespace cling {
llvm::StringRef Delim = platform::kEnvDelim,
bool Verbose = false);
///\brief Look for given file that can be reachable from current working
/// directory or any user supplied include paths in Args. This is useful
/// to look for a file (precompiled header) before a Preprocessor instance
/// has been created.
///
/// \param [in] Args - The argv vector to look for '-I' & '/I' flags
/// \param [in/out] File - File to look for, may mutate to an absolute path
/// \param [in] FM - File manger to resolve current dir with (can be null)
/// \param [in] FileType - File type for logging or nullptr for no logging
///
/// \return true if File is reachable and is a regular file
///
bool LookForFile(const std::vector<const char*>& Args, std::string& File,
const clang::FileManager* FM = nullptr,
const char* FileType = nullptr);
///\brief Adds multiple include paths separated by a delimter into the
/// given HeaderSearchOptions. This adds the paths but does no further
/// processing. See Interpreter::AddIncludePaths or CIFactory::createCI

View File

@ -666,44 +666,48 @@ static void stringifyPreprocSetting(PreprocessorOptions& PPOpts,
std::unique_ptr<CompilerInstance> CI(new CompilerInstance());
CI->createFileManager();
llvm::StringRef PCHFileName
std::string& PCHFileName
= Invocation->getPreprocessorOpts().ImplicitPCHInclude;
if (!PCHFileName.empty()) {
// Load target options etc from PCH.
struct PCHListener: public ASTReaderListener {
CompilerInvocation& m_Invocation;
if (cling::utils::LookForFile(argvCompile, PCHFileName,
&CI->getFileManager(),
COpts.Verbose ? "Precompiled header" : nullptr)) {
// Load target options etc from PCH.
struct PCHListener: public ASTReaderListener {
CompilerInvocation& m_Invocation;
PCHListener(CompilerInvocation& I): m_Invocation(I) {}
PCHListener(CompilerInvocation& I): m_Invocation(I) {}
bool ReadLanguageOptions(const LangOptions &LangOpts,
bool ReadLanguageOptions(const LangOptions &LangOpts,
bool /*Complain*/,
bool /*AllowCompatibleDifferences*/) override {
*m_Invocation.getLangOpts() = LangOpts;
return false;
}
bool ReadTargetOptions(const TargetOptions &TargetOpts,
bool /*Complain*/,
bool /*AllowCompatibleDifferences*/) override {
*m_Invocation.getLangOpts() = LangOpts;
return false;
}
bool ReadTargetOptions(const TargetOptions &TargetOpts,
bool /*Complain*/,
bool /*AllowCompatibleDifferences*/) override {
m_Invocation.getTargetOpts() = TargetOpts;
return false;
}
bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
bool /*Complain*/,
std::string &/*SuggestedPredefines*/) override {
// Import selected options, e.g. don't overwrite ImplicitPCHInclude.
PreprocessorOptions& myPP = m_Invocation.getPreprocessorOpts();
insertBehind(myPP.Macros, PPOpts.Macros);
insertBehind(myPP.Includes, PPOpts.Includes);
insertBehind(myPP.MacroIncludes, PPOpts.MacroIncludes);
return false;
}
};
PCHListener listener(*Invocation);
ASTReader::readASTFileControlBlock(PCHFileName,
CI->getFileManager(),
CI->getPCHContainerReader(),
false /*FindModuleFileExtensions*/,
listener);
m_Invocation.getTargetOpts() = TargetOpts;
return false;
}
bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
bool /*Complain*/,
std::string &/*SuggestedPredefines*/) override {
// Import selected options, e.g. don't overwrite ImplicitPCHInclude.
PreprocessorOptions& myPP = m_Invocation.getPreprocessorOpts();
insertBehind(myPP.Macros, PPOpts.Macros);
insertBehind(myPP.Includes, PPOpts.Includes);
insertBehind(myPP.MacroIncludes, PPOpts.MacroIncludes);
return false;
}
};
PCHListener listener(*Invocation);
ASTReader::readASTFileControlBlock(PCHFileName,
CI->getFileManager(),
CI->getPCHContainerReader(),
false /*FindModuleFileExtensions*/,
listener);
}
}
Invocation->getFrontendOpts().DisableFree = true;

View File

@ -9,9 +9,11 @@
#include "cling/Utils/Paths.h"
#include "cling/Utils/Output.h"
#include "clang/Basic/FileManager.h"
#include "clang/Lex/HeaderSearchOptions.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
namespace cling {
namespace utils {
@ -150,6 +152,65 @@ void LogNonExistantDirectory(llvm::StringRef Path) {
cling::log() << " ignoring nonexistent directory \"" << Path << "\"\n";
}
static void LogFileStatus(const char* Prefix, const char* FileType,
llvm::StringRef Path) {
cling::log() << Prefix << " " << FileType << " '" << Path << "'\n";
}
bool LookForFile(const std::vector<const char*>& Args, std::string& Path,
const clang::FileManager* FM, const char* FileType) {
if (llvm::sys::fs::is_regular_file(Path)) {
if (FileType)
LogFileStatus("Using", FileType, Path);
return true;
}
if (FileType)
LogFileStatus("Ignoring", FileType, Path);
SmallString<1024> FilePath;
if (FM) {
FilePath.assign(Path);
if (FM->FixupRelativePath(FilePath) &&
llvm::sys::fs::is_regular_file(FilePath)) {
if (FileType)
LogFileStatus("Using", FileType, FilePath.str());
Path = FilePath.str();
return true;
}
// Don't write same same log entry twice when FilePath == Path
if (FileType && !FilePath.str().equals(Path))
LogFileStatus("Ignoring", FileType, FilePath);
}
else if (llvm::sys::path::is_absolute(Path))
return false;
for (std::vector<const char*>::const_iterator It = Args.begin(),
End = Args.end(); It < End; ++It) {
const char* Arg = *It;
// TODO: Suppport '-iquote' and MSVC equivalent
if (!::strncmp("-I", Arg, 2) || !::strncmp("/I", Arg, 2)) {
if (!Arg[2]) {
if (++It >= End)
break;
FilePath.assign(*It);
}
else
FilePath.assign(Arg + 2);
llvm::sys::path::append(FilePath, Path.c_str());
if (llvm::sys::fs::is_regular_file(FilePath)) {
if (FileType)
LogFileStatus("Using", FileType, FilePath.str());
Path = FilePath.str();
return true;
}
if (FileType)
LogFileStatus("Ignoring", FileType, FilePath);
}
}
return false;
}
bool SplitPaths(llvm::StringRef PathStr,
llvm::SmallVectorImpl<llvm::StringRef>& Paths,
SplitMode Mode, llvm::StringRef Delim, bool Verbose) {

View File

@ -1,6 +1,10 @@
// RUN: mkdir -p %T/Rel/Path
// RUN: rm -f CompGen.h.pch
// RUN: rm -f %T/Rel/Path/Relative.pch
// RUN: clang -x c++-header -fexceptions -fcxx-exceptions -std=c++14 -pthread %S/Inputs/CompGen.h -o CompGen.h.pch
// RUN: clang -x c++-header -fexceptions -fcxx-exceptions -std=c++14 -pthread %S/Inputs/CompGen.h -o %T/Rel/Path/Relative.pch
// RUN: cat %s | %cling -I%p -Xclang -include-pch -Xclang CompGen.h.pch 2>&1 | FileCheck %s
// RUN: cat %s | %cling -I%p -I%T/Rel/Path -include-pch Relative.pch 2>&1 | FileCheck %s
//.storeState "a"
.x TriggerCompGen.h