Browse Source

Cleanup and slight improvement of cmake_file_api code

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

100
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;
set_file_api_queries(default_build_path);
auto compile_commands_path = default_build_path / "compile_commands.json";
bool canceled = false;
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))
return true;
set_file_api_queries(debug_build_path);
bool canceled = false;
Dialog::Message message("Creating/updating debug build", [&canceled] {
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) {
// 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);
if(!executables.empty()) {
return executables.front();
}
// Prefer the CMake file API (if available) which gives exact information about the targets a file belongs to
auto executable = get_executable_from_file_api(build_path, file_path);
if(executable)
return *executable;
// 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
@ -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_file = query_directory / "query.json";
boost::system::error_code ec;
if(!boost::filesystem::exists(query_directory, ec)) {
boost::system::error_code ec;
if(boost::filesystem::exists(query_file, ec))
return false;
boost::filesystem::create_directories(query_directory, ec);
if(ec) {
Terminal::get().print("\e[31mError\e[m: could not create " + filesystem::get_short_path(query_directory).string() + ": " + ec.message() + "\n", true);
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": [
{ "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";
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
return {};
}
// check all target-*.json files and filter for the given file path
std::vector<boost::filesystem::path> executables;
for(const auto &reply_file : boost::filesystem::directory_iterator(reply_directory)) {
if(reply_file.path().stem().string().find("target-") != 0) {
continue;
// Check all target-*.json files and filter for the given file path
std::vector<boost::filesystem::path> target_files;
for(const auto &reply_file : boost::filesystem::directory_iterator(reply_directory, ec)) {
auto reply_file_path = reply_file.path();
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()};
auto artifacts = json.array_optional("artifacts");
if(!artifacts || artifacts->empty()) {
continue;
}
auto relative_path = artifacts->front().string_optional("path");
if(!relative_path) {
continue;
}
boost::optional<boost::filesystem::path> executable;
ssize_t best_match_size = -1;
for(const auto &target_file : target_files) {
try {
JSON json(target_file);
auto type = json.string_optional("type");
if(!type || *type != "EXECUTABLE") {
if(json.string("type") != "EXECUTABLE")
continue;
}
auto sources = json.array_optional("sources");
if(!sources) {
auto artifacts = json.array("artifacts");
if(artifacts.empty())
continue;
auto relative_path = artifacts.front().string("path");
for(auto &source : json.array("sources")) {
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;
}
for(const auto &source : *sources) {
auto source_path = project_path / source.string_or("path", "");
if(source_path == file_path) {
executables.emplace_back(build_path / *relative_path);
}
}
}
return executables;
catch(...) {
}
}
return executable;
}

6
src/cmake.hpp

@ -1,5 +1,6 @@
#pragma once
#include <boost/filesystem.hpp>
#include <boost/optional.hpp>
#include <list>
#include <map>
#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);
// Cmake file API functions
void set_file_api_queries(const boost::filesystem::path &build_path);
std::vector<boost::filesystem::path> get_executables(const boost::filesystem::path &build_path, const boost::filesystem::path &file_path);
/// Returns true if file api query file was created, false otherwise including if the file already exists
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