diff --git a/src/cmake.cpp b/src/cmake.cpp index 177ec81..6ebbe9e 100644 --- a/src/cmake.cpp +++ b/src/cmake.cpp @@ -3,6 +3,7 @@ #include "config.hpp" #include "dialog.hpp" #include "filesystem.hpp" +#include "json.hpp" #include "terminal.hpp" #include "utility.hpp" #include @@ -59,6 +60,8 @@ bool CMake::update_default_build(const boost::filesystem::path &default_build_pa if(!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] { @@ -120,6 +123,8 @@ 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; @@ -145,6 +150,13 @@ 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(); + } + // 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 // are then used to identify if a file in compile_commands.json is part of an executable or not @@ -349,3 +361,68 @@ 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) { + auto reply_directory = build_path / ".cmake" / "api" / "v1" / "reply"; + + boost::system::error_code ec; + if(!boost::filesystem::exists(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; + } + + 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; + } + + auto type = json.string_optional("type"); + if(!type || *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); + } + } + } + return executables; +} diff --git a/src/cmake.hpp b/src/cmake.hpp index bfc5485..f04dd5e 100644 --- a/src/cmake.hpp +++ b/src/cmake.hpp @@ -22,4 +22,8 @@ private: std::list parameters; }; 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); }; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 367892c..e3f5d71 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -21,66 +21,70 @@ if(BUILD_TESTING) add_executable(process_test process_test.cpp $) target_link_libraries(process_test juci_shared) add_test(process_test process_test) - + add_executable(compile_commands_test compile_commands_test.cpp $) target_link_libraries(compile_commands_test juci_shared) add_test(compile_commands_test compile_commands_test) - + add_executable(filesystem_test filesystem_test.cpp $) target_link_libraries(filesystem_test juci_shared) add_test(filesystem_test filesystem_test) - + add_executable(cmake_build_test cmake_build_test.cpp $) target_link_libraries(cmake_build_test juci_shared) add_test(cmake_build_test cmake_build_test) - + + add_executable(cmake_file_api_test cmake_file_api_test.cpp $) + target_link_libraries(cmake_file_api_test juci_shared) + add_test(cmake_file_api_test cmake_file_api_test) + add_executable(meson_build_test meson_build_test.cpp $) target_link_libraries(meson_build_test juci_shared) add_test(meson_build_test meson_build_test) - + add_executable(source_test source_test.cpp $) target_link_libraries(source_test juci_shared) add_test(source_test source_test) - + add_executable(source_clang_test source_clang_test.cpp $) target_link_libraries(source_clang_test juci_shared) add_test(source_clang_test source_clang_test) - + add_executable(source_generic_test source_generic_test.cpp $) target_link_libraries(source_generic_test juci_shared) add_test(source_generic_test source_generic_test) - + add_executable(source_key_test source_key_test.cpp $) target_link_libraries(source_key_test juci_shared) add_test(source_key_test source_key_test) - + add_executable(terminal_test terminal_test.cpp $) target_link_libraries(terminal_test juci_shared) add_test(terminal_test terminal_test) - + add_executable(usages_clang_test usages_clang_test.cpp $) target_link_libraries(usages_clang_test juci_shared) add_test(usages_clang_test usages_clang_test) - + if(LIBLLDB_FOUND) add_executable(lldb_test lldb_test.cpp $) target_link_libraries(lldb_test juci_shared) add_test(lldb_test lldb_test) add_subdirectory("lldb_test_files") endif() - + add_executable(git_test git_test.cpp $) target_link_libraries(git_test juci_shared) add_test(git_test git_test) - + add_executable(ctags_grep_test ctags_grep_test.cpp $) target_link_libraries(ctags_grep_test juci_shared) add_test(ctags_grep_test ctags_grep_test) - + add_executable(tooltips_test tooltips_test.cpp $) target_link_libraries(tooltips_test juci_shared) add_test(tooltips_test tooltips_test) - + add_executable(utility_test utility_test.cpp $) target_link_libraries(utility_test juci_shared) add_test(utility_test utility_test) @@ -91,7 +95,7 @@ if(BUILD_TESTING) add_executable(language_protocol_server_test language_protocol_server_test.cpp) target_link_libraries(language_protocol_server_test juci_shared) - + add_executable(json_test json_test.cpp $) target_link_libraries(json_test juci_shared) add_test(json_test json_test) @@ -102,27 +106,27 @@ if(BUILD_FUZZING) target_compile_options(cmake_fuzzer PRIVATE -fsanitize=address,fuzzer) target_link_options(cmake_fuzzer PRIVATE -fsanitize=address,fuzzer) target_link_libraries(cmake_fuzzer juci_shared) - + add_executable(ctags_fuzzer fuzzers/ctags.cpp $) target_compile_options(ctags_fuzzer PRIVATE -fsanitize=address,fuzzer) target_link_options(ctags_fuzzer PRIVATE -fsanitize=address,fuzzer) target_link_libraries(ctags_fuzzer juci_shared) - + add_executable(docstring_fuzzer fuzzers/docstring.cpp $) target_compile_options(docstring_fuzzer PRIVATE -fsanitize=address,fuzzer) target_link_options(docstring_fuzzer PRIVATE -fsanitize=address,fuzzer) target_link_libraries(docstring_fuzzer juci_shared) - + add_executable(doxygen_fuzzer fuzzers/doxygen.cpp $) target_compile_options(doxygen_fuzzer PRIVATE -fsanitize=address,fuzzer) target_link_options(doxygen_fuzzer PRIVATE -fsanitize=address,fuzzer) target_link_libraries(doxygen_fuzzer juci_shared) - + add_executable(grep_fuzzer fuzzers/grep.cpp $) target_compile_options(grep_fuzzer PRIVATE -fsanitize=address,fuzzer) target_link_options(grep_fuzzer PRIVATE -fsanitize=address,fuzzer) target_link_libraries(grep_fuzzer juci_shared) - + add_executable(markdown_fuzzer fuzzers/markdown.cpp $) target_compile_options(markdown_fuzzer PRIVATE -fsanitize=address,fuzzer) target_link_options(markdown_fuzzer PRIVATE -fsanitize=address,fuzzer) diff --git a/tests/cmake_file_api_test.cpp b/tests/cmake_file_api_test.cpp new file mode 100644 index 0000000..ab48d99 --- /dev/null +++ b/tests/cmake_file_api_test.cpp @@ -0,0 +1,27 @@ +#include "cmake.hpp" +#include "config.hpp" +#include "process.hpp" +#include "project_build.hpp" +#include +#include +#include + +int main() { + auto app = Gtk::Application::create(); + Gsv::init(); + Config::get().project.default_build_path = "./build"; + Config::get().project.cmake.command = "cmake"; + + auto tests_path = boost::filesystem::canonical(JUCI_TESTS_PATH); + auto cmake_test_files_path = boost::filesystem::canonical(tests_path / "cmake_file_api_test_files"); + + CMake cmake(cmake_test_files_path); + g_assert(cmake.project_path == cmake_test_files_path); + + auto build = Project::Build::create(cmake_test_files_path); + g_assert(dynamic_cast(build.get())); + + g_assert(build->update_default(true)); + + g_assert(build->get_executable(cmake_test_files_path / "main.cpp") == cmake_test_files_path / "build" / "custom_build_folder" / "custom_executable"); +} diff --git a/tests/cmake_file_api_test_files/CMakeLists.txt b/tests/cmake_file_api_test_files/CMakeLists.txt new file mode 100644 index 0000000..2266dbb --- /dev/null +++ b/tests/cmake_file_api_test_files/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.1) + +project(test) +add_compile_options(-O0 -g) + +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/custom_build_folder) +add_executable(cmake_file_api_test_executable main.cpp) +set_target_properties(cmake_file_api_test_executable PROPERTIES OUTPUT_NAME "custom_executable") diff --git a/tests/cmake_file_api_test_files/main.cpp b/tests/cmake_file_api_test_files/main.cpp new file mode 100644 index 0000000..2a08c90 --- /dev/null +++ b/tests/cmake_file_api_test_files/main.cpp @@ -0,0 +1,4 @@ +int main() { + int an_int = 1; + an_int++; +}