From 350da301ec9eb10225d14503e97d4bb3b685240d Mon Sep 17 00:00:00 2001 From: eidheim Date: Tue, 5 Jul 2022 12:37:27 +0200 Subject: [PATCH] Cleanup and slight improvement of cmake_file_api code --- src/cmake.cpp | 112 ++++++++++++++++++++++++++++---------------------- src/cmake.hpp | 6 ++- 2 files changed, 66 insertions(+), 52 deletions(-) diff --git a/src/cmake.cpp b/src/cmake.cpp index aebdc4d..793eadb 100644 --- a/src/cmake.cpp +++ b/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 CMake::get_executables(const boost::filesystem::path &build_path, const boost::filesystem::path &file_path) { +boost::optional 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 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 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 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") { - continue; - } + if(json.string("type") != "EXECUTABLE") + continue; - auto sources = json.array_optional("sources"); - if(!sources) { - continue; - } - 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); + 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; + } + } } } + catch(...) { + } } - return executables; + + return executable; } diff --git a/src/cmake.hpp b/src/cmake.hpp index f04dd5e..3b15a3c 100644 --- a/src/cmake.hpp +++ b/src/cmake.hpp @@ -1,5 +1,6 @@ #pragma once #include +#include #include #include #include @@ -24,6 +25,7 @@ private: static void parse_file(const std::string &src, std::map> &variables, std::function &&on_function); // Cmake file API functions - void set_file_api_queries(const boost::filesystem::path &build_path); - std::vector 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 get_executable_from_file_api(const boost::filesystem::path &build_path, const boost::filesystem::path &file_path); };