mirror of
https://github.com/MaskRay/ccls.git
synced 2025-01-19 03:55:49 +00:00
Add Config::compilationDatabaseCommand
If specified, this is an external command that provides the JSON compilation database, instead of compile_commands.json
This commit is contained in:
parent
d33bf50181
commit
f9d7361953
@ -23,6 +23,11 @@ initialization options specified by the client. For example, in shell syntax:
|
|||||||
struct Config {
|
struct Config {
|
||||||
// Root directory of the project. **Not available for configuration**
|
// Root directory of the project. **Not available for configuration**
|
||||||
std::string projectRoot;
|
std::string projectRoot;
|
||||||
|
// If specified, this option overrides compile_commands.json and this
|
||||||
|
// external command will be executed with an option |projectRoot|.
|
||||||
|
// The initialization options will be provided as stdin.
|
||||||
|
// The stdout of the command should be the JSON compilation database.
|
||||||
|
std::string compilationDatabaseCommand;
|
||||||
// Directory containing compile_commands.json.
|
// Directory containing compile_commands.json.
|
||||||
std::string compilationDatabaseDirectory;
|
std::string compilationDatabaseDirectory;
|
||||||
// Cache directory for indexed files.
|
// Cache directory for indexed files.
|
||||||
@ -191,6 +196,7 @@ MAKE_REFLECT_STRUCT(Config::Completion, filterAndSort, detailedLabel);
|
|||||||
MAKE_REFLECT_STRUCT(Config::Extension, referenceContainer);
|
MAKE_REFLECT_STRUCT(Config::Extension, referenceContainer);
|
||||||
MAKE_REFLECT_STRUCT(Config::Index, comments, attributeMakeCallsToCtor);
|
MAKE_REFLECT_STRUCT(Config::Index, comments, attributeMakeCallsToCtor);
|
||||||
MAKE_REFLECT_STRUCT(Config,
|
MAKE_REFLECT_STRUCT(Config,
|
||||||
|
compilationDatabaseCommand,
|
||||||
compilationDatabaseDirectory,
|
compilationDatabaseDirectory,
|
||||||
cacheDirectory,
|
cacheDirectory,
|
||||||
cacheFormat,
|
cacheFormat,
|
||||||
|
@ -330,8 +330,8 @@ IndexFile* ConsumeFile(IndexParam* param, CXFile file) {
|
|||||||
// generating an index for it):
|
// generating an index for it):
|
||||||
if (param->seen_cx_files.insert(file).second) {
|
if (param->seen_cx_files.insert(file).second) {
|
||||||
std::string file_name = FileName(file);
|
std::string file_name = FileName(file);
|
||||||
// Sometimes the fill name will be empty. Not sure why. Not much we can do
|
// file_name may be empty when it contains .. and is outside of WorkingDir.
|
||||||
// with it.
|
// https://reviews.llvm.org/D42893 https://github.com/cquery-project/cquery/issues/413
|
||||||
if (!file_name.empty()) {
|
if (!file_name.empty()) {
|
||||||
// Add to all files we have seen so we can generate proper dependency
|
// Add to all files we have seen so we can generate proper dependency
|
||||||
// graph.
|
// graph.
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <optional.h>
|
#include <optional.h>
|
||||||
|
#include <string_view.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -49,4 +50,8 @@ void FreeUnusedMemory();
|
|||||||
// If true objective-c index tests will be run.
|
// If true objective-c index tests will be run.
|
||||||
bool RunObjectiveCIndexTests();
|
bool RunObjectiveCIndexTests();
|
||||||
|
|
||||||
|
// Stop self and wait for SIGCONT.
|
||||||
void TraceMe();
|
void TraceMe();
|
||||||
|
|
||||||
|
std::string GetExternalCommandOutput(const std::vector<std::string>& command,
|
||||||
|
std::string_view input);
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h> // required for stat.h
|
#include <sys/types.h> // required for stat.h
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@ -285,4 +286,37 @@ void TraceMe() {
|
|||||||
raise(SIGTSTP);
|
raise(SIGTSTP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string GetExternalCommandOutput(const std::vector<std::string>& command,
|
||||||
|
std::string_view input) {
|
||||||
|
int pin[2], pout[2];
|
||||||
|
pipe(pin);
|
||||||
|
pipe(pout);
|
||||||
|
pid_t child = fork();
|
||||||
|
if (child == 0) {
|
||||||
|
dup2(pout[0], 0);
|
||||||
|
dup2(pin[1], 1);
|
||||||
|
close(pin[0]);
|
||||||
|
close(pin[1]);
|
||||||
|
close(pout[0]);
|
||||||
|
close(pout[1]);
|
||||||
|
auto argv = new char*[command.size() + 1];
|
||||||
|
for (size_t i = 0; i < command.size(); i++)
|
||||||
|
argv[i] = const_cast<char*>(command[i].c_str());
|
||||||
|
argv[command.size()] = nullptr;
|
||||||
|
execvp(argv[0], argv);
|
||||||
|
_Exit(127);
|
||||||
|
}
|
||||||
|
close(pin[1]);
|
||||||
|
close(pout[0]);
|
||||||
|
write(pout[1], input.data(), input.size());
|
||||||
|
close(pout[1]);
|
||||||
|
std::string ret;
|
||||||
|
char buf[4096];
|
||||||
|
ssize_t n;
|
||||||
|
while ((n = read(pin[0], buf, sizeof buf)) > 0)
|
||||||
|
ret.append(buf, n);
|
||||||
|
waitpid(child, NULL, 0);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -152,4 +152,9 @@ bool RunObjectiveCIndexTests() {
|
|||||||
// TODO Wait for debugger to attach
|
// TODO Wait for debugger to attach
|
||||||
void TraceMe() {}
|
void TraceMe() {}
|
||||||
|
|
||||||
|
std::string GetExternalCommandOutput(const std::vector<std::string>& command,
|
||||||
|
std::string_view input) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -11,6 +11,11 @@
|
|||||||
#include <doctest/doctest.h>
|
#include <doctest/doctest.h>
|
||||||
#include <loguru.hpp>
|
#include <loguru.hpp>
|
||||||
|
|
||||||
|
#if defined(__unix__) || defined(__APPLE__)
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@ -348,17 +353,48 @@ std::vector<Project::Entry> LoadCompilationEntriesFromDirectory(
|
|||||||
if (FileExists(config->project_dir + "/.cquery"))
|
if (FileExists(config->project_dir + "/.cquery"))
|
||||||
return LoadFromDirectoryListing(init_opts, config);
|
return LoadFromDirectoryListing(init_opts, config);
|
||||||
|
|
||||||
|
// If |compilationDatabaseCommand| is specified, execute it to get the compdb.
|
||||||
|
std::string comp_db_dir;
|
||||||
|
if (init_opts->compilationDatabaseCommand.empty()) {
|
||||||
// Try to load compile_commands.json, but fallback to a project listing.
|
// Try to load compile_commands.json, but fallback to a project listing.
|
||||||
const auto& compilation_db_dir = opt_compilation_db_dir.empty()
|
comp_db_dir = opt_compilation_db_dir.empty() ? config->project_dir
|
||||||
? config->project_dir
|
|
||||||
: opt_compilation_db_dir;
|
: opt_compilation_db_dir;
|
||||||
|
} else {
|
||||||
|
#ifdef _WIN32
|
||||||
|
// TODO
|
||||||
|
#else
|
||||||
|
char tmpdir[] = "/tmp/cquery-compdb-XXXXXX";
|
||||||
|
if (!mkdtemp(tmpdir))
|
||||||
|
return {};
|
||||||
|
comp_db_dir = tmpdir;
|
||||||
|
rapidjson::StringBuffer input;
|
||||||
|
rapidjson::Writer<rapidjson::StringBuffer> writer(input);
|
||||||
|
JsonWriter json_writer(&writer);
|
||||||
|
Reflect(json_writer, *init_opts);
|
||||||
|
std::string contents = GetExternalCommandOutput(
|
||||||
|
std::vector<std::string>{init_opts->compilationDatabaseCommand,
|
||||||
|
config->project_dir},
|
||||||
|
input.GetString());
|
||||||
|
std::ofstream(comp_db_dir + "/compile_commands.json") << contents;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
LOG_S(INFO) << "Trying to load compile_commands.json";
|
LOG_S(INFO) << "Trying to load compile_commands.json";
|
||||||
CXCompilationDatabase_Error cx_db_load_error;
|
CXCompilationDatabase_Error cx_db_load_error;
|
||||||
CXCompilationDatabase cx_db = clang_CompilationDatabase_fromDirectory(
|
CXCompilationDatabase cx_db = clang_CompilationDatabase_fromDirectory(
|
||||||
compilation_db_dir.c_str(), &cx_db_load_error);
|
comp_db_dir.c_str(), &cx_db_load_error);
|
||||||
|
if (!init_opts->compilationDatabaseCommand.empty()) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
// TODO
|
||||||
|
#else
|
||||||
|
unlink((comp_db_dir + "/compile_commands.json").c_str());
|
||||||
|
rmdir(comp_db_dir.c_str());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
if (cx_db_load_error == CXCompilationDatabase_CanNotLoadDatabase) {
|
if (cx_db_load_error == CXCompilationDatabase_CanNotLoadDatabase) {
|
||||||
LOG_S(INFO) << "Unable to load compile_commands.json located at \""
|
LOG_S(INFO) << "Unable to load compile_commands.json located at \""
|
||||||
<< compilation_db_dir << "\"; using directory listing instead.";
|
<< comp_db_dir << "\"; using directory listing instead.";
|
||||||
return LoadFromDirectoryListing(init_opts, config);
|
return LoadFromDirectoryListing(init_opts, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -416,7 +452,6 @@ std::vector<Project::Entry> LoadCompilationEntriesFromDirectory(
|
|||||||
|
|
||||||
clang_time.ResetAndPrint("compile_commands.json clang time");
|
clang_time.ResetAndPrint("compile_commands.json clang time");
|
||||||
our_time.ResetAndPrint("compile_commands.json our time");
|
our_time.ResetAndPrint("compile_commands.json our time");
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user