mirror of
				https://github.com/MaskRay/ccls.git
				synced 2025-11-04 06:15:20 +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 {
 | 
			
		||||
  // 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.
 | 
			
		||||
@ -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,
 | 
			
		||||
 | 
			
		||||
@ -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.
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <optional.h>
 | 
			
		||||
#include <string_view.h>
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <string>
 | 
			
		||||
@ -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);
 | 
			
		||||
 | 
			
		||||
@ -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>
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -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>
 | 
			
		||||
@ -348,17 +353,48 @@ std::vector<Project::Entry> LoadCompilationEntriesFromDirectory(
 | 
			
		||||
  if (FileExists(config->project_dir + "/.cquery"))
 | 
			
		||||
    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.
 | 
			
		||||
  const auto& compilation_db_dir = opt_compilation_db_dir.empty()
 | 
			
		||||
                                       ? config->project_dir
 | 
			
		||||
    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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user