From 7ec8f03039119edc04858962b270a77a26e4400b Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 13 Nov 2016 14:33:53 +0100 Subject: [PATCH] Improved CMake::get_executable, now also looks in compile_commands.json if no executable was found previously. --- src/cmake.cc | 65 ++++++++++--- src/cmake.h | 2 +- src/project_build.cc | 6 +- tests/cmake_build_test.cc | 91 +++++++++++++------ .../build/compile_commands.json | 4 +- 5 files changed, 117 insertions(+), 51 deletions(-) diff --git a/src/cmake.cc b/src/cmake.cc index 0678622..ea756f3 100644 --- a/src/cmake.cc +++ b/src/cmake.cc @@ -4,6 +4,7 @@ #include "config.h" #include "terminal.h" #include +#include "compile_commands.h" CMake::CMake(const boost::filesystem::path &path) { const auto find_cmake_project=[this](const boost::filesystem::path &cmake_path) { @@ -110,29 +111,67 @@ bool CMake::update_debug_build(const boost::filesystem::path &debug_build_path, return false; } -boost::filesystem::path CMake::get_executable(const boost::filesystem::path &file_path) { - auto executables = get_functions_parameters("add_executable"); +boost::filesystem::path CMake::get_executable(const boost::filesystem::path &build_path, const boost::filesystem::path &file_path) { + auto cmake_executables = get_functions_parameters("add_executable"); - //Attempt to find executable based add_executable files and opened tab - boost::filesystem::path executable_path; + //Attempt to find executable based on add_executable in cmake files + auto cmake_fix_executable=[this, &build_path](std::string executable) { + size_t pos=executable.find(project_path.string()); + if(pos!=std::string::npos) + executable.replace(pos, project_path.string().size(), build_path.string()); + return executable; + }; if(!file_path.empty()) { - for(auto &executable: executables) { + for(auto &executable: cmake_executables) { if(executable.second.size()>1) { for(size_t c=1;c0 && cmake_executables[0].second[0].substr(0, 2)!="${") { + return cmake_fix_executable((executable.first.parent_path()/executable.second[0]).string()); + } + } + } + } + } + if(cmake_executables.size()>0 && cmake_executables[0].second.size()>0 && cmake_executables[0].second[0].size()>0 && + cmake_executables[0].second[0].substr(0, 2)!="${") { + return cmake_fix_executable((cmake_executables[0].first.parent_path()/cmake_executables[0].second[0]).string()); + } + + //Attempt to find executable based on compile_commands.json + CompileCommands compile_commands(build_path); + size_t compile_commands_best_match_size=-1; + boost::filesystem::path compile_commands_best_match_executable; + for(auto &command: compile_commands.commands) { + boost::system::error_code ec; + auto command_file=boost::filesystem::canonical(command.file, ec); + if(!ec) { + auto values=command.paramter_values("-o"); + if(!values.empty()) { + size_t pos; + values[0].erase(0, 11); + if((pos=values[0].find(".dir"))!=std::string::npos) { + boost::filesystem::path executable=values[0].substr(0, pos); + auto relative_path=filesystem::get_relative_path(command_file, project_path); + if(!relative_path.empty()) { + executable=build_path/relative_path.parent_path()/executable; + if(command_file==file_path) + return executable; + auto command_file_directory=command_file.parent_path(); + if(filesystem::file_in_path(file_path, command_file_directory)) { + auto size=command_file_directory.string().size(); + if(compile_commands_best_match_size==static_cast(-1) || compile_commands_best_match_size0 && executables[0].second.size()>0) - executable_path=executables[0].first.parent_path()/executables[0].second[0]; - return executable_path; + return compile_commands_best_match_executable; } void CMake::read_files() { diff --git a/src/cmake.h b/src/cmake.h index c345c46..ab67336 100644 --- a/src/cmake.h +++ b/src/cmake.h @@ -13,7 +13,7 @@ public: bool update_default_build(const boost::filesystem::path &default_build_path, bool force=false); bool update_debug_build(const boost::filesystem::path &debug_build_path, bool force=false); - boost::filesystem::path get_executable(const boost::filesystem::path &file_path); + boost::filesystem::path get_executable(const boost::filesystem::path &build_path, const boost::filesystem::path &file_path); private: std::vector paths; std::vector files; diff --git a/src/project_build.cc b/src/project_build.cc index 3e3c12a..afc04a1 100644 --- a/src/project_build.cc +++ b/src/project_build.cc @@ -97,11 +97,7 @@ bool Project::CMakeBuild::update_debug(bool force) { } boost::filesystem::path Project::CMakeBuild::get_executable(const boost::filesystem::path &path) { - auto executable=cmake.get_executable(path).string(); - size_t pos=executable.find(project_path.string()); - if(pos!=std::string::npos) - executable.replace(pos, project_path.string().size(), get_default_path().string()); - return executable; + return cmake.get_executable(get_default_path(), path).string(); } Project::MesonBuild::MesonBuild(const boost::filesystem::path &path) : Project::Build(), meson(path) { diff --git a/tests/cmake_build_test.cc b/tests/cmake_build_test.cc index a9a3ab8..0708f49 100644 --- a/tests/cmake_build_test.cc +++ b/tests/cmake_build_test.cc @@ -4,36 +4,67 @@ #include "config.h" #include +#include +using namespace std; + int main() { auto tests_path=boost::filesystem::canonical(JUCI_TESTS_PATH); - auto project_path=boost::filesystem::canonical(tests_path/".."); - - CMake cmake(tests_path); - - g_assert(cmake.project_path==project_path); - - auto functions_parameters=cmake.get_functions_parameters("project"); - g_assert(functions_parameters.at(0).second.at(0)=="juci"); - - g_assert(cmake.get_executable(tests_path/"cmake_build_test.cc").filename()=="cmake_build_test"); - - auto build=Project::Build::create(tests_path); - g_assert(dynamic_cast(build.get())); - - build=Project::Build::create(tests_path/"stubs"); - g_assert(dynamic_cast(build.get())); - g_assert(build->project_path==project_path); - - Config::get().project.default_build_path="./build"; - g_assert(build->get_default_path()==project_path/"./build"); - - Config::get().project.debug_build_path="/debug"; - g_assert(build->get_debug_path()==project_path/"./build/debug"); - - auto project_path_filename=project_path.filename(); - Config::get().project.debug_build_path="../debug_"; - g_assert(build->get_debug_path()==project_path/("../debug_"+project_path_filename.string())); - - Config::get().project.default_build_path="../build_"; - g_assert(build->get_default_path()==project_path/("../build_"+project_path_filename.string())); + { + auto project_path=boost::filesystem::canonical(tests_path/".."); + + { + CMake cmake(project_path); + g_assert(cmake.get_executable(project_path/"build", project_path)==""); + g_assert(cmake.get_executable(project_path/"build"/"non_existing_file.cc", project_path)==""); + } + { + CMake cmake(project_path/"src"); + g_assert(cmake.get_executable(project_path/"build", project_path/"src")==project_path/"build"/"src"/"juci"); + g_assert(cmake.get_executable(project_path/"build", project_path/"src"/"cmake.cc")==project_path/"build"/"src"/"juci"); + g_assert(cmake.get_executable(project_path/"build", project_path/"src"/"juci.cc")==project_path/"build"/"src"/"juci"); + g_assert(cmake.get_executable(project_path/"build", project_path/"src"/"non_existing_file.cc")==project_path/"build"/"src"/"juci"); + } + { + CMake cmake(tests_path); + + g_assert(cmake.project_path==project_path); + + auto functions_parameters=cmake.get_functions_parameters("project"); + g_assert(functions_parameters.at(0).second.at(0)=="juci"); + + g_assert(cmake.get_executable(project_path/"build", tests_path)==project_path/"build"/"tests"/"git_test"); + g_assert(cmake.get_executable(project_path/"build", tests_path/"cmake_build_test.cc")==project_path/"build"/"tests"/"cmake_build_test"); + g_assert(cmake.get_executable(project_path/"build", tests_path/"non_existing_file.cc")==project_path/"build"/"tests"/"git_test"); + } + + auto build=Project::Build::create(tests_path); + g_assert(dynamic_cast(build.get())); + + build=Project::Build::create(tests_path/"stubs"); + g_assert(dynamic_cast(build.get())); + g_assert(build->project_path==project_path); + + Config::get().project.default_build_path="./build"; + g_assert(build->get_default_path()==project_path/"./build"); + + Config::get().project.debug_build_path="/debug"; + g_assert(build->get_debug_path()==project_path/"./build/debug"); + + auto project_path_filename=project_path.filename(); + Config::get().project.debug_build_path="../debug_"; + g_assert(build->get_debug_path()==project_path/("../debug_"+project_path_filename.string())); + + Config::get().project.default_build_path="../build_"; + g_assert(build->get_default_path()==project_path/("../build_"+project_path_filename.string())); + } + { + auto project_path=tests_path/"source_clang_test_files"; + CMake cmake(project_path); + + g_assert(cmake.project_path==project_path); + + g_assert(cmake.get_executable(project_path/"build", project_path/"main.cpp")==project_path/"build"/"test"); + g_assert(cmake.get_executable(project_path/"build", project_path/"non_existing_file.cpp")==project_path/"build"/"test"); + g_assert(cmake.get_executable(project_path/"build", project_path)==project_path/"build"/"test"); + } } diff --git a/tests/source_clang_test_files/build/compile_commands.json b/tests/source_clang_test_files/build/compile_commands.json index 8c1f911..21f0088 100644 --- a/tests/source_clang_test_files/build/compile_commands.json +++ b/tests/source_clang_test_files/build/compile_commands.json @@ -1,7 +1,7 @@ [ { "directory": "build", - "command": "c++ -std=c++1y -Wall -Wextra -Wno-unused-parameter main.cpp", - "file": "main.cpp" + "command": "c++ -std=c++1y -Wall -Wextra -Wno-unused-parameter -o CMakeFiles/test.dir/main.cpp.o main.cpp", + "file": "../main.cpp" } ] \ No newline at end of file