mirror of
				https://github.com/MaskRay/ccls.git
				synced 2025-11-03 22:04:24 +00:00 
			
		
		
		
	Implement initialization option compilationDatabaseCommand on Windows
This commit is contained in:
		
							parent
							
								
									a7b2ce5c1f
								
							
						
					
					
						commit
						b6d7661fc4
					
				@ -16,8 +16,5 @@ void FreeUnusedMemory();
 | 
				
			|||||||
// Stop self and wait for SIGCONT.
 | 
					// Stop self and wait for SIGCONT.
 | 
				
			||||||
void TraceMe();
 | 
					void TraceMe();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::string GetExternalCommandOutput(const std::vector<std::string> &command,
 | 
					 | 
				
			||||||
                                     std::string_view input);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void SpawnThread(void *(*fn)(void *), void *arg);
 | 
					void SpawnThread(void *(*fn)(void *), void *arg);
 | 
				
			||||||
} // namespace ccls
 | 
					} // namespace ccls
 | 
				
			||||||
 | 
				
			|||||||
@ -61,49 +61,6 @@ void TraceMe() {
 | 
				
			|||||||
    raise(traceme[0] == 's' ? SIGSTOP : SIGTSTP);
 | 
					    raise(traceme[0] == 's' ? SIGSTOP : SIGTSTP);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::string GetExternalCommandOutput(const std::vector<std::string> &command,
 | 
					 | 
				
			||||||
                                     std::string_view input) {
 | 
					 | 
				
			||||||
  int pin[2], pout[2];
 | 
					 | 
				
			||||||
  if (pipe(pin) < 0) {
 | 
					 | 
				
			||||||
    perror("pipe(stdin)");
 | 
					 | 
				
			||||||
    return "";
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if (pipe(pout) < 0) {
 | 
					 | 
				
			||||||
    perror("pipe(stdout)");
 | 
					 | 
				
			||||||
    close(pin[0]);
 | 
					 | 
				
			||||||
    close(pin[1]);
 | 
					 | 
				
			||||||
    return "";
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  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]);
 | 
					 | 
				
			||||||
  // O_NONBLOCK is disabled, write(2) blocks until all bytes are written.
 | 
					 | 
				
			||||||
  (void)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);
 | 
					 | 
				
			||||||
  close(pin[0]);
 | 
					 | 
				
			||||||
  waitpid(child, NULL, 0);
 | 
					 | 
				
			||||||
  return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void SpawnThread(void *(*fn)(void *), void *arg) {
 | 
					void SpawnThread(void *(*fn)(void *), void *arg) {
 | 
				
			||||||
  pthread_t thd;
 | 
					  pthread_t thd;
 | 
				
			||||||
  pthread_attr_t attr;
 | 
					  pthread_attr_t attr;
 | 
				
			||||||
 | 
				
			|||||||
@ -45,11 +45,6 @@ void FreeUnusedMemory() {}
 | 
				
			|||||||
// 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 "";
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void SpawnThread(void *(*fn)(void *), void *arg) {
 | 
					void SpawnThread(void *(*fn)(void *), void *arg) {
 | 
				
			||||||
  std::thread(fn, arg).detach();
 | 
					  std::thread(fn, arg).detach();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -19,13 +19,17 @@
 | 
				
			|||||||
#include <llvm/ADT/STLExtras.h>
 | 
					#include <llvm/ADT/STLExtras.h>
 | 
				
			||||||
#include <llvm/ADT/StringSet.h>
 | 
					#include <llvm/ADT/StringSet.h>
 | 
				
			||||||
#include <llvm/Support/LineIterator.h>
 | 
					#include <llvm/Support/LineIterator.h>
 | 
				
			||||||
 | 
					#include <llvm/Support/Program.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <rapidjson/writer.h>
 | 
					#include <rapidjson/writer.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(__unix__) || defined(__APPLE__)
 | 
					#ifdef _WIN32
 | 
				
			||||||
 | 
					# include <Windows.h>
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
# include <unistd.h>
 | 
					# include <unistd.h>
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <array>
 | 
				
			||||||
#include <limits.h>
 | 
					#include <limits.h>
 | 
				
			||||||
#include <unordered_set>
 | 
					#include <unordered_set>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
@ -296,7 +300,8 @@ int ComputeGuessScore(std::string_view a, std::string_view b) {
 | 
				
			|||||||
} // namespace
 | 
					} // namespace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Project::LoadDirectory(const std::string &root, Project::Folder &folder) {
 | 
					void Project::LoadDirectory(const std::string &root, Project::Folder &folder) {
 | 
				
			||||||
  SmallString<256> Path, CDBDir;
 | 
					  SmallString<256> CDBDir, Path, StdinPath;
 | 
				
			||||||
 | 
					  std::string err_msg;
 | 
				
			||||||
  folder.entries.clear();
 | 
					  folder.entries.clear();
 | 
				
			||||||
  if (g_config->compilationDatabaseCommand.empty()) {
 | 
					  if (g_config->compilationDatabaseCommand.empty()) {
 | 
				
			||||||
    CDBDir = root;
 | 
					    CDBDir = root;
 | 
				
			||||||
@ -307,33 +312,49 @@ void Project::LoadDirectory(const std::string &root, Project::Folder &folder) {
 | 
				
			|||||||
    // If `compilationDatabaseCommand` is specified, execute it to get the
 | 
					    // If `compilationDatabaseCommand` is specified, execute it to get the
 | 
				
			||||||
    // compdb.
 | 
					    // compdb.
 | 
				
			||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
    // TODO
 | 
					    char tmpdir[L_tmpnam];
 | 
				
			||||||
 | 
					    tmpnam_s(tmpdir, L_tmpnam);
 | 
				
			||||||
 | 
					    CDBDir = tmpdir;
 | 
				
			||||||
 | 
					    if (sys::fs::create_directory(tmpdir, false))
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
    char tmpdir[] = "/tmp/ccls-compdb-XXXXXX";
 | 
					    char tmpdir[] = "/tmp/ccls-compdb-XXXXXX";
 | 
				
			||||||
    if (!mkdtemp(tmpdir))
 | 
					    if (!mkdtemp(tmpdir))
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    CDBDir = tmpdir;
 | 
					    CDBDir = tmpdir;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
    sys::path::append(Path, CDBDir, "compile_commands.json");
 | 
					    sys::path::append(Path, CDBDir, "compile_commands.json");
 | 
				
			||||||
    rapidjson::StringBuffer input;
 | 
					    sys::path::append(StdinPath, CDBDir, "stdin");
 | 
				
			||||||
    rapidjson::Writer<rapidjson::StringBuffer> writer(input);
 | 
					    {
 | 
				
			||||||
 | 
					      rapidjson::StringBuffer sb;
 | 
				
			||||||
 | 
					      rapidjson::Writer<rapidjson::StringBuffer> writer(sb);
 | 
				
			||||||
      JsonWriter json_writer(&writer);
 | 
					      JsonWriter json_writer(&writer);
 | 
				
			||||||
      Reflect(json_writer, *g_config);
 | 
					      Reflect(json_writer, *g_config);
 | 
				
			||||||
    std::string contents = GetExternalCommandOutput(
 | 
					      std::string input = sb.GetString();
 | 
				
			||||||
        std::vector<std::string>{g_config->compilationDatabaseCommand, root},
 | 
					      FILE *fout = fopen(StdinPath.c_str(), "wb");
 | 
				
			||||||
        input.GetString());
 | 
					      fwrite(input.c_str(), input.size(), 1, fout);
 | 
				
			||||||
    FILE *fout = fopen(Path.c_str(), "wb");
 | 
					 | 
				
			||||||
    fwrite(contents.c_str(), contents.size(), 1, fout);
 | 
					 | 
				
			||||||
      fclose(fout);
 | 
					      fclose(fout);
 | 
				
			||||||
#endif
 | 
					    }
 | 
				
			||||||
 | 
					    std::array<Optional<StringRef>, 3> Redir{StringRef(StdinPath),
 | 
				
			||||||
 | 
					                                             StringRef(Path), StringRef()};
 | 
				
			||||||
 | 
					    std::vector<StringRef> args{g_config->compilationDatabaseCommand, root};
 | 
				
			||||||
 | 
					    if (sys::ExecuteAndWait(args[0], args, llvm::None, Redir, 0, 0, &err_msg) <
 | 
				
			||||||
 | 
					        0) {
 | 
				
			||||||
 | 
					      LOG_S(ERROR) << "failed to execute " << args[0].str() << " "
 | 
				
			||||||
 | 
					                   << args[1].str() << ": " << err_msg;
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::string err_msg;
 | 
					 | 
				
			||||||
  std::unique_ptr<tooling::CompilationDatabase> CDB =
 | 
					  std::unique_ptr<tooling::CompilationDatabase> CDB =
 | 
				
			||||||
      tooling::CompilationDatabase::loadFromDirectory(CDBDir, err_msg);
 | 
					      tooling::CompilationDatabase::loadFromDirectory(CDBDir, err_msg);
 | 
				
			||||||
  if (!g_config->compilationDatabaseCommand.empty()) {
 | 
					  if (!g_config->compilationDatabaseCommand.empty()) {
 | 
				
			||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
    // TODO
 | 
					    DeleteFileA(StdinPath.c_str());
 | 
				
			||||||
 | 
					    DeleteFileA(Path.c_str());
 | 
				
			||||||
 | 
					    RemoveDirectoryA(CDBDir.c_str());
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
 | 
					    unlink(StdinPath.c_str());
 | 
				
			||||||
    unlink(Path.c_str());
 | 
					    unlink(Path.c_str());
 | 
				
			||||||
    rmdir(CDBDir.c_str());
 | 
					    rmdir(CDBDir.c_str());
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
@ -342,7 +363,10 @@ void Project::LoadDirectory(const std::string &root, Project::Folder &folder) {
 | 
				
			|||||||
  ProjectProcessor proc(folder);
 | 
					  ProjectProcessor proc(folder);
 | 
				
			||||||
  StringSet<> Seen;
 | 
					  StringSet<> Seen;
 | 
				
			||||||
  std::vector<Project::Entry> result;
 | 
					  std::vector<Project::Entry> result;
 | 
				
			||||||
  if (CDB) {
 | 
					  if (!CDB) {
 | 
				
			||||||
 | 
					    if (g_config->compilationDatabaseCommand.size() || sys::fs::exists(Path))
 | 
				
			||||||
 | 
					      LOG_S(ERROR) << "failed to load " << Path.c_str();
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
    LOG_S(INFO) << "loaded " << Path.c_str();
 | 
					    LOG_S(INFO) << "loaded " << Path.c_str();
 | 
				
			||||||
    for (tooling::CompileCommand &Cmd : CDB->getAllCompileCommands()) {
 | 
					    for (tooling::CompileCommand &Cmd : CDB->getAllCompileCommands()) {
 | 
				
			||||||
      static bool once;
 | 
					      static bool once;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user