Browse Source

Cleanup and slight improvement of cmake_file_api code

merge-requests/413/head
eidheim 3 years ago
parent
commit
350da301ec
  1. 112
      src/cmake.cpp
  2. 6
      src/cmake.hpp

112
src/cmake.cpp

@ -58,11 +58,9 @@ bool CMake::update_default_build(const boost::filesystem::path &default_build_pa
} }
} }
if(!force && boost::filesystem::exists(default_build_path / "compile_commands.json", ec)) if(!create_file_api_query(default_build_path) && !force && boost::filesystem::exists(default_build_path / "compile_commands.json", ec))
return true; return true;
set_file_api_queries(default_build_path);
auto compile_commands_path = default_build_path / "compile_commands.json"; auto compile_commands_path = default_build_path / "compile_commands.json";
bool canceled = false; bool canceled = false;
Dialog::Message message("Creating/updating default build", [&canceled] { Dialog::Message message("Creating/updating default build", [&canceled] {
@ -124,8 +122,6 @@ bool CMake::update_debug_build(const boost::filesystem::path &debug_build_path,
if(!force && boost::filesystem::exists(debug_build_path / "CMakeCache.txt", ec)) if(!force && boost::filesystem::exists(debug_build_path / "CMakeCache.txt", ec))
return true; return true;
set_file_api_queries(debug_build_path);
bool canceled = false; bool canceled = false;
Dialog::Message message("Creating/updating debug build", [&canceled] { Dialog::Message message("Creating/updating debug build", [&canceled] {
canceled = true; canceled = true;
@ -152,11 +148,10 @@ bool CMake::update_debug_build(const boost::filesystem::path &debug_build_path,
boost::filesystem::path CMake::get_executable(const boost::filesystem::path &build_path, const boost::filesystem::path &file_path) { boost::filesystem::path CMake::get_executable(const boost::filesystem::path &build_path, const boost::filesystem::path &file_path) {
// prefer the CMake file API (if available) which gives exact information about the targets a file belongs to // Prefer the CMake file API (if available) which gives exact information about the targets a file belongs to
auto executables = get_executables(build_path, file_path); auto executable = get_executable_from_file_api(build_path, file_path);
if(!executables.empty()) { if(executable)
return executables.front(); return *executable;
}
// CMake does not store in compile_commands.json if an object is part of an executable or not. // CMake does not store in compile_commands.json if an object is part of an executable or not.
// Therefore, executables are first attempted found in the cmake files. These executables // Therefore, executables are first attempted found in the cmake files. These executables
@ -363,67 +358,84 @@ void CMake::parse_file(const std::string &src, std::map<std::string, std::list<s
} }
} }
void CMake::set_file_api_queries(const boost::filesystem::path &build_path) { bool CMake::create_file_api_query(const boost::filesystem::path &build_path) {
auto query_directory = build_path / ".cmake" / "api" / "v1" / "query" / "client-jucipp"; auto query_directory = build_path / ".cmake" / "api" / "v1" / "query" / "client-jucipp";
auto query_file = query_directory / "query.json";
boost::system::error_code ec; boost::system::error_code ec;
if(!boost::filesystem::exists(query_directory, ec)) { if(boost::filesystem::exists(query_file, ec))
boost::system::error_code ec; return false;
boost::filesystem::create_directories(query_directory, ec);
if(ec) { boost::filesystem::create_directories(query_directory, ec);
Terminal::get().print("\e[31mError\e[m: could not create " + filesystem::get_short_path(query_directory).string() + ": " + ec.message() + "\n", true); if(ec) {
return; Terminal::get().print("\e[31mError\e[m: could not create cmake file api query directory " + filesystem::get_short_path(query_directory).string() + ": " + ec.message() + "\n", true);
} return false;
} }
filesystem::write(query_directory / "query.json", R"({ if(!filesystem::write(query_file, R"({
"requests": [ "requests": [
{ "kind": "codemodel" , "version": 2 } { "kind": "codemodel" , "version": 2 }
] ]
})"); })")) {
Terminal::get().print("\e[31mError\e[m: could not create cmake file api query file " + filesystem::get_short_path(query_file).string() + ": " + ec.message() + "\n", true);
return false;
}
return true;
} }
std::vector<boost::filesystem::path> CMake::get_executables(const boost::filesystem::path &build_path, const boost::filesystem::path &file_path) { boost::optional<boost::filesystem::path> CMake::get_executable_from_file_api(const boost::filesystem::path &build_path, const boost::filesystem::path &file_path) {
auto reply_directory = build_path / ".cmake" / "api" / "v1" / "reply"; auto reply_directory = build_path / ".cmake" / "api" / "v1" / "reply";
boost::system::error_code ec; boost::system::error_code ec;
if(!boost::filesystem::exists(reply_directory, ec)) { if(!boost::filesystem::is_directory(reply_directory, ec)) {
// If the reply directory does not exist, either CMake was not run or the file API is not yet supported // If the reply directory does not exist, either CMake was not run or the file API is not yet supported
return {}; return {};
} }
// check all target-*.json files and filter for the given file path // Check all target-*.json files and filter for the given file path
std::vector<boost::filesystem::path> executables; std::vector<boost::filesystem::path> target_files;
for(const auto &reply_file : boost::filesystem::directory_iterator(reply_directory)) { for(const auto &reply_file : boost::filesystem::directory_iterator(reply_directory, ec)) {
if(reply_file.path().stem().string().find("target-") != 0) { auto reply_file_path = reply_file.path();
continue; if(starts_with(reply_file_path.stem().string(), "target-"))
} target_files.emplace_back(reply_file_path);
}
std::sort(target_files.begin(), target_files.end(), [](const boost::filesystem::path &path1, const boost::filesystem::path &path2) {
return Natural::compare(path1.string(), path2.string()) < 0;
});
JSON json{reply_file.path()}; boost::optional<boost::filesystem::path> executable;
auto artifacts = json.array_optional("artifacts"); ssize_t best_match_size = -1;
if(!artifacts || artifacts->empty()) { for(const auto &target_file : target_files) {
continue; try {
} JSON json(target_file);
auto relative_path = artifacts->front().string_optional("path");
if(!relative_path) {
continue;
}
auto type = json.string_optional("type"); if(json.string("type") != "EXECUTABLE")
if(!type || *type != "EXECUTABLE") { continue;
continue;
}
auto sources = json.array_optional("sources"); auto artifacts = json.array("artifacts");
if(!sources) { if(artifacts.empty())
continue; continue;
}
for(const auto &source : *sources) { auto relative_path = artifacts.front().string("path");
auto source_path = project_path / source.string_or("path", "");
if(source_path == file_path) { for(auto &source : json.array("sources")) {
executables.emplace_back(build_path / *relative_path); auto source_file = project_path / source.string("path");
if(source_file == file_path)
return {build_path / relative_path};
auto source_directory = source_file.parent_path();
if(filesystem::file_in_path(file_path, source_directory)) {
auto size = std::distance(source_directory.begin(), source_directory.end());
if(size > best_match_size) {
best_match_size = size;
executable = build_path / relative_path;
}
}
} }
} }
catch(...) {
}
} }
return executables;
return executable;
} }

6
src/cmake.hpp

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/optional.hpp>
#include <list> #include <list>
#include <map> #include <map>
#include <vector> #include <vector>
@ -24,6 +25,7 @@ private:
static void parse_file(const std::string &src, std::map<std::string, std::list<std::string>> &variables, std::function<void(Function &&)> &&on_function); static void parse_file(const std::string &src, std::map<std::string, std::list<std::string>> &variables, std::function<void(Function &&)> &&on_function);
// Cmake file API functions // Cmake file API functions
void set_file_api_queries(const boost::filesystem::path &build_path); /// Returns true if file api query file was created, false otherwise including if the file already exists
std::vector<boost::filesystem::path> get_executables(const boost::filesystem::path &build_path, const boost::filesystem::path &file_path); bool create_file_api_query(const boost::filesystem::path &build_path);
boost::optional<boost::filesystem::path> get_executable_from_file_api(const boost::filesystem::path &build_path, const boost::filesystem::path &file_path);
}; };

Loading…
Cancel
Save