Skip to content

Commit

Permalink
Add Config::compilationDatabaseCommand
Browse files Browse the repository at this point in the history
If specified, this is an external command that provides the JSON compilation database, instead of compile_commands.json
  • Loading branch information
MaskRay committed Feb 20, 2018
1 parent d33bf50 commit f9d7361
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 9 deletions.
6 changes: 6 additions & 0 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ initialization options specified by the client. For example, in shell syntax:
struct Config {
// Root directory of the project. **Not available for configuration**
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.
std::string compilationDatabaseDirectory;
// Cache directory for indexed files.
Expand Down Expand Up @@ -191,6 +196,7 @@ MAKE_REFLECT_STRUCT(Config::Completion, filterAndSort, detailedLabel);
MAKE_REFLECT_STRUCT(Config::Extension, referenceContainer);
MAKE_REFLECT_STRUCT(Config::Index, comments, attributeMakeCallsToCtor);
MAKE_REFLECT_STRUCT(Config,
compilationDatabaseCommand,
compilationDatabaseDirectory,
cacheDirectory,
cacheFormat,
Expand Down
4 changes: 2 additions & 2 deletions src/indexer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -330,8 +330,8 @@ IndexFile* ConsumeFile(IndexParam* param, CXFile file) {
// generating an index for it):
if (param->seen_cx_files.insert(file).second) {
std::string file_name = FileName(file);
// Sometimes the fill name will be empty. Not sure why. Not much we can do
// with it.
// file_name may be empty when it contains .. and is outside of WorkingDir.
// https://reviews.llvm.org/D42893 https://github.com/cquery-project/cquery/issues/413
if (!file_name.empty()) {
// Add to all files we have seen so we can generate proper dependency
// graph.
Expand Down
5 changes: 5 additions & 0 deletions src/platform.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <optional.h>
#include <string_view.h>

#include <memory>
#include <string>
Expand Down Expand Up @@ -49,4 +50,8 @@ void FreeUnusedMemory();
// If true objective-c index tests will be run.
bool RunObjectiveCIndexTests();

// Stop self and wait for SIGCONT.
void TraceMe();

std::string GetExternalCommandOutput(const std::vector<std::string>& command,
std::string_view input);
34 changes: 34 additions & 0 deletions src/platform_posix.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h> // required for stat.h
#include <sys/wait.h>

#include <errno.h>
#include <fcntl.h>
Expand Down Expand Up @@ -285,4 +286,37 @@ void TraceMe() {
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
5 changes: 5 additions & 0 deletions src/platform_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -152,4 +152,9 @@ bool RunObjectiveCIndexTests() {
// TODO Wait for debugger to attach
void TraceMe() {}

std::string GetExternalCommandOutput(const std::vector<std::string>& command,
std::string_view input) {
return "";
}

#endif
49 changes: 42 additions & 7 deletions src/project.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@
#include <doctest/doctest.h>
#include <loguru.hpp>

#if defined(__unix__) || defined(__APPLE__)
#include <unistd.h>
#endif

#include <fstream>
#include <iostream>
#include <limits>
#include <sstream>
Expand Down Expand Up @@ -348,17 +353,48 @@ std::vector<Project::Entry> LoadCompilationEntriesFromDirectory(
if (FileExists(config->project_dir + "/.cquery"))
return LoadFromDirectoryListing(init_opts, config);

// Try to load compile_commands.json, but fallback to a project listing.
const auto& compilation_db_dir = opt_compilation_db_dir.empty()
? config->project_dir
: opt_compilation_db_dir;
// 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.
comp_db_dir = opt_compilation_db_dir.empty() ? config->project_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";
CXCompilationDatabase_Error cx_db_load_error;
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) {
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);
}

Expand Down Expand Up @@ -416,7 +452,6 @@ std::vector<Project::Entry> LoadCompilationEntriesFromDirectory(

clang_time.ResetAndPrint("compile_commands.json clang time");
our_time.ResetAndPrint("compile_commands.json our time");

return result;
}

Expand Down

0 comments on commit f9d7361

Please sign in to comment.