Improve compilation database handling (#142)
Co-authored-by: star9029 <hengxings783@gmail.com>
This commit is contained in:
@@ -2,77 +2,12 @@
|
||||
#include "Compiler/Command.h"
|
||||
#include "Compiler/Compilation.h"
|
||||
#include "Support/FileSystem.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
|
||||
namespace clice {
|
||||
|
||||
std::expected<void, std::string> mangle_command(llvm::StringRef command,
|
||||
llvm::SmallVectorImpl<const char*>& out,
|
||||
llvm::SmallVectorImpl<char>& buffer) {
|
||||
llvm::SmallString<128> current;
|
||||
llvm::SmallVector<uint32_t> indices;
|
||||
bool inSingleQuote = false;
|
||||
bool inDoubleQuote = false;
|
||||
|
||||
for(size_t i = 0; i < command.size(); ++i) {
|
||||
char c = command[i];
|
||||
if(c == ' ' && !inSingleQuote && !inDoubleQuote) {
|
||||
if(!current.empty()) {
|
||||
indices.push_back(buffer.size());
|
||||
buffer.append(current);
|
||||
buffer.push_back('\0');
|
||||
current.clear();
|
||||
}
|
||||
} else if(c == '\'' && !inDoubleQuote) {
|
||||
inSingleQuote = !inSingleQuote;
|
||||
} else if(c == '"' && !inSingleQuote) {
|
||||
inDoubleQuote = !inDoubleQuote;
|
||||
} else {
|
||||
current.push_back(c);
|
||||
}
|
||||
}
|
||||
|
||||
if(!current.empty()) {
|
||||
indices.push_back(buffer.size());
|
||||
buffer.append(current);
|
||||
buffer.push_back('\0');
|
||||
}
|
||||
|
||||
/// Add resource directory.
|
||||
indices.push_back(buffer.size());
|
||||
current = std::format("-resource-dir={}", fs::resource_dir);
|
||||
buffer.append(current);
|
||||
buffer.push_back('\0');
|
||||
|
||||
/// FIXME: use better way to remove args.
|
||||
for(size_t i = 0; i < indices.size(); ++i) {
|
||||
llvm::StringRef arg(buffer.data() + indices[i]);
|
||||
|
||||
/// Skip `-c` and `-o` arguments.
|
||||
if(arg == "-c") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(arg.starts_with("-o")) {
|
||||
if(arg == "-o") {
|
||||
++i;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if(arg.starts_with("@CMakeFiles")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/// TODO: remove PCH.
|
||||
|
||||
out.push_back(arg.data());
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
/// Update the compile commands with the given file.
|
||||
void CompilationDatabase::updateCommands(llvm::StringRef filename) {
|
||||
void CompilationDatabase::update_commands(this Self& self, llvm::StringRef filename) {
|
||||
auto path = path::real_path(filename);
|
||||
filename = path;
|
||||
|
||||
@@ -140,12 +75,12 @@ void CompilationDatabase::updateCommands(llvm::StringRef filename) {
|
||||
continue;
|
||||
}
|
||||
|
||||
commands[path] = *command;
|
||||
self.add_command(path, *command);
|
||||
}
|
||||
|
||||
log::info("Successfully loaded compile commands from {0}, total {1} commands",
|
||||
filename,
|
||||
commands.size());
|
||||
self.commands.size());
|
||||
|
||||
/// Scan all files to build module map.
|
||||
// CompilationParams params;
|
||||
@@ -159,29 +94,16 @@ void CompilationDatabase::updateCommands(llvm::StringRef filename) {
|
||||
// }
|
||||
//}
|
||||
|
||||
log::info("Successfully built module map, total {0} modules", moduleMap.size());
|
||||
}
|
||||
|
||||
void CompilationDatabase::updateCommand(llvm::StringRef file, llvm::StringRef command) {
|
||||
commands[path::real_path(file)] = command;
|
||||
log::info("Successfully built module map, total {0} modules", self.moduleMap.size());
|
||||
}
|
||||
|
||||
/// Update the module map with the given file and module name.
|
||||
void CompilationDatabase::updateModule(llvm::StringRef file, llvm::StringRef name) {
|
||||
void CompilationDatabase::update_module(llvm::StringRef file, llvm::StringRef name) {
|
||||
moduleMap[path::real_path(file)] = file;
|
||||
}
|
||||
|
||||
/// Lookup the compile commands of the given file.
|
||||
llvm::StringRef CompilationDatabase::getCommand(llvm::StringRef file) {
|
||||
auto iter = commands.find(file);
|
||||
if(iter == commands.end()) {
|
||||
return "";
|
||||
}
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
/// Lookup the module interface unit file path of the given module name.
|
||||
llvm::StringRef CompilationDatabase::getModuleFile(llvm::StringRef name) {
|
||||
llvm::StringRef CompilationDatabase::get_module_file(llvm::StringRef name) {
|
||||
auto iter = moduleMap.find(name);
|
||||
if(iter == moduleMap.end()) {
|
||||
return "";
|
||||
@@ -189,4 +111,81 @@ llvm::StringRef CompilationDatabase::getModuleFile(llvm::StringRef name) {
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
llvm::StringRef CompilationDatabase::save_string(this Self& self, llvm::StringRef string) {
|
||||
auto it = self.unique.find(string);
|
||||
|
||||
/// FIXME: arg may be empty?
|
||||
|
||||
/// If we already store the argument, reuse it.
|
||||
if(it != self.unique.end()) {
|
||||
return *it;
|
||||
}
|
||||
|
||||
/// Allocate new argument.
|
||||
const auto size = string.size();
|
||||
auto ptr = self.memory_pool.Allocate<char>(size + 1);
|
||||
std::memcpy(ptr, string.data(), size);
|
||||
ptr[size] = '\0';
|
||||
|
||||
/// Insert new argument.
|
||||
auto result = llvm::StringRef(ptr, size);
|
||||
self.unique.insert(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<const char*> CompilationDatabase::save_args(this Self& self,
|
||||
llvm::ArrayRef<const char*> args) {
|
||||
std::vector<const char*> result;
|
||||
result.reserve(args.size());
|
||||
|
||||
for(auto i = 0; i < args.size(); i++) {
|
||||
result.emplace_back(self.save_string(args[i]).data());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void CompilationDatabase::add_command(this Self& self,
|
||||
llvm::StringRef path,
|
||||
llvm::StringRef command,
|
||||
Style style) {
|
||||
llvm::SmallVector<const char*> args;
|
||||
|
||||
/// temporary allocator to meet the argument requirements of tokenize.
|
||||
llvm::BumpPtrAllocator allocator;
|
||||
llvm::StringSaver saver(allocator);
|
||||
|
||||
/// FIXME: we may want to check the first argument of command to
|
||||
/// make sure its mode.
|
||||
if(style == Style::GNU) {
|
||||
llvm::cl::TokenizeGNUCommandLine(command, saver, args);
|
||||
} else if(style == Style::MSVC) {
|
||||
llvm::cl::TokenizeWindowsCommandLineFull(command, saver, args);
|
||||
} else {
|
||||
std::abort();
|
||||
}
|
||||
|
||||
auto path_ = self.save_string(path);
|
||||
auto new_args = self.save_args(args);
|
||||
|
||||
auto it = self.commands.find(path_.data());
|
||||
if(it == self.commands.end()) {
|
||||
self.commands.try_emplace(path_.data(),
|
||||
std::make_unique<std::vector<const char*>>(std::move(new_args)));
|
||||
} else {
|
||||
*it->second = std::move(new_args);
|
||||
}
|
||||
}
|
||||
|
||||
llvm::ArrayRef<const char*> CompilationDatabase::get_command(this Self& self,
|
||||
llvm::StringRef path) {
|
||||
auto path_ = self.save_string(path);
|
||||
auto it = self.commands.find(path_.data());
|
||||
if(it != self.commands.end()) {
|
||||
return *it->second;
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace clice
|
||||
|
||||
@@ -42,18 +42,13 @@ auto create_invocation(CompilationParams& params,
|
||||
llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine>& diagnostic_engine)
|
||||
-> std::expected<std::unique_ptr<clang::CompilerInvocation>, std::string> {
|
||||
|
||||
/// Split orgin command into c-style command arguments for creating invocation.
|
||||
llvm::SmallString<1024> buffer;
|
||||
llvm::SmallVector<const char*, 32> args;
|
||||
TRY_OR_RETURN(mangle_command(params.command, args, buffer));
|
||||
|
||||
/// Create clang invocation.
|
||||
clang::CreateInvocationOptions options = {
|
||||
.Diags = diagnostic_engine,
|
||||
.VFS = params.vfs,
|
||||
};
|
||||
|
||||
auto invocation = clang::createInvocation(args, options);
|
||||
auto invocation = clang::createInvocation(params.arguments, options);
|
||||
if(!invocation) {
|
||||
return report_diagnostics("fail to create compiler invocation", *diagnostics);
|
||||
}
|
||||
@@ -221,7 +216,7 @@ std::expected<CompilationUnit, std::string> compile(CompilationParams& params, P
|
||||
|
||||
out.path = params.outPath.str();
|
||||
/// out.preamble = params.content.substr(0, *params.bound);
|
||||
out.command = params.command.str();
|
||||
/// out.command = params.arguments.str();
|
||||
/// FIXME: out.deps = info->deps();
|
||||
|
||||
return clang_compile<clang::GeneratePCHAction>(params, [&](clang::CompilerInstance& instance) {
|
||||
|
||||
@@ -47,7 +47,7 @@ async::Task<> Indexer::index(CompilationUnit& unit) {
|
||||
|
||||
async::Task<> Indexer::index(llvm::StringRef file) {
|
||||
CompilationParams params;
|
||||
params.command = database.getCommand(file);
|
||||
params.arguments = database.get_command(file);
|
||||
|
||||
auto AST = co_await async::submit([&] { return compile(params); });
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ async::Task<json::Value> Scheduler::completion(std::string path, std::uint32_t o
|
||||
|
||||
/// Set compilation params ... .
|
||||
CompilationParams params;
|
||||
params.command = database.getCommand(path);
|
||||
params.arguments = database.get_command(path);
|
||||
params.add_remapped_file(path, openFile->content);
|
||||
params.pch = {PCH->path, PCH->preamble.size()};
|
||||
params.completion = {path, offset};
|
||||
@@ -74,8 +74,9 @@ async::Task<bool> Scheduler::isPCHOutdated(llvm::StringRef path, llvm::StringRef
|
||||
}
|
||||
|
||||
/// Check command and preamble matchs.
|
||||
auto command = database.getCommand(path);
|
||||
if(openFile->PCH->command != command || openFile->PCH->preamble != preamble) {
|
||||
auto command = database.get_command(path);
|
||||
/// FIXME: check command. openFile->PCH->command != command
|
||||
if(openFile->PCH->preamble != preamble) {
|
||||
co_return true;
|
||||
}
|
||||
|
||||
@@ -104,7 +105,7 @@ async::Task<> Scheduler::buildPCH(std::string path, std::string content) {
|
||||
std::uint32_t bound,
|
||||
std::string content) -> async::Task<> {
|
||||
CompilationParams params;
|
||||
params.command = scheduler.database.getCommand(path);
|
||||
params.arguments = scheduler.database.get_command(path);
|
||||
params.outPath = path::join(config::index.dir, path::filename(path) + ".pch");
|
||||
params.add_remapped_file(path, content, bound);
|
||||
|
||||
@@ -161,7 +162,7 @@ async::Task<> Scheduler::buildAST(std::string path, std::string content) {
|
||||
}
|
||||
|
||||
CompilationParams params;
|
||||
params.command = database.getCommand(path);
|
||||
params.arguments = database.get_command(path);
|
||||
params.add_remapped_file(path, content);
|
||||
params.pch = {PCH->path, PCH->preamble.size()};
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ async::Task<json::Value> Server::onInitialize(json::Value value) {
|
||||
config::init(converter.workspace());
|
||||
|
||||
for(auto& dir: config::server.compile_commands_dirs) {
|
||||
database.updateCommands(dir + "/compile_commands.json");
|
||||
database.update_commands(dir + "/compile_commands.json");
|
||||
}
|
||||
|
||||
co_return result;
|
||||
|
||||
Reference in New Issue
Block a user