Files
clice/src/Compiler/Compiler.cpp
2024-10-13 15:46:20 +08:00

150 lines
5.1 KiB
C++

#include <Compiler/Compiler.h>
#include <Compiler/Preamble.h>
#include <clang/Lex/PreprocessorOptions.h>
namespace clice {
static void setInvocation(clang::CompilerInvocation& invocation) {
clang::LangOptions& langOpts = invocation.getLangOpts();
langOpts.CommentOpts.ParseAllComments = true;
langOpts.RetainCommentsFromSystemHeaders = true;
}
std::unique_ptr<clang::CompilerInvocation>
createInvocation(StringRef filename, StringRef content, llvm::ArrayRef<const char*> args, Preamble* preamble) {
clang::CreateInvocationOptions options;
// FIXME: explore VFS
auto vfs = llvm::vfs::getRealFileSystem();
// TODO: figure out should we use createInvocation?
auto invocation = clang::createInvocation(args, options);
// setInvocation(*invocation);
auto buffer = llvm::MemoryBuffer::getMemBufferCopy(content, filename);
if(preamble) {
auto bounds = clang::ComputePreambleBounds(invocation->getLangOpts(), *buffer, false);
// check if the preamble can be reused
if(preamble->data.CanReuse(*invocation, *buffer, bounds, *vfs)) {
llvm::outs() << "Resued preamble\n";
// reuse preamble
preamble->data.AddImplicitPreamble(*invocation, vfs, buffer.release());
}
} else {
invocation->getPreprocessorOpts().addRemappedFile(invocation->getFrontendOpts().Inputs[0].getFile(),
buffer.release());
}
return invocation;
}
std::unique_ptr<clang::CompilerInstance> createInstance(std::shared_ptr<clang::CompilerInvocation> invocation) {
auto instance = std::make_unique<clang::CompilerInstance>();
instance->setInvocation(std::move(invocation));
// FIXME: resolve diagnostics
instance->createDiagnostics(new clang::TextDiagnosticPrinter(llvm::outs(), new clang::DiagnosticOptions()), true);
if(!instance->createTarget()) {
llvm::errs() << "Failed to create target\n";
std::terminate();
}
return instance;
}
void buildModule() {
clang::CompilerInvocation invocation;
invocation.getLangOpts().SkipODRCheckInGMF = true;
auto& search = invocation.getHeaderSearchOpts();
search.ValidateASTInputFilesContent = true;
// TODO: insert all module name with their corresponding module files.
auto& prebuilts = search.PrebuiltModuleFiles;
// TODO: must set pcm output file.
auto& frontend = invocation.getFrontendOpts();
frontend.OutputFile = "...";
auto instance = createInstance(std::make_shared<clang::CompilerInvocation>(invocation));
clang::GenerateReducedModuleInterfaceAction action;
instance->ExecuteAction(action);
// TODO: check this.
instance->getDiagnostics().hasErrorOccurred();
}
void Compiler::buildPCH(llvm::StringRef filename, llvm::StringRef content, llvm::ArrayRef<const char*> args) {
// compute preamble bounds, i.e. the range of the preamble.
// if MaxLines set to false(0), i.e. limit the number of lines.
auto bounds = clang::Lexer::ComputePreamble(content, {}, false);
auto invocation = createInvocation(filename, content.substr(0, bounds.Size), args);
auto instance = createInstance(std::move(invocation));
auto& frontend = instance->getFrontendOpts();
frontend.OutputFile = "/home/ykiko/C++/clice2/build/cache/xxx.pch";
auto& preproc = instance->getPreprocessorOpts();
preproc.PrecompiledPreambleBytes.first = 0;
preproc.PrecompiledPreambleBytes.second = false;
preproc.GeneratePreamble = true;
llvm::outs() << "bounds size: " << bounds.Size << "\n";
// use to collect information in the process of building preamble, such as include files and macros
// TODO: inherit from clang::PreambleCallbacks and collect the information
clang::PreambleCallbacks callbacks = {};
auto action = clang::GeneratePCHAction();
if(!action.BeginSourceFile(*instance, instance->getFrontendOpts().Inputs[0])) {
llvm::errs() << "Failed to begin source file\n";
std::terminate();
}
if(auto error = action.Execute()) {
llvm::errs() << "Failed to execute action: " << error << "\n";
std::terminate();
}
instance->getASTContext().getTranslationUnitDecl()->dump();
action.EndSourceFile();
// auto err = instance->ExecuteAction(action);
//
////
//
// if(!err) {
// llvm::outs() << "Error has occured!!";
// std::terminate();
//}
}
void Compiler::applyPCH(clang::CompilerInvocation& invocation,
llvm::StringRef filename,
llvm::StringRef content,
llvm::StringRef filepath) {
auto bounds = clang::Lexer::ComputePreamble(content, invocation.getLangOpts(), false);
auto& PreprocessorOpts = invocation.getPreprocessorOpts();
PreprocessorOpts.PrecompiledPreambleBytes.first = bounds.Size;
PreprocessorOpts.PrecompiledPreambleBytes.second = bounds.PreambleEndsAtStartOfLine;
PreprocessorOpts.DisablePCHOrModuleValidation = clang::DisableValidationForModuleKind::PCH;
// key point
PreprocessorOpts.ImplicitPCHInclude = filepath;
PreprocessorOpts.UsePredefines = false;
}
} // namespace clice